From 34ff07008aeac189820d1fa8ecf5c79dab4f9338 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 30 Aug 2014 13:27:23 -0600 Subject: [PATCH] Add configuration options to start the system from a program on a file system --- sched/Kconfig | 52 +++++++ sched/init/os_bringup.c | 306 ++++++++++++++++++++++++++++++---------- tools/cfgdefine.c | 2 + 3 files changed, 286 insertions(+), 74 deletions(-) diff --git a/sched/Kconfig b/sched/Kconfig index c3f7dbbf2b..02f35d5a0a 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -218,6 +218,26 @@ endmenu # Clocks and Timers menu "Tasks and Scheduling" +choice + prompt "Initialization Task" + default INIT_ENTRYPOINT if !BUILD_KERNEL + default INIT_FILEPATH if BUILD_KERNEL && !BINFMT_DISABLE + default INIT_NONE if BUILD_KERNEL && BINFMT_DISABLE + +config INIT_NONE + bool + +config INIT_ENTRYPOINT + bool "Via application entry point" + depends on !BUILD_KERNEL + +config INIT_FILEPATH + bool "Via executable file" + depends on !BINFMT_DISABLE + +endchoice # Initialization task + +if INIT_ENTRYPOINT config USER_ENTRYPOINT string "Application entry point" default "main" @@ -226,6 +246,38 @@ config USER_ENTRYPOINT applications this is of the form 'app_main' where 'app' is the application name. If not defined, USER_ENTRYPOINT defaults to "main". +endif # INIT_ENTRYPOINT + +if INIT_FILEPATH + +config USER_INITPATH + string "Application initialization path" + default "/bin/init" + ---help--- + The name of the entry point for user applications. For the example + applications this is of the form 'app_main' where 'app' is the application + name. If not defined, USER_ENTRYPOINT defaults to "main". + +config INIT_SYMTAB + string "Symbol table" + default "NULL" + ---help--- + The name of othe global array that holds the exported symbol table. + The special string "NULL" may be provided if there is no symbol + table. Quotation marks will be stripped when config.h is generated. + +config INIT_NEXPORTS + string "Symbol table size" + default "0" + ---help--- + The size of the symbol table. NOTE that is is logically a numeric + value but is represent by a string. That allows you to put + sizeof(something) or a macro or a global variable name for the + symbol table size. Quotation marks will be stripped when config.h + is generated. + +endif # INIT_FILEPATH + config RR_INTERVAL int "Round robin timeslice (MSEC)" default 0 diff --git a/sched/init/os_bringup.c b/sched/init/os_bringup.c index 150aa4481e..b084bd1b0e 100644 --- a/sched/init/os_bringup.c +++ b/sched/init/os_bringup.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef CONFIG_PAGING # include "paging/paging.h" @@ -62,6 +63,59 @@ * Pre-processor Definitions ****************************************************************************/ +/* Configuration */ + +#if defined(CONFIG_INIT_NONE) + /* Kconfig logic will set CONFIG_INIT_NONE if dependencies are not met */ + +# error No initialization mechanism selected (CONFIG_INIT_NONE) + +#else +# if !defined(CONFIG_INIT_ENTRYPOINT) && !defined(CONFIG_INIT_FILEPATH) + /* For backward compatibility with older defconfig files when this was + * the way things were done. + */ + +# define CONFIG_INIT_ENTRYPOINT 1 +# endif + +# if defined(CONFIG_INIT_ENTRYPOINT) + /* Initialize by starting a task at an entry point */ + +# ifndef CONFIG_USER_ENTRYPOINT + /* Entry point name must have been provided */ + +# error CONFIG_USER_ENTRYPOINT must be defined +# endif + +# elif defined(CONFIG_INIT_FILEPATH) + /* Initialize by running an initialization program in the file system. + * Presumably the user has configured a board initialization function + * that will mount the file system containing the initialization + * program. + */ + +# ifndef CONFIG_BOARD_INITIALIZE +# warning You probably need CONFIG_BOARD_INITIALIZE to mount the file system +# endif + +# ifndef CONFIG_USER_INITPATH + /* Path to the initialization program must have been provided */ + +# error CONFIG_USER_INITPATH must be defined +# endif + +# if !defined(CONFIG_INIT_SYMTAB) || !defined(CONFIG_INIT_NEXPORTS) + /* No symbol information... assume no symbol table is available */ + +# undef CONFIG_INIT_SYMTAB +# undef CONFIG_INIT_NEXPORTS +# define CONFIG_INIT_SYMTAB NULL +# define CONFIG_INIT_NEXPORTS 0 +# endif +# endif +#endif + /* If NuttX is built as a separately compiled module, then the config.h header * file should contain the address of the entry point (or path to the file) * that will perform the application-level initialization. @@ -102,6 +156,170 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: os_pgworker + * + * Description: + * Start the page fill worker kernel thread that will resolve page faults. + * This should always be the first thread started because it may have to + * resolve page faults in other threads + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_PAGING +static inline void os_pgworker(void) +{ + /* Start the page fill worker kernel thread that will resolve page faults. + * This should always be the first thread started because it may have to + * resolve page faults in other threads + */ + + svdbg("Starting paging thread\n"); + + g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO, + CONFIG_PAGING_STACKSIZE, + (main_t)pg_worker, (FAR char * const *)NULL); + DEBUGASSERT(g_pgworker > 0); +} + +#else /* CONFIG_PAGING */ +# define os_pgworker() + +#endif /* CONFIG_PAGING */ + +/**************************************************************************** + * Name: os_workqueues + * + * Description: + * Start the worker threads that service the work queues. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_WORKQUEUE +static inline void os_workqueues(void) +{ +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_SCHED_USRWORK) + int taskid; +#endif + +#ifdef CONFIG_SCHED_HPWORK +#ifdef CONFIG_SCHED_LPWORK + svdbg("Starting high-priority kernel worker thread\n"); +#else + svdbg("Starting kernel worker thread\n"); +#endif + + g_work[HPWORK].pid = KERNEL_THREAD(HPWORKNAME, CONFIG_SCHED_WORKPRIORITY, + CONFIG_SCHED_WORKSTACKSIZE, + (main_t)work_hpthread, + (FAR char * const *)NULL); + DEBUGASSERT(g_work[HPWORK].pid > 0); + + /* Start a lower priority worker thread for other, non-critical continuation + * tasks + */ + +#ifdef CONFIG_SCHED_LPWORK + + svdbg("Starting low-priority kernel worker thread\n"); + + g_work[LPWORK].pid = KERNEL_THREAD(LPWORKNAME, CONFIG_SCHED_LPWORKPRIORITY, + CONFIG_SCHED_LPWORKSTACKSIZE, + (main_t)work_lpthread, + (FAR char * const *)NULL); + DEBUGASSERT(g_work[LPWORK].pid > 0); + +#endif /* CONFIG_SCHED_LPWORK */ +#endif /* CONFIG_SCHED_HPWORK */ + +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_SCHED_USRWORK) + /* Start the user-space work queue */ + + DEBUGASSERT(USERSPACE->work_usrstart != NULL); + taskid = USERSPACE->work_usrstart(); + DEBUGASSERT(taskid > 0); + UNUSED(taskid); +#endif +} + +#else /* CONFIG_SCHED_WORKQUEUE */ +# define os_workqueues() + +#endif /* CONFIG_SCHED_WORKQUEUE */ + +/**************************************************************************** + * Name: os_init_thread + * + * Description: + * Start the application initialization thread. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_INIT_ENTRYPOINT) +static inline void os_init_thread(void) +{ + int taskid; + + svdbg("Starting init thread\n"); + + /* Start the application initialization ask. In a flat build, this is + * entrypoint is given by the definitions, CONFIG_USER_ENTRYPOINT. In + * the protected build, however, we must get the address of the + * entrypoint from the header at the beginning of the user-space blob. + */ + +#ifdef CONFIG_BUILD_PROTECTED + DEBUGASSERT(USERSPACE->us_entrypoint != NULL); + taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT, + CONFIG_USERMAIN_STACKSIZE, USERSPACE->us_entrypoint, + (FAR char * const *)NULL); +#else + taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT, + CONFIG_USERMAIN_STACKSIZE, + (main_t)CONFIG_USER_ENTRYPOINT, + (FAR char * const *)NULL); +#endif + ASSERT(taskid > 0); +} + +#elif defined(CONFIG_INIT_FILEPATH) +static inline void os_init_thread(void) +{ + int ret; + + svdbg("Starting init task: %s\n", CONFIG_USER_INITPATH); + + ret = exec(CONFIG_USER_INITPATH, NULL, CONFIG_INIT_SYMTAB, + CONFIG_INIT_NEXPORTS); + ASSERT(ret >= 0); +} + +#elif defined(CONFIG_INIT_NONE) +# define os_init_thread() + +#else +# error "Cannot start initialization thread" + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -122,9 +340,15 @@ * drivers. * * And the main application entry point: - * symbols: + * symbols, either: * - * - USER_ENTRYPOINT: This is the default user application entry point. + * - CONFIG_USER_ENTRYPOINT: This is the default user application entry + * point, or + * - CONFIG_USER_INITPATH: The full path to the location in a mounted + * file system where we can expect to find the + * initialization program. Presumably, this file system + * was mounted by board-specific logic when + * board_initialize() was called. * * Input Parameters: * None @@ -136,8 +360,6 @@ int os_bringup(void) { - int taskid; - /* Setup up the initial environment for the idle task. At present, this * may consist of only the initial PATH variable. The PATH variable is * (probably) not used by the IDLE task. However, the environment @@ -154,65 +376,13 @@ int os_bringup(void) * resolve page faults in other threads */ -#ifdef CONFIG_PAGING - svdbg("Starting paging thread\n"); - - g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO, - CONFIG_PAGING_STACKSIZE, - (main_t)pg_worker, (FAR char * const *)NULL); - DEBUGASSERT(g_pgworker > 0); -#endif + os_pgworker(); /* Start the worker thread that will serve as the device driver "bottom- * half" and will perform misc garbage clean-up. */ -#ifdef CONFIG_SCHED_WORKQUEUE -#ifdef CONFIG_SCHED_HPWORK - -#ifdef CONFIG_SCHED_LPWORK - svdbg("Starting high-priority kernel worker thread\n"); -#else - svdbg("Starting kernel worker thread\n"); -#endif - - g_work[HPWORK].pid = KERNEL_THREAD(HPWORKNAME, CONFIG_SCHED_WORKPRIORITY, - CONFIG_SCHED_WORKSTACKSIZE, - (main_t)work_hpthread, (FAR char * const *)NULL); - DEBUGASSERT(g_work[HPWORK].pid > 0); - - /* Start a lower priority worker thread for other, non-critical continuation - * tasks - */ - -#ifdef CONFIG_SCHED_LPWORK - - svdbg("Starting low-priority kernel worker thread\n"); - - g_work[LPWORK].pid = KERNEL_THREAD(LPWORKNAME, CONFIG_SCHED_LPWORKPRIORITY, - CONFIG_SCHED_LPWORKSTACKSIZE, - (main_t)work_lpthread, (FAR char * const *)NULL); - DEBUGASSERT(g_work[LPWORK].pid > 0); - -#endif /* CONFIG_SCHED_LPWORK */ -#endif /* CONFIG_SCHED_HPWORK */ - -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_SCHED_USRWORK) - /* Start the user-space work queue */ - - DEBUGASSERT(USERSPACE->work_usrstart != NULL); - taskid = USERSPACE->work_usrstart(); - DEBUGASSERT(taskid > 0); -#endif - -#endif /* CONFIG_SCHED_WORKQUEUE */ - - /* Once the operating system has been initialized, the system must be - * started by spawning the user init thread of execution. This is the - * first user-mode thead. - */ - - svdbg("Starting init thread\n"); + os_workqueues(); /* Perform any last-minute, board-specific initialization, if so * configured. @@ -222,24 +392,12 @@ int os_bringup(void) board_initialize(); #endif - /* Start the default application. In a flat build, this is entrypoint - * is given by the definitions, CONFIG_USER_ENTRYPOINT. In the kernel - * build, however, we must get the address of the entrypoint from the - * header at the beginning of the user-space blob. + /* Once the operating system has been initialized, the system must be + * started by spawning the user initialization thread of execution. This + * is the first user-mode thread. */ -#ifdef CONFIG_BUILD_PROTECTED - DEBUGASSERT(USERSPACE->us_entrypoint != NULL); - taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT, - CONFIG_USERMAIN_STACKSIZE, USERSPACE->us_entrypoint, - (FAR char * const *)NULL); -#else - taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT, - CONFIG_USERMAIN_STACKSIZE, - (main_t)CONFIG_USER_ENTRYPOINT, - (FAR char * const *)NULL); -#endif - ASSERT(taskid > 0); + os_init_thread(); /* We an save a few bytes by discarding the IDLE thread's environment. */ diff --git a/tools/cfgdefine.c b/tools/cfgdefine.c index 8567e3292c..7e0a82f37e 100644 --- a/tools/cfgdefine.c +++ b/tools/cfgdefine.c @@ -69,6 +69,8 @@ static const char *dequote_list[] = "CONFIG_PASS1_TARGET", /* Pass1 build target */ "CONFIG_PASS1_OBJECT", /* Pass1 build object */ "CONFIG_DEBUG_OPTLEVEL", /* Custom debug level */ + "CONFIG_INIT_SYMTAB", /* Global symbol table */ + "CONFIG_INIT_NEXPORTS", /* Global symbol table size */ /* RGMP */