summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/arch/Kconfig2
-rw-r--r--nuttx/arch/arm/src/a1x/Make.defs2
-rw-r--r--nuttx/arch/arm/src/armv7-a/addrenv.h131
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv.c291
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv_utils.c295
-rw-r--r--nuttx/arch/arm/src/sama5/Make.defs2
-rw-r--r--nuttx/include/nuttx/addrenv.h21
-rw-r--r--nuttx/include/nuttx/arch.h21
8 files changed, 513 insertions, 252 deletions
diff --git a/nuttx/arch/Kconfig b/nuttx/arch/Kconfig
index 9a7aa1476..6aaf1bac1 100644
--- a/nuttx/arch/Kconfig
+++ b/nuttx/arch/Kconfig
@@ -235,7 +235,7 @@ config ARCH_STACK_DYNAMIC
general meaning of this configuration environment is simply that the
stack has its own address space.
- NOTE: This options is also *required* if BUILD_KERNEL and
+ NOTE: This option is also *required* if BUILD_KERNEL and
LIBC_EXECFUNCS are selected. Why? Because the caller's stack must
be preserved in its own address space when we instantiate the
environment of the new process in order to initialize it.
diff --git a/nuttx/arch/arm/src/a1x/Make.defs b/nuttx/arch/arm/src/a1x/Make.defs
index 98972d872..62f969220 100644
--- a/nuttx/arch/arm/src/a1x/Make.defs
+++ b/nuttx/arch/arm/src/a1x/Make.defs
@@ -91,7 +91,7 @@ CMN_CSRCS += up_task_start.c up_pthread_start.c up_signal_dispatch.c
endif
ifeq ($(CONFIG_ARCH_ADDRENV),y)
-CMN_CSRCS += arm_addrenv.c arm_pgalloc.c
+CMN_CSRCS += arm_addrenv.c arm_addrenv_utils.c arm_pgalloc.c
endif
ifeq ($(CONFIG_ELF),y)
diff --git a/nuttx/arch/arm/src/armv7-a/addrenv.h b/nuttx/arch/arm/src/armv7-a/addrenv.h
new file mode 100644
index 000000000..0d830ed06
--- /dev/null
+++ b/nuttx/arch/arm/src/armv7-a/addrenv.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+ * arch/arm/src/armv7-a/addrenv.h
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_ARMV7_A_ADDRENV_H
+#define __ARCH_ARM_SRC_ARMV7_A_ADDRENV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef CONFIG_ARCH_ADDRENV
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Using a 4KiB page size, each 1MiB section maps to a PTE containing
+ * 256*2KiB entries
+ */
+
+#define ENTRIES_PER_L2TABLE 256
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#endif /* __ASSEMBLY__ */
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: set_l2_entry
+ *
+ * Description:
+ * Set the L2 table entry as part of the initialization of the L2 Page
+ * table.
+ *
+ ****************************************************************************/
+
+void set_l2_entry(FAR uint32_t *l2table, uintptr_t paddr, uintptr_t vaddr,
+ uint32_t mmuflags);
+
+/****************************************************************************
+ * Name: arm_addrenv_create_region
+ *
+ * Description:
+ * Create one memory region.
+ *
+ * Returned Value:
+ * On success, the number of pages allocated is returned. Otherwise, a
+ * negated errno value is returned.
+ *
+ ****************************************************************************/
+
+int arm_addrenv_create_region(FAR uintptr_t **list, unsigned int listlen,
+ uintptr_t vaddr, size_t regionsize,
+ uint32_t mmuflags);
+
+/****************************************************************************
+ * Name: arm_addrenv_destroy_region
+ *
+ * Description:
+ * Destroy one memory region.
+ *
+ ****************************************************************************/
+
+void arm_addrenv_destroy_region(FAR uintptr_t **list, unsigned int listlen,
+ uintptr_t vaddr);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARCH_ADDRENV */
+#endif /* __ARCH_ARM_SRC_ARMV7_A_ADDRENV_H */
diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c
index c05f6b21e..c5e5a813c 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c
+++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c
@@ -63,6 +63,27 @@
* up_addrenv_detach - Release the threads reference to an address
* environment when a task/thread exits.
*
+ * CONFIG_ARCH_STACK_DYNAMIC=y indicates that the user process stack resides
+ * in its own address space. This options is also *required* if
+ * CONFIG_BUILD_KERNEL and CONFIG_LIBC_EXECFUNCS are selected. Why?
+ * Because the caller's stack must be preserved in its own address space
+ * when we instantiate the environment of the new process in order to
+ * initialize it.
+ *
+ * NOTE: The naming of the CONFIG_ARCH_STACK_DYNAMIC selection implies that
+ * dynamic stack allocation is supported. Certainly this option must be set
+ * if dynamic stack allocation is supported by a platform. But the more
+ * general meaning of this configuration environment is simply that the
+ * stack has its own address space.
+ *
+ * If CONFIG_ARCH_STACK_DYNAMIC=y is selected then the platform specific
+ * code must export these additional interfaces:
+ *
+ * up_addrenv_stackalloc - Create a stack address environment
+ * up_addrenv_stackfree - Destroy a stack address environment.
+ * up_addrenv_vstack - Returns the virtual base address of the stack
+ * up_addrenv_stackselect - Instantiate a stack address environment
+ *
****************************************************************************/
/****************************************************************************
@@ -72,18 +93,19 @@
#include <nuttx/config.h>
#include <string.h>
-#include <errno.h>
+#include <assert.h>
#include <debug.h>
-#include <nuttx/arch.h>
#include <nuttx/addrenv.h>
-#include <arch/arch.h>
+#include <nuttx/arch.h>
+#include <nuttx/pgalloc.h>
#include <arch/irq.h>
+#include "pginline.h"
#include "cache.h"
#include "mmu.h"
-#include "pginline.h"
+#include "addrenv.h"
#ifdef CONFIG_ARCH_ADDRENV
@@ -104,12 +126,6 @@
# error CONFIG_ARCH_HEAP_VBASE not aligned to section boundary
#endif
-/* Using a 4KiB page size, each 1MiB section maps to a PTE containing
- * 256*2KiB entries
- */
-
-#define ENTRIES_PER_L2TABLE 256
-
/****************************************************************************
* Private Data
****************************************************************************/
@@ -119,156 +135,6 @@
****************************************************************************/
/****************************************************************************
- * Name: set_l2_entry
- *
- * Description:
- * Set the L2 table entry as part of the initialization of the L2 Page
- * table.
- *
- ****************************************************************************/
-
-static void set_l2_entry(FAR uint32_t *l2table, uintptr_t paddr,
- uintptr_t vaddr, uint32_t mmuflags)
-{
- uint32_t index;
-
- /* The table divides a 1Mb address space up into 256 entries, each
- * corresponding to 4Kb of address space. The page table index is
- * related to the offset from the beginning of 1Mb region.
- */
-
- index = (vaddr & 0x000ff000) >> 12;
-
- /* Save the table entry */
-
- l2table[index] = (paddr | mmuflags);
-}
-
-/****************************************************************************
- * Name: up_addrenv_create_region
- *
- * 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,
- unsigned int listlen, uintptr_t vaddr,
- size_t regionsize, uint32_t mmuflags)
-{
- irqstate_t flags;
- uintptr_t paddr;
- FAR uint32_t *l2table;
-#ifndef CONFIG_ARCH_PGPOOL_MAPPING
- uint32_t l1save;
-#endif
- size_t nmapped;
- unsigned int npages;
- unsigned int i;
- unsigned int j;
-
- bvdbg("listlen=%d vaddr=%08lx regionsize=%ld, mmuflags=%08x\n",
- listlen, (unsigned long)vaddr, (unsigned long)regionsize,
- (unsigned int)mmuflags);
-
- /* Verify that we are configured with enough virtual address space to
- * support this memory region.
- *
- * npages pages correspondes to (npages << MM_PGSHIFT) bytes
- * listlen sections corresponds to (listlen << 20) bytes
- */
-
- npages = MM_NPAGES(regionsize);
- if (npages > (listlen << (20 - MM_PGSHIFT)))
- {
- bdbg("ERROR: npages=%u listlen=%u\n", npages, listlen);
- return -E2BIG;
- }
-
- /* Back the allocation up with physical pages and set up the level mapping
- * (which of course does nothing until the L2 page table is hooked into
- * the L1 page table).
- */
-
- nmapped = 0;
- for (i = 0; i < npages; i += ENTRIES_PER_L2TABLE)
- {
- /* Allocate one physical page for the L2 page table */
-
- paddr = mm_pgalloc(1);
- if (!paddr)
- {
- return -ENOMEM;
- }
-
- DEBUGASSERT(MM_ISALIGNED(paddr));
- list[i] = (FAR uintptr_t *)paddr;
-
- flags = irqsave();
-
-#ifdef CONFIG_ARCH_PGPOOL_MAPPING
- /* Get the virtual address corresponding to the physical page address */
-
- l2table = (FAR uint32_t *)arm_pgvaddr(paddr);
-#else
- /* Temporarily map the page into the virtual address space */
-
- l1save = mmu_l1_getentry(ARCH_SCRATCH_VBASE);
- mmu_l1_setentry(paddr & ~SECTION_MASK, ARCH_SCRATCH_VBASE, MMU_MEMFLAGS);
- l2table = (FAR uint32_t *)(ARCH_SCRATCH_VBASE | (paddr & SECTION_MASK));
-#endif
-
- /* Initialize the page table */
-
- memset(l2table, 0, ENTRIES_PER_L2TABLE * sizeof(uint32_t));
-
- /* Back up L2 entries with physical memory */
-
- for (j = 0; j < ENTRIES_PER_L2TABLE && nmapped < regionsize; j++)
- {
- /* Allocate one physical page for region data */
-
- paddr = mm_pgalloc(1);
- if (!paddr)
- {
-#ifndef CONFIG_ARCH_PGPOOL_MAPPING
- mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
-#endif
- irqrestore(flags);
- return -ENOMEM;
- }
-
- /* Map the .text region virtual address to this physical address */
-
- set_l2_entry(l2table, paddr, vaddr, mmuflags);
- nmapped += MM_PGSIZE;
- vaddr += MM_PGSIZE;
- }
-
- /* Make sure that the initialized L2 table is flushed to physical
- * memory.
- */
-
- arch_flush_dcache((uintptr_t)l2table,
- (uintptr_t)l2table +
- ENTRIES_PER_L2TABLE * sizeof(uint32_t));
-
-#ifndef CONFIG_ARCH_PGPOOL_MAPPING
- /* Restore the scratch section L1 page table entry */
-
- mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
-#endif
- irqrestore(flags);
- }
-
- return npages;
-}
-
-/****************************************************************************
* Name: up_addrenv_initdata
*
* Description:
@@ -345,79 +211,6 @@ static int up_addrenv_initdata(uintptr_t l2table)
#endif /* CONFIG_BUILD_KERNEL */
/****************************************************************************
- * Name: up_addrenv_destroy_region
- *
- * Description:
- * Destroy one memory region.
- *
- ****************************************************************************/
-
-static void up_addrenv_destroy_region(FAR uintptr_t **list,
- unsigned int listlen, uintptr_t vaddr)
-{
- irqstate_t flags;
- uintptr_t paddr;
- FAR uint32_t *l2table;
-#ifndef CONFIG_ARCH_PGPOOL_MAPPING
- uint32_t l1save;
-#endif
- int i;
- int j;
-
- bvdbg("listlen=%d vaddr=%08lx\n", listlen, (unsigned long)vaddr);
-
- for (i = 0; i < listlen; vaddr += SECTION_SIZE, list++, i++)
- {
- /* Unhook the L2 page table from the L1 page table */
-
- mmu_l1_clrentry(vaddr);
-
- /* Has this page table been allocated? */
-
- paddr = (uintptr_t)list[i];
- if (paddr != 0)
- {
- flags = irqsave();
-
-#ifdef CONFIG_ARCH_PGPOOL_MAPPING
- /* Get the virtual address corresponding to the physical page address */
-
- l2table = (FAR uint32_t *)arm_pgvaddr(paddr);
-#else
- /* Temporarily map the page into the virtual address space */
-
- l1save = mmu_l1_getentry(ARCH_SCRATCH_VBASE);
- mmu_l1_setentry(paddr & ~SECTION_MASK, ARCH_SCRATCH_VBASE, MMU_MEMFLAGS);
- l2table = (FAR uint32_t *)(ARCH_SCRATCH_VBASE | (paddr & SECTION_MASK));
-#endif
-
- /* Return the allocated pages to the page allocator */
-
- for (j = 0; j < ENTRIES_PER_L2TABLE; j++)
- {
- paddr = *l2table++;
- if (paddr != 0)
- {
- paddr &= PTE_SMALL_PADDR_MASK;
- mm_pgfree(paddr, 1);
- }
- }
-
-#ifndef CONFIG_ARCH_PGPOOL_MAPPING
- /* Restore the scratch section L1 page table entry */
-
- mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
-#endif
- irqrestore(flags);
-
- /* And free the L2 page table itself */
-
- mm_pgfree((uintptr_t)list[i], 1);
- }
- }
-}
-
-/****************************************************************************
* Public Functions
****************************************************************************/
@@ -469,9 +262,9 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize,
/* Allocate .text space pages */
- ret = up_addrenv_create_region(addrenv->text, ARCH_TEXT_NSECTS,
- CONFIG_ARCH_TEXT_VBASE, textsize,
- MMU_L2_UTEXTFLAGS);
+ ret = arm_addrenv_create_region(addrenv->text, ARCH_TEXT_NSECTS,
+ CONFIG_ARCH_TEXT_VBASE, textsize,
+ MMU_L2_UTEXTFLAGS);
if (ret < 0)
{
bdbg("ERROR: Failed to create .text region: %d\n", ret);
@@ -483,10 +276,10 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize,
* used when reporting the virtual data address in up_addrenv_vdata().
*/
- ret = up_addrenv_create_region(addrenv->data, ARCH_DATA_NSECTS,
- CONFIG_ARCH_DATA_VBASE,
- datasize + ARCH_DATA_RESERVE_SIZE,
- MMU_L2_UDATAFLAGS);
+ ret = arm_addrenv_create_region(addrenv->data, ARCH_DATA_NSECTS,
+ CONFIG_ARCH_DATA_VBASE,
+ datasize + ARCH_DATA_RESERVE_SIZE,
+ MMU_L2_UDATAFLAGS);
if (ret < 0)
{
bdbg("ERROR: Failed to create .bss/.data region: %d\n", ret);
@@ -509,9 +302,9 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize,
#ifdef CONFIG_BUILD_KERNEL
/* Allocate heap space pages */
- ret = up_addrenv_create_region(addrenv->heap, ARCH_HEAP_NSECTS,
- CONFIG_ARCH_HEAP_VBASE, heapsize,
- MMU_L2_UDATAFLAGS);
+ ret = arm_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);
@@ -554,19 +347,19 @@ int up_addrenv_destroy(FAR group_addrenv_t *addrenv)
/* Destroy the .text region */
- up_addrenv_destroy_region(addrenv->text, ARCH_TEXT_NSECTS,
- CONFIG_ARCH_TEXT_VBASE);
+ arm_addrenv_destroy_region(addrenv->text, ARCH_TEXT_NSECTS,
+ CONFIG_ARCH_TEXT_VBASE);
/* Destroy the .bss/.data region */
- up_addrenv_destroy_region(addrenv->data, ARCH_DATA_NSECTS,
- CONFIG_ARCH_DATA_VBASE);
+ arm_addrenv_destroy_region(addrenv->data, ARCH_DATA_NSECTS,
+ CONFIG_ARCH_DATA_VBASE);
#ifdef CONFIG_BUILD_KERNEL
/* Destroy the heap region */
- up_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS,
- CONFIG_ARCH_HEAP_VBASE);
+ arm_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS,
+ CONFIG_ARCH_HEAP_VBASE);
memset(addrenv, 0, sizeof(group_addrenv_t));
#endif
diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv_utils.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv_utils.c
new file mode 100644
index 000000000..1cf6c41f9
--- /dev/null
+++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv_utils.c
@@ -0,0 +1,295 @@
+/****************************************************************************
+ * arch/arm/src/armv7/arm_addrenv.c
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/pgalloc.h>
+
+#include <arch/irq.h>
+
+#include "cache.h"
+#include "mmu.h"
+#include "pginline.h"
+#include "addrenv.h"
+
+#ifdef CONFIG_ARCH_ADDRENV
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: set_l2_entry
+ *
+ * Description:
+ * Set the L2 table entry as part of the initialization of the L2 Page
+ * table.
+ *
+ ****************************************************************************/
+
+void set_l2_entry(FAR uint32_t *l2table, uintptr_t paddr, uintptr_t vaddr,
+ uint32_t mmuflags)
+{
+ uint32_t index;
+
+ /* The table divides a 1Mb address space up into 256 entries, each
+ * corresponding to 4Kb of address space. The page table index is
+ * related to the offset from the beginning of 1Mb region.
+ */
+
+ index = (vaddr & 0x000ff000) >> 12;
+
+ /* Save the table entry */
+
+ l2table[index] = (paddr | mmuflags);
+}
+
+/****************************************************************************
+ * Name: arm_addrenv_create_region
+ *
+ * Description:
+ * Create one memory region.
+ *
+ * Returned Value:
+ * On success, the number of pages allocated is returned. Otherwise, a
+ * negated errno value is returned.
+ *
+ ****************************************************************************/
+
+int arm_addrenv_create_region(FAR uintptr_t **list, unsigned int listlen,
+ uintptr_t vaddr, size_t regionsize,
+ uint32_t mmuflags)
+{
+ irqstate_t flags;
+ uintptr_t paddr;
+ FAR uint32_t *l2table;
+#ifndef CONFIG_ARCH_PGPOOL_MAPPING
+ uint32_t l1save;
+#endif
+ size_t nmapped;
+ unsigned int npages;
+ unsigned int i;
+ unsigned int j;
+
+ bvdbg("listlen=%d vaddr=%08lx regionsize=%ld, mmuflags=%08x\n",
+ listlen, (unsigned long)vaddr, (unsigned long)regionsize,
+ (unsigned int)mmuflags);
+
+ /* Verify that we are configured with enough virtual address space to
+ * support this memory region.
+ *
+ * npages pages correspondes to (npages << MM_PGSHIFT) bytes
+ * listlen sections corresponds to (listlen << 20) bytes
+ */
+
+ npages = MM_NPAGES(regionsize);
+ if (npages > (listlen << (20 - MM_PGSHIFT)))
+ {
+ bdbg("ERROR: npages=%u listlen=%u\n", npages, listlen);
+ return -E2BIG;
+ }
+
+ /* Back the allocation up with physical pages and set up the level mapping
+ * (which of course does nothing until the L2 page table is hooked into
+ * the L1 page table).
+ */
+
+ nmapped = 0;
+ for (i = 0; i < npages; i += ENTRIES_PER_L2TABLE)
+ {
+ /* Allocate one physical page for the L2 page table */
+
+ paddr = mm_pgalloc(1);
+ if (!paddr)
+ {
+ return -ENOMEM;
+ }
+
+ DEBUGASSERT(MM_ISALIGNED(paddr));
+ list[i] = (FAR uintptr_t *)paddr;
+
+ flags = irqsave();
+
+#ifdef CONFIG_ARCH_PGPOOL_MAPPING
+ /* Get the virtual address corresponding to the physical page address */
+
+ l2table = (FAR uint32_t *)arm_pgvaddr(paddr);
+#else
+ /* Temporarily map the page into the virtual address space */
+
+ l1save = mmu_l1_getentry(ARCH_SCRATCH_VBASE);
+ mmu_l1_setentry(paddr & ~SECTION_MASK, ARCH_SCRATCH_VBASE, MMU_MEMFLAGS);
+ l2table = (FAR uint32_t *)(ARCH_SCRATCH_VBASE | (paddr & SECTION_MASK));
+#endif
+
+ /* Initialize the page table */
+
+ memset(l2table, 0, ENTRIES_PER_L2TABLE * sizeof(uint32_t));
+
+ /* Back up L2 entries with physical memory */
+
+ for (j = 0; j < ENTRIES_PER_L2TABLE && nmapped < regionsize; j++)
+ {
+ /* Allocate one physical page for region data */
+
+ paddr = mm_pgalloc(1);
+ if (!paddr)
+ {
+#ifndef CONFIG_ARCH_PGPOOL_MAPPING
+ mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
+#endif
+ irqrestore(flags);
+ return -ENOMEM;
+ }
+
+ /* Map the .text region virtual address to this physical address */
+
+ set_l2_entry(l2table, paddr, vaddr, mmuflags);
+ nmapped += MM_PGSIZE;
+ vaddr += MM_PGSIZE;
+ }
+
+ /* Make sure that the initialized L2 table is flushed to physical
+ * memory.
+ */
+
+ arch_flush_dcache((uintptr_t)l2table,
+ (uintptr_t)l2table +
+ ENTRIES_PER_L2TABLE * sizeof(uint32_t));
+
+#ifndef CONFIG_ARCH_PGPOOL_MAPPING
+ /* Restore the scratch section L1 page table entry */
+
+ mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
+#endif
+ irqrestore(flags);
+ }
+
+ return npages;
+}
+
+/****************************************************************************
+ * Name: arm_addrenv_destroy_region
+ *
+ * Description:
+ * Destroy one memory region.
+ *
+ ****************************************************************************/
+
+void arm_addrenv_destroy_region(FAR uintptr_t **list, unsigned int listlen,
+ uintptr_t vaddr)
+{
+ irqstate_t flags;
+ uintptr_t paddr;
+ FAR uint32_t *l2table;
+#ifndef CONFIG_ARCH_PGPOOL_MAPPING
+ uint32_t l1save;
+#endif
+ int i;
+ int j;
+
+ bvdbg("listlen=%d vaddr=%08lx\n", listlen, (unsigned long)vaddr);
+
+ for (i = 0; i < listlen; vaddr += SECTION_SIZE, list++, i++)
+ {
+ /* Unhook the L2 page table from the L1 page table */
+
+ mmu_l1_clrentry(vaddr);
+
+ /* Has this page table been allocated? */
+
+ paddr = (uintptr_t)list[i];
+ if (paddr != 0)
+ {
+ flags = irqsave();
+
+#ifdef CONFIG_ARCH_PGPOOL_MAPPING
+ /* Get the virtual address corresponding to the physical page address */
+
+ l2table = (FAR uint32_t *)arm_pgvaddr(paddr);
+#else
+ /* Temporarily map the page into the virtual address space */
+
+ l1save = mmu_l1_getentry(ARCH_SCRATCH_VBASE);
+ mmu_l1_setentry(paddr & ~SECTION_MASK, ARCH_SCRATCH_VBASE, MMU_MEMFLAGS);
+ l2table = (FAR uint32_t *)(ARCH_SCRATCH_VBASE | (paddr & SECTION_MASK));
+#endif
+
+ /* Return the allocated pages to the page allocator */
+
+ for (j = 0; j < ENTRIES_PER_L2TABLE; j++)
+ {
+ paddr = *l2table++;
+ if (paddr != 0)
+ {
+ paddr &= PTE_SMALL_PADDR_MASK;
+ mm_pgfree(paddr, 1);
+ }
+ }
+
+#ifndef CONFIG_ARCH_PGPOOL_MAPPING
+ /* Restore the scratch section L1 page table entry */
+
+ mmu_l1_restore(ARCH_SCRATCH_VBASE, l1save);
+#endif
+ irqrestore(flags);
+
+ /* And free the L2 page table itself */
+
+ mm_pgfree((uintptr_t)list[i], 1);
+ }
+ }
+}
+
+#endif /* CONFIG_ARCH_ADDRENV */
diff --git a/nuttx/arch/arm/src/sama5/Make.defs b/nuttx/arch/arm/src/sama5/Make.defs
index c07fcc81a..fb2bc48ed 100644
--- a/nuttx/arch/arm/src/sama5/Make.defs
+++ b/nuttx/arch/arm/src/sama5/Make.defs
@@ -93,7 +93,7 @@ CMN_CSRCS += up_task_start.c up_pthread_start.c up_signal_dispatch.c
endif
ifeq ($(CONFIG_ARCH_ADDRENV),y)
-CMN_CSRCS += arm_addrenv.c arm_pgalloc.c
+CMN_CSRCS += arm_addrenv.c arm_addrenv_utils.c arm_pgalloc.c
endif
ifeq ($(CONFIG_ELF),y)
diff --git a/nuttx/include/nuttx/addrenv.h b/nuttx/include/nuttx/addrenv.h
index 5f5ee5f1f..936b7ee14 100644
--- a/nuttx/include/nuttx/addrenv.h
+++ b/nuttx/include/nuttx/addrenv.h
@@ -274,6 +274,27 @@ struct addrenv_reserve_s
* up_addrenv_detach - Release the thread's reference to an address
* environment when a task/thread exits.
*
+ * CONFIG_ARCH_STACK_DYNAMIC=y indicates that the user process stack resides
+ * in its own address space. This options is also *required* if
+ * CONFIG_BUILD_KERNEL and CONFIG_LIBC_EXECFUNCS are selected. Why?
+ * Because the caller's stack must be preserved in its own address space
+ * when we instantiate the environment of the new process in order to
+ * initialize it.
+ *
+ * NOTE: The naming of the CONFIG_ARCH_STACK_DYNAMIC selection implies that
+ * dynamic stack allocation is supported. Certainly this option must be set
+ * if dynamic stack allocation is supported by a platform. But the more
+ * general meaning of this configuration environment is simply that the
+ * stack has its own address space.
+ *
+ * If CONFIG_ARCH_STACK_DYNAMIC=y is selected then the platform specific
+ * code must export these additional interfaces:
+ *
+ * up_addrenv_stackalloc - Create a stack address environment
+ * up_addrenv_stackfree - Destroy a stack address environment.
+ * up_addrenv_vstack - Returns the virtual base address of the stack
+ * up_addrenv_stackselect - Instantiate a stack address environment
+ *
****************************************************************************/
/* Prototyped in include/nuttx/arch.h as part of the OS/platform interface */
diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h
index e577dc4b5..dafff424f 100644
--- a/nuttx/include/nuttx/arch.h
+++ b/nuttx/include/nuttx/arch.h
@@ -747,6 +747,27 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages);
* up_addrenv_detach - Release the threads reference to an address
* environment when a task/thread exits.
*
+ * CONFIG_ARCH_STACK_DYNAMIC=y indicates that the user process stack resides
+ * in its own address space. This options is also *required* if
+ * CONFIG_BUILD_KERNEL and CONFIG_LIBC_EXECFUNCS are selected. Why?
+ * Because the caller's stack must be preserved in its own address space
+ * when we instantiate the environment of the new process in order to
+ * initialize it.
+ *
+ * NOTE: The naming of the CONFIG_ARCH_STACK_DYNAMIC selection implies that
+ * dynamic stack allocation is supported. Certainly this option must be set
+ * if dynamic stack allocation is supported by a platform. But the more
+ * general meaning of this configuration environment is simply that the
+ * stack has its own address space.
+ *
+ * If CONFIG_ARCH_STACK_DYNAMIC=y is selected then the platform specific
+ * code must export these additional interfaces:
+ *
+ * up_addrenv_stackalloc - Create a stack address environment
+ * up_addrenv_stackfree - Destroy a stack address environment.
+ * up_addrenv_vstack - Returns the virtual base address of the stack
+ * up_addrenv_stackselect - Instantiate a stack address environment
+ *
****************************************************************************/
/****************************************************************************
* Name: up_addrenv_create