diff --git a/ChangeLog.txt b/ChangeLog.txt index aa1b8a62b..a98e0a872 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1498,4 +1498,6 @@ at /dev/telnetN (2015-12-07). * netutils/ping: Unfinished implementation of ping/ping6 using raw sockets (2015-12-11). + * examples/module: Add a test harness for verifying NuttX kernel + modules (2015-12-12). diff --git a/examples/Kconfig b/examples/Kconfig index f7fa2c8fa..e50fa1e21 100644 --- a/examples/Kconfig +++ b/examples/Kconfig @@ -33,6 +33,7 @@ source "$APPSDIR/examples/ltdc/Kconfig" source "$APPSDIR/examples/media/Kconfig" source "$APPSDIR/examples/mm/Kconfig" source "$APPSDIR/examples/modbus/Kconfig" +source "$APPSDIR/examples/module/Kconfig" source "$APPSDIR/examples/mount/Kconfig" source "$APPSDIR/examples/mtdpart/Kconfig" source "$APPSDIR/examples/mtdrwb/Kconfig" diff --git a/examples/README.txt b/examples/README.txt index 67a3ad872..919040f24 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -738,6 +738,68 @@ examples/mm This is a simple test of the memory manager. +examples/module +^^^^^^^^^^^^^^ + + This example builds a small loadable module test case. This includes on + character driver under examples/module/drivers. This driver is built using + the relocatable ELF format and installed in a ROMFS file system. At run time, + the driver module is loaded and exercises. Requires CONFIG_MODULE. + Other configuration options: + + CONFIG_EXAMPLES_ELF_DEVMINOR - The minor device number of the ROMFS block + driver. For example, the N in /dev/ramN. Used for registering the RAM + block driver that will hold the ROMFS file system containing the ELF + executables to be tested. Default: 0 + + CONFIG_EXAMPLES_ELF_DEVPATH - The path to the ROMFS block driver device. This + must match EXAMPLES_ELF_DEVMINOR. Used for registering the RAM block driver + that will hold the ROMFS file system containing the ELF executables to be + tested. Default: "/dev/ram0" + + NOTES: + + 1. CFLAGS should be provided in CELFFLAGS. RAM and FLASH memory regions + may require long allcs. For ARM, this might be: + + CELFFLAGS = $(CFLAGS) -mlong-calls + + Similarly for C++ flags which must be provided in CXXELFFLAGS. + + 2. Your top-level nuttx/Make.defs file must also include an approproate definition, + LDELFFLAGS, to generate a relocatable ELF object. With GNU LD, this should + include '-r' and '-e '. + + LDELFFLAGS = -r -e module_initialize + + If you use GCC to link, you make also need to include '-nostdlib' or + '-nostartfiles' and '-nodefaultlibs'. + + 3. This example also requires genromfs. genromfs can be build as part of the + nuttx toolchain. Or can built from the genromfs sources that can be found + in the NuttX tools repository (genromfs-0.5.2.tar.gz). In any event, the + PATH variable must include the path to the genromfs executable. + + 4. ELF size: The ELF files in this example are, be default, quite large + because they include a lot of "build garbage". You can greatly reduce the + size of the ELF binaries are using the 'objcopy --strip-unneeded' command to + remove un-necessary information from the ELF files. + + 5. Simulator. You cannot use this example with the the NuttX simulator on + Cygwin. That is because the Cygwin GCC does not generate ELF file but + rather some Windows-native binary format. + + If you really want to do this, you can create a NuttX x86 buildroot toolchain + and use that be build the ELF executables for the ROMFS file system. + + 6. Linker scripts. You might also want to use a linker scripts to combine + sections better. An example linker script is at nuttx/sched/module/gnu-elf.ld. + That example might have to be tuned for your particular linker output to + position additional sections correctly. The GNU LD LDELFFLAGS then might + be: + + LDELFFLAGS = -r -e module_initialize -T$(TOPDIR)/sched/module/gnu-elf.ld + examples/modbus ^^^^^^^^^^^^^^^ diff --git a/examples/module/.gitignore b/examples/module/.gitignore new file mode 100644 index 000000000..4cfc495be --- /dev/null +++ b/examples/module/.gitignore @@ -0,0 +1,3 @@ +/Make.dep +/.depend +/.built diff --git a/examples/module/Kconfig b/examples/module/Kconfig new file mode 100644 index 000000000..a4f9d7802 --- /dev/null +++ b/examples/module/Kconfig @@ -0,0 +1,45 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_MODULE + bool "Module Example" + default n + ---help--- + Enable the module example + +if EXAMPLES_MODULE + +config EXAMPLES_MODULE_LIBC + bool "Link with LIBC" + default n + depends on !BUILD_KERNEL + ---help--- + Link with the C library (and also math library if it was built). + By default, all undefined symbols must be provided via a symbol + table. But if this option is selected, then each MODULE test program + will link with the SYSCALL library and will interface with the OS + system calls. You probably will NOT want this option, however, + because it will substantially increase the size of code. For + example, a separate copy of printf() would be linked with every + program greatly increasing the total code size. This option is + primarily intended only for testing. + +config EXAMPLES_MODULE_DEVMINOR + int "ROMFS Minor Device Number" + default 0 + ---help--- + The minor device number of the ROMFS block. For example, the N in /dev/ramN. + Used for registering the RAM block driver that will hold the ROMFS file system + containing the MODULE executables to be tested. Default: 0 + +config EXAMPLES_MODULE_DEVPATH + string "ROMFS Device Path" + default "/dev/ram0" + ---help--- + The path to the ROMFS block driver device. This must match EXAMPLES_MODULE_DEVMINOR. + Used for registering the RAM block driver that will hold the ROMFS file system + containing the MODULE executables to be tested. Default: "/dev/ram0" + +endif diff --git a/examples/module/Make.defs b/examples/module/Make.defs new file mode 100644 index 000000000..0a012432d --- /dev/null +++ b/examples/module/Make.defs @@ -0,0 +1,38 @@ +############################################################################ +# apps/examples/module/Make.defs +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifeq ($(CONFIG_EXAMPLES_MODULE),y) +CONFIGURED_APPS += examples/module +endif diff --git a/examples/module/Makefile b/examples/module/Makefile new file mode 100644 index 000000000..f869adf30 --- /dev/null +++ b/examples/module/Makefile @@ -0,0 +1,151 @@ +############################################################################ +# apps/examples/module/Makefile +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Module example built-in application info + +APPNAME = module +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Module Example + +ASRCS = +CSRCS = symtab.c +MAINSRC = module_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +CONFIG_XYZ_PROGNAME ?= discover$(EXEEXT) +PROGNAME = $(CONFIG_XYZ_PROGNAME) + +ROOTDEPPATH = --dep-path . --dep-path drivers + +# Build targets + +VPATH = drivers + +all: .built +.PHONY: really_build clean_drivers clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +# This is a little messy. The build is broken into two pieces: (1) the +# drivers/ subdir build that auto-generates several files, and (2) the real +# build. This is done because we need a fresh build context after auto- +# generating the source files. + +really_build: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +.built: + @$(MAKE) -C drivers TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + @$(MAKE) TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" really_build + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +# We can't make dependencies in this directory because the required +# header files may not yet exist. + +.depend: + @touch $@ + +depend: .depend + +clean_drivers: + @$(MAKE) -C drivers TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) clean + +clean: clean_drivers + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/examples/module/drivers/.gitignore b/examples/module/drivers/.gitignore new file mode 100644 index 000000000..500f6638f --- /dev/null +++ b/examples/module/drivers/.gitignore @@ -0,0 +1,6 @@ +/romfs +/romfs.h +/romfs.img +/symtab.c +/varlist.tmp + diff --git a/examples/module/drivers/Makefile b/examples/module/drivers/Makefile new file mode 100644 index 000000000..f2f6f93b1 --- /dev/null +++ b/examples/module/drivers/Makefile @@ -0,0 +1,98 @@ +############################################################################ +# apps/examples/module/drivers/Makefile +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ALL_SUBDIRS = chardev +BUILD_SUBDIRS = chardev + +MODULE_DIR = $(APPDIR)/examples/module +DRIVER_DIR = $(MODULE_DIR)/drivers +ROMFS_DIR = $(DRIVER_DIR)/romfs +ROMFS_IMG = $(DRIVER_DIR)/romfs.img +ROMFS_HDR = $(DRIVER_DIR)/romfs.h +SYMTAB_SRC = $(DRIVER_DIR)/symtab.c + +define DIR_template +$(1)_$(2): + $(Q) $(MAKE) -C $(1) $(3) TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" ROMFS_DIR="$(ROMFS_DIR)" CROSSDEV=$(CROSSDEV) +endef + +all: $(ROMFS_HDR) $(DIRLIST_HDR) $(SYMTAB_SRC) +.PHONY: all build clean install populate + +$(foreach DIR, $(BUILD_SUBDIRS), $(eval $(call DIR_template,$(DIR),build, all))) +$(foreach DIR, $(ALL_SUBDIRS), $(eval $(call DIR_template,$(DIR),clean,clean))) +$(foreach DIR, $(BUILD_SUBDIRS), $(eval $(call DIR_template,$(DIR),install,install))) + +# Build program(s) in each sud-directory + +build: $(foreach DIR, $(BUILD_SUBDIRS), $(DIR)_build) + +# Install each program in the romfs directory + +install: $(foreach DIR, $(BUILD_SUBDIRS), $(DIR)_install) + +# Create the romfs directory + +$(ROMFS_DIR): + $(Q) mkdir $(ROMFS_DIR) + +# Populate the romfs directory + +populate: $(ROMFS_DIR) build install + +# Create the romfs.img file from the populated romfs directory + +$(ROMFS_IMG): populate + $(Q) genromfs -f $@ -d $(ROMFS_DIR) -V "MODULETEST" + +# Create the romfs.h header file from the romfs.img file + +$(ROMFS_HDR) : $(ROMFS_IMG) + $(Q) (cd $(DRIVER_DIR); xxd -i romfs.img | sed -e "s/^unsigned/static const unsigned/g" >$@) + +# Create the exported symbol table + +$(SYMTAB_SRC): build + $(Q) $(DRIVER_DIR)/mksymtab.sh $(ROMFS_DIR) >$@ + +# Clean each subdirectory + +clean: $(foreach DIR, $(ALL_SUBDIRS), $(DIR)_clean) + $(Q) rm -f $(ROMFS_HDR) $(DIRLIST_HDR) $(ROMFS_IMG) $(SYMTAB_SRC) + $(Q) rm -rf $(ROMFS_DIR) diff --git a/examples/module/drivers/chardev/.gitignore b/examples/module/drivers/chardev/.gitignore new file mode 100644 index 000000000..9a80a2252 --- /dev/null +++ b/examples/module/drivers/chardev/.gitignore @@ -0,0 +1,2 @@ +hello + diff --git a/examples/module/drivers/chardev/Makefile b/examples/module/drivers/chardev/Makefile new file mode 100644 index 000000000..adeb983dc --- /dev/null +++ b/examples/module/drivers/chardev/Makefile @@ -0,0 +1,81 @@ +############################################################################ +# examples/module/drivers/chardev/Makefile +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +NUTTXLIB = "${shell cygpath -w $(TOPDIR)$(DELIM)lib}" +else +NUTTXLIB = "$(TOPDIR)$(DELIM)lib" +endif + +KDEFINE = ${shell $(TOPDIR)/tools/define.sh "$(CC)" __KERNEL__} +CFLAGS += $(KDEFINE) + +ifeq ($(CONFIG_EXAMPLES_MODULE_LIBC),y) +LDMODULEFLAGS += -Bstatic +LDLIBPATH += -L $(NUTTXLIB) +endif + +ifeq ($(CONFIG_EXAMPLES_MODULE_LIBC),y) +ifeq ($(CONFIG_BUILD_PROTECTED),y) +LDLIBS += -luc +else +LDLIBS += -lc +endif +endif + +BIN = chardev + +SRCS = $(BIN).c +OBJS = $(SRCS:.c=$(OBJEXT)) + +all: $(BIN) + +$(OBJS): %$(OBJEXT): %.c + @echo "CC: $<" + $(Q) $(CC) -c $(CMODULEFLAGS) $< -o $@ + +$(BIN): $(OBJS) + @echo "LD: $<" + $(Q) $(LD) $(LDMODULEFLAGS) $(LDLIBPATH) -o $@ $(ARCHCRT0OBJ) $^ $(LDLIBS) + +clean: + $(call DMODULEILE, $(BIN)) + $(call CLEAN) + +install: + $(Q) mkdir -p $(ROMFS_DIR) + $(Q) install $(BIN) $(ROMFS_DIR)/$(BIN) diff --git a/examples/module/drivers/chardev/chardev b/examples/module/drivers/chardev/chardev new file mode 100644 index 000000000..ccf22f1c5 Binary files /dev/null and b/examples/module/drivers/chardev/chardev differ diff --git a/examples/module/drivers/chardev/chardev.c b/examples/module/drivers/chardev/chardev.c new file mode 100644 index 000000000..15fb38ec3 --- /dev/null +++ b/examples/module/drivers/chardev/chardev.c @@ -0,0 +1,142 @@ +/**************************************************************************** + * apps/examples/module/drivers/chardev/chardev.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private data + ****************************************************************************/ + +static const char g_read_string[] = "Hi there, apps/examples/module test\n"; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ssize_t chardev_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t chardev_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations chardev_fops = +{ + 0, /* open */ + 0, /* close */ + chardev_read, /* read */ + chardev_write, /* write */ + 0, /* seek */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , 0 /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , 0 /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: chardev_read + ****************************************************************************/ + +static ssize_t chardev_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + size_t rdlen = strlen(g_read_string); + ssize_t ret = MIN(len, rdlen); + + memcpy(buffer, g_read_string, ret); + + syslog(LOG_INFO, "chardev_read: Returning %d bytes\n", (int)ret); + lib_dumpbuffer("chardev_read: Returning", (FAR const uint8_t *)buffer, ret); + return ret; +} + +/**************************************************************************** + * Name: chardev_write + ****************************************************************************/ + +static ssize_t chardev_write(FAR struct file *filep, FAR const char *buffer, + size_t len) +{ + syslog(LOG_INFO, "chardev_write: Writing %d bytes\n", (int)len); + lib_dumpbuffer("chardev_write: Writing", (FAR const uint8_t *)buffer, len); + return len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: module_initialize + * + * Description: + * Register /dev/zero + * + ****************************************************************************/ + +void module_initialize(void) +{ + (void)register_driver("/dev/chardev", &chardev_fops, 0666, NULL); +} diff --git a/examples/module/drivers/mksymtab.sh b/examples/module/drivers/mksymtab.sh new file mode 100644 index 000000000..bb0ea5937 --- /dev/null +++ b/examples/module/drivers/mksymtab.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +usage="Usage: $0 " + +# Check for the required ROMFS directory path + +dir=$1 +if [ -z "$dir" ]; then + echo "ERROR: Missing " + echo "" + echo $usage + exit 1 +fi + +if [ ! -d "$dir" ]; then + echo "ERROR: Directory $dir does not exist" + echo "" + echo $usage + exit 1 +fi + +# Extract all of the undefined symbols from the MODULE files and create a +# list of sorted, unique undefined variable names. + +varlist=`find ${dir} -executable -type f | xargs nm | fgrep ' U ' | sed -e "s/^[ ]*//g" | cut -d' ' -f2 | sort | uniq` + +# Now output the symbol table as a structure in a C source file. All +# undefined symbols are declared as void* types. If the toolchain does +# any kind of checking for function vs. data objects, then this could +# faile + +echo "#include " +echo "#include " +echo "" + +for var in $varlist; do + echo "extern void *${var};" +done + +echo "" +echo "const struct symtab_s exports[] = " +echo "{" + +for var in $varlist; do + echo " {\"${var}\", &${var}}," +done + +echo "};" +echo "" +echo "const int nexports = sizeof(exports) / sizeof(struct symtab_s);" + diff --git a/examples/module/module_main.c b/examples/module/module_main.c new file mode 100644 index 000000000..d443b1019 --- /dev/null +++ b/examples/module/module_main.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * examples/module/module_main.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "drivers/romfs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Check configuration. This is not all of the configuration settings that + * are required -- only the more obvious. + */ + +#if CONFIG_NFILE_DESCRIPTORS < 1 +# error "You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file" +#endif + +#ifndef CONFIG_MODULE +# error "You must select CONFIG_MODULE in your configuration file" +#endif + +#ifndef CONFIG_FS_ROMFS +# error "You must select CONFIG_FS_ROMFS in your configuration file" +#endif + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# error "You must not disable mountpoints via CONFIG_DISABLE_MOUNTPOINT in your configuration file" +#endif + +/* Describe the ROMFS file system */ + +#define SECTORSIZE 64 +#define NSECTORS(b) (((b)+SECTORSIZE-1)/SECTORSIZE) +#define MOUNTPT "/mnt/romfs" + +#ifndef CONFIG_EXAMPLES_MODULE_DEVMINOR +# define CONFIG_EXAMPLES_MODULE_DEVMINOR 0 +#endif + +#ifndef CONFIG_EXAMPLES_MODULE_DEVPATH +# define CONFIG_EXAMPLES_MODULE_DEVPATH "/dev/ram0" +#endif + +/**************************************************************************** + * Private data + ****************************************************************************/ + +static const char g_write_string[] = "Hi there, installed driver\n"; + +/**************************************************************************** + * Symbols from Auto-Generated Code + ****************************************************************************/ + +extern const struct symtab_s exports[]; +extern const int nexports; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: module_main + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int module_main(int argc, char *argv[]) +#endif +{ + struct module_s module; + char buffer[128]; + ssize_t nbytes; + int ret; + int fd; + + /* Create a ROM disk for the ROMFS filesystem */ + + printf("Registering romdisk at /dev/ram%d\n", CONFIG_EXAMPLES_MODULE_DEVMINOR); + ret = romdisk_register(CONFIG_EXAMPLES_MODULE_DEVMINOR, (FAR uint8_t *)romfs_img, + NSECTORS(romfs_img_len), SECTORSIZE); + if (ret < 0) + { + fprintf(stderr, "ERROR: romdisk_register failed: %d\n", ret); + exit(EXIT_FAILURE); + } + + /* Mount the file system */ + + printf("Mounting ROMFS filesystem at target=%s with source=%s\n", + MOUNTPT, CONFIG_EXAMPLES_MODULE_DEVPATH); + + ret = mount(CONFIG_EXAMPLES_MODULE_DEVPATH, MOUNTPT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + fprintf(stderr, "ERROR: mount(%s,%s,romfs) failed: %s\n", + CONFIG_EXAMPLES_MODULE_DEVPATH, MOUNTPT, errno); + exit(EXIT_FAILURE); + } + + /* Install the character driver */ + + memset(&module, 0, sizeof(struct module_s)); + module.filename = MOUNTPT "/chardev"; + module.exports = exports; + module.nexports = nexports; + + ret = insmod(&module); + if (ret < 0) + { + fprintf(stderr, "ERROR: insmod failed: %d\n", ret); + exit(EXIT_FAILURE); + } + + /* Open the installed character driver */ + + fd = open("/dev/chardev", O_RDWR); + if (fd < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: Failed to open /dev/chardev: %d\n", errcode); + exit(EXIT_FAILURE); + } + + /* Read from the character driver */ + + nbytes = read(fd, buffer, 128); + if (nbytes < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: Read from /dev/chardev failed: %d\n", errcode); + close(fd); + exit(EXIT_FAILURE); + } + + printf("Read %d bytes: %d\n", (int)nbytes); + lib_dumpbuffer("Bytes read", (FAR const uint8_t *)buffer, nbytes); + + /* Write to the character driver */ + + nbytes = write(fd, g_write_string, strlen(g_write_string)); + if (nbytes < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: Write to /dev/chardev failed: %d\n", errcode); + close(fd); + exit(EXIT_FAILURE); + } + + printf("Wrote %d bytes: %d\n", (int)nbytes); + lib_dumpbuffer("Bytes read", (FAR const uint8_t *)g_write_string, nbytes); + + close(fd); + return EXIT_SUCCESS; +}