/* * @brief Initialize a new thread from its stack space * * The thread control structure 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 pStackmem the pointer to aligned stack memory * @param stackSize the stack size in bytes * @param pEntry thread entry point routine * @param parameter1 first param to entry point * @param parameter2 second param to entry point * @param parameter3 third param to entry point * @param priority thread priority * @param options thread options: K_ESSENTIAL * * @return N/A */ void _new_thread(struct k_thread *thread, k_thread_stack_t stack, size_t stackSize, _thread_entry_t pEntry, void *parameter1, void *parameter2, void *parameter3, int priority, unsigned int options) { char *pStackMem = K_THREAD_STACK_BUFFER(stack); _ASSERT_VALID_PRIO(priority, pEntry); char *stackEnd = pStackMem + stackSize; struct init_stack_frame *pInitCtx; _new_thread_init(thread, pStackMem, stackSize, priority, options); /* carve the thread entry struct from the "base" of the stack */ pInitCtx = (struct init_stack_frame *)(STACK_ROUND_DOWN(stackEnd) - sizeof(struct init_stack_frame)); pInitCtx->pc = ((u32_t)_thread_entry_wrapper); pInitCtx->r0 = (u32_t)pEntry; pInitCtx->r1 = (u32_t)parameter1; pInitCtx->r2 = (u32_t)parameter2; pInitCtx->r3 = (u32_t)parameter3; /* * For now set the interrupt priority to 15 * we can leave interrupt enable flag set to 0 as * seti instruction in the end of the _Swap() will * enable the interrupts based on intlock_key * value. */ #ifdef CONFIG_ARC_STACK_CHECKING pInitCtx->status32 = _ARC_V2_STATUS32_SC | _ARC_V2_STATUS32_E(_ARC_V2_DEF_IRQ_LEVEL); thread->arch.stack_base = (u32_t) stackEnd; #else pInitCtx->status32 = _ARC_V2_STATUS32_E(_ARC_V2_DEF_IRQ_LEVEL); #endif #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 /* * intlock_key is constructed based on ARCv2 ISA Programmer's * Reference Manual CLRI instruction description: * dst[31:6] dst[5] dst[4] dst[3:0] * 26'd0 1 STATUS32.IE STATUS32.E[3:0] */ thread->arch.intlock_key = 0x3F; thread->arch.relinquish_cause = _CAUSE_COOP; thread->callee_saved.sp = (u32_t)pInitCtx - ___callee_saved_stack_t_SIZEOF; /* initial values in all other regs/k_thread entries are irrelevant */ thread_monitor_init(thread); }
void _new_thread(struct k_thread *thread, k_thread_stack_t *stack, size_t stack_size, k_thread_entry_t thread_func, void *arg1, void *arg2, void *arg3, int priority, unsigned int options) { char *stack_memory = K_THREAD_STACK_BUFFER(stack); _ASSERT_VALID_PRIO(priority, thread_func); struct __esf *stack_init; _new_thread_init(thread, stack_memory, stack_size, priority, options); /* Initial stack frame for thread */ stack_init = (struct __esf *) STACK_ROUND_DOWN(stack_memory + stack_size - sizeof(struct __esf)); /* Setup the initial stack frame */ stack_init->a0 = (u32_t)thread_func; stack_init->a1 = (u32_t)arg1; stack_init->a2 = (u32_t)arg2; stack_init->a3 = (u32_t)arg3; /* * Following the RISC-V architecture, * the MSTATUS register (used to globally enable/disable interrupt), * as well as the MEPC register (used to by the core to save the * value of the program counter at which an interrupt/exception occcurs) * need to be saved on the stack, upon an interrupt/exception * and restored prior to returning from the interrupt/exception. * This shall allow to handle nested interrupts. * * Given that context switching is performed via a system call exception * within the RISCV32 architecture implementation, initially set: * 1) MSTATUS to SOC_MSTATUS_DEF_RESTORE in the thread stack to enable * interrupts when the newly created thread will be scheduled; * 2) MEPC to the address of the _thread_entry_wrapper in the thread * stack. * Hence, when going out of an interrupt/exception/context-switch, * after scheduling the newly created thread: * 1) interrupts will be enabled, as the MSTATUS register will be * restored following the MSTATUS value set within the thread stack; * 2) the core will jump to _thread_entry_wrapper, as the program * counter will be restored following the MEPC value set within the * thread stack. */ stack_init->mstatus = SOC_MSTATUS_DEF_RESTORE; stack_init->mepc = (u32_t)_thread_entry_wrapper; thread->callee_saved.sp = (u32_t)stack_init; thread_monitor_init(thread); }
/** * @brief Create a new kernel execution thread * * Initializes the k_thread object and sets up initial stack frame. * * @param thread pointer to thread struct memory, including any space needed * for extra coprocessor context * @param stack the pointer to aligned stack memory * @param stack_size the stack size in bytes * @param entry thread entry point routine * @param arg1 first param to entry point * @param arg2 second param to entry point * @param arg3 third param to entry point * @param priority thread priority * @param options thread options: K_ESSENTIAL, K_FP_REGS, K_SSE_REGS * * Note that in this arch we cheat quite a bit: we use as stack a normal * pthreads stack and therefore we ignore the stack size * */ void _new_thread(struct k_thread *thread, k_thread_stack_t *stack, size_t stack_size, k_thread_entry_t thread_func, void *arg1, void *arg2, void *arg3, int priority, unsigned int options) { char *stack_memory = K_THREAD_STACK_BUFFER(stack); _ASSERT_VALID_PRIO(priority, thread_func); posix_thread_status_t *thread_status; _new_thread_init(thread, stack_memory, stack_size, priority, options); /* We store it in the same place where normal archs store the * "initial stack frame" */ thread_status = (posix_thread_status_t *) STACK_ROUND_DOWN(stack_memory + stack_size - sizeof(*thread_status)); /* _thread_entry() arguments */ thread_status->entry_point = thread_func; thread_status->arg1 = arg1; thread_status->arg2 = arg2; thread_status->arg3 = arg3; #if defined(CONFIG_ARCH_HAS_THREAD_ABORT) thread_status->aborted = 0; #endif thread->callee_saved.thread_status = (u32_t)thread_status; posix_new_thread(thread_status); thread_monitor_init(thread); }
void _new_thread(struct k_thread *thread, k_thread_stack_t stack, size_t stackSize, void (*pEntry)(void *, void *, void *), 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); }
static void nrf5_rx_thread(void *arg1, void *arg2, void *arg3) { struct device *dev = (struct device *)arg1; struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); struct net_buf *frag = NULL; enum net_verdict ack_result; struct net_pkt *pkt; u8_t pkt_len; ARG_UNUSED(arg2); ARG_UNUSED(arg3); while (1) { pkt = NULL; SYS_LOG_DBG("Waiting for frame"); k_sem_take(&nrf5_radio->rx_wait, K_FOREVER); SYS_LOG_DBG("Frame received"); pkt = net_pkt_get_reserve_rx(0, K_NO_WAIT); if (!pkt) { SYS_LOG_ERR("No pkt available"); goto out; } #if defined(CONFIG_IEEE802154_NRF5_RAW) /** * Reserve 1 byte for length */ net_pkt_set_ll_reserve(pkt, 1); #endif frag = net_pkt_get_frag(pkt, K_NO_WAIT); if (!frag) { SYS_LOG_ERR("No frag available"); goto out; } net_pkt_frag_insert(pkt, frag); /* rx_mpdu contains length, psdu, fcs|lqi * The last 2 bytes contain LQI or FCS, depending if * automatic CRC handling is enabled or not, respectively. */ #if defined(CONFIG_IEEE802154_NRF5_RAW) pkt_len = nrf5_radio->rx_psdu[0]; #else pkt_len = nrf5_radio->rx_psdu[0] - NRF5_FCS_LENGTH; #endif /* Skip length (first byte) and copy the payload */ memcpy(frag->data, nrf5_radio->rx_psdu + 1, pkt_len); net_buf_add(frag, pkt_len); nrf_drv_radio802154_buffer_free(nrf5_radio->rx_psdu); ack_result = ieee802154_radio_handle_ack(nrf5_radio->iface, pkt); if (ack_result == NET_OK) { SYS_LOG_DBG("ACK packet handled"); goto out; } SYS_LOG_DBG("Caught a packet (%u) (LQI: %u)", pkt_len, nrf5_radio->lqi); if (net_recv_data(nrf5_radio->iface, pkt) < 0) { SYS_LOG_DBG("Packet dropped by NET stack"); goto out; } net_analyze_stack("nRF5 rx stack", K_THREAD_STACK_BUFFER(nrf5_radio->rx_stack), K_THREAD_STACK_SIZEOF(nrf5_radio->rx_stack)); continue; out: if (pkt) { net_pkt_unref(pkt); } } }