From 795ddd7e80183ba903eddbe4e933fbf4d981e1aa Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 12 Dec 2015 17:42:25 -0600 Subject: [PATCH] OS modules: Add basic procfs support. A module registry that will eventually be used to support lsmod --- ChangeLog | 5 +- configs | 2 +- fs/procfs/Kconfig | 7 + fs/procfs/fs_procfs.c | 5 + include/nuttx/module.h | 81 ++++++--- net/procfs/procfs.h | 4 - sched/module/Make.defs | 12 +- sched/module/mod_insmod.c | 151 +++++++++++------ sched/module/mod_procfs.c | 320 +++++++++++++++++++++++++++++++++++ sched/module/mod_registry.c | 247 +++++++++++++++++++++++++++ sched/module/mod_rmmod.c | 55 +++++- sched/module/module.h | 104 ++++++++++++ syscall/syscall.csv | 4 +- syscall/syscall_lookup.h | 2 +- syscall/syscall_stublookup.c | 3 +- 15 files changed, 910 insertions(+), 92 deletions(-) create mode 100644 sched/module/mod_procfs.c create mode 100644 sched/module/mod_registry.c diff --git a/ChangeLog b/ChangeLog index b79a3add18..2595cd0f84 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11237,5 +11237,6 @@ just the ELF module support with name changes (2015-12-10). * configs/samv71-xult/module: Add configuration for testing OS modules (2015-12-12). - * sched/module: Add an implementation of rmmod() (2015-11-12). - + * sched/module: Add an implementation of rmmod() (2015-12-12). + * sched/module and fs/procfs: Add some basic module procfs support + (2015-12-12), diff --git a/configs b/configs index 050dca048e..4a56b7ba64 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit 050dca048e92cec8f8d04075553d75025a31f2d4 +Subproject commit 4a56b7ba643607bbfadaef3628a7322b642ffa3f diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig index 39d5011842..7f3620f9c8 100644 --- a/fs/procfs/Kconfig +++ b/fs/procfs/Kconfig @@ -32,6 +32,13 @@ config FS_PROCFS_EXCLUDE_PROCESS This will reduce code space, but then giving access to process info was kinda the whole point of procfs, but hey, whatever. +config FS_PROCFS_EXCLUDE_MODULE + bool "Exclude module information" + depends on MODULE + default n + ---help--- + Causes the module information to be excluded from the procfs system. + config FS_PROCFS_EXCLUDE_UPTIME bool "Exclude uptime" default n diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index c9032560e6..8da8842fb4 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -77,6 +77,7 @@ extern const struct procfs_operations proc_operations; extern const struct procfs_operations cpuload_operations; +extern const struct procfs_operations module_operations; extern const struct procfs_operations uptime_operations; /* This is not good. These are implemented in other sub-systems. Having to @@ -119,6 +120,10 @@ static const struct procfs_entry_s g_procfs_entries[] = { "cpuload", &cpuload_operations }, #endif +#if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + { "modules", &module_operations }, +#endif + #if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) //{ "fs/smartfs", &smartfs_procfsoperations }, { "fs/smartfs**", &smartfs_procfsoperations }, diff --git a/include/nuttx/module.h b/include/nuttx/module.h index be8859ec63..8b9c2cfc8e 100644 --- a/include/nuttx/module.h +++ b/include/nuttx/module.h @@ -60,10 +60,6 @@ # define CONFIG_MODULE_ALIGN_LOG2 2 #endif -#ifndef CONFIG_MODULE_STACKSIZE -# define CONFIG_MODULE_STACKSIZE 2048 -#endif - #ifndef CONFIG_MODULE_BUFFERSIZE # define CONFIG_MODULE_BUFFERSIZE 128 #endif @@ -72,6 +68,8 @@ # define CONFIG_MODULE_BUFFERINCR 32 #endif +#define MODULENAME_MAX 16 + /**************************************************************************** * Public Types ****************************************************************************/ @@ -114,25 +112,12 @@ typedef CODE int (*mod_uninitializer_t)(FAR void *arg); typedef CODE int (*mod_initializer_t)(mod_uninitializer_t *uninitializer, FAR void **arg); -/* This describes the file to be loaded. */ +#ifdef __KERNEL__ +/* This is the type of the callback function used by mod_registry_foreach() */ -struct symtab_s; -struct module_s -{ - /* Information provided to insmod by the caller */ - - FAR const char *filename; /* Full path to the binary to be loaded */ - FAR const struct symtab_s *exports; /* Table of exported symbols */ - int nexports; /* The number of symbols in exports[] */ - - /* Information provided from insmod (if successful) describing the - * resources used by the loaded module. - */ - - mod_uninitializer_t uninitializer; /* Module uninitializer function */ - FAR void *arg; /* Uninitializer argument */ - FAR void *alloc; /* Allocated kernel memory */ -}; +struct module_s; +typedef CODE int (*mod_callback_t)(FAR struct module_s *modp, FAR void *arg); +#endif /**************************************************************************** * Public Function Prototypes @@ -154,9 +139,22 @@ extern "C" * Verify that the file is an ELF module binary and, if so, load the * module into kernel memory and initialize it for use. * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modulename - The name that can be used to refer to the module after + * it has been loaded. + * exports - Table of exported symbols + * nexports - The number of symbols in exports[] + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * ****************************************************************************/ -int insmod(FAR struct module_s *modp); +int insmod(FAR const char *filename, FAR const char *modulename, + FAR const struct symtab_s *exports, int nexports); /**************************************************************************** * Name: rmmod @@ -164,9 +162,44 @@ int insmod(FAR struct module_s *modp); * Description: * Remove a previously installed module from memory. * + * Input Parameters: + * + * modulename - The module name. This is the name module name that was + * provided to insmod when the module was loaded. + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * ****************************************************************************/ -int rmmod(FAR struct module_s *modp); +int rmmod(FAR const char *modulename); + +/**************************************************************************** + * Name: mod_registry_foreach + * + * Description: + * Visit each module in the registry. This is an internal OS interface and + * not available for use by applications. + * + * Input Parameters: + * callback - This callback function was be called for each entry in the + * registry. + * arg - This opaque argument will be passed to the callback function. + * + * Returned Value: + * This function normally returns zero (OK). If, however, any callback + * function returns a non-zero value, the traversal will be terminated and + * that non-zero value will be returned. + * + * Assumptions: + * The caller does NOT hold the lock on the module registry. + * + ****************************************************************************/ + +#ifdef __KERNEL__ +int mod_registry_foreach(mod_callback_t callback, FAR void *arg); +#endif #undef EXTERN #if defined(__cplusplus) diff --git a/net/procfs/procfs.h b/net/procfs/procfs.h index feba657a0d..889f350725 100644 --- a/net/procfs/procfs.h +++ b/net/procfs/procfs.h @@ -60,10 +60,6 @@ * Public Type Definitions ****************************************************************************/ -/* This enumeration identifies all of the thread attributes that can be - * accessed via the procfs file system. - */ - /* This structure describes one open "file" */ struct net_driver_s; /* Forward reference */ diff --git a/sched/module/Make.defs b/sched/module/Make.defs index fbe5fffca6..ec60760c8a 100644 --- a/sched/module/Make.defs +++ b/sched/module/Make.defs @@ -42,8 +42,16 @@ CSRCS += mod_insmod.c mod_rmmod.c # loadable module library CSRCS += mod_bind.c mod_init.c mod_iobuffer.c mod_load.c mod_read.c -CSRCS += mod_sections.c mod_symbols.c mod_uninit.c mod_unload.c -CSRCS += mod_verify.c +CSRCS += mod_registry.c mod_sections.c mod_symbols.c mod_uninit.c +CSRCS += mod_unload.c mod_verify.c + +# procfs support + +ifeq ($(CONFIG_FS_PROCFS),y) +ifneq ($(CONFIG_FS_PROCFS_EXCLUDE_MODULE),y) +CSRCS += mod_procfs.c +endif +endif # Hook the module subdirectory into the build diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index e27cfe3848..82c3e591dc 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -47,6 +47,7 @@ #include #include +#include #include #include "module/module.h" @@ -66,7 +67,7 @@ #endif #ifdef CONFIG_MODULE_DUMPBUFFER -# define mod_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n) +# define mod_dumpbuffer(m,b,n) svdbgdumpbuffer(m,b,n) #else # define mod_dumpbuffer(m,b,n) #endif @@ -88,50 +89,50 @@ static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) { int i; - bdbg("LOAD_INFO:\n"); - bdbg(" textalloc: %08lx\n", (long)loadinfo->textalloc); - bdbg(" datastart: %08lx\n", (long)loadinfo->datastart); - bdbg(" textsize: %ld\n", (long)loadinfo->textsize); - bdbg(" datasize: %ld\n", (long)loadinfo->datasize); - bdbg(" filelen: %ld\n", (long)loadinfo->filelen); - bdbg(" filfd: %d\n", loadinfo->filfd); - bdbg(" symtabidx: %d\n", loadinfo->symtabidx); - bdbg(" strtabidx: %d\n", loadinfo->strtabidx); + sdbg("LOAD_INFO:\n"); + sdbg(" textalloc: %08lx\n", (long)loadinfo->textalloc); + sdbg(" datastart: %08lx\n", (long)loadinfo->datastart); + sdbg(" textsize: %ld\n", (long)loadinfo->textsize); + sdbg(" datasize: %ld\n", (long)loadinfo->datasize); + sdbg(" filelen: %ld\n", (long)loadinfo->filelen); + sdbg(" filfd: %d\n", loadinfo->filfd); + sdbg(" symtabidx: %d\n", loadinfo->symtabidx); + sdbg(" strtabidx: %d\n", loadinfo->strtabidx); - bdbg("ELF Header:\n"); - bdbg(" e_ident: %02x %02x %02x %02x\n", + sdbg("ELF Header:\n"); + sdbg(" e_ident: %02x %02x %02x %02x\n", loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); - bdbg(" e_type: %04x\n", loadinfo->ehdr.e_type); - bdbg(" e_machine: %04x\n", loadinfo->ehdr.e_machine); - bdbg(" e_version: %08x\n", loadinfo->ehdr.e_version); - bdbg(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); - bdbg(" e_phoff: %d\n", loadinfo->ehdr.e_phoff); - bdbg(" e_shoff: %d\n", loadinfo->ehdr.e_shoff); - bdbg(" e_flags: %08x\n" , loadinfo->ehdr.e_flags); - bdbg(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); - bdbg(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); - bdbg(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); - bdbg(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); - bdbg(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); - bdbg(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); + sdbg(" e_type: %04x\n", loadinfo->ehdr.e_type); + sdbg(" e_machine: %04x\n", loadinfo->ehdr.e_machine); + sdbg(" e_version: %08x\n", loadinfo->ehdr.e_version); + sdbg(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); + sdbg(" e_phoff: %d\n", loadinfo->ehdr.e_phoff); + sdbg(" e_shoff: %d\n", loadinfo->ehdr.e_shoff); + sdbg(" e_flags: %08x\n" , loadinfo->ehdr.e_flags); + sdbg(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); + sdbg(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); + sdbg(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); + sdbg(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); + sdbg(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); + sdbg(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) { for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf32_Shdr *shdr = &loadinfo->shdr[i]; - bdbg("Sections %d:\n", i); - bdbg(" sh_name: %08x\n", shdr->sh_name); - bdbg(" sh_type: %08x\n", shdr->sh_type); - bdbg(" sh_flags: %08x\n", shdr->sh_flags); - bdbg(" sh_addr: %08x\n", shdr->sh_addr); - bdbg(" sh_offset: %d\n", shdr->sh_offset); - bdbg(" sh_size: %d\n", shdr->sh_size); - bdbg(" sh_link: %d\n", shdr->sh_link); - bdbg(" sh_info: %d\n", shdr->sh_info); - bdbg(" sh_addralign: %d\n", shdr->sh_addralign); - bdbg(" sh_entsize: %d\n", shdr->sh_entsize); + sdbg("Sections %d:\n", i); + sdbg(" sh_name: %08x\n", shdr->sh_name); + sdbg(" sh_type: %08x\n", shdr->sh_type); + sdbg(" sh_flags: %08x\n", shdr->sh_flags); + sdbg(" sh_addr: %08x\n", shdr->sh_addr); + sdbg(" sh_offset: %d\n", shdr->sh_offset); + sdbg(" sh_size: %d\n", shdr->sh_size); + sdbg(" sh_link: %d\n", shdr->sh_link); + sdbg(" sh_info: %d\n", shdr->sh_info); + sdbg(" sh_addralign: %d\n", shdr->sh_addralign); + sdbg(" sh_entsize: %d\n", shdr->sh_entsize); } } } @@ -165,49 +166,90 @@ static void mod_dumpinitializer(mod_initializer_t initializer, * Verify that the file is an ELF module binary and, if so, load the * module into kernel memory and initialize it for use. * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modulename - The name that can be used to refer to the module after + * it has been loaded. + * exports - Table of exported symbols + * nexports - The number of symbols in exports[] + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * ****************************************************************************/ -int insmod(FAR struct module_s *modp) +int insmod(FAR const char *filename, FAR const char *modulename, + FAR const struct symtab_s *exports, int nexports) { struct mod_loadinfo_s loadinfo; + FAR struct module_s *modp; mod_initializer_t initializer; int ret; - DEBUGASSERT(modp != NULL && modp->filename != NULL); - bvdbg("Loading file: %s\n", modp->filename); + DEBUGASSERT(filename != NULL && modulename != NULL); + svdbg("Loading file: %s\n", filename); + + /* Get exclusive access to the module registry */ + + mod_registry_lock(); + + /* Check if this module is already installed */ + + if (mod_registry_find(modulename) != NULL) + { + mod_registry_unlock(); + ret = -EEXIST; + goto errout_with_lock; + } /* Initialize the ELF library to load the program binary. */ - ret = mod_initialize(modp->filename, &loadinfo); + ret = mod_initialize(filename, &loadinfo); mod_dumploadinfo(&loadinfo); if (ret != 0) { - bdbg("Failed to initialize for load of ELF program: %d\n", ret); - goto errout; + sdbg("ERROR: Failed to initialize to load module: %d\n", ret); + goto errout_with_lock; } + /* Allocate a module registry entry to hold the module data */ + + modp = (FAR struct module_s *)kmm_zalloc(sizeof(struct module_s)); + if (ret != 0) + { + sdbg("Failed to initialize for load of ELF program: %d\n", ret); + goto errout_with_loadinfo; + } + + /* Save the module name in the registry entry */ + + strncpy(modp->modulename, modulename, MODULENAME_MAX); + /* Load the program binary */ ret = mod_load(&loadinfo); mod_dumploadinfo(&loadinfo); if (ret != 0) { - bdbg("Failed to load ELF program binary: %d\n", ret); - goto errout_with_init; + sdbg("Failed to load ELF program binary: %d\n", ret); + goto errout_with_registry_entry; } /* Bind the program to the exported symbol table */ - ret = mod_bind(&loadinfo, modp->exports, modp->nexports); + ret = mod_bind(&loadinfo, exports, nexports); if (ret != 0) { - bdbg("Failed to bind symbols program binary: %d\n", ret); + sdbg("Failed to bind symbols program binary: %d\n", ret); goto errout_with_load; } /* Return the load information */ modp->alloc = (FAR void *)loadinfo.textalloc; + modp->size = loadinfo.textsize + loadinfo.datasize; /* Get the module initializer entry point */ @@ -219,19 +261,28 @@ int insmod(FAR struct module_s *modp) ret = initializer(&modp->uninitializer, &modp->arg); if (ret < 0) { - bdbg("Failed to initialize the module: %d\n", ret); + sdbg("Failed to initialize the module: %d\n", ret); goto errout_with_load; } + /* Add the new module entry to the registry */ + + mod_registry_add(modp); + mod_uninitialize(&loadinfo); + mod_registry_unlock(); return OK; errout_with_load: mod_unload(&loadinfo); -errout_with_init: +errout_with_registry_entry: + kmm_free(modp); +errout_with_loadinfo: mod_uninitialize(&loadinfo); -errout: - return ret; +errout_with_lock: + mod_registry_unlock(); + set_errno(-ret); + return ERROR; } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_procfs.c b/sched/module/mod_procfs.c new file mode 100644 index 0000000000..dca2db91b5 --- /dev/null +++ b/sched/module/mod_procfs.c @@ -0,0 +1,320 @@ +/**************************************************************************** + * sched/module/mod_procfs.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 "module.h" + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \ + !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define MOD_LINELEN 64 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one open "file" */ + +struct modprocfs_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + + /* Read helpers */ + + FAR char *buffer; /* User buffer pointer */ + size_t buflen; /* Size of the user buffer */ + size_t remaining; /* Space remaining in user buffer */ + size_t totalsize; /* Total size returned by read() */ + off_t offset; /* Offset skip on output */ + + /* Line buffer */ + + uint8_t lineno; /* Line number */ + uint8_t linesize; /* Number of valid characters in line[] */ + char line[MOD_LINELEN]; /* Pre-allocated buffer for formatted lines */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* File system methods */ + +static int modprocfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int modprocfs_close(FAR struct file *filep); +static ssize_t modprocfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int modprocfs_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int modprocfs_stat(FAR const char *relpath, FAR struct stat *buf); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* See include/nutts/fs/procfs.h + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct procfs_operations module_operations = +{ + modprocfs_open, /* open */ + modprocfs_close, /* close */ + modprocfs_read, /* read */ + NULL, /* write */ + modprocfs_dup, /* dup */ + + NULL, /* opendir */ + NULL, /* closedir */ + NULL, /* readdir */ + NULL, /* rewinddir */ + + modprocfs_stat /* stat */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modprocfs_callback + ****************************************************************************/ + +static int modprocfs_callback(FAR struct module_s *modp, FAR void *arg) +{ + FAR struct modprocfs_file_s *priv; + size_t linesize; + size_t copysize; + + DEBUGASSERT(modp != NULL && arg != NULL); + priv = (FAR struct modprocfs_file_s *)arg; + + linesize = snprintf(priv->line, MOD_LINELEN, "%s,%p,%p,%p,%lu\n", + modp->modulename, modp->uninitializer, modp->arg, + modp->alloc, (unsigned long)modp->size); + copysize = procfs_memcpy(priv->line, linesize, priv->buffer, + priv->remaining, &priv->offset); + priv->totalsize += copysize; + priv->buffer += copysize; + priv->remaining -= copysize; + + return (priv->totalsize >= priv->buflen) ? 1 : 0; +} + +/**************************************************************************** + * Name: modprocfs_open + ****************************************************************************/ + +static int modprocfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct modprocfs_file_s *priv; + + fvdbg("Open '%s'\n", relpath); + + /* PROCFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + * + * REVISIT: Write-able proc files could be quite useful. + */ + + if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)) + { + fdbg("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + /* Allocate the open file structure */ + + priv = (FAR struct modprocfs_file_s *)kmm_zalloc(sizeof(struct modprocfs_file_s)); + if (!priv) + { + fdbg("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* Save the open file structure as the open-specific state in + * filep->f_priv. + */ + + filep->f_priv = (FAR void *)priv; + return OK; +} + +/**************************************************************************** + * Name: modprocfs_close + ****************************************************************************/ + +static int modprocfs_close(FAR struct file *filep) +{ + FAR struct modprocfs_file_s *priv; + + /* Recover our private data from the struct file instance */ + + priv = (FAR struct modprocfs_file_s *)filep->f_priv; + DEBUGASSERT(priv); + + /* Release the file attributes structure */ + + kmm_free(priv); + filep->f_priv = NULL; + return OK; +} + +/**************************************************************************** + * Name: modprocfs_read + ****************************************************************************/ + +static ssize_t modprocfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct modprocfs_file_s *priv; + int ret; + + fvdbg("buffer=%p buflen=%lu\n", buffer, (unsigned long)buflen); + + /* Recover our private data from the struct file instance */ + + priv = (FAR struct modprocfs_file_s *)filep->f_priv; + DEBUGASSERT(priv); + + /* Traverse all installed modules */ + + priv->remaining = buflen; + priv->totalsize = 0; + priv->buffer = buffer; + priv->buflen = buflen; + priv->offset = filep->f_pos; + + ret = mod_registry_foreach(modprocfs_callback, priv); + if (ret >= 0) + { + filep->f_pos += priv->totalsize; + return priv->totalsize; + } + + return ret; +} + +/**************************************************************************** + * Name: modprocfs_dup + * + * Description: + * Duplicate open file data in the new file structure. + * + ****************************************************************************/ + +static int modprocfs_dup(FAR const struct file *oldp, FAR struct file *newp) +{ + FAR struct modprocfs_file_s *oldpriv; + FAR struct modprocfs_file_s *newpriv; + + fvdbg("Dup %p->%p\n", oldp, newp); + + /* Recover our private data from the old struct file instance */ + + oldpriv = (FAR struct modprocfs_file_s *)oldp->f_priv; + DEBUGASSERT(oldpriv); + + /* Allocate a new container to hold the task and attribute selection */ + + newpriv = (FAR struct modprocfs_file_s *)kmm_zalloc(sizeof(struct modprocfs_file_s)); + if (!newpriv) + { + fdbg("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* The copy the file attribtes from the old attributes to the new */ + + memcpy(newpriv, oldpriv, sizeof(struct modprocfs_file_s)); + + /* Save the new attributes in the new file structure */ + + newp->f_priv = (FAR void *)newpriv; + return OK; +} + +/**************************************************************************** + * Name: modprocfs_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int modprocfs_stat(FAR const char *relpath, FAR struct stat *buf) +{ + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS && + * !CONFIG_FS_PROCFS_EXCLUDE_MODULE */ diff --git a/sched/module/mod_registry.c b/sched/module/mod_registry.c new file mode 100644 index 0000000000..7df1168b35 --- /dev/null +++ b/sched/module/mod_registry.c @@ -0,0 +1,247 @@ +/**************************************************************************** + * sched/module/mod_registry.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 "module.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static sem_t g_mod_lock = SEM_INITIALIZER(1); +static FAR struct module_s *g_mod_registry; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mod_registry_lock + * + * Description: + * Get exclusive access to the module registry. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_registry_lock(void) +{ + while (sem_post(&g_mod_lock) < 0) + { + DEBUGASSERT(errno == EINTR); + } +} + +/**************************************************************************** + * Name: mod_registry_unlock + * + * Description: + * Relinquish the lock on the module registry + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_registry_unlock(void) +{ + sem_post(&g_mod_lock); +} + +/**************************************************************************** + * Name: mod_registry_add + * + * Description: + * Add a new entry to the module registry. + * + * Input Parameters: + * modp - The module data structure to be registered. + * + * Returned Value: + * None + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +void mod_registry_add(FAR struct module_s *modp) +{ + DEBUGASSERT(modp); + modp->flink = g_mod_registry; + g_mod_registry = modp; +} + +/**************************************************************************** + * Name: mod_registry_del + * + * Description: + * Remove a module entry from the registry + * + * Input Parameters: + * modp - The registry entry to be removed. + * + * Returned Value: + * Zero (OK) is returned if the registry entry was deleted. Otherwise, + * a negated errno value is returned. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +int mod_registry_del(FAR struct module_s *modp) +{ + FAR struct module_s *prev; + FAR struct module_s *curr; + + for (prev = NULL, curr = g_mod_registry; + curr != NULL && curr != modp; + prev = curr, curr = curr->flink); + + if (curr == NULL) + { + sdbg("ERROR: Could not find module entry\n"); + return -ENOENT; + } + + if (prev == NULL) + { + g_mod_registry = modp->flink; + } + else + { + prev->flink = modp->flink; + } + + modp->flink = NULL; + return OK; +} + +/**************************************************************************** + * Name: mod_registry_find + * + * Description: + * Find an entry in the module registry using the name of the module. + * + * Input Parameters: + * modulename - The name of the module to be found + * + * Returned Value: + * If the registry entry is found, a pointer to the module entry is + * returned. NULL is returned if the they entry is not found. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +FAR struct module_s *mod_registry_find(FAR const char *modulename) +{ + FAR struct module_s *modp; + + for (modp = g_mod_registry; + modp != NULL && strncmp(modp->modulename, modulename, MODULENAME_MAX) != 0; + modp = modp->flink); + + return modp; +} + +/**************************************************************************** + * Name: mod_registry_foreach + * + * Description: + * Visit each module in the registry + * + * Input Parameters: + * callback - This callback function was be called for each entry in the + * registry. + * arg - This opaque argument will be passed to the callback function. + * + * Returned Value: + * This function normally returns zero (OK). If, however, any callback + * function returns a non-zero value, the traversal will be terminated and + * that non-zero value will be returned. + * + * Assumptions: + * The caller does *NOT* hold the lock on the module registry. + * + ****************************************************************************/ + +int mod_registry_foreach(mod_callback_t callback, FAR void *arg) +{ + FAR struct module_s *modp; + int ret; + + /* Get exclusive access to the module registry */ + + mod_registry_lock(); + + /* Visit each installed module */ + + for (modp = g_mod_registry; modp != NULL; modp = modp->flink) + { + /* Perform the callback */ + + ret = callback(modp, arg); + if (ret != 0) + { + return ret; + } + } + + mod_registry_unlock(); + return OK; +} \ No newline at end of file diff --git a/sched/module/mod_rmmod.c b/sched/module/mod_rmmod.c index 339ef808a3..c9ac15b0ec 100644 --- a/sched/module/mod_rmmod.c +++ b/sched/module/mod_rmmod.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -60,13 +61,37 @@ * Description: * Remove a previously installed module from memory. * + * Input Parameters: + * + * modulename - The module name. This is the name module name that was + * provided to insmod when the module was loaded. + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * ****************************************************************************/ -int rmmod(FAR struct module_s *modp) +int rmmod(FAR const char *modulename) { + FAR struct module_s *modp; int ret = OK; - DEBUGASSERT(modp != NULL); + DEBUGASSERT(modulename != NULL); + + /* Get exclusive access to the module registry */ + + mod_registry_lock(); + + /* Find the module entry for this modulename in the registry */ + + modp = mod_registry_find(modulename); + if (modp == NULL) + { + sdbg("ERROR: Failed to find module %s: %d\n", modulename, ret); + ret = -ENOENT; + goto errout_with_lock; + } /* Is there an uninitializer? */ @@ -81,7 +106,7 @@ int rmmod(FAR struct module_s *modp) if (ret < 0) { sdbg("ERROR: Failed to uninitialize the module: %d\n", ret); - return ret; + goto errout_with_lock; } /* Nullify so that the uninitializer cannot be called again */ @@ -92,7 +117,7 @@ int rmmod(FAR struct module_s *modp) /* Release resources held by the module */ - if (modp->alloc != 0) + if (modp->alloc != NULL) { /* Free the module memory */ @@ -101,9 +126,29 @@ int rmmod(FAR struct module_s *modp) /* Nullify so that the memory cannot be freed again */ modp->alloc = NULL; + modp->size = 0; } - return ret; + /* Remove the module from the registry */ + + ret = mod_registry_del(modp); + if (ret < 0) + { + sdbg("ERROR: Failed to remove the module from the registry: %d\n", ret); + goto errout_with_lock; + } + + mod_registry_unlock(); + + /* And free the registry entry */ + + kmm_free(modp); + return OK; + +errout_with_lock: + mod_registry_unlock(); + set_errno(-ret); + return ERROR; } #endif /* CONFIG_MODULE */ diff --git a/sched/module/module.h b/sched/module/module.h index 7f96df366d..db04560959 100644 --- a/sched/module/module.h +++ b/sched/module/module.h @@ -52,6 +52,19 @@ * Public Types ****************************************************************************/ +/* This describes the file to be loaded. */ + +struct symtab_s; +struct module_s +{ + FAR struct module_s *flink; /* Supports a singly linked list */ + FAR char modulename[MODULENAME_MAX]; /* Module name */ + mod_uninitializer_t uninitializer; /* Module uninitializer function */ + FAR void *arg; /* Uninitializer argument */ + FAR void *alloc; /* Allocated kernel memory */ + size_t size; /* Size of the kernel memory allocation */ +}; + /* This struct provides a description of the currently loaded instantiation * of the kernel module. */ @@ -332,4 +345,95 @@ int mod_allocbuffer(FAR struct mod_loadinfo_s *loadinfo); int mod_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo, size_t increment); +/**************************************************************************** + * Name: mod_registry_lock + * + * Description: + * Get exclusive access to the module registry. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_registry_lock(void); + +/**************************************************************************** + * Name: mod_registry_unlock + * + * Description: + * Relinquish the lock on the module registry + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mod_registry_unlock(void); + +/**************************************************************************** + * Name: mod_registry_add + * + * Description: + * Add a new entry to the module registry. + * + * Input Parameters: + * modp - The module data structure to be registered. + * + * Returned Value: + * None + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +void mod_registry_add(FAR struct module_s *modp); + +/**************************************************************************** + * Name: mod_registry_del + * + * Description: + * Remove a module entry from the registry + * + * Input Parameters: + * modp - The registry entry to be removed. + * + * Returned Value: + * Zero (OK) is returned if the registry entry was deleted. Otherwise, + * a negated errno value is returned. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +int mod_registry_del(FAR struct module_s *modp); + +/**************************************************************************** + * Name: mod_registry_find + * + * Description: + * Find an entry in the module registry using the name of the module. + * + * Input Parameters: + * modulename - The name of the module to be found + * + * Returned Value: + * If the registry entry is found, a pointer to the module entry is + * returned. NULL is returned if the they entry is not found. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +FAR struct module_s *mod_registry_find(FAR const char *modulename); + #endif /* __SCHED_MODULE_MODULE_H */ diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 50ebab9612..6cde8e6996 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -28,7 +28,7 @@ "getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*" "getpid","unistd.h","","pid_t" "getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*" -"insmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR struct module_s *" +"insmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR const char *","FAR const struct symtab_s *","int" "ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long" "kill","signal.h","!defined(CONFIG_DISABLE_SIGNALS)","int","pid_t","int" "listen","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int" @@ -98,7 +98,7 @@ "rename","stdio.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","FAR const char*" "rewinddir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","void","FAR DIR*" "rmdir","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*" -"rmmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR struct module_s *" +"rmmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR const char *" "sched_getparam","sched.h","","int","pid_t","struct sched_param*" "sched_getscheduler","sched.h","","int","pid_t" "sched_getstreams","nuttx/sched.h","CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0","FAR struct streamlist*" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 62ccbd2d5f..d97852872c 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -111,7 +111,7 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) */ #ifdef CONFIG_MODULE - SYSCALL_LOOKUP(insmod, 1, STUB_insmod) + SYSCALL_LOOKUP(insmod, 3, STUB_insmod) SYSCALL_LOOKUP(rmmod, 1, STUB_rmmod) #endif diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index e23e801f19..6a49cd227c 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -112,7 +112,8 @@ uintptr_t STUB_waitid(int nbr, uintptr_t parm1, uintptr_t parm2, */ #ifdef CONFIG_MODULE -uintptr_t STUB_insmod(int nbr, uintptr_t parm1); +uintptr_t STUB_insmod(int nbr, uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3); uintptr_t STUB_rmmod(int nbr, uintptr_t parm1); #endif