blob: 7b35c2e7cd4ed4bbadd86bf58fa3d1d85283ee59 [file] [log] [blame]
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -07001/*
2 * Early initialization code for riscv
3 *
4 * Copyright 2015 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14 * GNU General Public License for more details.
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -070015 */
16
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +010017#include <arch/encoding.h>
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -070018#include <arch/exception.h>
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +020019#include <console/console.h>
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -070020#include <string.h>
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +020021#include <vm.h>
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080022
23static uint64_t *time;
24static uint64_t *timecmp;
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -070025
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020026static const char *const exception_names[] = {
27 "Instruction address misaligned",
28 "Instruction access fault",
29 "Illegal instruction",
30 "Breakpoint",
31 "Load address misaligned",
32 "Load access fault",
33 "Store address misaligned",
34 "Store access fault",
35 "Environment call from U-mode",
36 "Environment call from S-mode",
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +010037 "Reserved (10)",
38 "Environment call from M-mode",
39 "Instruction page fault",
40 "Load page fault",
41 "Reserved (14)",
42 "Store page fault",
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020043};
44
45static const char *mstatus_to_previous_mode(uintptr_t ms)
46{
47 switch (ms & MSTATUS_MPP) {
48 case 0x00000000: return "user";
49 case 0x00000800: return "supervisor";
50 case 0x00001000: return "hypervisor";
51 case 0x00001800: return "machine";
52 }
53
54 return "unknown";
55}
56
57static void print_trap_information(const trapframe *tf)
58{
59 const char *previous_mode;
60 bool mprv = !!(tf->status & MSTATUS_MPRV);
61
62 /* Leave some space around the trap message */
63 printk(BIOS_DEBUG, "\n");
64
65 if (tf->cause < ARRAY_SIZE(exception_names))
66 printk(BIOS_DEBUG, "Exception: %s\n",
67 exception_names[tf->cause]);
68 else
69 printk(BIOS_DEBUG, "Trap: Unknown cause %p\n",
70 (void *)tf->cause);
71
72 previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
73 printk(BIOS_DEBUG, "Previous mode: %s%s\n",
74 previous_mode, mprv? " (MPRV)":"");
75 printk(BIOS_DEBUG, "Bad instruction pc: %p\n", (void *)tf->epc);
76 printk(BIOS_DEBUG, "Bad address: %p\n", (void *)tf->badvaddr);
77 printk(BIOS_DEBUG, "Stored ra: %p\n", (void*) tf->gpr[1]);
78 printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
79}
80
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080081static void gettimer(void)
82{
Jonathan Neuschäferc90f1d72017-09-26 01:44:45 +020083 /*
84 * FIXME: This hard-coded value (currently) works on spike, but we
85 * should really read it from the device tree.
86 */
87 uintptr_t clint = 0x02000000;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080088
Jonathan Neuschäferc90f1d72017-09-26 01:44:45 +020089 time = (void *)(clint + 0xbff8);
90 timecmp = (void *)(clint + 0x4000);
91
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080092 if (!time)
93 die("Got timer interrupt but found no timer.");
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080094 if (!timecmp)
Jonathan Neuschäferc90f1d72017-09-26 01:44:45 +020095 die("Got timer interrupt but found no timecmp.");
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080096}
97
98static void interrupt_handler(trapframe *tf)
99{
100 uint64_t cause = tf->cause & ~0x8000000000000000ULL;
Ronald G. Minnich6f3a53b2017-01-15 17:40:51 +0100101 uint32_t msip, ssie;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800102
103 switch (cause) {
104 case IRQ_M_TIMER:
105 // The only way to reset the timer interrupt is to
106 // write mtimecmp. But we also have to ensure the
107 // comparison fails, for a long time, to let
108 // supervisor interrupt handler compute a new value
109 // and set it. Finally, it fires if mtimecmp is <=
110 // mtime, not =, so setting mtimecmp to 0 won't work
111 // to clear the interrupt and disable a new one. We
112 // have to set the mtimecmp far into the future.
113 // Akward!
114 //
115 // Further, maybe the platform doesn't have the
116 // hardware or the payload never uses it. We hold off
117 // querying some things until we are sure we need
118 // them. What to do if we can not find them? There are
119 // no good options.
120
121 // This hart may have disabled timer interrupts. If
122 // so, just return. Kernels should only enable timer
123 // interrupts on one hart, and that should be hart 0
124 // at present, as we only search for
125 // "core{0{0{timecmp" above.
126 ssie = read_csr(sie);
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +0100127 if (!(ssie & SIP_STIP))
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800128 break;
129
130 if (!timecmp)
131 gettimer();
Ronald G. Minnich6f3a53b2017-01-15 17:40:51 +0100132 //printk(BIOS_SPEW, "timer interrupt\n");
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800133 *timecmp = (uint64_t) -1;
Ronald G. Minnich6f3a53b2017-01-15 17:40:51 +0100134 msip = read_csr(mip);
135 msip |= SIP_STIP;
136 write_csr(mip, msip);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800137 break;
138 default:
139 printk(BIOS_EMERG, "======================================\n");
Martin Rothe18e6422017-06-03 20:03:18 -0600140 printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n",
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800141 cause);
142 printk(BIOS_EMERG, "======================================\n");
143 print_trap_information(tf);
144 break;
145 }
146}
147void trap_handler(trapframe *tf)
148{
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700149 write_csr(mscratch, tf);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800150 if (tf->cause & 0x8000000000000000ULL) {
151 interrupt_handler(tf);
152 return;
153 }
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700154
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200155 switch(tf->cause) {
156 case CAUSE_MISALIGNED_FETCH:
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +0100157 case CAUSE_FETCH_ACCESS:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200158 case CAUSE_ILLEGAL_INSTRUCTION:
159 case CAUSE_BREAKPOINT:
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +0100160 case CAUSE_LOAD_ACCESS:
161 case CAUSE_STORE_ACCESS:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200162 case CAUSE_USER_ECALL:
Jonathan Neuschäfer3ca8b592017-11-20 00:57:32 +0100163 case CAUSE_SUPERVISOR_ECALL:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200164 case CAUSE_HYPERVISOR_ECALL:
165 case CAUSE_MACHINE_ECALL:
166 print_trap_information(tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700167 break;
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200168 case CAUSE_MISALIGNED_LOAD:
169 print_trap_information(tf);
Jonathan Neuschäfer1b1d4b72016-07-07 20:53:29 +0200170 handle_misaligned_load(tf);
Jonathan Neuschäferb0de8512017-11-24 23:12:15 +0100171 return;
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200172 case CAUSE_MISALIGNED_STORE:
173 print_trap_information(tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700174 handle_misaligned_store(tf);
Jonathan Neuschäferb0de8512017-11-24 23:12:15 +0100175 return;
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700176 default:
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800177 printk(BIOS_EMERG, "================================\n");
Martin Rothe18e6422017-06-03 20:03:18 -0600178 printk(BIOS_EMERG, "coreboot: can not handle a trap:\n");
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800179 printk(BIOS_EMERG, "================================\n");
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200180 print_trap_information(tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700181 break;
182 }
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200183
184 die("Can't recover from trap. Halting.\n");
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700185}
186
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200187static uint32_t fetch_instruction(uintptr_t vaddr) {
188 printk(BIOS_SPEW, "fetching instruction at 0x%016zx\n", (size_t)vaddr);
189 return mprv_read_u32((uint32_t *) vaddr);
190}
191
Jonathan Neuschäfer1b1d4b72016-07-07 20:53:29 +0200192void handle_misaligned_load(trapframe *tf) {
Jonathan Neuschäfer2f72a612016-10-12 00:17:59 +0200193 printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700194 uintptr_t faultingInstructionAddr = tf->epc;
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200195 insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700196 printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
197 insn_t widthMask = 0x7000;
198 insn_t memWidth = (faultingInstruction & widthMask) >> 12;
199 insn_t destMask = 0xF80;
200 insn_t destRegister = (faultingInstruction & destMask) >> 7;
Jonathan Neuschäfer5a01d6a2017-09-23 21:39:06 +0200201 printk(BIOS_DEBUG, "Width: %d bits\n", (1 << memWidth) * 8);
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700202 if (memWidth == 3) {
203 // load double, handle the issue
204 void* badAddress = (void*) tf->badvaddr;
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200205 uint64_t value = 0;
206 for (int i = 0; i < 8; i++) {
207 value <<= 8;
208 value += mprv_read_u8(badAddress+i);
209 }
210 tf->gpr[destRegister] = value;
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700211 } else {
212 // panic, this should not have happened
Jonathan Neuschäfer2af174a2016-10-12 00:18:00 +0200213 die("Code should not reach this path, misaligned on a non-64 bit store/load\n");
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700214 }
215
216 // return to where we came from
217 write_csr(mepc, read_csr(mepc) + 4);
Thaminda Edirisooriyad9653e12015-09-10 10:55:17 -0700218}
219
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700220void handle_misaligned_store(trapframe *tf) {
Jonathan Neuschäfer2f72a612016-10-12 00:17:59 +0200221 printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700222 uintptr_t faultingInstructionAddr = tf->epc;
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200223 insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700224 printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
225 insn_t widthMask = 0x7000;
226 insn_t memWidth = (faultingInstruction & widthMask) >> 12;
227 insn_t srcMask = 0x1F00000;
228 insn_t srcRegister = (faultingInstruction & srcMask) >> 20;
Jonathan Neuschäfer5a01d6a2017-09-23 21:39:06 +0200229 printk(BIOS_DEBUG, "Width: %d bits\n", (1 << memWidth) * 8);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700230 if (memWidth == 3) {
231 // store double, handle the issue
232 void* badAddress = (void*) tf->badvaddr;
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200233 uint64_t value = tf->gpr[srcRegister];
234 for (int i = 0; i < 8; i++) {
235 mprv_write_u8(badAddress+i, value);
236 value >>= 8;
237 }
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700238 } else {
239 // panic, this should not have happened
Jonathan Neuschäfer2af174a2016-10-12 00:18:00 +0200240 die("Code should not reach this path, misaligned on a non-64 bit store/load\n");
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700241 }
242
243 // return to where we came from
244 write_csr(mepc, read_csr(mepc) + 4);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700245}