/** * \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 #include #include #include #include #include #include #include #include // 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"); }