1/**
2 * \file
3 * \brief ARM execution and miscellany
4 */
5
6/*
7 * Copyright (c) 2007-2009, ETH Zurich.
8 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
9 * All rights reserved.
10 *
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
14 */
15
16#include <kernel.h>
17#include <dispatch.h>
18#include <init.h>
19#include <arch/arm/arm.h>
20#include <arm_hal.h>
21#include <exec.h>
22#include <exceptions.h>
23#include <misc.h>
24#include <sysreg.h>   // for invalidating tlb and cache
25
26static arch_registers_state_t upcall_state;
27
28STATIC_ASSERT(X0_REG   ==  0, "");
29STATIC_ASSERT(PC_REG   == 32, "");
30STATIC_ASSERT(SPSR_REG == 33, "");
31
32extern uint32_t ctr;
33
34void __attribute__((noreturn)) do_resume(uint64_t *regs);
35
36/// Ensure context is for user-mode with interrupts enabled.
37static inline void
38ensure_user_mode_policy(arch_registers_state_t *state)
39{
40    uintptr_t cpsr_if_mode = CPSR_F_MASK | AARCH64_MODE_USR;
41
42    if ((state->named.spsr & (CPSR_IF_MASK | AARCH64_MODE_MASK)) != cpsr_if_mode) {
43        assert(0 == (state->named.spsr & AARCH64_MODE_PRIV));
44        state->named.spsr &= CPSR_IF_MASK | AARCH64_MODE_MASK;
45        state->named.spsr |= cpsr_if_mode;
46    }
47}
48
49/**
50 * \brief Go to user-space at entry point 'entry'.
51 *
52 * This function goes to user-space and starts executing the program at
53 * its entry point at virtual address 'entry'.
54 *
55 * \param entry Entry point address of program to execute.
56 */
57void __attribute__ ((noreturn))
58execute(lvaddr_t entry)
59{
60    dispatcher_handle_t handle = dcb_current->disp;
61    struct dispatcher_shared_aarch64 *disp_aarch64 =
62        get_dispatcher_shared_aarch64(handle);
63
64    arch_registers_state_t *state = &upcall_state;
65    assert(0 != disp_aarch64->got_base);
66
67    /* XXX - why is this here? */
68    state->named.x10 = disp_aarch64->got_base;
69
70    struct dispatcher_shared_generic *disp_gen
71        = get_dispatcher_shared_generic(handle);
72
73    state->named.x0 = disp_gen->udisp;
74
75    state->named.pc = entry;
76    ensure_user_mode_policy(state);
77    do_resume(state->regs);
78}
79
80/**
81 * \brief Resume the given user-space snapshot.
82 *
83 * This function resumes user-space execution by restoring the CPU
84 * registers with the ones given in the array, pointed to by 'state'.
85 */
86uint32_t ctr=0;
87void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
88{
89    ctr++;
90    ensure_user_mode_policy(state);
91
92	//printf("thread reg..%p\n",state->named.rtls);
93    /*
94      This function succeeds the first time executed, i.e.
95      when init is started for the first time.
96      If we hold the execution here after the first execption, we are still good
97    */
98    //    while(ctr>1);
99    do_resume(state->regs);
100}
101
102void wait_for_interrupt(void)
103{
104    // Load magic and enable interrupts.
105    __asm volatile(
106        "mov    w0, #" XTR(WAIT_FOR_INTERRUPT_MAGIC) "              \n\t"
107        "0:                                             \n\t"
108#if defined(__ARM_ARCH_8A__)
109        "msr daifclr, #2                  \n\t"
110        "wfi                  \n\t"
111#else
112          // If no WFI functionality exists on system, just
113          // spinning here is okay.
114#error "Unknown platform for wait_for_interrupt"
115#endif //
116        "b      0b                                      \n\t" ::: "r0");
117
118    panic("wfi returned");
119}
120