From d956936535224c5ae8b4546a23657bb6e193653e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 13 Sep 2014 13:45:35 -0600 Subject: [PATCH] Add logic need to manage a virtualized stack. Not yet incorporated into base OS logic. --- arch/arm/src/a1x/Make.defs | 3 + arch/arm/src/armv7-a/arm_addrenv.c | 4 +- arch/arm/src/armv7-a/arm_addrenv_stack.c | 288 +++++++++++++++++++++++ arch/arm/src/sama5/Make.defs | 3 + 4 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/armv7-a/arm_addrenv_stack.c diff --git a/arch/arm/src/a1x/Make.defs b/arch/arm/src/a1x/Make.defs index 62f9692201..22f5065446 100644 --- a/arch/arm/src/a1x/Make.defs +++ b/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/arch/arm/src/armv7-a/arm_addrenv.c b/arch/arm/src/armv7-a/arm_addrenv.c index c5e5a813c4..257a14a36a 100644 --- a/arch/arm/src/armv7-a/arm_addrenv.c +++ b/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/arch/arm/src/armv7-a/arm_addrenv_stack.c b/arch/arm/src/armv7-a/arm_addrenv_stack.c new file mode 100644 index 0000000000..225906f817 --- /dev/null +++ b/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 + * + * 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 + +#include +#include +#include + +#include +#include +#include + +#include + +#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/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index fb2bc48ed6..59654e5e3c 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/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)