134 lines
3.9 KiB
C
134 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2016 Cadence Design Systems, Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifdef CONFIG_INIT_STACKS
|
|
#include <string.h>
|
|
#endif /* CONFIG_INIT_STACKS */
|
|
#ifdef CONFIG_DEBUG
|
|
#include <misc/printk.h>
|
|
#endif
|
|
#include <kernel_structs.h>
|
|
#include <wait_q.h>
|
|
#include <xtensa_config.h>
|
|
|
|
extern void _xt_user_exit(void);
|
|
|
|
/*
|
|
* @brief Initialize a new thread
|
|
*
|
|
* Any coprocessor context data is put at the lower address of the stack. An
|
|
* initial context, to be "restored" by __return_from_coop(), is put at
|
|
* the other end of the stack, and thus reusable by the stack when not
|
|
* needed anymore.
|
|
*
|
|
* The initial context is a basic stack frame that contains arguments for
|
|
* _thread_entry() return address, that points at _thread_entry()
|
|
* and status register.
|
|
*
|
|
* <options> is currently unused.
|
|
*
|
|
* @param thread pointer to k_thread memory
|
|
* @param pStackmem the pointer to aligned stack memory
|
|
* @param stackSize the stack size in bytes
|
|
* @param pEntry thread entry point routine
|
|
* @param p1 first param to entry point
|
|
* @param p2 second param to entry point
|
|
* @param p3 third param to entry point
|
|
* @param priority thread priority
|
|
* @param options is unused (saved for future expansion)
|
|
*
|
|
* @return N/A
|
|
*/
|
|
|
|
void _new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
|
size_t stackSize, k_thread_entry_t pEntry,
|
|
void *p1, void *p2, void *p3,
|
|
int priority, unsigned int options)
|
|
{
|
|
char *pStack = K_THREAD_STACK_BUFFER(stack);
|
|
|
|
/* Align stack end to maximum alignment requirement. */
|
|
char *stackEnd = (char *)ROUND_DOWN(pStack + stackSize, 16);
|
|
#if XCHAL_CP_NUM > 0
|
|
u32_t *cpSA;
|
|
char *cpStack;
|
|
#endif
|
|
|
|
_new_thread_init(thread, pStack, stackSize, priority, options);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
printk("\nstackPtr = %p, stackSize = %d\n", pStack, stackSize);
|
|
printk("stackEnd = %p\n", stackEnd);
|
|
#endif
|
|
#if XCHAL_CP_NUM > 0
|
|
/* Ensure CP state descriptor is correctly initialized */
|
|
cpStack = thread->arch.preempCoprocReg.cpStack; /* short hand alias */
|
|
memset(cpStack, 0, XT_CP_ASA); /* Set to zero to avoid bad surprises */
|
|
/* Coprocessor's stack is allocated just after the k_thread */
|
|
cpSA = (u32_t *)(thread->arch.preempCoprocReg.cpStack + XT_CP_ASA);
|
|
/* Coprocessor's save area alignment is at leat 16 bytes */
|
|
*cpSA = ROUND_UP(cpSA + 1,
|
|
(XCHAL_TOTAL_SA_ALIGN < 16 ? 16 : XCHAL_TOTAL_SA_ALIGN));
|
|
#ifdef CONFIG_DEBUG
|
|
printk("cpStack = %p\n", thread->arch.preempCoprocReg.cpStack);
|
|
printk("cpAsa = %p\n",
|
|
*(void **)(thread->arch.preempCoprocReg.cpStack + XT_CP_ASA));
|
|
#endif
|
|
#endif
|
|
/* Thread's first frame alignment is granted as both operands are
|
|
* aligned
|
|
*/
|
|
XtExcFrame *pInitCtx =
|
|
(XtExcFrame *)(stackEnd - (XT_XTRA_SIZE - XT_CP_SIZE));
|
|
#ifdef CONFIG_DEBUG
|
|
printk("pInitCtx = %p\n", pInitCtx);
|
|
#endif
|
|
/* Explicitly initialize certain saved registers */
|
|
|
|
/* task entrypoint */
|
|
pInitCtx->pc = (u32_t)_thread_entry;
|
|
|
|
/* physical top of stack frame */
|
|
pInitCtx->a1 = (u32_t)pInitCtx + XT_STK_FRMSZ;
|
|
|
|
/* user exception exit dispatcher */
|
|
pInitCtx->exit = (u32_t)_xt_user_exit;
|
|
|
|
/* Set initial PS to int level 0, EXCM disabled, user mode.
|
|
* Also set entry point argument arg.
|
|
*/
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
pInitCtx->a2 = (u32_t)pEntry;
|
|
pInitCtx->a3 = (u32_t)p1;
|
|
pInitCtx->a4 = (u32_t)p2;
|
|
pInitCtx->a5 = (u32_t)p3;
|
|
pInitCtx->ps = PS_UM | PS_EXCM;
|
|
#else
|
|
/* For windowed ABI set also WOE and CALLINC
|
|
* (pretend task is 'call4')
|
|
*/
|
|
pInitCtx->a6 = (u32_t)pEntry;
|
|
pInitCtx->a7 = (u32_t)p1;
|
|
pInitCtx->a8 = (u32_t)p2;
|
|
pInitCtx->a9 = (u32_t)p3;
|
|
pInitCtx->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
|
|
#endif
|
|
thread->callee_saved.topOfStack = pInitCtx;
|
|
thread->arch.flags = 0;
|
|
#ifdef CONFIG_THREAD_MONITOR
|
|
/*
|
|
* In debug mode thread->entry give direct access to the thread entry
|
|
* and the corresponding parameters.
|
|
*/
|
|
thread->entry = (struct __thread_entry *)(pInitCtx);
|
|
#endif
|
|
/* initial values in all other registers/k_thread entries are
|
|
* irrelevant
|
|
*/
|
|
|
|
thread_monitor_init(thread);
|
|
}
|
|
|