diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-09-14 11:19:34 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-09-14 11:19:34 -0600 |
commit | 353f0c65ac5f95d88b7f372c3732471ffa063dfa (patch) | |
tree | 4709f8b81b119f70f78f96067a4e304ae7b64641 /nuttx | |
parent | 9bb50fec6cf9622960169034df00cc638e9d989c (diff) | |
download | px4-nuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.tar.gz px4-nuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.tar.bz2 px4-nuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.zip |
Initial integration of kernel stack (does not work)
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/Documentation/NuttxPortingGuide.html | 5 | ||||
-rwxr-xr-x | nuttx/arch/arm/include/armv7-a/irq.h | 6 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/addrenv.h | 6 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c | 30 | ||||
-rw-r--r-- | nuttx/arch/arm/src/armv7-a/arm_syscall.c | 35 | ||||
-rw-r--r-- | nuttx/binfmt/binfmt_execmodule.c | 35 | ||||
-rw-r--r-- | nuttx/include/nuttx/arch.h | 6 | ||||
-rw-r--r-- | nuttx/sched/sched/sched_releasetcb.c | 12 |
8 files changed, 105 insertions, 30 deletions
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index 0a336ec00..aa4f3129a 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -3320,18 +3320,19 @@ VxWorks provides the following comparable interface: <h3><a name="up_addrenv_kstackalloc">4.4.15 <code>up_addrenv_kstackalloc()</code></a></h3> <p><b>Function Prototype</b>:<p> <ul> - <code>int up_addrenv_kstackalloc(FAR struct tcb_s *tcb, size_t stacksize);</code> + <code>int up_addrenv_kstackalloc(FAR struct tcb_s *tcb);</code> </ul> <p><b>Description</b>:</p> <ul> <p> This function is called when a new thread is created to allocate the new thread's kernel stack. + This function may be called for certain terminating threads which have no kernel stack. + It must be tolerant of that case. </p> </ul> <p><b>Input Parameters</b>:</p> <ul> <li><code>tcb</code>: The TCB of the thread that requires the kernel stack.</li> - <li><code>stacksize</code>: The size (in bytes) of the kernel stack needed by the thread.</li> </ul> <p><b>Returned Value</b>:</p> <ul> diff --git a/nuttx/arch/arm/include/armv7-a/irq.h b/nuttx/arch/arm/include/armv7-a/irq.h index 46303c016..3813e919a 100755 --- a/nuttx/arch/arm/include/armv7-a/irq.h +++ b/nuttx/arch/arm/include/armv7-a/irq.h @@ -276,7 +276,7 @@ struct xcptcontext #ifdef CONFIG_ARCH_ADDRENV #ifdef CONFIG_ARCH_STACK_DYNAMIC - /* This table holds the physical address of the level 2 page table used + /* This array holds the physical address of the level 2 page table used * to map the thread's stack memory. This array will be initially of * zeroed and would be back-up up with pages during page fault exception * handling to support dynamically sized stacks for each thread. @@ -284,6 +284,7 @@ struct xcptcontext FAR uintptr_t *ustack[ARCH_STACK_NSECTS]; #endif + #ifdef CONFIG_ARCH_KERNEL_STACK /* In this configuration, all syscalls execute from an internal kernel * stack. Why? Because when we instantiate and initialize the address @@ -293,7 +294,8 @@ struct xcptcontext * stack in place. */ - FAR uint32_t *kstack; + FAR uint32_t *ustkptr; /* Saved user stack pointer */ + FAR uint32_t *kstack; /* Allocate base of the (aligned) kernel stack */ #endif #endif }; diff --git a/nuttx/arch/arm/src/armv7-a/addrenv.h b/nuttx/arch/arm/src/armv7-a/addrenv.h index 0d830ed06..60cfb342a 100644 --- a/nuttx/arch/arm/src/armv7-a/addrenv.h +++ b/nuttx/arch/arm/src/armv7-a/addrenv.h @@ -51,6 +51,12 @@ * Pre-processor Definitions ****************************************************************************/ +/* Aligned size of the kernel stack */ + +#ifdef CONFIG_ARCH_KERNEL_STACK +# define ARCH_KERNEL_STACKSIZE ((CONFIG_ARCH_KERNEL_STACKSIZE + 7) & ~7) +#endif + /* Using a 4KiB page size, each 1MiB section maps to a PTE containing * 256*2KiB entries */ diff --git a/nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c b/nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c index 2102e0ad2..852b03620 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c +++ b/nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c @@ -117,6 +117,8 @@ #include <nuttx/addrenv.h> #include <nuttx/arch.h> +#include "addrenv.h" + #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK) /**************************************************************************** @@ -140,27 +142,27 @@ * * Description: * This function is called when a new thread is created to allocate - * the new thread's kernel stack. + * the new thread's kernel stack. This function may be called for certain + * terminating threads which have no kernel stack. It must be tolerant of + * that case. * * Input Parameters: * tcb - The TCB of the thread that requires the kernel stack. - * stacksize - The size (in bytes) of the kernel stack needed by the - * thread. * * Returned Value: * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ -int up_addrenv_kstackalloc(FAR struct tcb_s *tcb, size_t stacksize) +int up_addrenv_kstackalloc(FAR struct tcb_s *tcb) { - bvdbg("tcb=%p stacksize=%lu\n", tcb, (unsigned long)stacksize); + bvdbg("tcb=%p stacksize=%u\n", tcb, ARCH_KERNEL_STACKSIZE); - DEBUGASSERT(tcb && tcb->xcp.kstack == 0 && stackize > 0); + DEBUGASSERT(tcb && tcb->xcp.kstack == 0); /* Allocate the kernel stack */ - tcb->xcp.kstack = (FAR uint32_t *)kmm_memalign(8, stacksize); + tcb->xcp.kstack = (FAR uint32_t *)kmm_memalign(8, ARCH_KERNEL_STACKSIZE); if (!tcb->xcp.kstack) { bdbg("ERROR: Failed to allocate the kernel stack\n"); @@ -188,12 +190,18 @@ int up_addrenv_kstackalloc(FAR struct tcb_s *tcb, size_t stacksize) int up_addrenv_kstackfree(FAR struct tcb_s *tcb) { bvdbg("tcb=%p\n", tcb); - DEBUGASSERT(tcb && tcb->xcp.kstack); + DEBUGASSERT(tcb); + + /* Does the exiting thread have a kernel stack? */ - /* Free the kernel stack */ + if (tcb->xcp.kstack) + { + /* Yes.. Free the kernel stack */ + + kmm_free(tcb->xcp.kstack); + tcb->xcp.kstack = NULL; + } - kmm_free(tcb->xcp.kstack); - tcb->xcp.kstack = NULL; return OK; } diff --git a/nuttx/arch/arm/src/armv7-a/arm_syscall.c b/nuttx/arch/arm/src/armv7-a/arm_syscall.c index b5f803402..9fb46f388 100644 --- a/nuttx/arch/arm/src/armv7-a/arm_syscall.c +++ b/nuttx/arch/arm/src/armv7-a/arm_syscall.c @@ -51,6 +51,7 @@ #include "arm.h" #include "svcall.h" +#include "addrenv.h" #include "up_internal.h" /**************************************************************************** @@ -219,13 +220,27 @@ uint32_t *arm_syscall(uint32_t *regs) #ifdef CONFIG_BUILD_KERNEL regs[REG_CPSR] = rtcb->xcp.syscall[index].cpsr; #endif - rtcb->xcp.nsyscalls = index; - /* The return value must be in R0-R1. dispatch_syscall() temporarily * moved the value for R0 into R2. */ regs[REG_R0] = regs[REG_R2]; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is the outermost SYSCALL and if there is a saved user stack + * pointer, then restore the user stack pointer on this final return to + * user code. + */ + + if (index == 0 && rtcb->xcp.ustkptr != NULL) + { + regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr; + rtcb->xcp.ustkptr = NULL; + } +#endif + /* Save the new SYSCALL nesting level */ + + rtcb->xcp.nsyscalls = index; } break; @@ -421,7 +436,6 @@ uint32_t *arm_syscall(uint32_t *regs) #ifdef CONFIG_BUILD_KERNEL rtcb->xcp.syscall[index].cpsr = regs[REG_CPSR]; #endif - rtcb->xcp.nsyscalls = index + 1; regs[REG_PC] = (uint32_t)dispatch_syscall; #ifdef CONFIG_BUILD_KERNEL @@ -434,6 +448,21 @@ uint32_t *arm_syscall(uint32_t *regs) #else svcdbg("ERROR: Bad SYS call: %d\n", regs[REG_R0]); #endif + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* If this is the first SYSCALL and if there is an allocated + * kernel stack, then switch to the kernel stack. + */ + + if (index == 0 && rtcb->xcp.kstack != NULL) + { + rtcb->xcp.ustkptr = (FAR uint32_t *)regs[REG_SP]; + regs[REG_SP] = (uint32_t)rtcb->xcp.kstack + ARCH_KERNEL_STACKSIZE; + } +#endif + /* Save the new SYSCALL nesting level */ + + rtcb->xcp.nsyscalls = index + 1; } break; } diff --git a/nuttx/binfmt/binfmt_execmodule.c b/nuttx/binfmt/binfmt_execmodule.c index baed131bf..3756fbaf6 100644 --- a/nuttx/binfmt/binfmt_execmodule.c +++ b/nuttx/binfmt/binfmt_execmodule.c @@ -165,7 +165,8 @@ int exec_module(FAR const struct binary_s *binp) goto errout; } -#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) +#ifdef CONFIG_ARCH_ADDRENV +#ifdef CONFIG_BUILD_KERNEL /* Instantiate the address environment containing the user heap */ ret = up_addrenv_select(&binp->addrenv, &oldenv); @@ -182,6 +183,19 @@ int exec_module(FAR const struct binary_s *binp) up_addrenv_heapsize(&binp->addrenv)); #endif +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Allocate the kernel stack */ + + ret = up_addrenv_kstackalloc(&tcb->cmn); + if (ret < 0) + { + bdbg("ERROR: up_addrenv_select() failed: %d\n", ret); + err = -ret; + goto errout_with_addrenv; + } +#endif +#endif + /* Allocate the stack for the new task. * * REVISIT: This allocation is currently always from the user heap. That @@ -192,7 +206,7 @@ int exec_module(FAR const struct binary_s *binp) if (!stack) { err = ENOMEM; - goto errout_with_addrenv; + goto errout_with_kstack; } /* Initialize the task */ @@ -203,7 +217,7 @@ int exec_module(FAR const struct binary_s *binp) { err = get_errno(); bdbg("task_init() failed: %d\n", err); - goto errout_with_stack; + goto errout_with_kstack; } /* Note that tcb->flags are not modified. 0=normal task */ @@ -229,7 +243,7 @@ int exec_module(FAR const struct binary_s *binp) { err = -ret; bdbg("ERROR: up_addrenv_clone() failed: %d\n", ret); - goto errout_with_stack; + goto errout_with_tcbinit; } /* Mark that this group has an address environment */ @@ -257,7 +271,7 @@ int exec_module(FAR const struct binary_s *binp) { err = get_errno(); bdbg("task_activate() failed: %d\n", err); - goto errout_with_stack; + goto errout_with_tcbinit; } #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) @@ -268,24 +282,31 @@ int exec_module(FAR const struct binary_s *binp) { bdbg("ERROR: up_addrenv_select() failed: %d\n", ret); err = -ret; - goto errout_with_stack; + goto errout_with_tcbinit; } #endif return (int)pid; -errout_with_stack: +errout_with_tcbinit: tcb->cmn.stack_alloc_ptr = NULL; sched_releasetcb(&tcb->cmn, TCB_FLAG_TTYPE_TASK); kumm_free(stack); goto errout; +errout_with_kstack: +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) + (void)up_addrenv_kstackfree(tcb); + errout_with_addrenv: +#endif #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) (void)up_addrenv_restore(&oldenv); + errout_with_tcb: #endif kmm_free(tcb); + errout: set_errno(err); bdbg("returning errno: %d\n", err); diff --git a/nuttx/include/nuttx/arch.h b/nuttx/include/nuttx/arch.h index d4b55d841..aa65d33c9 100644 --- a/nuttx/include/nuttx/arch.h +++ b/nuttx/include/nuttx/arch.h @@ -1151,7 +1151,9 @@ int up_addrenv_ustackselect(FAR const struct tcb_s *tcb); * * Description: * This function is called when a new thread is created to allocate - * the new thread's kernel stack. + * the new thread's kernel stack. This function may be called for certain + * terminating threads which have no kernel stack. It must be tolerant of + * that case. * * Input Parameters: * tcb - The TCB of the thread that requires the kernel stack. @@ -1164,7 +1166,7 @@ int up_addrenv_ustackselect(FAR const struct tcb_s *tcb); ****************************************************************************/ #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK) -int up_addrenv_kstackalloc(FAR struct tcb_s *tcb, size_t stacksize); +int up_addrenv_kstackalloc(FAR struct tcb_s *tcb); #endif /**************************************************************************** diff --git a/nuttx/sched/sched/sched_releasetcb.c b/nuttx/sched/sched/sched_releasetcb.c index f731a2442..ea4460016 100644 --- a/nuttx/sched/sched/sched_releasetcb.c +++ b/nuttx/sched/sched/sched_releasetcb.c @@ -114,13 +114,13 @@ int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype) if (tcb) { - /* Relase any timers that the task might hold. We do this +#ifndef CONFIG_DISABLE_POSIX_TIMERS + /* Release any timers that the task might hold. We do this * before release the PID because it may still be trying to * deliver signals (although interrupts are should be * disabled here). */ -#ifndef CONFIG_DISABLE_POSIX_TIMERS #ifdef CONFIG_HAVE_WEAKFUNCTIONS if (timer_deleteall != NULL) #endif @@ -147,9 +147,9 @@ int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype) up_release_stack(tcb, ttype); } +#ifdef CONFIG_PIC /* Delete the task's allocated DSpace region (external modules only) */ -#ifdef CONFIG_PIC if (tcb->dspace) { if (tcb->dspace->crefs <= 1) @@ -163,6 +163,12 @@ int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype) } #endif +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK) + /* Release the kernel stack */ + + (void)up_addrenv_kstackfree(tcb); +#endif + /* Release this thread's reference to the address environment */ #ifdef CONFIG_ARCH_ADDRENV |