/* * See header file for description. */ portSTACK_TYPE * ICACHE_FLASH_ATTR pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { #define SET_STKREG(r,v) sp[(r) >> 2] = (portSTACK_TYPE)(v) portSTACK_TYPE *sp, *tp; /* Create interrupt stack frame aligned to 16 byte boundary */ sp = (portSTACK_TYPE*) (((INT32U)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf); /* Clear the entire frame (do not use memset() because we don't depend on C library) */ for (tp = sp; tp <= pxTopOfStack; ++tp) *tp = 0; /* Explicitly initialize certain saved registers */ SET_STKREG( XT_STK_PC, pxCode ); /* task entrypoint */ SET_STKREG( XT_STK_A0, 0 ); /* to terminate GDB backtrace */ SET_STKREG( XT_STK_A1, (INT32U)sp + XT_STK_FRMSZ ); /* physical top of stack frame */ SET_STKREG( XT_STK_A2, pvParameters ); /* parameters */ SET_STKREG( XT_STK_EXIT, _xt_user_exit ); /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ #ifdef __XTENSA_CALL0_ABI__ SET_STKREG( XT_STK_PS, PS_UM | PS_EXCM ); #else /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ SET_STKREG( XT_STK_PS, PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1) ); #endif return sp; }
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) #endif { StackType_t *sp, *tp; XtExcFrame *frame; #if XCHAL_CP_NUM > 0 uint32_t *p; #endif /* Create interrupt stack frame aligned to 16 byte boundary */ sp = (StackType_t *) (((UBaseType_t)(pxTopOfStack + 1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf); /* Clear the entire frame (do not use memset() because we don't depend on C library) */ for (tp = sp; tp <= pxTopOfStack; ++tp) *tp = 0; frame = (XtExcFrame *) sp; /* Explicitly initialize certain saved registers */ frame->pc = (UBaseType_t) pxCode; /* task entrypoint */ frame->a0 = 0; /* to terminate GDB backtrace */ frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */ frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ /* Also set entry point argument parameter. */ #ifdef __XTENSA_CALL0_ABI__ frame->a2 = (UBaseType_t) pvParameters; frame->ps = PS_UM | PS_EXCM; #else /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ frame->a6 = (UBaseType_t) pvParameters; frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); #endif #ifdef XT_USE_SWPRI /* Set the initial virtual priority mask value to all 1's. */ frame->vpri = 0xFFFFFFFF; #endif #if XCHAL_CP_NUM > 0 /* Init the coprocessor save area (see xtensa_context.h) */ /* No access to TCB here, so derive indirectly. Stack growth is top to bottom. * //p = (uint32_t *) xMPUSettings->coproc_area; */ p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE) & ~0xf); p[0] = 0; p[1] = 0; p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN; #endif return sp; }
void z_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 = Z_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 z_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 */ /* Set to zero to avoid bad surprises */ (void)memset(cpStack, 0, XT_CP_ASA); /* 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)z_thread_entry; /* physical top of stack frame */ pInitCtx->a1 = (u32_t)pInitCtx + XT_STK_FRMSZ; /* user exception exit dispatcher */ pInitCtx->exit = (u32_t)z_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; /* initial values in all other registers/k_thread entries are * irrelevant */ }
char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_start, int stack_size) { /* Stack layout after task stack initialization * * +------------------------+ * | | TOP * | thread_control_block | * stack_start + stack_size ==> | | top_of_stack+1 * +------------------------+ * top_of_stack ==> | | * | XT_CP_SA | * | (optional) | * | ... | ... * | cpstored | XT_CPSTORED * top_of_stack + 1 - XT_CP_SIZE ==> | cpenable | XT_CPENABLE * (cp_state) +------------------------+ * | | * | XT_STK_FRAME | * | | XT_STK_... * | a2 = arg | XT_STK_A2 * | a1 = sp + XT_STK_FRMSZ | XT_STK_A1 * | a0 = sched_task_exit | XT_STK_A0 * | ps = PS_UM | PS_EXCM | XT_STK_PS * | pc = task_func | XT_STK_PC * sp = top_of_stack + 1 - XT_CP_SIZE ==> | exit = _xt_user_exit | XT_STK_EXIT * - XT_STK_FRMSZ +------------------------+ * | | * | remaining stack space | * | available for data | * stack_start (preallocated var) ==> | | BOTTOM * +------------------------+ * * Initialized stack frame represents the registers as set when the * the task function would have been called. * * Registers in a called function * * pc - PC at the beginning in the function * a0 - return address from the function (return address to caller) * a1 - current stack pointer at the beginning in the function * a2 - first argument of the function */ /* stack is [stack_start+0 ... stack_start+stack_size-1] */ uint8_t *top_of_stack; uint8_t *sp; top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size-1); /* BEGIN - code from FreeRTOS port for Xtensa from Cadence */ /* Create interrupt stack frame aligned to 16 byte boundary */ sp = (uint8_t*)(((uint32_t)(top_of_stack+1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf); /* Clear whole stack with a known value to assist debugging */ #if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK) /* Unfortunatly, this affects thread_measure_stack_free function */ memset(stack_start, 0, stack_size); #else memset(sp, 0, XT_STK_FRMSZ + XT_CP_SIZE); #endif /* ensure that stack is big enough */ assert (sp > (uint8_t*)stack_start); XtExcFrame* exc_frame = (XtExcFrame*)sp; /* Explicitly initialize certain saved registers for call0 ABI */ exc_frame->pc = (uint32_t)task_func; /* task entry point */ exc_frame->a0 = (uint32_t)task_exit; /* task exit point*/ exc_frame->a1 = (uint32_t)sp + XT_STK_FRMSZ; /* physical top of stack frame */ exc_frame->exit = (uint32_t)_xt_user_exit; /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ /* Also set entry point argument parameter. */ #ifdef __XTENSA_CALL0_ABI__ /* for CALL0 ABI set in parameter a2 to task argument */ exc_frame->ps = PS_UM | PS_EXCM; exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */ #else /* for Windowed Register ABI set PS.CALLINC=01 to handle task entry as call4 return address in a4 and parameter in a6 and */ exc_frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); exc_frame->a4 = (uint32_t)task_exit; /* task exit point*/ exc_frame->a6 = (uint32_t)arg; /* parameters for task_func */ #endif #ifdef XT_USE_SWPRI /* Set the initial virtual priority mask value to all 1's. */ exc_frame->vpri = 0xFFFFFFFF; #endif #if XCHAL_CP_NUM > 0 /* Init the coprocessor save area (see xtensa_context.h) */ /* No access to TCB here, so derive indirectly. Stack growth is top to bottom. */ /* p = (uint32_t *) xMPUSettings->coproc_area; */ uint32_t *p; p = (uint32_t *)(((uint32_t) top_of_stack+1 - XT_CP_SIZE)); p[0] = 0; p[1] = 0; p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN; #endif /* END - code from FreeRTOS port for Xtensa from Cadence */ DEBUG("%s start=%p size=%d top=%p sp=%p free=%u\n", __func__, stack_start, stack_size, top_of_stack, sp, sp-(uint8_t*)stack_start); return (char*)sp; }