1 /*
2 * Copyright 2021, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include "traps.h"
7 #include <KernelExport.h>
8 #include <arch_cpu_defs.h>
9 #include <arch_int.h>
10 #include <Htif.h>
11 #include <Clint.h>
12
13
14 // TODO: Put machine mode code in separate section and keep it loaded when
15 // kernel is running.
16
17
18 struct iframe {
19 uint64 ra;
20 uint64 t6;
21 uint64 sp;
22 uint64 gp;
23 uint64 tp;
24 uint64 t0;
25 uint64 t1;
26 uint64 t2;
27 uint64 t5;
28 uint64 s1;
29 uint64 a0;
30 uint64 a1;
31 uint64 a2;
32 uint64 a3;
33 uint64 a4;
34 uint64 a5;
35 uint64 a6;
36 uint64 a7;
37 uint64 s2;
38 uint64 s3;
39 uint64 s4;
40 uint64 s5;
41 uint64 s6;
42 uint64 s7;
43 uint64 s8;
44 uint64 s9;
45 uint64 s10;
46 uint64 s11;
47 uint64 t3;
48 uint64 t4;
49 uint64 fp;
50 uint64 epc;
51 };
52
53
54 __attribute__ ((aligned (16))) char sMStack[64*1024];
55
56
57 extern "C" void MVec();
58 extern "C" void MVecS();
59
60 static void
InitPmp()61 InitPmp()
62 {
63 // Setup physical memory protecton. By default physical memory can be only
64 // accessed from machine mode.
65
66 // We allow access to whole physical memory from non-machine mode.
67
68 SetPmpaddr0((~0L) >> 10);
69 SetPmpcfg0((1 << pmpR) | (1 << pmpW) | (1 << pmpX) | (pmpMatchNapot));
70 }
71
72
73 extern "C" status_t __attribute__((naked))
MSyscall(uint64 op,...)74 MSyscall(uint64 op, ...)
75 {
76 asm volatile("ecall");
77 asm volatile("ret");
78 }
79
80
81 extern "C" void
MTrap(iframe * frame)82 MTrap(iframe* frame)
83 {
84 uint64 cause = Mcause();
85 /*
86 HtifOutString("MTrap("); WriteCause(Mcause()); HtifOutString(")\n");
87 dprintf(" mstatus: "); WriteMstatus(Mstatus()); dprintf("\n");
88 dprintf(" mie: "); WriteInterruptSet(Mie()); dprintf("\n");
89 dprintf(" mip: "); WriteInterruptSet(Mip()); dprintf("\n");
90 dprintf(" sie: "); WriteInterruptSet(Sie()); dprintf("\n");
91 dprintf(" sip: "); WriteInterruptSet(Sip()); dprintf("\n");
92 dprintf(" mscratch: 0x%" B_PRIxADDR "\n", Mscratch());
93 DoStackTrace(Fp(), 0);
94 */
95 switch (cause) {
96 case causeMEcall:
97 case causeSEcall: {
98 frame->epc += 4;
99 uint64 op = frame->a0;
100 switch (op) {
101 case kMSyscallSwitchToSmode: {
102 HtifOutString("switchToSmodeMmodeSyscall()\n");
103 if (cause != causeMEcall) {
104 frame->a0 = B_NOT_ALLOWED;
105 return;
106 }
107 MstatusReg status{.val = Mstatus()};
108 status.mpp = modeS;
109 SetMedeleg(
110 0xffff & ~((1 << causeMEcall) | (1 << causeSEcall)));
111 SetMideleg(0xffff & ~(1 << mTimerInt));
112 SetMstatus(status.val);
113 dprintf("modeM stack: 0x%" B_PRIxADDR ", 0x%" B_PRIxADDR
114 "\n", (addr_t)sMStack,
115 (addr_t)(sMStack + sizeof(sMStack)));
116 SetMscratch((addr_t)(sMStack + sizeof(sMStack)));
117 SetMtvec((uint64)MVecS);
118 frame->a0 = B_OK;
119 return;
120 }
121 case kMSyscallSetTimer: {
122 bool enable = frame->a1 != 0;
123 /*
124 dprintf("setTimerMmodeSyscall(%d, %" B_PRIu64 ")\n",
125 enable, frame->a2);
126 */
127 // dprintf(" mtime: %" B_PRIu64 "\n", gClintRegs->mTime);
128 ClearBitsMip(1 << sTimerInt);
129 if (!enable) {
130 ClearBitsMie(1 << mTimerInt);
131 } else {
132 gClintRegs->mtimecmp[0] = frame->a2;
133 SetBitsMie(1 << mTimerInt);
134 }
135 frame->a0 = B_OK;
136 return;
137 }
138 default:
139 frame->a0 = B_NOT_SUPPORTED;
140 return;
141 }
142 break;
143 }
144 case causeInterrupt + mTimerInt: {
145 ClearBitsMie(1 << mTimerInt);
146 SetBitsMip(1 << sTimerInt);
147 return;
148 }
149 }
150 HtifOutString("unhandled MTrap\n");
151 HtifShutdown();
152 }
153
154
155 void
traps_init()156 traps_init()
157 {
158 SetMtvec((uint64)MVec);
159 MstatusReg mstatus{.val = Mstatus()};
160 mstatus.ie = 1 << modeM;
161 SetMstatus(mstatus.val);
162 InitPmp();
163 MSyscall(kMSyscallSwitchToSmode);
164 }
165