summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-10 15:55:36 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-10 15:55:36 -0600
commit7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2 (patch)
tree776264ed920f68eed300648dffe198e286495000
parent22c64f6c542675d4865d2a013468089c92f43869 (diff)
downloadpx4-nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.tar.gz
px4-nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.tar.bz2
px4-nuttx-7b3a98b2ec57f8c56a1669b818d03dfcd1a84fb2.zip
Add logic to initialize the per-process user heap when each user process is started
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html68
-rw-r--r--nuttx/arch/arm/include/arch.h12
-rwxr-xr-xnuttx/arch/arm/include/armv7-a/irq.h4
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv.c90
-rw-r--r--nuttx/arch/z80/src/z180/z180_mmu.c64
-rw-r--r--nuttx/binfmt/binfmt_execmodule.c40
-rw-r--r--nuttx/binfmt/libelf/libelf.h6
-rw-r--r--nuttx/binfmt/libelf/libelf_addrenv.c8
-rw-r--r--nuttx/binfmt/libelf/libelf_load.c18
-rw-r--r--nuttx/binfmt/libnxflat/libnxflat.h2
-rw-r--r--nuttx/binfmt/libnxflat/libnxflat_addrenv.c15
-rw-r--r--nuttx/include/nuttx/addrenv.h33
-rw-r--r--nuttx/include/nuttx/arch.h60
-rw-r--r--nuttx/include/nuttx/mm.h2
-rw-r--r--nuttx/mm/umm_initialize.c36
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);
}