Add configuration options to start the system from a program on a file system
This commit is contained in:
parent
a5cfd5deba
commit
34ff07008a
|
@ -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
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/kthread.h>
|
||||
#include <nuttx/userspace.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
|
||||
#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. */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue