diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-09-10 15:55:36 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-09-10 15:55:36 -0600 |
commit | 7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2 (patch) | |
tree | 776264ed920f68eed300648dffe198e286495000 | |
parent | 22c64f6c542675d4865d2a013468089c92f43869 (diff) | |
download | nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.tar.gz nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.tar.bz2 nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.zip |
Add logic to initialize the per-process user heap when each user process is started
-rw-r--r-- | nuttx/Documentation/NuttxPortingGuide.html | 68 | ||||
-rw-r--r-- | nuttx/arch/arm/include/arch.h | 12 | ||||
-rwxr-xr-x | nuttx/arch/arm/include/armv7-a/irq.h | 4 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_addrenv.c | 90 | ||||
-rw-r--r-- | nuttx/arch/z80/src/z180/z180_mmu.c | 64 | ||||
-rw-r--r-- | nuttx/binfmt/binfmt_execmodule.c | 40 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf.h | 6 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_addrenv.c | 8 | ||||
-rw-r--r-- | nuttx/binfmt/libelf/libelf_load.c | 18 | ||||
-rw-r--r-- | nuttx/binfmt/libnxflat/libnxflat.h | 2 | ||||
-rw-r--r-- | nuttx/binfmt/libnxflat/libnxflat_addrenv.c | 15 | ||||
-rw-r--r-- | nuttx/include/nuttx/addrenv.h | 33 | ||||
-rw-r--r-- | nuttx/include/nuttx/arch.h | 60 | ||||
-rw-r--r-- | nuttx/include/nuttx/mm.h | 2 | ||||
-rw-r--r-- | nuttx/mm/umm_initialize.c | 36 |
15 files changed, 326 insertions, 132 deletions
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index a2d1d0884..eb5a67cc1 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -12,7 +12,7 @@ <h1><big><font color="#3c34ec"> <i>NuttX RTOS Porting Guide</i> </font></big></h1> - <p>Last Updated: August 29, 2014</p> + <p>Last Updated: September 10, 2014</p> </td> </tr> </table> @@ -110,11 +110,12 @@ <a href="#up_addrenv_destroy">4.4.2 <code>up_addrenv_destroy()</code></a></br> <a href="#up_addrenv_vtext">4.4.3 <code>up_addrenv_vtext()</code></a></br> <a href="#up_addrenv_vdata">4.4.4 <code>up_addrenv_vdata()</code></a></br> - <a href="#up_addrenv_select">4.4.5 <code>up_addrenv_select()</code></a></br> - <a href="#up_addrenv_restore">4.4.6 <code>up_addrenv_restore()</code></a></br> - <a href="#up_addrenv_clone">4.4.7 <code>up_addrenv_clone()</code></a></br> - <a href="#up_addrenv_attach">4.4.8 <code>up_addrenv_attach()</code></a></br> - <a href="#up_addrenv_detach">4.4.9 <code>up_addrenv_detach()</code></a> + <a href="#up_addrenv_heapsize">4.4.5 <code>up_addrenv_heapsize()</code></a></br> + <a href="#up_addrenv_select">4.4.6 <code>up_addrenv_select()</code></a></br> + <a href="#up_addrenv_restore">4.4.7 <code>up_addrenv_restore()</code></a></br> + <a href="#up_addrenv_clone">4.4.8 <code>up_addrenv_clone()</code></a></br> + <a href="#up_addrenv_attach">4.4.9 <code>up_addrenv_attach()</code></a></br> + <a href="#up_addrenv_detach">4.4.10 <code>up_addrenv_detach()</code></a> </ul> <a href="#exports">4.5 APIs Exported by NuttX to Architecture-Specific Logic</a> <ul> @@ -2927,15 +2928,19 @@ VxWorks provides the following comparable interface: Returns the virtual base address of the <code>.bss</code>/<code>.data</code> address environment. </li> <li> - <a href="#up_addrenv_select">4.4.5 <code>up_addrenv_select()</code></a>: + <a href="#up_addrenv_heapsize">4.4.5 <code>up_addrenv_heapsize()</code></a>: + Return the initial heap size. + </li> + <li> + <a href="#up_addrenv_select">4.4.6 <code>up_addrenv_select()</code></a>: Instantiate an address environment. </li> <li> - <a href="#up_addrenv_restore">4.4.6 <code>up_addrenv_restore()</code></a>: + <a href="#up_addrenv_restore">4.4.7 <code>up_addrenv_restore()</code></a>: Restore an address environment. </li> <li> - <a href="#up_addrenv_clone">4.4.7 <code>up_addrenv_clone()</code></a>: + <a href="#up_addrenv_clone">4.4.8 <code>up_addrenv_clone()</code></a>: Copy an address environment from one location to another. </li> </ul> @@ -2948,12 +2953,12 @@ VxWorks provides the following comparable interface: </p> <ul> <li> - <a href="#up_addrenv_attach">4.4.8 <code>up_addrenv_attach()</code></a>: + <a href="#up_addrenv_attach">4.4.9 <code>up_addrenv_attach()</code></a>: Clone the group address environment assigned to a new thread. This operation is done when a pthread is created that share's the same address environment. </li> <li> - <a href="#up_addrenv_detach">4.4.9 <code>up_addrenv_detach()</code></a>: + <a href="#up_addrenv_detach">4.4.10 <code>up_addrenv_detach()</code></a>: Release the thread's reference to a group address environment when a task/thread exits. </li> </ul> @@ -2963,7 +2968,7 @@ VxWorks provides the following comparable interface: <h3><a name="up_addrenv_create">4.4.1 <code>up_addrenv_create()</code></a></h3> <p><b>Function Prototype</b>:</p> <ul> - <code>int up_addrenv_create(size_t textsize, size_t datasize, FAR group_addrenv_t *addrenv);</code> + <code>int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, FAR group_addrenv_t *addrenv);</code> </ul> <p><b>Description</b>:</p> <ul> @@ -2974,6 +2979,7 @@ VxWorks provides the following comparable interface: <ul> <li><code>textsize</code>: The size (in bytes) of the <code>.text</code> address environment needed by the task. This region may be read/execute only.</li> <li><code>datasize</code>: The size (in bytes) of the <code>.bss/.data</code> address environment needed by the task. This region may be read/write only.</li> + <li><code>heapsize</code>: The initial size (in bytes) of the heap address environment needed by the task. This region may be read/write only.</li> <li><code>addrenv</code>: The location to return the representation of the task address environment.</li> </ul> <p><b>Returned Value</b>:</p> @@ -2992,7 +2998,7 @@ VxWorks provides the following comparable interface: </ul> <p><b>Input Parameters</b>:</p> <ul> - <li><code>addrenv</code>: The representation of the task address environment previously returned by up_addrenv_create.</li> + <li><code>addrenv</code>: The representation of the task address environment previously returned by <code>up_addrenv_create()</code>.</li> </ul> <p><b>Returned Value</b>:</p> <ul> @@ -3011,7 +3017,7 @@ VxWorks provides the following comparable interface: </ul> <p><b>Input Parameters</b>:</p> <ul> - <li><code>addrenv</code>: The representation of the task address environment previously returned by up_addrenv_create.</li> + <li><code>addrenv</code>: The representation of the task address environment previously returned by <code>up_addrenv_create()</code>.</li> <li><code>vtext</code>: The location to return the virtual address.</li> </ul> <p><b>Returned Value</b>:</p> @@ -3031,7 +3037,7 @@ VxWorks provides the following comparable interface: </ul> <p><b>Input Parameters</b>:</p> <ul> - <li><code>addrenv</code>: The representation of the task address environment previously returned by up_addrenv_create.</li> + <li><code>addrenv</code>: The representation of the task address environment previously returned by <code>up_addrenv_create()</code>.</li> <li><code>textsize</code>: For some implementations, the text and data will be saved in the same memory region (read/write/execute) and, in this case, the virtual address of the data just lies at this offset into the common region.</li> <li><code>vdata</code>: The location to return the virtual address.</li> </ul> @@ -3040,7 +3046,27 @@ VxWorks provides the following comparable interface: Zero (<code>OK</code>) on success; a negated <code>errno</code> value on failure. </ul> -<h3><a name="up_addrenv_select">4.4.5 <code>up_addrenv_select()</code></a></h3> +<h3><a name="up_addrenv_heapsize">4.4.5 <code>up_addrenv_heapsize()</code></a></h3> +<p><b>Function Prototype</b>:<p> +<ul> + <code>ssize_t up_addrenv_heapsize(FAR const group_addrenv_t *addrenv);</code> +</ul> +<p><b>Description</b>:</p> +<ul> + Return the initial heap allocation size. + That is the amount of memory allocated by <code>up_addrenv_create()</code> when the heap memory region was first created. + This may or may not differ from the <code>heapsize</code> parameter that was passed to <code>up_addrenv_create()</code>. +</ul> +<p><b>Input Parameters</b>:</p> +<ul> + <li><code>addrenv</code>: The representation of the task address environment previously returned by <code>up_addrenv_create()</code>.</li> +</ul> +<p><b>Returned Value</b>:</p> +<ul> + The initial heap size allocated is returned on success; a negated <code>errno</code> value on failure. +</ul> + +<h3><a name="up_addrenv_select">4.4.6 <code>up_addrenv_select()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> <code>int up_addrenv_select(group_addrenv_t *addrenv, save_addrenv_t *oldenv);</code> @@ -3052,7 +3078,7 @@ VxWorks provides the following comparable interface: </ul> <p><b>Input Parameters</b>:</p> <ul> - <li><code>addrenv</code>: The representation of the task address environment previously returned by up_addrenv_create.</li> + <li><code>addrenv</code>: The representation of the task address environment previously returned by <code>up_addrenv_create()</code>.</li> <li><code>oldenv</code>: The address environment that was in place before <code>up_addrenv_select()</code> was called. This may be used with <code>up_addrenv_restore()</code> to restore the original address environment that was in place before <code>up_addrenv_select()</code> was called. @@ -3064,7 +3090,7 @@ VxWorks provides the following comparable interface: Zero (<code>OK</code>) on success; a negated <code>errno</code> value on failure. </ul> -<h3><a name="up_addrenv_restore">4.4.6 <code>up_addrenv_restore()</code></a></h3> +<h3><a name="up_addrenv_restore">4.4.7 <code>up_addrenv_restore()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> <code>int up_addrenv_restore(save_addrenv_t oldenv);</code> @@ -3083,7 +3109,7 @@ VxWorks provides the following comparable interface: Zero (<code>OK</code>) on success; a negated <code>errno</code> value on failure. </ul> -<h3><a name="up_addrenv_clone">4.4.7 <code>up_addrenv_clone()</code></a></h3> +<h3><a name="up_addrenv_clone">4.4.8 <code>up_addrenv_clone()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> <code>int up_addrenv_clone(FAR const task_group_s *src, FAR struct task_group_s *dest);</code> @@ -3102,7 +3128,7 @@ VxWorks provides the following comparable interface: Zero (<code>OK</code>) on success; a negated <code>errno</code> value on failure. </ul> -<h3><a name="up_addrenv_attach">4.4.8 <code>up_addrenv_attach()</code></a></h3> +<h3><a name="up_addrenv_attach">4.4.9 <code>up_addrenv_attach()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> <code>int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb);</code> @@ -3128,7 +3154,7 @@ VxWorks provides the following comparable interface: Zero (<code>OK</code>) on success; a negated <code>errno</code> value on failure. </ul> -<h3><a name="up_addrenv_detach">4.4.9 <code>up_addrenv_detach()</code></a></h3> +<h3><a name="up_addrenv_detach">4.4.10 <code>up_addrenv_detach()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> <code>int up_addrenv_detach(FAR struct task_group_s *group, FAR struct task_group_s *tcb);</code> diff --git a/nuttx/arch/arm/include/arch.h b/nuttx/arch/arm/include/arch.h index 2f1991622..02e66aaf4 100644 --- a/nuttx/arch/arm/include/arch.h +++ b/nuttx/arch/arm/include/arch.h @@ -133,9 +133,19 @@ do { \ struct group_addrenv_s { + /* Level 1 page table entries for each group section */ + FAR uintptr_t *text[ARCH_TEXT_NSECTS]; FAR uintptr_t *data[ARCH_DATA_NSECTS]; FAR uintptr_t *heap[ARCH_HEAP_NSECTS]; + + /* Initial heap allocation (in bytes). This exists only provide an + * indirect path for passing the size of the initial heap to the heap + * initialization logic. These operations are separated in time and + * architecture. REVISIT: I would like a better way to do this. + */ + + size_t heapsize; }; typedef struct group_addrenv_s group_addrenv_t; @@ -153,9 +163,7 @@ struct save_addrenv_s { FAR uint32_t text[ARCH_TEXT_NSECTS]; FAR uint32_t data[ARCH_DATA_NSECTS]; -#if 0 /* Not yet implemented */ FAR uint32_t heap[ARCH_HEAP_NSECTS]; -#endif }; typedef struct save_addrenv_s save_addrenv_t; diff --git a/nuttx/arch/arm/include/armv7-a/irq.h b/nuttx/arch/arm/include/armv7-a/irq.h index 00e7244ae..f9d5225b3 100755 --- a/nuttx/arch/arm/include/armv7-a/irq.h +++ b/nuttx/arch/arm/include/armv7-a/irq.h @@ -274,17 +274,15 @@ struct xcptcontext struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; #endif -#ifdef CONFIG_ARCH_ADDRENV +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) /* This table holds the physical address of the level 2 page table used * to map the thread's stack memory. This array will be initially of * zeroed and would be back-up up with pages during page fault exception * handling to support dynamically sized stacks for each thread. */ -#if 0 /* Not yet implemented */ FAR uintptr_t *stack[ARCH_STACK_NSECTS]; #endif -#endif }; #endif diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c index 4d68fd655..aa28efbdb 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c +++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c @@ -40,27 +40,28 @@ * is an abstract representation of a task group's address environment and * must be defined in arch/arch.h if CONFIG_ARCH_ADDRENV is defined. * - * up_addrenv_create - Create an address environment - * up_addrenv_destroy - Destroy an address environment. - * up_addrenv_vtext - Returns the virtual base address of the .text - * address environment - * up_addrenv_vdata - Returns the virtual base address of the .bss/.data - * address environment - * up_addrenv_select - Instantiate an address environment - * up_addrenv_restore - Restore an address environment - * up_addrenv_clone - Copy an address environment from one location to - * another. + * up_addrenv_create - Create an address environment + * up_addrenv_destroy - Destroy an address environment. + * up_addrenv_vtext - Returns the virtual base address of the .text + * address environment + * up_addrenv_vdata - Returns the virtual base address of the .bss/.data + * address environment + * up_addrenv_heapsize - Returns the size of the initial heap allocation. + * up_addrenv_select - Instantiate an address environment + * up_addrenv_restore - Restore an address environment + * up_addrenv_clone - Copy an address environment from one location to + * another. * * Higher-level interfaces used by the tasking logic. These interfaces are * used by the functions in sched/ and all operate on the thread which whose * group been assigned an address environment by up_addrenv_clone(). * - * up_addrenv_attach - Clone the address environment assigned to one TCB - * to another. This operation is done when a pthread - * is created that share's the same address - * environment. - * up_addrenv_detach - Release the threads reference to an address - * environment when a task/thread exits. + * up_addrenv_attach - Clone the address environment assigned to one TCB + * to another. This operation is done when a pthread + * is created that share's the same address + * environment. + * up_addrenv_detach - Release the threads reference to an address + * environment when a task/thread exits. * ****************************************************************************/ @@ -153,6 +154,10 @@ static void set_l2_entry(FAR uint32_t *l2table, uintptr_t paddr, * Description: * Create one memory region. * + * Returned Value: + * On success, the number of pages allocated is returned. Otherwise, a + * negated errno value is returned. + * ****************************************************************************/ static int up_addrenv_create_region(FAR uintptr_t **list, @@ -264,7 +269,7 @@ static int up_addrenv_create_region(FAR uintptr_t **list, irqrestore(flags); } - return OK; + return npages; } /**************************************************************************** @@ -437,6 +442,8 @@ static void up_addrenv_destroy_region(FAR uintptr_t **list, * actual size of the data region that is allocated will include a * OS private reserved region at the beginning. The size of the * private, reserved region is give by ARCH_DATA_RESERVE_SIZE. + * heapsize - The initial size (in bytes) of the heap address environment + * needed by the task. This region may be read/write only. * addrenv - The location to return the representation of the task address * environment. * @@ -445,7 +452,7 @@ static void up_addrenv_destroy_region(FAR uintptr_t **list, * ****************************************************************************/ -int up_addrenv_create(size_t textsize, size_t datasize, +int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, FAR group_addrenv_t *addrenv) { int ret; @@ -503,8 +510,22 @@ int up_addrenv_create(size_t textsize, size_t datasize, } #endif - /* Notice that no pages are yet allocated for the heap */ + /* Allocate heap space pages */ + + ret = up_addrenv_create_region(addrenv->heap, ARCH_HEAP_NSECTS, + CONFIG_ARCH_HEAP_VBASE, heapsize, + MMU_L2_UDATAFLAGS); + if (ret < 0) + { + bdbg("ERROR: Failed to create heap region: %d\n", ret); + goto errout; + } + /* Save the initial heap size allocated. This will be needed when + * the heap data structures are initialized. + */ + + addrenv->heapsize = (size_t)ret << MM_PGSHIFT; return OK; errout: @@ -543,12 +564,10 @@ int up_addrenv_destroy(FAR group_addrenv_t *addrenv) up_addrenv_destroy_region(addrenv->data, ARCH_DATA_NSECTS, CONFIG_ARCH_DATA_VBASE); -#if 0 /* Not yet implemented */ /* Destroy the heap region */ up_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS, CONFIG_ARCH_HEAP_VBASE); -#endif memset(addrenv, 0, sizeof(group_addrenv_t)); return OK; @@ -617,6 +636,31 @@ int up_addrenv_vdata(FAR group_addrenv_t *addrenv, uintptr_t textsize, } /**************************************************************************** + * Name: up_addrenv_heapsize + * + * Description: + * Return the initial heap allocation size. That is the amount of memory + * allocated by up_addrenv_create() when the heap memory region was first + * created. This may or may not differ from the heapsize parameter that + * was passed to up_addrenv_create() + * + * Input Parameters: + * addrenv - The representation of the task address environment previously + * returned by up_addrenv_create. + * + * Returned Value: + * The initial heap size allocated is returned on success; a negated + * errno value on failure. + * + ****************************************************************************/ + +ssize_t up_addrenv_heapsize(FAR const group_addrenv_t *addrenv) +{ + DEBUGASSERT(addrenv); + return (ssize_t)addrenv->heapsize; +} + +/**************************************************************************** * Name: up_addrenv_select * * Description: @@ -698,7 +742,6 @@ int up_addrenv_select(FAR const group_addrenv_t *addrenv, } } -#if 0 /* Not yet implemented */ for (vaddr = CONFIG_ARCH_HEAP_VBASE, i = 0; i < ARCH_HEAP_NSECTS; vaddr += SECTION_SIZE, i++) @@ -722,7 +765,6 @@ int up_addrenv_select(FAR const group_addrenv_t *addrenv, mmu_l1_clrentry(vaddr); } } -#endif return OK; } @@ -770,7 +812,6 @@ int up_addrenv_restore(FAR const save_addrenv_t *oldenv) mmu_l1_restore(vaddr, oldenv->data[i]); } -#if 0 /* Not yet implemented */ for (vaddr = CONFIG_ARCH_HEAP_VBASE, i = 0; i < ARCH_HEAP_NSECTS; vaddr += SECTION_SIZE, i++) @@ -779,7 +820,6 @@ int up_addrenv_restore(FAR const save_addrenv_t *oldenv) mmu_l1_restore(vaddr, oldenv->heap[i]); } -#endif return OK; } diff --git a/nuttx/arch/z80/src/z180/z180_mmu.c b/nuttx/arch/z80/src/z180/z180_mmu.c index e1373851d..e63e18403 100644 --- a/nuttx/arch/z80/src/z180/z180_mmu.c +++ b/nuttx/arch/z80/src/z180/z180_mmu.c @@ -184,15 +184,16 @@ return g_physhandle ? OK : -ENOMEM; * is an abstract representation of a task group's address environment and * must be defined in arch/arch.h if CONFIG_ARCH_ADDRENV is defined. * - * up_addrenv_create - Create an address environment - * up_addrenv_destroy - Destroy an address environment. - * up_addrenv_vtext - Returns the virtual base address of the .text - * address environment - * up_addrenv_vdata - Returns the virtual base address of the .bss/.data - * address environment - * up_addrenv_select - Instantiate an address environment - * up_addrenv_restore - Restore an address environment - * up_addrenv_clone - Copy an address environment from one location to + * up_addrenv_create - Create an address environment + * up_addrenv_destroy - Destroy an address environment. + * up_addrenv_vtext - Returns the virtual base address of the .text + * address environment + * up_addrenv_vdata - Returns the virtual base address of the .bss/.data + * address environment + * up_addrenv_heapsize - Returns the size of the initial heap allocation. + * up_addrenv_select - Instantiate an address environment + * up_addrenv_restore - Restore an address environment + * up_addrenv_clone - Copy an address environment from one location to * another. * * Higher-level interfaces used by the tasking logic. These interfaces are @@ -200,11 +201,11 @@ return g_physhandle ? OK : -ENOMEM; * group been assigned an address environment by up_addrenv_clone(). * * up_addrenv_attach - Clone the address environment assigned to one TCB - * to another. This operation is done when a pthread - * is created that share's the same address - * environment. - * up_addrenv_detach - Release the threads reference to an address - * environment when a task/thread exits. + * to another. This operation is done when a pthread + * is created that share's the same address + * environment. + * up_addrenv_detach - Release the threads reference to an address + * environment when a task/thread exits. * ****************************************************************************/ /**************************************************************************** @@ -220,6 +221,11 @@ return g_physhandle ? OK : -ENOMEM; * textsize - The size (in bytes) of the .text address environment needed * by the task. This region may be read/execute only. * datasize - The size (in bytes) of the .data/.bss address environment + * needed by the task. This region may be read/write only. NOTE: The + * actual size of the data region that is allocated will include a + * OS private reserved region at the beginning. The size of the + * private, reserved region is give by ARCH_DATA_RESERVE_SIZE. + * heapsize - The initial size (in bytes) of the heap address environment * needed by the task. This region may be read/write only. * addrenv - The location to return the representation of the task address * environment. @@ -229,7 +235,7 @@ return g_physhandle ? OK : -ENOMEM; * ****************************************************************************/ -int up_addrenv_create(size_t textsize, size_t datasize, +int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, FAR group_addrenv_t *addrenv) { FAR struct z180_cbr_s *cbr; @@ -241,7 +247,7 @@ int up_addrenv_create(size_t textsize, size_t datasize, /* Convert the size from bytes to numbers of pages */ - envsize = textsize + datasize; + envsize = textsize + datasize + heapsize; npages = PHYS_ALIGNUP(envsize); if (npages < 1) { @@ -390,6 +396,32 @@ int up_addrenv_vdata(FAR group_addrenv_t *addrenv, uintptr_t textsize, } /**************************************************************************** + * Name: up_addrenv_heapsize + * + * Description: + * Return the initial heap allocation size. That is the amount of memory + * allocated by up_addrenv_create() when the heap memory region was first + * created. This may or may not differ from the heapsize parameter that + * was passed to up_addrenv_create() + * + * Input Parameters: + * addrenv - The representation of the task address environment previously + * returned by up_addrenv_create. + * + * Returned Value: + * The initial heap size allocated is returned on success; a negated + * errno value on failure. + * + ****************************************************************************/ + +ssize_t up_addrenv_heapsize(FAR const group_addrenv_t *addrenv) +{ + /* Not implemented */ + + return (ssize_t)-ENOSYS; +} + +/**************************************************************************** * Name: up_addrenv_select * * Description: diff --git a/nuttx/binfmt/binfmt_execmodule.c b/nuttx/binfmt/binfmt_execmodule.c index 1afb4e8b3..b9a1dde79 100644 --- a/nuttx/binfmt/binfmt_execmodule.c +++ b/nuttx/binfmt/binfmt_execmodule.c @@ -48,6 +48,7 @@ #include <nuttx/arch.h> #include <nuttx/kmalloc.h> +#include <nuttx/mm.h> #include <nuttx/binfmt/binfmt.h> #include "sched/sched.h" @@ -164,9 +165,9 @@ int exec_module(FAR const struct binary_s *binp) goto errout; } - /* Instantiate the address environment containing the destructors */ - #ifdef CONFIG_ARCH_ADDRENV + /* Instantiate the address environment containing the user heap */ + ret = up_addrenv_select(&binp->addrenv, &oldenv); if (ret < 0) { @@ -174,9 +175,18 @@ int exec_module(FAR const struct binary_s *binp) err = -ret; goto errout_with_tcb; } + + /* Initialize the user heap */ + + umm_initialize((FAR void *)CONFIG_ARCH_HEAP_VBASE, + up_addrenv_heapsize(&binp->addrenv)); #endif - /* Allocate the stack for the new task (always from the user heap) */ + /* Allocate the stack for the new task. + * + * REVISIT: This allocation is currently always from the user heap. That + * will need to change if/when we want to support dynamic stack allocation. + */ stack = (FAR uint32_t*)kumm_malloc(binp->stacksize); if (!stack) @@ -185,18 +195,6 @@ int exec_module(FAR const struct binary_s *binp) goto errout_with_addrenv; } - /* Restore the address environment */ - -#ifdef CONFIG_ARCH_ADDRENV - ret = up_addrenv_restore(&oldenv); - if (ret < 0) - { - bdbg("ERROR: up_addrenv_select() failed: %d\n", ret); - err = -ret; - goto errout_with_stack; - } -#endif - /* Initialize the task */ ret = task_init((FAR struct tcb_s *)tcb, binp->filename, binp->priority, @@ -262,6 +260,18 @@ int exec_module(FAR const struct binary_s *binp) goto errout_with_stack; } +#ifdef CONFIG_ARCH_ADDRENV + /* Restore the address environment of the caller */ + + ret = up_addrenv_restore(&oldenv); + if (ret < 0) + { + bdbg("ERROR: up_addrenv_select() failed: %d\n", ret); + err = -ret; + goto errout_with_stack; + } +#endif + return (int)pid; errout_with_stack: diff --git a/nuttx/binfmt/libelf/libelf.h b/nuttx/binfmt/libelf/libelf.h index 4304e64f2..58ec757b8 100644 --- a/nuttx/binfmt/libelf/libelf.h +++ b/nuttx/binfmt/libelf/libelf.h @@ -283,6 +283,8 @@ int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo); * for the ELF image (read/execute). * datasize - The size (in bytes) of the .bss/.data address environment * needed for the ELF image (read/write). + * heapsize - The initial size (in bytes) of the heap address environment + * needed by the task. This region may be read/write only. * * Returned Value: * Zero (OK) on success; a negated errno value on failure. @@ -290,13 +292,13 @@ int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo); ****************************************************************************/ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, - size_t datasize); + size_t datasize, size_t heapsize); /**************************************************************************** * Name: elf_addrenv_select * * Description: - * Temporarity select the task's address environemnt. + * Temporarily select the task's address environemnt. * * Input Parameters: * loadinfo - Load state information diff --git a/nuttx/binfmt/libelf/libelf_addrenv.c b/nuttx/binfmt/libelf/libelf_addrenv.c index 08beed008..6b3be4306 100644 --- a/nuttx/binfmt/libelf/libelf_addrenv.c +++ b/nuttx/binfmt/libelf/libelf_addrenv.c @@ -80,6 +80,8 @@ * for the ELF image (read/execute). * datasize - The size (in bytes) of the .bss/.data address environment * needed for the ELF image (read/write). + * heapsize - The initial size (in bytes) of the heap address environment + * needed by the task. This region may be read/write only. * * Returned Value: * Zero (OK) on success; a negated errno value on failure. @@ -87,7 +89,7 @@ ****************************************************************************/ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, - size_t datasize) + size_t datasize, size_t heapsize) { #ifdef CONFIG_ARCH_ADDRENV FAR void *vtext; @@ -96,7 +98,7 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, /* Create an address environment for the new ELF task */ - ret = up_addrenv_create(textsize, datasize, &loadinfo->addrenv); + ret = up_addrenv_create(textsize, datasize, heapsize, &loadinfo->addrenv); if (ret < 0) { bdbg("ERROR: up_addrenv_create failed: %d\n", ret); @@ -145,7 +147,7 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, * * Description: * Release the address environment previously created by - * elf_addrenv_create(). This function is called only under certain error + * elf_addrenv_alloc(). This function is called only under certain error * conditions after the module has been loaded but not yet started. * After the module has been started, the address environment will * automatically be freed when the module exits. diff --git a/nuttx/binfmt/libelf/libelf_load.c b/nuttx/binfmt/libelf/libelf_load.c index 5fd4ce570..75ecb30fc 100644 --- a/nuttx/binfmt/libelf/libelf_load.c +++ b/nuttx/binfmt/libelf/libelf_load.c @@ -49,6 +49,7 @@ #include <errno.h> #include <debug.h> +#include <nuttx/addrenv.h> #include <nuttx/binfmt/elf.h> #include "libelf.h" @@ -62,7 +63,11 @@ #define ELF_ALIGNDOWN(a) ((unsigned long)(a) & ~ELF_ALIGN_MASK) #ifndef MAX -#define MAX(x,y) ((x) > (y) ? (x) : (y)) +# define MAX(x,y) ((x) > (y) ? (x) : (y)) +#endif + +#ifndef MIN +# define MIN(x,y) ((x) < (y) ? (x) : (y)) #endif /**************************************************************************** @@ -229,6 +234,7 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) int elf_load(FAR struct elf_loadinfo_s *loadinfo) { + size_t heapsize; int ret; bvdbg("loadinfo: %p\n", loadinfo); @@ -247,9 +253,17 @@ int elf_load(FAR struct elf_loadinfo_s *loadinfo) elf_elfsize(loadinfo); + /* Determine the heapsize to allocate */ + +#ifdef CONFIG_ARCH_STACK_DYNAMIC + heapsize = ARCH_HEAP_SIZE; +#else + heapsize = MIN(ARCH_HEAP_SIZE, CONFIG_ELF_STACKSIZE); +#endif + /* Allocate (and zero) memory for the ELF file. */ - ret = elf_addrenv_alloc(loadinfo, loadinfo->textsize, loadinfo->datasize); + ret = elf_addrenv_alloc(loadinfo, loadinfo->textsize, loadinfo->datasize, heapsize); if (ret < 0) { bdbg("ERROR: elf_addrenv_alloc() failed: %d\n", ret); diff --git a/nuttx/binfmt/libnxflat/libnxflat.h b/nuttx/binfmt/libnxflat/libnxflat.h index fc3826295..32d82df74 100644 --- a/nuttx/binfmt/libnxflat/libnxflat.h +++ b/nuttx/binfmt/libnxflat/libnxflat.h @@ -116,7 +116,7 @@ int nxflat_addrenv_alloc(FAR struct nxflat_loadinfo_s *loadinfo, size_t envsize) * * Description: * Release the address environment previously created by - * nxflat_addrenv_create(). This function is called only under certain + * nxflat_addrenv_alloc(). This function is called only under certain * error conditions after the module has been loaded but not yet * started. After the module has been started, the address environment * will automatically be freed when the module exits. diff --git a/nuttx/binfmt/libnxflat/libnxflat_addrenv.c b/nuttx/binfmt/libnxflat/libnxflat_addrenv.c index fb3dbe09a..c7e82f537 100644 --- a/nuttx/binfmt/libnxflat/libnxflat_addrenv.c +++ b/nuttx/binfmt/libnxflat/libnxflat_addrenv.c @@ -52,6 +52,10 @@ * Pre-Processor Definitions ****************************************************************************/ +#ifndef MIN +# define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif + /**************************************************************************** * Private Constant Data ****************************************************************************/ @@ -88,6 +92,7 @@ int nxflat_addrenv_alloc(FAR struct nxflat_loadinfo_s *loadinfo, size_t envsize) #ifdef CONFIG_ARCH_ADDRENV FAR void *vdata; save_addrenv_t oldenv; + size_t heapsize; int ret; #endif @@ -103,9 +108,17 @@ int nxflat_addrenv_alloc(FAR struct nxflat_loadinfo_s *loadinfo, size_t envsize) } #ifdef CONFIG_ARCH_ADDRENV + /* Determine the heapsize to allocate */ + +#ifdef CONFIG_ARCH_STACK_DYNAMIC + heapsize = ARCH_HEAP_SIZE; +#else + heapsize = MIN(loadinfo->stacksize, ARCH_HEAP_SIZE); +#endif + /* Create a D-Space address environment for the new NXFLAT task */ - ret = up_addrenv_create(envsize, &loadinfo->addrenv); + ret = up_addrenv_create(0, envsize, heapsize, &loadinfo->addrenv); if (ret < 0) { bdbg("ERROR: up_addrenv_create failed: %d\n", ret); diff --git a/nuttx/include/nuttx/addrenv.h b/nuttx/include/nuttx/addrenv.h index 6b1fc2809..385bce32e 100644 --- a/nuttx/include/nuttx/addrenv.h +++ b/nuttx/include/nuttx/addrenv.h @@ -245,27 +245,28 @@ struct addrenv_reserve_s * is an abstract representation of a task group's address environment and * must be defined in arch/arch.h if CONFIG_ARCH_ADDRENV is defined. * - * up_addrenv_create - Create an address environment - * up_addrenv_destroy - Destroy an address environment. - * up_addrenv_vtext - Returns the virtual base address of the .text - * address environment - * up_addrenv_vdata - Returns the virtual base address of the .bss/.data - * address environment - * up_addrenv_select - Instantiate an address environment - * up_addrenv_restore - Restore an address environment - * up_addrenv_clone - Copy an address environment from one location to - * another. + * up_addrenv_create - Create an address environment + * up_addrenv_destroy - Destroy an address environment. + * up_addrenv_vtext - Returns the virtual base address of the .text + * address environment + * up_addrenv_vdata - Returns the virtual base address of the .bss/.data + * address environment + * up_addrenv_heapsize - Returns the size of the initial heap allocation. + * up_addrenv_select - Instantiate an address environment + * up_addrenv_restore - Restore an address environment + * up_addrenv_clone - Copy an address environment from one location to + * another. * * Higher-level interfaces used by the tasking logic. These interfaces are * used by the functions in sched/ and all operate on the thread which whose * group been assigned an address environment by up_addrenv_clone(). * - * up_addrenv_attach - Clone the address environment assigned to one TCB - * to another. This operation is done when a pthread - * is created that share's the same address - * environment. - * up_addrenv_detach - Release the threads reference to an address - * environment when a task/thread exits. + * up_addrenv_attach - Clone the address environment assigned to one TCB + * to another. This operation is done when a pthread + * is created that share's the same address + * environment. + * up_addrenv_detach - Release the threads reference to an address + * environment when a task/thread exits. * ****************************************************************************/ diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h index 9344383a8..92deaacca 100644 --- a/nuttx/include/nuttx/arch.h +++ b/nuttx/include/nuttx/arch.h @@ -724,27 +724,28 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages); * is an abstract representation of a task group's address environment and * must be defined in arch/arch.h if CONFIG_ARCH_ADDRENV is defined. * - * up_addrenv_create - Create an address environment - * up_addrenv_destroy - Destroy an address environment. - * up_addrenv_vtext - Returns the virtual base address of the .text - * address environment - * up_addrenv_vdata - Returns the virtual base address of the .bss/.data - * address environment - * up_addrenv_select - Instantiate an address environment - * up_addrenv_restore - Restore an address environment - * up_addrenv_clone - Copy an address environment from one location to - * another. + * up_addrenv_create - Create an address environment + * up_addrenv_destroy - Destroy an address environment. + * up_addrenv_vtext - Returns the virtual base address of the .text + * address environment + * up_addrenv_vdata - Returns the virtual base address of the .bss/.data + * address environment + * up_addrenv_heapsize - Returns the size of the initial heap allocation. + * up_addrenv_select - Instantiate an address environment + * up_addrenv_restore - Restore an address environment + * up_addrenv_clone - Copy an address environment from one location to + * another. * * Higher-level interfaces used by the tasking logic. These interfaces are * used by the functions in sched/ and all operate on the thread which whose * group been assigned an address environment by up_addrenv_clone(). * - * up_addrenv_attach - Clone the address environment assigned to one TCB - * to another. This operation is done when a pthread - * is created that share's the same address - * environment. - * up_addrenv_detach - Release the threads reference to an address - * environment when a task/thread exits. + * up_addrenv_attach - Clone the address environment assigned to one TCB + * to another. This operation is done when a pthread + * is created that share's the same address + * environment. + * up_addrenv_detach - Release the threads reference to an address + * environment when a task/thread exits. * ****************************************************************************/ /**************************************************************************** @@ -764,6 +765,8 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages); * actual size of the data region that is allocated will include a * OS private reserved region at the beginning. The size of the * private, reserved region is give by ARCH_DATA_RESERVE_SIZE. + * heapsize - The initial size (in bytes) of the heap address environment + * needed by the task. This region may be read/write only. * addrenv - The location to return the representation of the task address * environment. * @@ -773,7 +776,7 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages); ****************************************************************************/ #ifdef CONFIG_ARCH_ADDRENV -int up_addrenv_create(size_t textsize, size_t datasize, +int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, FAR group_addrenv_t *addrenv); #endif @@ -851,6 +854,29 @@ int up_addrenv_vdata(FAR group_addrenv_t *addrenv, uintptr_t textsize, #endif /**************************************************************************** + * Name: up_addrenv_heapsize + * + * Description: + * Return the initial heap allocation size. That is the amount of memory + * allocated by up_addrenv_create() when the heap memory region was first + * created. This may or may not differ from the heapsize parameter that + * was passed to up_addrenv_create() + * + * Input Parameters: + * addrenv - The representation of the task address environment previously + * returned by up_addrenv_create. + * + * Returned Value: + * The initial heap size allocated is returned on success; a negated + * errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_ADDRENV +ssize_t up_addrenv_heapsize(FAR const group_addrenv_t *addrenv); +#endif + +/**************************************************************************** * Name: up_addrenv_select * * Description: diff --git a/nuttx/include/nuttx/mm.h b/nuttx/include/nuttx/mm.h index 3330b2bfc..b748c16b4 100644 --- a/nuttx/include/nuttx/mm.h +++ b/nuttx/include/nuttx/mm.h @@ -297,9 +297,7 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, /* Functions contained in umm_initialize.c **********************************/ -#if !defined(CONFIG_BUILD_PROTECTED) || !defined(__KERNEL__) void umm_initialize(FAR void *heap_start, size_t heap_size); -#endif /* Functions contained in kmm_initialize.c **********************************/ diff --git a/nuttx/mm/umm_initialize.c b/nuttx/mm/umm_initialize.c index d7288e474..fb812d5c5 100644 --- a/nuttx/mm/umm_initialize.c +++ b/nuttx/mm/umm_initialize.c @@ -88,8 +88,36 @@ struct mm_heap_s g_mmheap; * * Description: * This is a simple wrapper for the mm_initialize() function. This - * function is exported from the user-space blob so that the kernel - * can initialize the user-mode allocator. + * function will initialize the user heap. + * + * CONFIG_BUILD_FLAT: + * There is only kernel mode "blob" containing both containing both + * kernel and application code. There is only one heap that use is + * used by both the kernel and application logic. + * + * In this configuration, this function is called early in os_start() + * to initialize the common heap. + * + * CONFIG_BUILD_PROTECTED + * In this configuration, there are two "blobs", one containing + * protected kernel logic and one containing unprotected application + * logic. Depending upon the setting of CONFIG_MM_KERNEL_HEAP there + * may be only a signal shared heap, much as with CONFIG_BUILD_FLAT. + * Or there may be separate protected/kernel and unprotected/user + * heaps. + * + * In either case, this function is still called early in os_start() + * to initialize the user heap. + * + * CONFIG_BUILD_KERNEL + * In this configuration there are multiple user heaps, one for each + * user process. Furthermore, each heap is initially empty; memory + * is added to each heap dynamically via sbrk(). The heap data + * structure was set to zero when the address environment was created. + * Otherwise, the heap is uninitialized. + * + * This function is not called at all. Rather, this function is called + * when each user process is created before the first allocation is made. * * Parameters: * heap_start - Address of the beginning of the (initial) memory region @@ -102,10 +130,6 @@ struct mm_heap_s g_mmheap; void umm_initialize(FAR void *heap_start, size_t heap_size) { -#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) - DEBUGASSERT(ARCH_DATA_RESERVE_SIZE >= sizeof(struct addrenv_reserve_s)); -#endif - mm_initialize(USR_HEAP, heap_start, heap_size); } |