aos/kernel/arch/armv8/exec.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

124 lines
3.7 KiB
C

/**
* \file
* \brief ARM execution and miscellany
*/
/*
* Copyright (c) 2007-2009, ETH Zurich.
* Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
#include <dispatch.h>
#include <init.h>
#include <arch/arm/arm.h>
#include <arm_hal.h>
#include <exec.h>
#include <exceptions.h>
#include <misc.h>
#include <sysreg.h> // for invalidating tlb and cache
static arch_registers_state_t upcall_state;
STATIC_ASSERT(X0_REG == 0, "");
STATIC_ASSERT(PC_REG == 32, "");
STATIC_ASSERT(SPSR_REG == 33, "");
extern uint32_t ctr;
void __attribute__((noreturn)) do_resume(uint64_t *regs);
/// Ensure context is for user-mode with interrupts enabled.
static inline void
ensure_user_mode_policy(arch_registers_state_t *state)
{
uintptr_t cpsr_if_mode = CPSR_F_MASK | AARCH64_MODE_USR;
if ((state->named.spsr & (CPSR_IF_MASK | AARCH64_MODE_MASK)) != cpsr_if_mode) {
assert(0 == (state->named.spsr & AARCH64_MODE_PRIV));
state->named.spsr &= CPSR_IF_MASK | AARCH64_MODE_MASK;
state->named.spsr |= cpsr_if_mode;
}
}
/**
* \brief Go to user-space at entry point 'entry'.
*
* This function goes to user-space and starts executing the program at
* its entry point at virtual address 'entry'.
*
* \param entry Entry point address of program to execute.
*/
void __attribute__ ((noreturn))
execute(lvaddr_t entry)
{
dispatcher_handle_t handle = dcb_current->disp;
struct dispatcher_shared_aarch64 *disp_aarch64 =
get_dispatcher_shared_aarch64(handle);
arch_registers_state_t *state = &upcall_state;
assert(0 != disp_aarch64->got_base);
/* XXX - why is this here? */
state->named.x10 = disp_aarch64->got_base;
struct dispatcher_shared_generic *disp_gen
= get_dispatcher_shared_generic(handle);
state->named.x0 = disp_gen->udisp;
state->named.pc = entry;
ensure_user_mode_policy(state);
do_resume(state->regs);
}
/**
* \brief Resume the given user-space snapshot.
*
* This function resumes user-space execution by restoring the CPU
* registers with the ones given in the array, pointed to by 'state'.
*/
uint32_t ctr=0;
void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
{
ctr++;
ensure_user_mode_policy(state);
//printf("thread reg..%p\n",state->named.rtls);
/*
This function succeeds the first time executed, i.e.
when init is started for the first time.
If we hold the execution here after the first execption, we are still good
*/
// while(ctr>1);
do_resume(state->regs);
}
void wait_for_interrupt(void)
{
// Load magic and enable interrupts.
__asm volatile(
/* Reset the kernel stack pointer. */
"ldr x1, =kernel_stack \n\t" // load the address of the kernel stack
"ldr x2, [x1] \n\t" // read the entry of the kernel stack
"mov sp, x2 \n\t"
"mov w0, #" XTR(WAIT_FOR_INTERRUPT_MAGIC) "\n\t"
"0: \n\t"
#if defined(__ARM_ARCH_8A__)
"msr daifclr, #2 \n\t"
"wfi \n\t"
#else
// If no WFI functionality exists on system, just
// spinning here is okay.
#error "Unknown platform for wait_for_interrupt"
#endif //
"b 0b \n\t" ::: "r0");
panic("wfi returned");
}