xref: /haiku/src/system/boot/platform/riscv/traps.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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
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))
74 MSyscall(uint64 op, ...)
75 {
76 	asm volatile("ecall");
77 	asm volatile("ret");
78 }
79 
80 
81 extern "C" void
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
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