coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
trap_handler.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Early initialization code for riscv
4  */
5 
6 #include <arch/encoding.h>
7 #include <arch/exception.h>
8 #include <console/console.h>
9 #include <vm.h>
10 #include <mcall.h>
11 #include <sbi.h>
12 #include <types.h>
13 
14 static 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",
25  "Reserved (10)",
26  "Environment call from M-mode",
27  "Instruction page fault",
28  "Load page fault",
29  "Reserved (14)",
30  "Store page fault",
31 };
32 
33 static const char *mstatus_to_previous_mode(uintptr_t ms)
34 {
35  switch (ms & MSTATUS_MPP) {
36  case 0x00000000: return "user";
37  case 0x00000800: return "supervisor";
38  case 0x00001000: return "hypervisor";
39  case 0x00001800: return "machine";
40  }
41 
42  return "unknown";
43 }
44 
45 static void print_trap_information(const trapframe *tf)
46 {
47  const char *previous_mode;
48  bool mprv = !!(tf->status & MSTATUS_MPRV);
49  int hart_id = read_csr(mhartid);
50 
51  /* Leave some space around the trap message */
52  printk(BIOS_DEBUG, "\n");
53 
54  if (tf->cause < ARRAY_SIZE(exception_names))
55  printk(BIOS_DEBUG, "Exception: %s\n",
56  exception_names[tf->cause]);
57  else
58  printk(BIOS_DEBUG, "Trap: Unknown cause %p\n",
59  (void *)tf->cause);
60 
61  previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
62  printk(BIOS_DEBUG, "Hart ID: %d\n", hart_id);
63  printk(BIOS_DEBUG, "Previous mode: %s%s\n",
64  previous_mode, mprv? " (MPRV)":"");
65  printk(BIOS_DEBUG, "Bad instruction pc: %p\n", (void *)tf->epc);
66  printk(BIOS_DEBUG, "Bad address: %p\n", (void *)tf->badvaddr);
67  printk(BIOS_DEBUG, "Stored ra: %p\n", (void*) tf->gpr[1]);
68  printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
69 }
70 
71 static void interrupt_handler(trapframe *tf)
72 {
73  uint64_t cause = tf->cause & ~0x8000000000000000ULL;
74 
75  switch (cause) {
76  case IRQ_M_TIMER:
77  /*
78  * Set interrupt pending for supervisor mode and disable timer
79  * interrupt in machine mode.
80  * To receive another timer interrupt just set timecmp and
81  * enable machine mode timer interrupt again.
82  */
83 
84  clear_csr(mie, MIP_MTIP);
85  set_csr(mip, MIP_STIP);
86 
87  break;
88  case IRQ_M_SOFT:
89  if (HLS()->ipi_pending & IPI_SOFT) {
90  set_csr(mip, MIP_SSIP);
91  } else if (HLS()->ipi_pending & IPI_FENCE_I) {
92  asm volatile("fence.i");
93  } else if (HLS()->ipi_pending & IPI_SFENCE_VMA) {
94  asm volatile("sfence.vma");
95  } else if (HLS()->ipi_pending & IPI_SFENCE_VMA_ASID) {
96  asm volatile("sfence.vma");
97  } else if (HLS()->ipi_pending & IPI_SHUTDOWN) {
98  while (HLS()->ipi_pending & IPI_SHUTDOWN)
99  asm volatile("wfi");
100  }
101  break;
102  default:
103  printk(BIOS_EMERG, "======================================\n");
104  printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n",
105  cause);
106  printk(BIOS_EMERG, "======================================\n");
108  break;
109  }
110 }
112 {
113  write_csr(mscratch, tf);
114  if (tf->cause & 0x8000000000000000ULL) {
115  interrupt_handler(tf);
116  return;
117  }
118 
119  switch (tf->cause) {
121  case CAUSE_FETCH_ACCESS:
123  case CAUSE_BREAKPOINT:
124  case CAUSE_LOAD_ACCESS:
125  case CAUSE_STORE_ACCESS:
126  case CAUSE_USER_ECALL:
128  case CAUSE_MACHINE_ECALL:
130  break;
132  handle_sbi(tf);
133  return;
137  handle_misaligned(tf);
138  return;
139  default:
140  printk(BIOS_EMERG, "================================\n");
141  printk(BIOS_EMERG, "coreboot: can not handle a trap:\n");
142  printk(BIOS_EMERG, "================================\n");
144  break;
145  }
146 
147  die("Can't recover from trap. Halting.\n");
148 }
149 
150 /* This function used to redirect trap to s-mode. */
151 void redirect_trap(void)
152 {
153  write_csr(sbadaddr, read_csr(mbadaddr));
154  write_csr(sepc, read_csr(mepc));
155  write_csr(scause, read_csr(mcause));
156  write_csr(mepc, read_csr(stvec));
157 
158  uintptr_t status = read_csr(mstatus);
159  uintptr_t mpp = EXTRACT_FIELD(status, MSTATUS_MPP);
160  status = INSERT_FIELD(status, MSTATUS_MPP, 1);
161  status = INSERT_FIELD(status, MSTATUS_SPP, mpp & 1);
162  write_csr(mstatus, status);
163 }
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
#define IRQ_M_SOFT
Definition: encoding.h:143
#define CAUSE_ILLEGAL_INSTRUCTION
Definition: encoding.h:964
#define MIP_SSIP
Definition: encoding.h:98
#define CAUSE_MISALIGNED_LOAD
Definition: encoding.h:966
#define CAUSE_MACHINE_ECALL
Definition: encoding.h:973
#define MSTATUS_MPP
Definition: encoding.h:16
#define CAUSE_STORE_ACCESS
Definition: encoding.h:969
#define MIP_STIP
Definition: encoding.h:101
#define MIP_MTIP
Definition: encoding.h:103
#define CAUSE_HYPERVISOR_ECALL
Definition: encoding.h:972
#define CAUSE_MISALIGNED_FETCH
Definition: encoding.h:962
#define IRQ_M_TIMER
Definition: encoding.h:146
#define CAUSE_LOAD_ACCESS
Definition: encoding.h:967
#define CAUSE_BREAKPOINT
Definition: encoding.h:965
#define CAUSE_FETCH_ACCESS
Definition: encoding.h:963
#define CAUSE_SUPERVISOR_ECALL
Definition: encoding.h:971
#define CAUSE_USER_ECALL
Definition: encoding.h:970
#define MSTATUS_SPP
Definition: encoding.h:14
#define CAUSE_MISALIGNED_STORE
Definition: encoding.h:968
#define MSTATUS_MPRV
Definition: encoding.h:19
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_EMERG
BIOS_EMERG - Emergency / Fatal.
Definition: loglevel.h:25
#define HLS()
Definition: mcall.h:63
void handle_misaligned(trapframe *tf)
Definition: misaligned.c:159
#define IPI_SHUTDOWN
Definition: sbi.h:22
void handle_sbi(trapframe *tf)
Definition: sbi.c:58
#define IPI_SFENCE_VMA
Definition: sbi.h:20
#define IPI_SOFT
Definition: sbi.h:18
#define IPI_FENCE_I
Definition: sbi.h:19
#define IPI_SFENCE_VMA_ASID
Definition: sbi.h:21
unsigned long uintptr_t
Definition: stdint.h:21
unsigned long long uint64_t
Definition: stdint.h:17
uintptr_t badvaddr
Definition: exception.h:12
uintptr_t gpr[32]
Definition: exception.h:9
uintptr_t cause
Definition: exception.h:13
uintptr_t status
Definition: exception.h:10
uintptr_t epc
Definition: exception.h:11
void trap_handler(trapframe *tf)
Definition: trap_handler.c:111
static const char *const exception_names[]
Definition: trap_handler.c:14
void redirect_trap(void)
Definition: trap_handler.c:151
static const char * mstatus_to_previous_mode(uintptr_t ms)
Definition: trap_handler.c:33
static void interrupt_handler(trapframe *tf)
Definition: trap_handler.c:71
static void print_trap_information(const trapframe *tf)
Definition: trap_handler.c:45
#define INSERT_FIELD(val, which, fieldval)
Definition: vm.h:11
#define EXTRACT_FIELD(val, which)
Definition: vm.h:10