blob: 2f22ce29e54add868fb482b8adbb3ab51da31d97 [file] [log] [blame]
Patrick Georgid1e50f92020-03-04 15:00:05 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -07002/*
3 * Early initialization code for riscv
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -07004 */
5
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +01006#include <arch/encoding.h>
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -07007#include <arch/exception.h>
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +02008#include <console/console.h>
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +02009#include <vm.h>
Xiang Wang22e0c562018-08-15 16:27:05 +080010#include <mcall.h>
11#include <sbi.h>
Felix Helddd9edef2021-09-16 21:51:06 +020012#include <types.h>
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080013
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020014static const char *const exception_names[] = {
15 "Instruction address misaligned",
16 "Instruction access fault",
17 "Illegal instruction",
18 "Breakpoint",
19 "Load address misaligned",
20 "Load access fault",
21 "Store address misaligned",
22 "Store access fault",
23 "Environment call from U-mode",
24 "Environment call from S-mode",
Jonathan Neuschäfera5c49b82018-02-16 13:36:46 +010025 "Reserved (10)",
26 "Environment call from M-mode",
27 "Instruction page fault",
28 "Load page fault",
29 "Reserved (14)",
30 "Store page fault",
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020031};
32
33static const char *mstatus_to_previous_mode(uintptr_t ms)
34{
35 switch (ms & MSTATUS_MPP) {
Philipp Hug8e365392024-03-01 10:59:56 +000036 case 0x00000000:
37 return "user";
38 case 0x00000800:
39 return "supervisor";
40 case 0x00001000:
41 return "hypervisor";
42 case 0x00001800:
43 return "machine";
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020044 }
45
46 return "unknown";
47}
48
Maximilian Brune5d0fa0d2024-03-07 22:56:27 +010049static void print_trap_information(const struct trapframe *tf)
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020050{
51 const char *previous_mode;
52 bool mprv = !!(tf->status & MSTATUS_MPRV);
Philipp Hug909be6a2018-10-26 13:00:26 +020053 int hart_id = read_csr(mhartid);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020054
55 /* Leave some space around the trap message */
56 printk(BIOS_DEBUG, "\n");
57
58 if (tf->cause < ARRAY_SIZE(exception_names))
Philipp Hug8e365392024-03-01 10:59:56 +000059 printk(BIOS_DEBUG, "Exception: %s\n", exception_names[tf->cause]);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020060 else
Philipp Hug8e365392024-03-01 10:59:56 +000061 printk(BIOS_DEBUG, "Trap: Unknown cause %p\n", (void *)tf->cause);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020062
63 previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
Philipp Hug909be6a2018-10-26 13:00:26 +020064 printk(BIOS_DEBUG, "Hart ID: %d\n", hart_id);
Philipp Hug8e365392024-03-01 10:59:56 +000065 printk(BIOS_DEBUG, "Previous mode: %s%s\n", previous_mode, mprv ? " (MPRV)" : "");
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020066 printk(BIOS_DEBUG, "Bad instruction pc: %p\n", (void *)tf->epc);
67 printk(BIOS_DEBUG, "Bad address: %p\n", (void *)tf->badvaddr);
Elyes Haouas2ba796e2022-11-18 15:21:37 +010068 printk(BIOS_DEBUG, "Stored ra: %p\n", (void *)tf->gpr[1]);
69 printk(BIOS_DEBUG, "Stored sp: %p\n", (void *)tf->gpr[2]);
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +020070}
71
Maximilian Brune5d0fa0d2024-03-07 22:56:27 +010072static void interrupt_handler(struct trapframe *tf)
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080073{
74 uint64_t cause = tf->cause & ~0x8000000000000000ULL;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080075
76 switch (cause) {
77 case IRQ_M_TIMER:
Philipp Hug1ed082b2018-10-29 21:32:51 +010078 /*
79 * Set interrupt pending for supervisor mode and disable timer
80 * interrupt in machine mode.
81 * To receive another timer interrupt just set timecmp and
82 * enable machine mode timer interrupt again.
83 */
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080084
Philipp Hug1ed082b2018-10-29 21:32:51 +010085 clear_csr(mie, MIP_MTIP);
86 set_csr(mip, MIP_STIP);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080087
Ronald G. Minnichd9307c22016-12-12 15:09:42 -080088 break;
Xiang Wang22e0c562018-08-15 16:27:05 +080089 case IRQ_M_SOFT:
90 if (HLS()->ipi_pending & IPI_SOFT) {
91 set_csr(mip, MIP_SSIP);
92 } else if (HLS()->ipi_pending & IPI_FENCE_I) {
93 asm volatile("fence.i");
94 } else if (HLS()->ipi_pending & IPI_SFENCE_VMA) {
95 asm volatile("sfence.vma");
96 } else if (HLS()->ipi_pending & IPI_SFENCE_VMA_ASID) {
97 asm volatile("sfence.vma");
98 } else if (HLS()->ipi_pending & IPI_SHUTDOWN) {
99 while (HLS()->ipi_pending & IPI_SHUTDOWN)
100 asm volatile("wfi");
101 }
102 break;
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800103 default:
104 printk(BIOS_EMERG, "======================================\n");
Philipp Hug8e365392024-03-01 10:59:56 +0000105 printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n", cause);
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800106 printk(BIOS_EMERG, "======================================\n");
107 print_trap_information(tf);
108 break;
109 }
110}
Philipp Hug8e365392024-03-01 10:59:56 +0000111
Maximilian Brune5d0fa0d2024-03-07 22:56:27 +0100112void (*trap_handler)(struct trapframe *tf) = default_trap_handler;
Philipp Hug8e365392024-03-01 10:59:56 +0000113
Maximilian Brune5d0fa0d2024-03-07 22:56:27 +0100114void default_trap_handler(struct trapframe *tf)
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800115{
Ronald G. Minnichd9307c22016-12-12 15:09:42 -0800116 if (tf->cause & 0x8000000000000000ULL) {
117 interrupt_handler(tf);
118 return;
119 }
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700120
Elyes HAOUAS0ce41f12018-11-13 10:03:31 +0100121 switch (tf->cause) {
Felix Singer6ff711c2023-12-08 10:39:44 +0100122 case CAUSE_FETCH_ACCESS:
123 case CAUSE_ILLEGAL_INSTRUCTION:
124 case CAUSE_BREAKPOINT:
125 case CAUSE_LOAD_ACCESS:
126 case CAUSE_STORE_ACCESS:
127 case CAUSE_USER_ECALL:
128 case CAUSE_HYPERVISOR_ECALL:
129 case CAUSE_MACHINE_ECALL:
130 print_trap_information(tf);
131 break;
132 case CAUSE_SUPERVISOR_ECALL:
133 handle_sbi(tf);
134 return;
Ronald G Minnich3ee97e42024-03-21 14:04:58 -0700135 case CAUSE_MISALIGNED_FETCH:
Felix Singer6ff711c2023-12-08 10:39:44 +0100136 case CAUSE_MISALIGNED_LOAD:
137 case CAUSE_MISALIGNED_STORE:
138 print_trap_information(tf);
Felix Singer6ff711c2023-12-08 10:39:44 +0100139 return;
140 default:
141 printk(BIOS_EMERG, "================================\n");
142 printk(BIOS_EMERG, "coreboot: can not handle a trap:\n");
143 printk(BIOS_EMERG, "================================\n");
144 print_trap_information(tf);
145 break;
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700146 }
Jonathan Neuschäfer363526c2016-08-13 04:20:09 +0200147
148 die("Can't recover from trap. Halting.\n");
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700149}
150
Xiang Wangcda59b52018-08-09 16:20:35 +0800151/* This function used to redirect trap to s-mode. */
152void redirect_trap(void)
153{
Arthur Heymans917261d2023-04-19 21:25:08 +0200154 write_csr(stval, read_csr(mtval));
Xiang Wangcda59b52018-08-09 16:20:35 +0800155 write_csr(sepc, read_csr(mepc));
156 write_csr(scause, read_csr(mcause));
157 write_csr(mepc, read_csr(stvec));
Jonathan Neuschäferb6648cd2016-08-22 19:37:15 +0200158
Xiang Wangcda59b52018-08-09 16:20:35 +0800159 uintptr_t status = read_csr(mstatus);
160 uintptr_t mpp = EXTRACT_FIELD(status, MSTATUS_MPP);
161 status = INSERT_FIELD(status, MSTATUS_MPP, 1);
162 status = INSERT_FIELD(status, MSTATUS_SPP, mpp & 1);
163 write_csr(mstatus, status);
Thaminda Edirisooriya95ba4c82015-08-26 14:54:31 -0700164}