summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-13 13:45:35 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-13 13:45:35 -0600
commitf7dfe6c8a364a7185a0c6654804660578326e1e0 (patch)
tree8aa7997661d38edc71de892ece316e632f2506ef
parentfcb6166e6bb8e335e1d3fccd088bb87d8585ba8d (diff)
downloadnuttx-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.defs3
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv.c4
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv_stack.c288
-rw-r--r--nuttx/arch/arm/src/sama5/Make.defs3
-rw-r--r--nuttx/include/nuttx/arch.h88
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: