1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Early initialization code for riscv
6 #include <arch/encoding.h>
7 #include <arch/exception.h>
8 #include <console/console.h>
14 static const char *const exception_names
[] = {
15 "Instruction address misaligned",
16 "Instruction access fault",
17 "Illegal instruction",
19 "Load address misaligned",
21 "Store address misaligned",
23 "Environment call from U-mode",
24 "Environment call from S-mode",
26 "Environment call from M-mode",
27 "Instruction page fault",
33 static const char *mstatus_to_previous_mode(uintptr_t ms
)
35 switch (ms
& MSTATUS_MPP
) {
49 static void print_trap_information(const struct trapframe
*tf
)
51 const char *previous_mode
;
52 bool mprv
= !!(tf
->status
& MSTATUS_MPRV
);
53 int hart_id
= read_csr(mhartid
);
55 /* Leave some space around the trap message */
56 printk(BIOS_DEBUG
, "\n");
58 if (tf
->cause
< ARRAY_SIZE(exception_names
))
59 printk(BIOS_DEBUG
, "Exception: %s\n", exception_names
[tf
->cause
]);
61 printk(BIOS_DEBUG
, "Trap: Unknown cause %p\n", (void *)tf
->cause
);
63 previous_mode
= mstatus_to_previous_mode(read_csr(mstatus
));
64 printk(BIOS_DEBUG
, "Hart ID: %d\n", hart_id
);
65 printk(BIOS_DEBUG
, "Previous mode: %s%s\n", previous_mode
, mprv
? " (MPRV)" : "");
66 printk(BIOS_DEBUG
, "Bad instruction pc: %p\n", (void *)tf
->epc
);
67 printk(BIOS_DEBUG
, "Bad address: %p\n", (void *)tf
->badvaddr
);
68 printk(BIOS_DEBUG
, "Stored ra: %p\n", (void *)tf
->gpr
[1]);
69 printk(BIOS_DEBUG
, "Stored sp: %p\n", (void *)tf
->gpr
[2]);
72 static void interrupt_handler(struct trapframe
*tf
)
74 uint64_t cause
= tf
->cause
& ~0x8000000000000000ULL
;
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.
85 clear_csr(mie
, MIP_MTIP
);
86 set_csr(mip
, MIP_STIP
);
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
)
104 printk(BIOS_EMERG
, "======================================\n");
105 printk(BIOS_EMERG
, "coreboot: Unknown machine interrupt: 0x%llx\n", cause
);
106 printk(BIOS_EMERG
, "======================================\n");
107 print_trap_information(tf
);
112 void trap_handler(struct trapframe
*tf
)
114 if (tf
->cause
& 0x8000000000000000ULL
) {
115 interrupt_handler(tf
);
120 case CAUSE_FETCH_ACCESS
:
121 case CAUSE_ILLEGAL_INSTRUCTION
:
122 case CAUSE_BREAKPOINT
:
123 case CAUSE_LOAD_ACCESS
:
124 case CAUSE_STORE_ACCESS
:
125 case CAUSE_USER_ECALL
:
126 case CAUSE_HYPERVISOR_ECALL
:
127 case CAUSE_MACHINE_ECALL
:
128 print_trap_information(tf
);
130 case CAUSE_SUPERVISOR_ECALL
:
133 case CAUSE_MISALIGNED_FETCH
:
134 case CAUSE_MISALIGNED_LOAD
:
135 case CAUSE_MISALIGNED_STORE
:
136 print_trap_information(tf
);
139 printk(BIOS_EMERG
, "================================\n");
140 printk(BIOS_EMERG
, "coreboot: can not handle a trap:\n");
141 printk(BIOS_EMERG
, "================================\n");
142 print_trap_information(tf
);
146 die("Can't recover from trap. Halting.\n");
149 /* This function used to redirect trap to s-mode. */
150 void redirect_trap(void)
152 write_csr(stval
, read_csr(mtval
));
153 write_csr(sepc
, read_csr(mepc
));
154 write_csr(scause
, read_csr(mcause
));
155 write_csr(mepc
, read_csr(stvec
));
157 uintptr_t status
= read_csr(mstatus
);
158 uintptr_t mpp
= EXTRACT_FIELD(status
, MSTATUS_MPP
);
159 status
= INSERT_FIELD(status
, MSTATUS_MPP
, 1);
160 status
= INSERT_FIELD(status
, MSTATUS_SPP
, mpp
& 1);
161 write_csr(mstatus
, status
);