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(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 SetMip(Mip() & ~(1 << sTimerInt)); 129 if (!enable) { 130 SetMie(Mie() & ~(1 << mTimerInt)); 131 } else { 132 gClintRegs->mtimecmp[0] = frame->a2; 133 SetMie(Mie() | (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 SetMie(Mie() & ~(1 << mTimerInt)); 146 SetMip(Mip() | (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(Mstatus()); 160 mstatus.ie = 1 << modeM; 161 SetMstatus(mstatus.val); 162 InitPmp(); 163 MSyscall(kMSyscallSwitchToSmode); 164 } 165