1/**
2 * \file
3 * \brief ARM execution and miscellany
4 */
5
6/*
7 * Copyright (c) 2007-2009,2016 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <kernel.h>
16
17#include <cache.h>
18#include <dispatch.h>
19#include <init.h>
20#include <arm.h>
21#include <platform.h>
22#include <exec.h>
23#include <exceptions.h>
24#include <misc.h>
25/* XXX - not AArch64-compatible. */
26#include <cp15.h>   // for invalidating tlb and cache
27
28static arch_registers_state_t upcall_state =
29{
30    .named.fpscr = 0x01000000
31};
32
33extern uint32_t ctr;
34
35STATIC_ASSERT(CPSR_REG ==  0, "");
36STATIC_ASSERT(R0_REG   ==  1, "");
37STATIC_ASSERT(PC_REG   == 16, "");
38
39void __attribute__((noreturn)) do_resume(uint32_t *regs);
40
41/// Ensure context is for user-mode with interrupts enabled.
42static inline void
43ensure_user_mode_policy(arch_registers_state_t *state)
44{
45    uintptr_t cpsr_if_mode = CPSR_F_MASK | ARM_MODE_USR;
46
47    if ((state->named.cpsr & (CPSR_IF_MASK | ARM_MODE_MASK)) != cpsr_if_mode) {
48        assert(0 == (state->named.cpsr & ARM_MODE_PRIV));
49        state->named.cpsr &= CPSR_IF_MASK | ARM_MODE_MASK;
50        state->named.cpsr |= cpsr_if_mode;
51    }
52}
53
54/**
55 * \brief Go to user-space at entry point 'entry'.
56 *
57 * This function goes to user-space and starts executing the program at
58 * its entry point at virtual address 'entry'.
59 *
60 * \param entry Entry point address of program to execute.
61 */
62void __attribute__ ((noreturn))
63execute(lvaddr_t entry)
64{
65    dispatcher_handle_t handle = dcb_current->disp;
66    struct dispatcher_shared_arm *disp_arm = get_dispatcher_shared_arm(handle);
67
68    arch_registers_state_t *state = &upcall_state;
69    assert(0 != disp_arm->got_base);
70
71    /* XXX - not AArch64-compatible. */
72    state->named.r9 = disp_arm->got_base;
73
74    state->named.pc = entry;
75    ensure_user_mode_policy(state);
76    do_resume(state->regs);
77}
78
79/**
80 * \brief Resume the given user-space snapshot.
81 *
82 * This function resumes user-space execution by restoring the CPU
83 * registers with the ones given in the array, pointed to by 'state'.
84 */
85uint32_t ctr=0;
86void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
87{
88    ctr++;
89    ensure_user_mode_policy(state);
90
91    /*
92      This function succeeds the first time executed, i.e.
93      when init is started for the first time.
94      If we hold the execution here after the first execption, we are still good
95    */
96    //    while(ctr>1);
97    do_resume(state->regs);
98}
99
100bool waiting_for_interrupt= 0;
101
102/* XXX - not AArch64-compatible. */
103void wait_for_interrupt(void)
104{
105    // XXX - is this true?
106    // REVIEW: Timer interrupt could be masked here.
107
108    /* If we're waiting on an interrupt in the kernel, it must be because
109     * there was no runnable dispatcher. */
110    assert(dcb_current == NULL);
111
112    /* Let the IRQ handler know that we expect an interrupt in kernel mode, so
113     * it shouldn't panic. */
114    waiting_for_interrupt= 1;
115
116    /* Unmask IRQ and wait. */
117    __asm volatile("cpsie i");
118    while(1) __asm volatile("wfi");
119}
120