1 /*
2  * Copyright 2014, General Dynamics C4 Systems
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #include <config.h>
8 #include <model/statedata.h>
9 #include <arch/fastpath/fastpath.h>
10 #include <arch/kernel/traps.h>
11 #include <arch/machine/debug.h>
12 #include <arch/machine/debug_conf.h>
13 #include <api/syscall.h>
14 #include <linker.h>
15 #include <machine/fpu.h>
16 
17 #include <benchmark/benchmark_track.h>
18 #include <benchmark/benchmark_utilisation.h>
19 
20 /** DONT_TRANSLATE */
restore_user_context(void)21 void VISIBLE NORETURN restore_user_context(void)
22 {
23     NODE_UNLOCK_IF_HELD;
24 
25     word_t cur_thread_reg = (word_t) NODE_STATE(ksCurThread);
26 
27     c_exit_hook();
28 
29 #ifdef ARM_CP14_SAVE_AND_RESTORE_NATIVE_THREADS
30     restore_user_debug_context(NODE_STATE(ksCurThread));
31 #endif
32 
33 #ifdef CONFIG_HAVE_FPU
34     lazyFPURestore(NODE_STATE(ksCurThread));
35 #endif /* CONFIG_HAVE_FPU */
36 
37     if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
38         asm volatile(
39             /* Set stack pointer to point at the r0 of the user context. */
40             "mov sp, %[cur_thread_reg] \n"
41             /* Pop user registers */
42             "pop {r0-r12}              \n"
43             /* Retore the user stack pointer */
44             "pop {lr}                  \n"
45             "msr sp_usr, lr            \n"
46             /* prepare the exception return lr */
47             "ldr lr, [sp, #4]          \n"
48             "msr elr_hyp, lr           \n"
49             /* prepare the user status register */
50             "ldr lr, [sp, #8]          \n"
51             "msr spsr_hyp, lr          \n"
52             /* Finally, pop our LR */
53             "pop {lr}                  \n"
54             /* Return to user */
55             "eret"
56             : /* no output */
57             : [cur_thread_reg] "r"(cur_thread_reg)
58             : "memory"
59         );
60     } else {
61         asm volatile("mov sp, %[cur_thread] \n\
62                   ldmdb sp, {r0-lr}^ \n\
63                   rfeia sp"
64                      : /* no output */
65                      : [cur_thread] "r"(cur_thread_reg + NextIP * sizeof(word_t))
66                     );
67     }
68     UNREACHABLE();
69 }
70