summaryrefslogtreecommitdiff
path: root/lib/sbi_trap.c
blob: f9c70a63fe9a857d0ff4d9e925b21b03dacf02a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * Copyright (c) 2018 Western Digital Corporation or its affiliates.
 *
 * Authors:
 *   Anup Patel <anup.patel@wdc.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>

static void __attribute__((noreturn)) sbi_trap_error(const char *msg,
						int rc, u32 hartid,
						ulong mcause,
						struct sbi_trap_regs *regs)
{
	sbi_printf("%s: hart%d: %s (error %d)\n",
		   __func__, hartid, msg, rc);
	sbi_printf("%s: hart%d: mcause=0x%lx mepc=0x%lx mstatus=0x%lx\n",
		   __func__, hartid, mcause, regs->mepc, regs->mstatus);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "ra", regs->ra, "sp", regs->sp);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "gp", regs->gp, "tp", regs->tp);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s0", regs->s0, "s1", regs->s1);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "a0", regs->a0, "a1", regs->a1);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "a2", regs->a2, "a3", regs->a3);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "a4", regs->a4, "a5", regs->a5);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "a6", regs->a6, "a7", regs->a7);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s2", regs->s2, "s3", regs->s3);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s4", regs->s4, "s5", regs->s5);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s6", regs->s6, "s7", regs->s7);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s8", regs->s8, "s9", regs->s9);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "s10", regs->s10, "s11", regs->s11);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "t0", regs->t0, "t1", regs->t1);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "t2", regs->t2, "t3", regs->t3);
	sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
		   __func__, hartid, "t4", regs->t4, "t5", regs->t5);
	sbi_printf("%s: hart%d: %s=0x%lx\n",
		   __func__, hartid, "t6", regs->t6);

	sbi_hart_hang();
}

void sbi_trap_handler(struct sbi_trap_regs *regs,
		      struct sbi_scratch *scratch)
{
	int rc;
	const char *msg;
	u32 hartid = csr_read(mhartid);
	ulong mcause = csr_read(mcause);

	if (mcause & (1UL << (__riscv_xlen - 1))) {
		mcause &= ~(1UL << (__riscv_xlen - 1));
		switch (mcause) {
		case IRQ_M_TIMER:
			sbi_timer_process(scratch, hartid);
			break;
		case IRQ_M_SOFT:
			sbi_ipi_process(scratch, hartid);
			break;
		default:
			sbi_trap_error("unhandled external interrupt",
					SBI_ENOTSUPP, hartid, mcause, regs);
			break;
		};
		return;
	}

	rc = SBI_ENOTSUPP;
	msg = "trap handler failed";
	switch (mcause) {
	case CAUSE_ILLEGAL_INSTRUCTION:
		rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
		msg = "illegal instruction handler failed";
		break;
	case CAUSE_SUPERVISOR_ECALL:
	case CAUSE_HYPERVISOR_ECALL:
		rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
		msg = "ecall handler failed";
		break;
	default:
		break;
	};

	if (rc) {
		sbi_trap_error(msg, rc, hartid, mcause, regs);
	}
}