xref: /kvm-unit-tests/lib/riscv/processor.c (revision a1418d6dbe810aded6885366cc6e782caa21a2cc)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
4  */
5 #include <libcflat.h>
6 #include <asm/csr.h>
7 #include <asm/isa.h>
8 #include <asm/processor.h>
9 #include <asm/setup.h>
10 
11 extern unsigned long ImageBase;
12 
13 void show_regs(struct pt_regs *regs)
14 {
15 	struct thread_info *info = current_thread_info();
16 	uintptr_t loadaddr = (uintptr_t)&ImageBase;
17 	unsigned int w = __riscv_xlen / 4;
18 
19 	printf("Load address: %" PRIxPTR "\n", loadaddr);
20 	printf("CPU%3d : hartid=%lx\n", info->cpu, info->hartid);
21 	printf("status : %.*lx\n", w, regs->status);
22 	printf("cause  : %.*lx\n", w, regs->cause);
23 	printf("badaddr: %.*lx\n", w, regs->badaddr);
24 	printf("pc: %.*lx (%lx) ra: %.*lx (%lx)\n", w, regs->epc, regs->epc - loadaddr, w, regs->ra, regs->ra - loadaddr);
25 	printf("sp: %.*lx gp: %.*lx tp : %.*lx\n", w, regs->sp, w, regs->gp, w, regs->tp);
26 	printf("a0: %.*lx a1: %.*lx a2 : %.*lx a3 : %.*lx\n", w, regs->a0, w, regs->a1, w, regs->a2, w, regs->a3);
27 	printf("a4: %.*lx a5: %.*lx a6 : %.*lx a7 : %.*lx\n", w, regs->a4, w, regs->a5, w, regs->a6, w, regs->a7);
28 	printf("t0: %.*lx t1: %.*lx t2 : %.*lx t3 : %.*lx\n", w, regs->t0, w, regs->t1, w, regs->t2, w, regs->t3);
29 	printf("t4: %.*lx t5: %.*lx t6 : %.*lx\n", w, regs->t4, w, regs->t5, w, regs->t6);
30 	printf("s0: %.*lx s1: %.*lx s2 : %.*lx s3 : %.*lx\n", w, regs->s0, w, regs->s1, w, regs->s2, w, regs->s3);
31 	printf("s4: %.*lx s5: %.*lx s6 : %.*lx s7 : %.*lx\n", w, regs->s4, w, regs->s5, w, regs->s6, w, regs->s7);
32 	printf("s8: %.*lx s9: %.*lx s10: %.*lx s11: %.*lx\n", w, regs->s8, w, regs->s9, w, regs->s10, w, regs->s11);
33 }
34 
35 void do_handle_exception(struct pt_regs *regs)
36 {
37 	struct thread_info *info = current_thread_info();
38 
39 	if (regs->cause & CAUSE_IRQ_FLAG) {
40 		unsigned long irq_cause = regs->cause & ~CAUSE_IRQ_FLAG;
41 
42 		assert(irq_cause < INTERRUPT_CAUSE_MAX);
43 		if (info->interrupt_handlers[irq_cause]) {
44 			info->interrupt_handlers[irq_cause](regs);
45 			return;
46 		}
47 	} else {
48 		assert(regs->cause < EXCEPTION_CAUSE_MAX);
49 
50 		if (info->exception_handlers[regs->cause]) {
51 			info->exception_handlers[regs->cause](regs);
52 			return;
53 		}
54 	}
55 
56 	show_regs(regs);
57 	dump_frame_stack((void *)regs->epc, (void *)regs->s0);
58 	abort();
59 }
60 
61 void install_irq_handler(unsigned long cause, void (*handler)(struct pt_regs *))
62 {
63 	struct thread_info *info = current_thread_info();
64 
65 	assert(cause < INTERRUPT_CAUSE_MAX);
66 	info->interrupt_handlers[cause] = handler;
67 }
68 
69 void install_exception_handler(unsigned long cause, void (*handler)(struct pt_regs *))
70 {
71 	struct thread_info *info = current_thread_info();
72 
73 	assert(cause < EXCEPTION_CAUSE_MAX);
74 	info->exception_handlers[cause] = handler;
75 }
76 
77 void thread_info_init(void)
78 {
79 	unsigned long hartid = csr_read(CSR_SSCRATCH);
80 	int cpu = hartid_to_cpu(hartid);
81 
82 	isa_init(&cpus[cpu]);
83 	csr_write(CSR_SSCRATCH, &cpus[cpu]);
84 }
85