Move static helper routines from arm_addrenv.c and may them global so that they can be shared both forthcoming stack address environment logic.

This commit is contained in:
Gregory Nutt 2014-09-13 13:17:44 -06:00
parent 5db6d0b6f9
commit f965ca1fed
8 changed files with 513 additions and 252 deletions

View File

@ -235,7 +235,7 @@ config ARCH_STACK_DYNAMIC
general meaning of this configuration environment is simply that the general meaning of this configuration environment is simply that the
stack has its own address space. 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 LIBC_EXECFUNCS are selected. Why? Because the caller's stack must
be preserved in its own address space when we instantiate the be preserved in its own address space when we instantiate the
environment of the new process in order to initialize it. environment of the new process in order to initialize it.

View File

@ -91,7 +91,7 @@ CMN_CSRCS += up_task_start.c up_pthread_start.c up_signal_dispatch.c
endif endif
ifeq ($(CONFIG_ARCH_ADDRENV),y) 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 endif
ifeq ($(CONFIG_ELF),y) ifeq ($(CONFIG_ELF),y)

View File

@ -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 */

View File

@ -63,6 +63,27 @@
* up_addrenv_detach - Release the threads reference to an address * up_addrenv_detach - Release the threads reference to an address
* environment when a task/thread exits. * 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 <nuttx/config.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <assert.h>
#include <debug.h> #include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/addrenv.h> #include <nuttx/addrenv.h>
#include <arch/arch.h> #include <nuttx/arch.h>
#include <nuttx/pgalloc.h>
#include <arch/irq.h> #include <arch/irq.h>
#include "pginline.h"
#include "cache.h" #include "cache.h"
#include "mmu.h" #include "mmu.h"
#include "pginline.h" #include "addrenv.h"
#ifdef CONFIG_ARCH_ADDRENV #ifdef CONFIG_ARCH_ADDRENV
@ -104,12 +126,6 @@
# error CONFIG_ARCH_HEAP_VBASE not aligned to section boundary # error CONFIG_ARCH_HEAP_VBASE not aligned to section boundary
#endif #endif
/* Using a 4KiB page size, each 1MiB section maps to a PTE containing
* 256*2KiB entries
*/
#define ENTRIES_PER_L2TABLE 256
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
@ -118,156 +134,6 @@
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* 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 * Name: up_addrenv_initdata
* *
@ -344,79 +210,6 @@ static int up_addrenv_initdata(uintptr_t l2table)
} }
#endif /* CONFIG_BUILD_KERNEL */ #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 * Public Functions
****************************************************************************/ ****************************************************************************/
@ -469,9 +262,9 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize,
/* Allocate .text space pages */ /* Allocate .text space pages */
ret = up_addrenv_create_region(addrenv->text, ARCH_TEXT_NSECTS, ret = arm_addrenv_create_region(addrenv->text, ARCH_TEXT_NSECTS,
CONFIG_ARCH_TEXT_VBASE, textsize, CONFIG_ARCH_TEXT_VBASE, textsize,
MMU_L2_UTEXTFLAGS); MMU_L2_UTEXTFLAGS);
if (ret < 0) if (ret < 0)
{ {
bdbg("ERROR: Failed to create .text region: %d\n", ret); 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(). * used when reporting the virtual data address in up_addrenv_vdata().
*/ */
ret = up_addrenv_create_region(addrenv->data, ARCH_DATA_NSECTS, ret = arm_addrenv_create_region(addrenv->data, ARCH_DATA_NSECTS,
CONFIG_ARCH_DATA_VBASE, CONFIG_ARCH_DATA_VBASE,
datasize + ARCH_DATA_RESERVE_SIZE, datasize + ARCH_DATA_RESERVE_SIZE,
MMU_L2_UDATAFLAGS); MMU_L2_UDATAFLAGS);
if (ret < 0) if (ret < 0)
{ {
bdbg("ERROR: Failed to create .bss/.data region: %d\n", ret); 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 #ifdef CONFIG_BUILD_KERNEL
/* Allocate heap space pages */ /* Allocate heap space pages */
ret = up_addrenv_create_region(addrenv->heap, ARCH_HEAP_NSECTS, ret = arm_addrenv_create_region(addrenv->heap, ARCH_HEAP_NSECTS,
CONFIG_ARCH_HEAP_VBASE, heapsize, CONFIG_ARCH_HEAP_VBASE, heapsize,
MMU_L2_UDATAFLAGS); MMU_L2_UDATAFLAGS);
if (ret < 0) if (ret < 0)
{ {
bdbg("ERROR: Failed to create heap region: %d\n", ret); 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 */ /* Destroy the .text region */
up_addrenv_destroy_region(addrenv->text, ARCH_TEXT_NSECTS, arm_addrenv_destroy_region(addrenv->text, ARCH_TEXT_NSECTS,
CONFIG_ARCH_TEXT_VBASE); CONFIG_ARCH_TEXT_VBASE);
/* Destroy the .bss/.data region */ /* Destroy the .bss/.data region */
up_addrenv_destroy_region(addrenv->data, ARCH_DATA_NSECTS, arm_addrenv_destroy_region(addrenv->data, ARCH_DATA_NSECTS,
CONFIG_ARCH_DATA_VBASE); CONFIG_ARCH_DATA_VBASE);
#ifdef CONFIG_BUILD_KERNEL #ifdef CONFIG_BUILD_KERNEL
/* Destroy the heap region */ /* Destroy the heap region */
up_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS, arm_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS,
CONFIG_ARCH_HEAP_VBASE); CONFIG_ARCH_HEAP_VBASE);
memset(addrenv, 0, sizeof(group_addrenv_t)); memset(addrenv, 0, sizeof(group_addrenv_t));
#endif #endif

View File

@ -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 */

View File

@ -93,7 +93,7 @@ CMN_CSRCS += up_task_start.c up_pthread_start.c up_signal_dispatch.c
endif endif
ifeq ($(CONFIG_ARCH_ADDRENV),y) 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 endif
ifeq ($(CONFIG_ELF),y) ifeq ($(CONFIG_ELF),y)

View File

@ -274,6 +274,27 @@ struct addrenv_reserve_s
* up_addrenv_detach - Release the thread's reference to an address * up_addrenv_detach - Release the thread's reference to an address
* environment when a task/thread exits. * 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 */ /* Prototyped in include/nuttx/arch.h as part of the OS/platform interface */

View File

@ -747,6 +747,27 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages);
* up_addrenv_detach - Release the threads reference to an address * up_addrenv_detach - Release the threads reference to an address
* environment when a task/thread exits. * 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 * Name: up_addrenv_create