blob: 6b39faba796bbd9484fe8addadba4339104d8edc [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>
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +020020#include <vm.h>
Xiang Wang22e0c562018-08-15 16:27:05 +080021#include <mcall.h>
22#include <sbi.h>
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080023
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020024static const char *const exception_names[] = {
25 "Instruction address misaligned",
26 "Instruction access fault",
27 "Illegal instruction",
28 "Breakpoint",
29 "Load address misaligned",
30 "Load access fault",
31 "Store address misaligned",
32 "Store access fault",
33 "Environment call from U-mode",
34 "Environment call from S-mode",
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +010035 "Reserved (10)",
36 "Environment call from M-mode",
37 "Instruction page fault",
38 "Load page fault",
39 "Reserved (14)",
40 "Store page fault",
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020041};
42
43static const char *mstatus_to_previous_mode(uintptr_t ms)
44{
45 switch (ms & MSTATUS_MPP) {
46 case 0x00000000: return "user";
47 case 0x00000800: return "supervisor";
48 case 0x00001000: return "hypervisor";
49 case 0x00001800: return "machine";
50 }
51
52 return "unknown";
53}
54
55static void print_trap_information(const trapframe *tf)
56{
57 const char *previous_mode;
58 bool mprv = !!(tf->status & MSTATUS_MPRV);
Philipp Hug909be6a2018-10-26 13:00:26 +020059 int hart_id = read_csr(mhartid);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020060
61 /* Leave some space around the trap message */
62 printk(BIOS_DEBUG, "\n");
63
64 if (tf->cause < ARRAY_SIZE(exception_names))
65 printk(BIOS_DEBUG, "Exception: %s\n",
66 exception_names[tf->cause]);
67 else
68 printk(BIOS_DEBUG, "Trap: Unknown cause %p\n",
69 (void *)tf->cause);
70
71 previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
Philipp Hug909be6a2018-10-26 13:00:26 +020072 printk(BIOS_DEBUG, "Hart ID: %d\n", hart_id);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020073 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 interrupt_handler(trapframe *tf)
82{
83 uint64_t cause = tf->cause & ~0x8000000000000000ULL;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080084
85 switch (cause) {
86 case IRQ_M_TIMER:
Philipp Hug1ed082b2018-10-29 21:32:51 +010087 /*
88 * Set interrupt pending for supervisor mode and disable timer
89 * interrupt in machine mode.
90 * To receive another timer interrupt just set timecmp and
91 * enable machine mode timer interrupt again.
92 */
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080093
Philipp Hug1ed082b2018-10-29 21:32:51 +010094 clear_csr(mie, MIP_MTIP);
95 set_csr(mip, MIP_STIP);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080096
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080097 break;
Xiang Wang22e0c562018-08-15 16:27:05 +080098 case IRQ_M_SOFT:
99 if (HLS()->ipi_pending & IPI_SOFT) {
100 set_csr(mip, MIP_SSIP);
101 } else if (HLS()->ipi_pending & IPI_FENCE_I) {
102 asm volatile("fence.i");
103 } else if (HLS()->ipi_pending & IPI_SFENCE_VMA) {
104 asm volatile("sfence.vma");
105 } else if (HLS()->ipi_pending & IPI_SFENCE_VMA_ASID) {
106 asm volatile("sfence.vma");
107 } else if (HLS()->ipi_pending & IPI_SHUTDOWN) {
108 while (HLS()->ipi_pending & IPI_SHUTDOWN)
109 asm volatile("wfi");
110 }
111 break;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800112 default:
113 printk(BIOS_EMERG, "======================================\n");
Martin Rothe18e6422017-06-03 20:03:18 -0600114 printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n",
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800115 cause);
116 printk(BIOS_EMERG, "======================================\n");
117 print_trap_information(tf);
118 break;
119 }
120}
121void trap_handler(trapframe *tf)
122{
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700123 write_csr(mscratch, tf);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800124 if (tf->cause & 0x8000000000000000ULL) {
125 interrupt_handler(tf);
126 return;
127 }
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700128
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +0100129 switch (tf->cause) {
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200130 case CAUSE_MISALIGNED_FETCH:
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +0100131 case CAUSE_FETCH_ACCESS:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200132 case CAUSE_ILLEGAL_INSTRUCTION:
133 case CAUSE_BREAKPOINT:
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +0100134 case CAUSE_LOAD_ACCESS:
135 case CAUSE_STORE_ACCESS:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200136 case CAUSE_USER_ECALL:
137 case CAUSE_HYPERVISOR_ECALL:
138 case CAUSE_MACHINE_ECALL:
139 print_trap_information(tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700140 break;
Xiang Wang22e0c562018-08-15 16:27:05 +0800141 case CAUSE_SUPERVISOR_ECALL:
142 handle_sbi(tf);
143 return;
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200144 case CAUSE_MISALIGNED_LOAD:
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200145 case CAUSE_MISALIGNED_STORE:
146 print_trap_information(tf);
Xiang Wangcda59b52018-08-09 16:20:35 +0800147 handle_misaligned(tf);
Jonathan Neuschäferb0de8512017-11-24 23:12:15 +0100148 return;
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700149 default:
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800150 printk(BIOS_EMERG, "================================\n");
Martin Rothe18e6422017-06-03 20:03:18 -0600151 printk(BIOS_EMERG, "coreboot: can not handle a trap:\n");
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800152 printk(BIOS_EMERG, "================================\n");
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200153 print_trap_information(tf);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700154 break;
155 }
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200156
157 die("Can't recover from trap. Halting.\n");
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700158}
159
Xiang Wangcda59b52018-08-09 16:20:35 +0800160/* This function used to redirect trap to s-mode. */
161void redirect_trap(void)
162{
163 write_csr(sbadaddr, read_csr(mbadaddr));
164 write_csr(sepc, read_csr(mepc));
165 write_csr(scause, read_csr(mcause));
166 write_csr(mepc, read_csr(stvec));
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200167
Xiang Wangcda59b52018-08-09 16:20:35 +0800168 uintptr_t status = read_csr(mstatus);
169 uintptr_t mpp = EXTRACT_FIELD(status, MSTATUS_MPP);
170 status = INSERT_FIELD(status, MSTATUS_MPP, 1);
171 status = INSERT_FIELD(status, MSTATUS_SPP, mpp & 1);
172 write_csr(mstatus, status);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700173}