/* * Copyright (c) 2019 Carlo Caione * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief New thread creation for ARM64 Cortex-A * * Core thread related primitives for the ARM64 Cortex-A */ #include #include #include #include #ifdef CONFIG_USERSPACE static bool is_user(struct k_thread *thread) { return (thread->base.user_options & K_USER) != 0; } #endif void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, char *stack_ptr, k_thread_entry_t entry, void *p1, void *p2, void *p3) { z_arch_esf_t *pInitCtx; pInitCtx = Z_STACK_PTR_TO_FRAME(struct __esf, stack_ptr); pInitCtx->x0 = (uint64_t)entry; pInitCtx->x1 = (uint64_t)p1; pInitCtx->x2 = (uint64_t)p2; pInitCtx->x3 = (uint64_t)p3; /* * - ELR_ELn: to be used by eret in z_arm64_exit_exc() to return * to z_thread_entry() with entry in x0(entry_point) and the * parameters already in place in x1(arg1), x2(arg2), x3(arg3). * - SPSR_ELn: to enable IRQs (we are masking FIQs). */ #ifdef CONFIG_USERSPACE /* * If the new thread is a user thread we jump into * arch_user_mode_enter() when still in EL1. */ if (is_user(thread)) { pInitCtx->elr = (uint64_t)arch_user_mode_enter; } else { pInitCtx->elr = (uint64_t)z_thread_entry; } pInitCtx->tpidrro_el0 = 0x0; thread->arch.priv_stack_start = 0; #else pInitCtx->elr = (uint64_t)z_thread_entry; #endif pInitCtx->spsr = SPSR_MODE_EL1T | DAIF_FIQ_BIT; /* * We are saving SP to pop out entry and parameters when going through * z_arm64_exit_exc() */ thread->callee_saved.sp = (uint64_t)pInitCtx; thread->switch_handle = thread; } void *z_arch_get_next_switch_handle(struct k_thread **old_thread) { *old_thread = _current; return z_get_next_switch_handle(*old_thread); } #ifdef CONFIG_USERSPACE FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, void *p1, void *p2, void *p3) { z_arch_esf_t *pInitCtx; uintptr_t stack_ptr; /* Map the thread stack */ z_arm64_thread_pt_init(_current); /* Setup the private stack */ _current->arch.priv_stack_start = (uint64_t)(_current->stack_obj); /* Reset the stack pointer to the base discarding any old context */ stack_ptr = Z_STACK_PTR_ALIGN(_current->stack_info.start + _current->stack_info.size - _current->stack_info.delta); /* * Reconstruct the ESF from scratch to leverage the z_arm64_exit_exc() * macro that will simulate a return from exception to move from EL1t * to EL0t. On return we will be in userspace. */ pInitCtx = Z_STACK_PTR_TO_FRAME(struct __esf, stack_ptr); pInitCtx->spsr = DAIF_FIQ_BIT | SPSR_MODE_EL0T; pInitCtx->elr = (uint64_t)z_thread_entry; /* The thread will be in user context */ pInitCtx->tpidrro_el0 = 0x1; pInitCtx->x0 = (uint64_t)user_entry; pInitCtx->x1 = (uint64_t)p1; pInitCtx->x2 = (uint64_t)p2; pInitCtx->x3 = (uint64_t)p3; /* All the needed information is already in the ESF */ z_arm64_userspace_enter(pInitCtx); CODE_UNREACHABLE; } #endif