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 <limits.h>
7 #include <asm/csr.h>
8 #include <asm/isa.h>
9 #include <asm/processor.h>
10 #include <asm/setup.h>
11 #include <asm/smp.h>
12
13 extern unsigned long ImageBase;
14
show_regs(struct pt_regs * regs)15 void show_regs(struct pt_regs *regs)
16 {
17 struct thread_info *info = current_thread_info();
18 uintptr_t loadaddr = (uintptr_t)&ImageBase;
19 unsigned int w = __riscv_xlen / 4;
20
21 printf("Load address: %" PRIxPTR "\n", loadaddr);
22 printf("CPU%3d : hartid=%lx\n", info->cpu, info->hartid);
23 printf("status : %.*lx\n", w, regs->status);
24 printf("cause : %.*lx\n", w, regs->cause);
25 printf("badaddr: %.*lx\n", w, regs->badaddr);
26 printf("pc: %.*lx (%lx) ra: %.*lx (%lx)\n", w, regs->epc, regs->epc - loadaddr, w, regs->ra, regs->ra - loadaddr);
27 printf("sp: %.*lx gp: %.*lx tp : %.*lx\n", w, regs->sp, w, regs->gp, w, regs->tp);
28 printf("a0: %.*lx a1: %.*lx a2 : %.*lx a3 : %.*lx\n", w, regs->a0, w, regs->a1, w, regs->a2, w, regs->a3);
29 printf("a4: %.*lx a5: %.*lx a6 : %.*lx a7 : %.*lx\n", w, regs->a4, w, regs->a5, w, regs->a6, w, regs->a7);
30 printf("t0: %.*lx t1: %.*lx t2 : %.*lx t3 : %.*lx\n", w, regs->t0, w, regs->t1, w, regs->t2, w, regs->t3);
31 printf("t4: %.*lx t5: %.*lx t6 : %.*lx\n", w, regs->t4, w, regs->t5, w, regs->t6);
32 printf("s0: %.*lx s1: %.*lx s2 : %.*lx s3 : %.*lx\n", w, regs->s0, w, regs->s1, w, regs->s2, w, regs->s3);
33 printf("s4: %.*lx s5: %.*lx s6 : %.*lx s7 : %.*lx\n", w, regs->s4, w, regs->s5, w, regs->s6, w, regs->s7);
34 printf("s8: %.*lx s9: %.*lx s10: %.*lx s11: %.*lx\n", w, regs->s8, w, regs->s9, w, regs->s10, w, regs->s11);
35 }
36
do_handle_exception(struct pt_regs * regs)37 void do_handle_exception(struct pt_regs *regs)
38 {
39 struct thread_info *info = current_thread_info();
40
41 if (regs->cause & CAUSE_IRQ_FLAG) {
42 unsigned long irq_cause = regs->cause & ~CAUSE_IRQ_FLAG;
43
44 assert(irq_cause < INTERRUPT_CAUSE_MAX);
45 if (info->interrupt_handlers[irq_cause]) {
46 info->interrupt_handlers[irq_cause](regs);
47 return;
48 }
49 } else {
50 assert(regs->cause < EXCEPTION_CAUSE_MAX);
51
52 if (info->exception_handlers[regs->cause]) {
53 info->exception_handlers[regs->cause](regs);
54 return;
55 }
56 }
57
58 show_regs(regs);
59 dump_frame_stack((void *)regs->epc, (void *)regs->s0);
60 abort();
61 }
62
install_irq_handler(unsigned long cause,void (* handler)(struct pt_regs *))63 void install_irq_handler(unsigned long cause, void (*handler)(struct pt_regs *))
64 {
65 struct thread_info *info = current_thread_info();
66
67 assert(cause < INTERRUPT_CAUSE_MAX);
68 info->interrupt_handlers[cause] = handler;
69 }
70
install_exception_handler(unsigned long cause,void (* handler)(struct pt_regs *))71 void install_exception_handler(unsigned long cause, void (*handler)(struct pt_regs *))
72 {
73 struct thread_info *info = current_thread_info();
74
75 assert(cause < EXCEPTION_CAUSE_MAX);
76 info->exception_handlers[cause] = handler;
77 }
78
thread_info_init(void)79 void thread_info_init(void)
80 {
81 unsigned long hartid = csr_read(CSR_SSCRATCH);
82 int cpu = hartid_to_cpu(hartid);
83
84 isa_init(&cpus[cpu]);
85 csr_write(CSR_SSCRATCH, &cpus[cpu]);
86 }
87
local_hart_init(void)88 void local_hart_init(void)
89 {
90 if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
91 csr_write(CSR_STIMECMP, ULONG_MAX);
92 if (__riscv_xlen == 32)
93 csr_write(CSR_STIMECMPH, ULONG_MAX);
94 }
95 }
96