diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-09-13 13:45:35 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-09-13 13:45:35 -0600 |
commit | f7dfe6c8a364a7185a0c6654804660578326e1e0 (patch) | |
tree | 8aa7997661d38edc71de892ece316e632f2506ef | |
parent | fcb6166e6bb8e335e1d3fccd088bb87d8585ba8d (diff) | |
download | nuttx-f7dfe6c8a364a7185a0c6654804660578326e1e0.tar.gz nuttx-f7dfe6c8a364a7185a0c6654804660578326e1e0.tar.bz2 nuttx-f7dfe6c8a364a7185a0c6654804660578326e1e0.zip |
Add logic need to manage a virtualized stack. Not yet incorporated into base OS logic.
-rw-r--r-- | nuttx/arch/arm/src/a1x/Make.defs | 3 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_addrenv.c | 4 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_addrenv_stack.c | 288 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sama5/Make.defs | 3 | ||||
-rw-r--r-- | nuttx/include/nuttx/arch.h | 88 |
5 files changed, 384 insertions, 2 deletions
diff --git a/nuttx/arch/arm/src/a1x/Make.defs b/nuttx/arch/arm/src/a1x/Make.defs index 62f969220..22f506544 100644 --- a/nuttx/arch/arm/src/a1x/Make.defs +++ b/nuttx/arch/arm/src/a1x/Make.defs @@ -92,6 +92,9 @@ endif ifeq ($(CONFIG_ARCH_ADDRENV),y) CMN_CSRCS += arm_addrenv.c arm_addrenv_utils.c arm_pgalloc.c +ifeq ($(CONFIG_ARCH_STACK_DYNAMIC),y) +CMN_CSRCS += arm_addrenv_stack.c +endif endif ifeq ($(CONFIG_ELF),y) diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c index c5e5a813c..257a14a36 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_addrenv.c +++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv.c @@ -255,7 +255,7 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, memset(addrenv, 0, sizeof(group_addrenv_t)); - /* Back the allocation up with physical pages and set up the level mapping + /* Back the allocation up with physical pages and set up the level 2 mapping * (which of course does nothing until the L2 page table is hooked into * the L1 page table). */ @@ -360,9 +360,9 @@ int up_addrenv_destroy(FAR group_addrenv_t *addrenv) arm_addrenv_destroy_region(addrenv->heap, ARCH_HEAP_NSECTS, CONFIG_ARCH_HEAP_VBASE); +#endif memset(addrenv, 0, sizeof(group_addrenv_t)); -#endif return OK; } diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv_stack.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv_stack.c new file mode 100644 index 000000000..225906f81 --- /dev/null +++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv_stack.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * arch/arm/src/armv7/arm_addrenv_stack.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. + * + ****************************************************************************/ +/**************************************************************************** + * Address Environment Interfaces + * + * Low-level interfaces used in binfmt/ to instantiate tasks with address + * environments. These interfaces all operate on type group_addrenv_t which + * 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_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. + * + * 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 + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/sched.h> +#include <nuttx/addrenv.h> + +#include <arch/irq.h> + +#include "mmu.h" +#include "addrenv.h" + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration */ + +#if (CONFIG_ARCH_STACK_VBASE & SECTION_MASK) != 0 +# error CONFIG_ARCH_STACK_VBASE not aligned to section boundary +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_addrenv_stackalloc + * + * Description: + * This function is called when a new thread is created in order to + * instantiate an address environment for the new thread's stack. + * up_addrenv_stackalloc() is essentially the allocator of the physical + * memory for the new task's stack. + * + * Input Parameters: + * tcb - The TCB of the thread that requires the stack address environment. + * stacksize - The size (in bytes) of the initial stack 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. + * + ****************************************************************************/ + +int up_addrenv_stackalloc(FAR struct tcb_s *tcb, size_t stacksize) +{ + int ret; + + bvdbg("tcb=%p stacksize=%lu\n", tcb, (unsigned long)stacksize); + + DEBUGASSERT(tcb); + + /* Initialize the address environment list to all zeroes */ + + memset(tcb->xcp.stack, 0, ARCH_STACK_NSECTS * sizeof(uintptr_t *)); + + /* Back the allocation up with physical pages and set up the level 2 mapping + * (which of course does nothing until the L2 page table is hooked into + * the L1 page table). + */ + + /* Allocate .text space pages */ + + ret = arm_addrenv_create_region(tcb->xcp.stack, ARCH_STACK_NSECTS, + CONFIG_ARCH_STACK_VBASE, stacksize, + MMU_L2_UDATAFLAGS); + if (ret < 0) + { + bdbg("ERROR: Failed to create stack region: %d\n", ret); + up_addrenv_stackfree(tcb); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: up_addrenv_stackfree + * + * Description: + * This function is called when any thread exits. This function then + * destroys the defunct address environment for the thread's stack, + * releasing the underlying physical memory. + * + * Input Parameters: + * tcb - The TCB of the thread that no longer requires the stack address + * environment. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_addrenv_stackfree(FAR struct tcb_s *tcb) +{ + bvdbg("tcb=%p\n", tcb); + DEBUGASSERT(tcb); + + /* Destroy the stack region */ + + arm_addrenv_destroy_region(tcb->xcp.stack, ARCH_STACK_NSECTS, + CONFIG_ARCH_STACK_VBASE); + + memset(tcb->xcp.stack, 0, ARCH_STACK_NSECTS * sizeof(uintptr_t *)); + return OK; +} + +/**************************************************************************** + * Name: up_addrenv_vstack + * + * Description: + * Return the virtual address associated with the newly create stack + * address environment. + * + * Input Parameters: + * tcb - The TCB of the thread with the stack address environment of + * interest. + * vstack - The location to return the stack virtual base address. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_addrenv_vstack(FAR const struct tcb_s *tcb, FAR void **vstack) +{ + bvdbg("Return=%p\n", (FAR void *)CONFIG_ARCH_STACK_VBASE); + + /* Not much to do in this case */ + + DEBUGASSERT(tcb); + *vstack = (FAR void *)CONFIG_ARCH_STACK_VBASE; + return OK; +} + +/**************************************************************************** + * Name: up_addrenv_stackselect + * + * Description: + * After an address environment has been established for a task's stack + * (via up_addrenv_stackalloc(). This function may be called to instantiate + * that address environment in the virtual address space. This is a + * necessary step before each context switch to the newly created thread + * (including the initial thread startup). + * + * Input Parameters: + * tcb - The TCB of the thread with the stack address environment to be + * instantiated. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_addrenv_stackselect(FAR const struct tcb_s *tcb) +{ + uintptr_t vaddr; + uintptr_t paddr; + int i; + + DEBUGASSERT(tcb); + + for (vaddr = CONFIG_ARCH_STACK_VBASE, i = 0; + i < ARCH_TEXT_NSECTS; + vaddr += ARCH_STACK_NSECTS, i++) + { + /* Set (or clear) the new page table entry */ + + paddr = (uintptr_t)tcb->xcp.stack[i]; + if (paddr) + { + mmu_l1_setentry(paddr, vaddr, MMU_L1_PGTABFLAGS); + } + else + { + mmu_l1_clrentry(vaddr); + } + } + + return OK; +} + +#endif /* CONFIG_ARCH_ADDRENV */ diff --git a/nuttx/arch/arm/src/sama5/Make.defs b/nuttx/arch/arm/src/sama5/Make.defs index fb2bc48ed..59654e5e3 100644 --- a/nuttx/arch/arm/src/sama5/Make.defs +++ b/nuttx/arch/arm/src/sama5/Make.defs @@ -94,6 +94,9 @@ endif ifeq ($(CONFIG_ARCH_ADDRENV),y) CMN_CSRCS += arm_addrenv.c arm_addrenv_utils.c arm_pgalloc.c +ifeq ($(CONFIG_ARCH_STACK_DYNAMIC),y) +CMN_CSRCS += arm_addrenv_stack.c +endif endif ifeq ($(CONFIG_ELF),y) diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h index dafff424f..d626e230a 100644 --- a/nuttx/include/nuttx/arch.h +++ b/nuttx/include/nuttx/arch.h @@ -1044,6 +1044,94 @@ int up_addrenv_detach(FAR struct task_group_s *group, FAR struct tcb_s *tcb); #endif /**************************************************************************** + * Name: up_addrenv_stackalloc + * + * Description: + * This function is called when a new thread is created in order to + * instantiate an address environment for the new thread's stack. + * up_addrenv_stackalloc() is essentially the allocator of the physical + * memory for the new task's stack. + * + * Input Parameters: + * tcb - The TCB of the thread that requires the stack address environment. + * stacksize - The size (in bytes) of the initial stack 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. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) +int up_addrenv_stackalloc(FAR struct tcb_s *tcb, size_t stacksize); +#endif + +/**************************************************************************** + * Name: up_addrenv_stackfree + * + * Description: + * This function is called when any thread exits. This function then + * destroys the defunct address environment for the thread's stack, + * releasing the underlying physical memory. + * + * Input Parameters: + * tcb - The TCB of the thread that no longer requires the stack address + * environment. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) +int up_addrenv_stackfree(FAR struct tcb_s *tcb); +#endif + +/**************************************************************************** + * Name: up_addrenv_vstack + * + * Description: + * Return the virtual address associated with the newly create stack + * address environment. + * + * Input Parameters: + * tcb - The TCB of the thread with the stack address environment of + * interest. + * vstack - The location to return the stack virtual base address. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) +int up_addrenv_vstack(FAR const struct tcb_s *tcb, FAR void **vstack); +#endif + +/**************************************************************************** + * Name: up_addrenv_stackselect + * + * Description: + * After an address environment has been established for a task's stack + * (via up_addrenv_stackalloc(). This function may be called to instantiate + * that address environment in the virtual address space. This is a + * necessary step before each context switch to the newly created thread + * (including the initial thread startup). + * + * Input Parameters: + * tcb - The TCB of the thread with the stack address environment to be + * instantiated. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_STACK_DYNAMIC) +int up_addrenv_stackselect(FAR const struct tcb_s *tcb); +#endif + +/**************************************************************************** * Name: up_interrupt_context * * Description: |