summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-14 11:19:34 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-14 11:19:34 -0600
commit353f0c65ac5f95d88b7f372c3732471ffa063dfa (patch)
tree4709f8b81b119f70f78f96067a4e304ae7b64641
parent9bb50fec6cf9622960169034df00cc638e9d989c (diff)
downloadnuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.tar.gz
nuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.tar.bz2
nuttx-353f0c65ac5f95d88b7f372c3732471ffa063dfa.zip
Initial integration of kernel stack (does not work)
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html5
-rwxr-xr-xnuttx/arch/arm/include/armv7-a/irq.h6
-rw-r--r--nuttx/arch/arm/src/armv7-a/addrenv.h6
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_addrenv_kstack.c30
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_syscall.c35
-rw-r--r--nuttx/binfmt/binfmt_execmodule.c35
-rw-r--r--nuttx/include/nuttx/arch.h6
-rw-r--r--nuttx/sched/sched/sched_releasetcb.c12
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