Initial integration of kernel stack (does not work)

This commit is contained in:
Gregory Nutt 2014-09-14 11:19:34 -06:00
parent 25ee232fd4
commit 3649dab9bd
8 changed files with 105 additions and 30 deletions

View File

@ -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>

View File

@ -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
};

View File

@ -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
*/

View File

@ -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);
/* Free the kernel stack */
/* Does the exiting thread have a 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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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
/****************************************************************************

View File

@ -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