1/*
2 * Copyright 2018, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13/*
14 *
15 * Copyright 2016, 2017 Hesham Almatary, Data61/CSIRO <hesham.almatary@data61.csiro.au>
16 * Copyright 2015, 2016 Hesham Almatary <heshamelmatary@gmail.com>
17 */
18
19#include <config.h>
20#include <model/statedata.h>
21#include <arch/fastpath/fastpath.h>
22#include <arch/kernel/traps.h>
23#include <machine/debug.h>
24#include <api/syscall.h>
25#include <util.h>
26#include <arch/machine/hardware.h>
27
28#include <benchmark/benchmark_track.h>
29#include <benchmark/benchmark_utilisation.h>
30
31/** DONT_TRANSLATE */
32void VISIBLE NORETURN restore_user_context(void)
33{
34    word_t cur_thread_reg = (word_t) NODE_STATE(ksCurThread)->tcbArch.tcbContext.registers;
35
36    c_exit_hook();
37
38    NODE_UNLOCK_IF_HELD;
39
40    asm volatile(
41        "mv t0, %[cur_thread]       \n"
42        LOAD_S " ra, (0*%[REGSIZE])(t0)  \n"
43        LOAD_S "  sp, (1*%[REGSIZE])(t0)  \n"
44        LOAD_S "  gp, (2*%[REGSIZE])(t0)  \n"
45        /* skip tp */
46        /* skip x5/t0 */
47        LOAD_S "  t2, (6*%[REGSIZE])(t0)  \n"
48        LOAD_S "  s0, (7*%[REGSIZE])(t0)  \n"
49        LOAD_S "  s1, (8*%[REGSIZE])(t0)  \n"
50        LOAD_S "  a0, (9*%[REGSIZE])(t0) \n"
51        LOAD_S "  a1, (10*%[REGSIZE])(t0) \n"
52        LOAD_S "  a2, (11*%[REGSIZE])(t0) \n"
53        LOAD_S "  a3, (12*%[REGSIZE])(t0) \n"
54        LOAD_S "  a4, (13*%[REGSIZE])(t0) \n"
55        LOAD_S "  a5, (14*%[REGSIZE])(t0) \n"
56        LOAD_S "  a6, (15*%[REGSIZE])(t0) \n"
57        LOAD_S "  a7, (16*%[REGSIZE])(t0) \n"
58        LOAD_S "  s2, (17*%[REGSIZE])(t0) \n"
59        LOAD_S "  s3, (18*%[REGSIZE])(t0) \n"
60        LOAD_S "  s4, (19*%[REGSIZE])(t0) \n"
61        LOAD_S "  s5, (20*%[REGSIZE])(t0) \n"
62        LOAD_S "  s6, (21*%[REGSIZE])(t0) \n"
63        LOAD_S "  s7, (22*%[REGSIZE])(t0) \n"
64        LOAD_S "  s8, (23*%[REGSIZE])(t0) \n"
65        LOAD_S "  s9, (24*%[REGSIZE])(t0) \n"
66        LOAD_S "  s10, (25*%[REGSIZE])(t0)\n"
67        LOAD_S "  s11, (26*%[REGSIZE])(t0)\n"
68        LOAD_S "  t3, (27*%[REGSIZE])(t0) \n"
69        LOAD_S "  t4, (28*%[REGSIZE])(t0) \n"
70        LOAD_S "  t5, (29*%[REGSIZE])(t0) \n"
71        LOAD_S "  t6, (30*%[REGSIZE])(t0) \n"
72        /* Get next restored tp */
73        LOAD_S "  t1, (3*%[REGSIZE])(t0)  \n"
74        /* get restored tp */
75        "add tp, t1, x0  \n"
76        /* get sepc */
77        LOAD_S "  t1, (34*%[REGSIZE])(t0)\n"
78        "csrw sepc, t1  \n"
79
80        /* Write back sscratch with cur_thread_reg to get it back on the next trap entry */
81        "csrw sscratch, t0         \n"
82
83        LOAD_S "  t1, (32*%[REGSIZE])(t0) \n"
84        "csrw sstatus, t1\n"
85
86        LOAD_S "  t1, (5*%[REGSIZE])(t0) \n"
87        LOAD_S "  t0, (4*%[REGSIZE])(t0) \n"
88        "sret"
89        : /* no output */
90        : [REGSIZE] "i" (sizeof(word_t)),
91        [cur_thread] "r" (cur_thread_reg)
92        : "memory"
93    );
94
95    UNREACHABLE();
96}
97
98void VISIBLE NORETURN
99c_handle_interrupt(void)
100{
101    NODE_LOCK_IRQ;
102
103    c_entry_hook();
104
105    handleInterruptEntry();
106
107    restore_user_context();
108    UNREACHABLE();
109}
110
111void VISIBLE NORETURN
112c_handle_exception(void)
113{
114    NODE_LOCK_SYS;
115
116    c_entry_hook();
117
118    handle_exception();
119
120    restore_user_context();
121    UNREACHABLE();
122}
123
124void NORETURN
125slowpath(syscall_t syscall)
126{
127    /* check for undefined syscall */
128    if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) {
129        handleUnknownSyscall(syscall);
130    } else {
131        handleSyscall(syscall);
132    }
133
134    restore_user_context();
135    UNREACHABLE();
136}
137
138void VISIBLE NORETURN
139c_handle_syscall(word_t cptr, word_t msgInfo, word_t unused1, word_t unused2, word_t unused3, word_t unused4, word_t unused5, syscall_t syscall)
140{
141    NODE_LOCK_SYS;
142
143    c_entry_hook();
144
145#ifdef CONFIG_FASTPATH
146    if (syscall == (syscall_t)SysCall) {
147        fastpath_call(cptr, msgInfo);
148        UNREACHABLE();
149    } else if (syscall == (syscall_t)SysReplyRecv) {
150        fastpath_reply_recv(cptr, msgInfo);
151        UNREACHABLE();
152    }
153#endif /* CONFIG_FASTPATH */
154    slowpath(syscall);
155    UNREACHABLE();
156}
157