124 lines
3.7 KiB
C
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");
|
|
}
|