zephyr/arch/arm/core/aarch64/thread.c

90 lines
2.1 KiB
C

/*
* Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com>
*
* 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 <kernel.h>
#include <ksched.h>
#include <wait_q.h>
#include <arch/cpu.h>
struct init_stack_frame {
/* top of the stack / most recently pushed */
/* SPSR_ELn and ELR_ELn */
uint64_t spsr;
uint64_t elr;
/*
* Registers restored by z_arm64_exit_exc(). We are not interested in
* registers x4 -> x18 + x30 but we need to account for those anyway
*/
uint64_t unused[16];
/*
* z_arm64_exit_exc() pulls these off the stack and into argument
* registers before calling z_thread_entry():
* - x2 <- arg2
* - x3 <- arg3
* - x0 <- entry_point
* - x1 <- arg1
*/
uint64_t arg2;
uint64_t arg3;
uint64_t entry_point;
uint64_t arg1;
/* least recently pushed */
};
/*
* An initial context, to be "restored" by z_arm64_context_switch(), is put at
* the other end of the stack, and thus reusable by the stack when not needed
* anymore.
*/
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)
{
struct init_stack_frame *pInitCtx;
pInitCtx = Z_STACK_PTR_TO_FRAME(struct init_stack_frame, stack_ptr);
pInitCtx->entry_point = (uint64_t)entry;
pInitCtx->arg1 = (uint64_t)p1;
pInitCtx->arg2 = (uint64_t)p2;
pInitCtx->arg3 = (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).
*/
pInitCtx->elr = (uint64_t)z_thread_entry;
pInitCtx->spsr = SPSR_MODE_EL1H | DAIF_FIQ;
/*
* 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);
}