xref: /kvm-unit-tests/lib/riscv/processor.c (revision 17f6f2fd17935eb5e564f621c71244b4a3ddeafb)
1386561f8SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only
2386561f8SAndrew Jones /*
3386561f8SAndrew Jones  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
4386561f8SAndrew Jones  */
5386561f8SAndrew Jones #include <libcflat.h>
6*94ca1aafSAndrew Jones #include <limits.h>
7386561f8SAndrew Jones #include <asm/csr.h>
8db0ae91cSAndrew Jones #include <asm/isa.h>
9386561f8SAndrew Jones #include <asm/processor.h>
10386561f8SAndrew Jones #include <asm/setup.h>
11*94ca1aafSAndrew Jones #include <asm/smp.h>
12386561f8SAndrew Jones 
13e442bc9cSAndrew Jones extern unsigned long ImageBase;
14386561f8SAndrew Jones 
show_regs(struct pt_regs * regs)15386561f8SAndrew Jones void show_regs(struct pt_regs *regs)
16386561f8SAndrew Jones {
179c92b28eSAndrew Jones 	struct thread_info *info = current_thread_info();
18e442bc9cSAndrew Jones 	uintptr_t loadaddr = (uintptr_t)&ImageBase;
19386561f8SAndrew Jones 	unsigned int w = __riscv_xlen / 4;
20386561f8SAndrew Jones 
21e442bc9cSAndrew Jones 	printf("Load address: %" PRIxPTR "\n", loadaddr);
229c92b28eSAndrew Jones 	printf("CPU%3d : hartid=%lx\n", info->cpu, info->hartid);
23386561f8SAndrew Jones 	printf("status : %.*lx\n", w, regs->status);
24386561f8SAndrew Jones 	printf("cause  : %.*lx\n", w, regs->cause);
25386561f8SAndrew Jones 	printf("badaddr: %.*lx\n", w, regs->badaddr);
26e442bc9cSAndrew Jones 	printf("pc: %.*lx (%lx) ra: %.*lx (%lx)\n", w, regs->epc, regs->epc - loadaddr, w, regs->ra, regs->ra - loadaddr);
27386561f8SAndrew Jones 	printf("sp: %.*lx gp: %.*lx tp : %.*lx\n", w, regs->sp, w, regs->gp, w, regs->tp);
28386561f8SAndrew Jones 	printf("a0: %.*lx a1: %.*lx a2 : %.*lx a3 : %.*lx\n", w, regs->a0, w, regs->a1, w, regs->a2, w, regs->a3);
29386561f8SAndrew Jones 	printf("a4: %.*lx a5: %.*lx a6 : %.*lx a7 : %.*lx\n", w, regs->a4, w, regs->a5, w, regs->a6, w, regs->a7);
30386561f8SAndrew Jones 	printf("t0: %.*lx t1: %.*lx t2 : %.*lx t3 : %.*lx\n", w, regs->t0, w, regs->t1, w, regs->t2, w, regs->t3);
31386561f8SAndrew Jones 	printf("t4: %.*lx t5: %.*lx t6 : %.*lx\n", w, regs->t4, w, regs->t5, w, regs->t6);
32386561f8SAndrew Jones 	printf("s0: %.*lx s1: %.*lx s2 : %.*lx s3 : %.*lx\n", w, regs->s0, w, regs->s1, w, regs->s2, w, regs->s3);
33386561f8SAndrew Jones 	printf("s4: %.*lx s5: %.*lx s6 : %.*lx s7 : %.*lx\n", w, regs->s4, w, regs->s5, w, regs->s6, w, regs->s7);
34386561f8SAndrew Jones 	printf("s8: %.*lx s9: %.*lx s10: %.*lx s11: %.*lx\n", w, regs->s8, w, regs->s9, w, regs->s10, w, regs->s11);
35386561f8SAndrew Jones }
36386561f8SAndrew Jones 
do_handle_exception(struct pt_regs * regs)37386561f8SAndrew Jones void do_handle_exception(struct pt_regs *regs)
38386561f8SAndrew Jones {
39386561f8SAndrew Jones 	struct thread_info *info = current_thread_info();
40386561f8SAndrew Jones 
41a3c0b550SAndrew Jones 	if (regs->cause & CAUSE_IRQ_FLAG) {
42a3c0b550SAndrew Jones 		unsigned long irq_cause = regs->cause & ~CAUSE_IRQ_FLAG;
43a3c0b550SAndrew Jones 
44a3c0b550SAndrew Jones 		assert(irq_cause < INTERRUPT_CAUSE_MAX);
45a3c0b550SAndrew Jones 		if (info->interrupt_handlers[irq_cause]) {
46a3c0b550SAndrew Jones 			info->interrupt_handlers[irq_cause](regs);
47a3c0b550SAndrew Jones 			return;
48a3c0b550SAndrew Jones 		}
49a3c0b550SAndrew Jones 	} else {
50386561f8SAndrew Jones 		assert(regs->cause < EXCEPTION_CAUSE_MAX);
51a3c0b550SAndrew Jones 
52386561f8SAndrew Jones 		if (info->exception_handlers[regs->cause]) {
53386561f8SAndrew Jones 			info->exception_handlers[regs->cause](regs);
54386561f8SAndrew Jones 			return;
55386561f8SAndrew Jones 		}
56a3c0b550SAndrew Jones 	}
57386561f8SAndrew Jones 
58386561f8SAndrew Jones 	show_regs(regs);
596c2108dbSAndrew Jones 	dump_frame_stack((void *)regs->epc, (void *)regs->s0);
606c2108dbSAndrew Jones 	abort();
61386561f8SAndrew Jones }
62386561f8SAndrew Jones 
install_irq_handler(unsigned long cause,void (* handler)(struct pt_regs *))63a3c0b550SAndrew Jones void install_irq_handler(unsigned long cause, void (*handler)(struct pt_regs *))
64a3c0b550SAndrew Jones {
65a3c0b550SAndrew Jones 	struct thread_info *info = current_thread_info();
66a3c0b550SAndrew Jones 
67a3c0b550SAndrew Jones 	assert(cause < INTERRUPT_CAUSE_MAX);
68a3c0b550SAndrew Jones 	info->interrupt_handlers[cause] = handler;
69a3c0b550SAndrew Jones }
70a3c0b550SAndrew Jones 
install_exception_handler(unsigned long cause,void (* handler)(struct pt_regs *))71386561f8SAndrew Jones void install_exception_handler(unsigned long cause, void (*handler)(struct pt_regs *))
72386561f8SAndrew Jones {
73386561f8SAndrew Jones 	struct thread_info *info = current_thread_info();
74386561f8SAndrew Jones 
75386561f8SAndrew Jones 	assert(cause < EXCEPTION_CAUSE_MAX);
76386561f8SAndrew Jones 	info->exception_handlers[cause] = handler;
77386561f8SAndrew Jones }
78386561f8SAndrew Jones 
thread_info_init(void)79386561f8SAndrew Jones void thread_info_init(void)
80386561f8SAndrew Jones {
81386561f8SAndrew Jones 	unsigned long hartid = csr_read(CSR_SSCRATCH);
82386561f8SAndrew Jones 	int cpu = hartid_to_cpu(hartid);
83386561f8SAndrew Jones 
84db0ae91cSAndrew Jones 	isa_init(&cpus[cpu]);
85386561f8SAndrew Jones 	csr_write(CSR_SSCRATCH, &cpus[cpu]);
86386561f8SAndrew Jones }
87*94ca1aafSAndrew Jones 
local_hart_init(void)88*94ca1aafSAndrew Jones void local_hart_init(void)
89*94ca1aafSAndrew Jones {
90*94ca1aafSAndrew Jones 	if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
91*94ca1aafSAndrew Jones 		csr_write(CSR_STIMECMP, ULONG_MAX);
92*94ca1aafSAndrew Jones 		if (__riscv_xlen == 32)
93*94ca1aafSAndrew Jones 			csr_write(CSR_STIMECMPH, ULONG_MAX);
94*94ca1aafSAndrew Jones 	}
95*94ca1aafSAndrew Jones }
96