system76-coreboot/src/arch/riscv/trap_handler.c
Maximilian Brune db1e9ce832 arch/riscv: Remove ram probing
Previously RAM probing was necessary for our QEMU-RISCV target in order
to find the available amount of memory.
Now we get the memory from the devicetree propagated by QEMU, so there
is no reason to keep it anymore.

Tested:
Start QEMU-RISCV and cause an exception to make sure the trap handler
still works.

Signed-off-by: Maximilian Brune <maximilian.brune@9elements.com>
Change-Id: I9b1e0dc78fc2a66d6085fe99a71245ff46f8e63c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83873
Reviewed-by: Elyes Haouas <ehaouas@noos.fr>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2024-08-20 12:54:12 +00:00

163 lines
4.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Early initialization code for riscv
*/
#include <arch/encoding.h>
#include <arch/exception.h>
#include <console/console.h>
#include <vm.h>
#include <mcall.h>
#include <sbi.h>
#include <types.h>
static const char *const exception_names[] = {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store address misaligned",
"Store access fault",
"Environment call from U-mode",
"Environment call from S-mode",
"Reserved (10)",
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
"Reserved (14)",
"Store page fault",
};
static const char *mstatus_to_previous_mode(uintptr_t ms)
{
switch (ms & MSTATUS_MPP) {
case 0x00000000:
return "user";
case 0x00000800:
return "supervisor";
case 0x00001000:
return "hypervisor";
case 0x00001800:
return "machine";
}
return "unknown";
}
static void print_trap_information(const struct trapframe *tf)
{
const char *previous_mode;
bool mprv = !!(tf->status & MSTATUS_MPRV);
int hart_id = read_csr(mhartid);
/* Leave some space around the trap message */
printk(BIOS_DEBUG, "\n");
if (tf->cause < ARRAY_SIZE(exception_names))
printk(BIOS_DEBUG, "Exception: %s\n", exception_names[tf->cause]);
else
printk(BIOS_DEBUG, "Trap: Unknown cause %p\n", (void *)tf->cause);
previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
printk(BIOS_DEBUG, "Hart ID: %d\n", hart_id);
printk(BIOS_DEBUG, "Previous mode: %s%s\n", previous_mode, mprv ? " (MPRV)" : "");
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", (void *)tf->epc);
printk(BIOS_DEBUG, "Bad address: %p\n", (void *)tf->badvaddr);
printk(BIOS_DEBUG, "Stored ra: %p\n", (void *)tf->gpr[1]);
printk(BIOS_DEBUG, "Stored sp: %p\n", (void *)tf->gpr[2]);
}
static void interrupt_handler(struct trapframe *tf)
{
uint64_t cause = tf->cause & ~0x8000000000000000ULL;
switch (cause) {
case IRQ_M_TIMER:
/*
* Set interrupt pending for supervisor mode and disable timer
* interrupt in machine mode.
* To receive another timer interrupt just set timecmp and
* enable machine mode timer interrupt again.
*/
clear_csr(mie, MIP_MTIP);
set_csr(mip, MIP_STIP);
break;
case IRQ_M_SOFT:
if (HLS()->ipi_pending & IPI_SOFT) {
set_csr(mip, MIP_SSIP);
} else if (HLS()->ipi_pending & IPI_FENCE_I) {
asm volatile("fence.i");
} else if (HLS()->ipi_pending & IPI_SFENCE_VMA) {
asm volatile("sfence.vma");
} else if (HLS()->ipi_pending & IPI_SFENCE_VMA_ASID) {
asm volatile("sfence.vma");
} else if (HLS()->ipi_pending & IPI_SHUTDOWN) {
while (HLS()->ipi_pending & IPI_SHUTDOWN)
asm volatile("wfi");
}
break;
default:
printk(BIOS_EMERG, "======================================\n");
printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n", cause);
printk(BIOS_EMERG, "======================================\n");
print_trap_information(tf);
break;
}
}
void trap_handler(struct trapframe *tf)
{
if (tf->cause & 0x8000000000000000ULL) {
interrupt_handler(tf);
return;
}
switch (tf->cause) {
case CAUSE_FETCH_ACCESS:
case CAUSE_ILLEGAL_INSTRUCTION:
case CAUSE_BREAKPOINT:
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_USER_ECALL:
case CAUSE_HYPERVISOR_ECALL:
case CAUSE_MACHINE_ECALL:
print_trap_information(tf);
break;
case CAUSE_SUPERVISOR_ECALL:
handle_sbi(tf);
return;
case CAUSE_MISALIGNED_FETCH:
case CAUSE_MISALIGNED_LOAD:
case CAUSE_MISALIGNED_STORE:
print_trap_information(tf);
return;
default:
printk(BIOS_EMERG, "================================\n");
printk(BIOS_EMERG, "coreboot: can not handle a trap:\n");
printk(BIOS_EMERG, "================================\n");
print_trap_information(tf);
break;
}
die("Can't recover from trap. Halting.\n");
}
/* This function used to redirect trap to s-mode. */
void redirect_trap(void)
{
write_csr(stval, read_csr(mtval));
write_csr(sepc, read_csr(mepc));
write_csr(scause, read_csr(mcause));
write_csr(mepc, read_csr(stvec));
uintptr_t status = read_csr(mstatus);
uintptr_t mpp = EXTRACT_FIELD(status, MSTATUS_MPP);
status = INSERT_FIELD(status, MSTATUS_MPP, 1);
status = INSERT_FIELD(status, MSTATUS_SPP, mpp & 1);
write_csr(mstatus, status);
}