Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions arch/xtensa/include/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,23 @@ struct xcptcontext

uint32_t *regs;

#ifdef CONFIG_ARCH_KERNEL_STACK
/* In a kernel build the kernel cannot run on the stack of the process it
* is working for. That stack lives in a cache-MMU window which
* up_addrenv_select() reprograms, so it would move out from under the
* kernel the moment it touched another process's address environment --
* taking the exception frame and every spilled register window with it.
* Each thread therefore gets a small stack of its own in kernel memory,
* which no address environment change can disturb.
*/

uint32_t *kstack; /* Allocated base of the kernel stack */
uint32_t *ktopstk; /* Top of the kernel stack (initial stack pointer) */
uint32_t *ustkptr; /* Saved user stack pointer, while in a system call */
uint32_t *kstkptr; /* Saved kernel stack pointer, while a user signal
* handler runs on the user stack */
#endif

#ifdef CONFIG_LIB_SYSCALL
/* The following array holds the return address and the exc_return value
* needed to return from each nested system call.
Expand Down
14 changes: 12 additions & 2 deletions arch/xtensa/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,20 @@ ifneq ($(CONFIG_WINDOWS_NATIVE),y)
endif

# This is part of the top-level export target
#
# A kernel build links its user programs outside this tree, against the
# export package, so crt0 has to travel with it: apps/import expects to
# find it as startup/crt0.o.

ifeq ($(CONFIG_BUILD_KERNEL),y)
EXPORT_STARTUP_OBJS = $(STARTUP_OBJS) $(STARTUP_ELF_OBJS)
else
EXPORT_STARTUP_OBJS = $(STARTUP_OBJS)
endif

export_startup: $(STARTUP_OBJS)
export_startup: $(EXPORT_STARTUP_OBJS)
$(Q) if [ -d "$(EXPORT_DIR)/startup" ]; then \
cp -f $(STARTUP_OBJS) "$(EXPORT_DIR)/startup"; \
cp -f $(EXPORT_STARTUP_OBJS) "$(EXPORT_DIR)/startup"; \
else \
echo "$(EXPORT_DIR)/startup does not exist"; \
exit 1; \
Expand Down
6 changes: 5 additions & 1 deletion arch/xtensa/src/common/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ ifeq ($(CONFIG_XTENSA_SEMIHOSTING_HOSTFS),y)
CMN_CSRCS += xtensa_hostfs.c
endif

ifeq ($(CONFIG_BUILD_PROTECTED),y)
ifeq ($(CONFIG_ARCH_KERNEL_STACK),y)
CMN_CSRCS += xtensa_addrenv_kstack.c
endif

ifneq ($(CONFIG_BUILD_FLAT),y)
CMN_UASRCS += xtensa_signal_handler.S
CMN_ASRCS += xtensa_dispatch_syscall.S
CMN_CSRCS += xtensa_task_start.c xtensa_pthread_start.c
Expand Down
48 changes: 48 additions & 0 deletions arch/xtensa/src/common/crt0.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/macro.h>

#include <sys/types.h>
#include <stdlib.h>
Expand Down Expand Up @@ -55,6 +56,53 @@ int main(int argc, char *argv[]);
* Private Functions
****************************************************************************/

#ifdef CONFIG_BUILD_KERNEL

/****************************************************************************
* Name: sig_trampoline
*
* Description:
* The user-space signal handler trampoline. A kernel build cannot reach
* the one in xtensa_signal_handler.S -- that lives in libarch, which user
* programs do not link -- so it is carried here in crt0 instead, and
* _start() publishes it to the kernel through ARCH_DATA_RESERVE. The
* kernel enters it from the SYS_signal_handler case of xtensa_swint().
*
* Written as file-scope assembly rather than as a naked function because
* GCC does not implement the naked attribute on Xtensa: it would emit a
* window-rotating prologue and quietly invalidate the register assignments
* below.
*
* Input Parameters:
* a2 = sighand, the user-space signal handling function
* a3, a4, a5 = signo, info and ucontext, its arguments
*
* Returned Value:
* None. This function does not return in the normal sense; it returns
* via the SYS_signal_handler_return syscall.
*
****************************************************************************/

__asm__
(
" .text\n"
" .global sig_trampoline\n"
" .type sig_trampoline, @function\n"
" .align 4\n"
"sig_trampoline:\n"
" mov a6, a3\n" /* Move signo into the callee's a2 */
" mov a7, a4\n" /* Move info into the callee's a3 */
" mov a8, a5\n" /* Move ucontext into the callee's a4 */
" callx4 a2\n" /* Call the signal handler */
" movi a2, " STRINGIFY(SYS_signal_handler_return) "\n"
" syscall\n" /* Will not return */
" .size sig_trampoline, .-sig_trampoline\n"
);

void sig_trampoline(void);

#endif /* CONFIG_BUILD_KERNEL */

#ifdef CONFIG_HAVE_CXXINITIALIZE

/****************************************************************************
Expand Down
129 changes: 129 additions & 0 deletions arch/xtensa/src/common/xtensa_addrenv_kstack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/****************************************************************************
* arch/xtensa/src/common/xtensa_addrenv_kstack.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

/****************************************************************************
* Included Files
****************************************************************************/

#include <nuttx/config.h>

#include <assert.h>
#include <debug.h>
#include <errno.h>

#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/sched.h>

#include "xtensa.h"

#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

/* The Xtensa windowed ABI requires 16-byte stack alignment */

#define KSTACK_ALIGNMENT 16
#define KSTACK_ALIGN_DOWN(a) ((a) & ~(KSTACK_ALIGNMENT - 1))

/****************************************************************************
* Public Functions
****************************************************************************/

/****************************************************************************
* Name: up_addrenv_kstackalloc
*
* Description:
* 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.
*
* The stack comes from the kernel heap, which lives in internal SRAM and
* is mapped identically no matter which address environment is selected.
* That is the whole point of it: the kernel needs somewhere to keep the
* exception frame and its spilled register windows that does not move when
* up_addrenv_select() reprograms the user cache-MMU windows.
*
* Input Parameters:
* tcb - The TCB of the thread that requires the kernel stack.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/

int up_addrenv_kstackalloc(struct tcb_s *tcb)
{
DEBUGASSERT(tcb && tcb->xcp.kstack == NULL);

tcb->xcp.kstack = kmm_memalign(KSTACK_ALIGNMENT, ARCH_KERNEL_STACKSIZE);
if (tcb->xcp.kstack == NULL)
{
berr("ERROR: Failed to allocate the kernel stack\n");
return -ENOMEM;
}

/* Xtensa stacks grow down and must stay aligned, so the usable top is the
* far end of the allocation.
*/

tcb->xcp.ktopstk = (uint32_t *)
KSTACK_ALIGN_DOWN((uintptr_t)tcb->xcp.kstack + ARCH_KERNEL_STACKSIZE);

return OK;
}

/****************************************************************************
* Name: up_addrenv_kstackfree
*
* Description:
* This function is called when any thread exits. This function frees
* the kernel stack.
*
* Input Parameters:
* tcb - The TCB of the thread that no longer requires the kernel stack.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/

int up_addrenv_kstackfree(struct tcb_s *tcb)
{
DEBUGASSERT(tcb);

/* Does the exiting thread have a kernel stack? */

if (tcb->xcp.kstack != NULL)
{
kmm_free(tcb->xcp.kstack);
tcb->xcp.kstack = NULL;
tcb->xcp.ktopstk = NULL;
}

return OK;
}

#endif /* CONFIG_ARCH_ADDRENV && CONFIG_ARCH_KERNEL_STACK */
13 changes: 13 additions & 0 deletions arch/xtensa/src/common/xtensa_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,24 @@ void up_initial_state(struct tcb_s *tcb)
const uint32_t base = ALIGN_UP((uint32_t)&_rodata_reserved_align,
TCB_SIZE);
#endif
#ifdef CONFIG_ARCH_KERNEL_STACK
/* The kernel stack is allocated before the thread's initial state is set
* up, so hold on to it across the wipe below.
*/

uint32_t *kstack = xcp->kstack;
uint32_t *ktopstk = xcp->ktopstk;
#endif

/* Initialize the initial exception register context structure */

memset(xcp, 0, sizeof(struct xcptcontext));

#ifdef CONFIG_ARCH_KERNEL_STACK
xcp->kstack = kstack;
xcp->ktopstk = ktopstk;
#endif

/* Initialize the idle thread stack */

if (tcb->pid == IDLE_PROCESS_ID)
Expand Down
Loading
Loading