1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2016-17 Microsemi Corporation.
4  * Padmarao Begari, Microsemi Corporation <padmarao.begari@microsemi.com>
5  *
6  * Copyright (C) 2017 Andes Technology Corporation
7  * Rick Chen, Andes Technology Corporation <rick@andestech.com>
8  *
9  * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
10  */
11 
12 #include <common.h>
13 #include <efi_loader.h>
14 #include <hang.h>
15 #include <irq_func.h>
16 #include <asm/global_data.h>
17 #include <asm/ptrace.h>
18 #include <asm/system.h>
19 #include <asm/encoding.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
show_efi_loaded_images(uintptr_t epc)23 static void show_efi_loaded_images(uintptr_t epc)
24 {
25 	efi_print_image_infos((void *)epc);
26 }
27 
show_regs(struct pt_regs * regs)28 static void show_regs(struct pt_regs *regs)
29 {
30 #ifdef CONFIG_SHOW_REGS
31 	printf("\nSP:  " REG_FMT " GP:  " REG_FMT " TP:  " REG_FMT "\n",
32 	       regs->sp, regs->gp, regs->tp);
33 	printf("T0:  " REG_FMT " T1:  " REG_FMT " T2:  " REG_FMT "\n",
34 	       regs->t0, regs->t1, regs->t2);
35 	printf("S0:  " REG_FMT " S1:  " REG_FMT " A0:  " REG_FMT "\n",
36 	       regs->s0, regs->s1, regs->a0);
37 	printf("A1:  " REG_FMT " A2:  " REG_FMT " A3:  " REG_FMT "\n",
38 	       regs->a1, regs->a2, regs->a3);
39 	printf("A4:  " REG_FMT " A5:  " REG_FMT " A6:  " REG_FMT "\n",
40 	       regs->a4, regs->a5, regs->a6);
41 	printf("A7:  " REG_FMT " S2:  " REG_FMT " S3:  " REG_FMT "\n",
42 	       regs->a7, regs->s2, regs->s3);
43 	printf("S4:  " REG_FMT " S5:  " REG_FMT " S6:  " REG_FMT "\n",
44 	       regs->s4, regs->s5, regs->s6);
45 	printf("S7:  " REG_FMT " S8:  " REG_FMT " S9:  " REG_FMT "\n",
46 	       regs->s7, regs->s8, regs->s9);
47 	printf("S10: " REG_FMT " S11: " REG_FMT " T3:  " REG_FMT "\n",
48 	       regs->s10, regs->s11, regs->t3);
49 	printf("T4:  " REG_FMT " T5:  " REG_FMT " T6:  " REG_FMT "\n",
50 	       regs->t4, regs->t5, regs->t6);
51 #endif
52 }
53 
54 /**
55  * instr_len() - get instruction length
56  *
57  * @i:		low 16 bits of the instruction
58  * Return:	number of u16 in instruction
59  */
instr_len(u16 i)60 static int instr_len(u16 i)
61 {
62 	if ((i & 0x03) != 0x03)
63 		return 1;
64 	/* Instructions with more than 32 bits are not yet specified */
65 	return 2;
66 }
67 
68 /**
69  * show_code() - display code leading to exception
70  *
71  * @epc:	program counter
72  */
show_code(ulong epc)73 static void show_code(ulong epc)
74 {
75 	u16 *pos = (u16 *)(epc & ~1UL);
76 	int i, len = instr_len(*pos);
77 
78 	printf("\nCode: ");
79 	for (i = -8; i; ++i)
80 		printf("%04x ", pos[i]);
81 	printf("(");
82 	for (i = 0; i < len; ++i)
83 		printf("%04x%s", pos[i], i + 1 == len ? ")\n" : " ");
84 }
85 
_exit_trap(ulong code,ulong epc,ulong tval,struct pt_regs * regs)86 static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
87 {
88 	static const char * const exception_code[] = {
89 		"Instruction address misaligned",
90 		"Instruction access fault",
91 		"Illegal instruction",
92 		"Breakpoint",
93 		"Load address misaligned",
94 		"Load access fault",
95 		"Store/AMO address misaligned",
96 		"Store/AMO access fault",
97 		"Environment call from U-mode",
98 		"Environment call from S-mode",
99 		"Reserved",
100 		"Environment call from M-mode",
101 		"Instruction page fault",
102 		"Load page fault",
103 		"Reserved",
104 		"Store/AMO page fault",
105 	};
106 
107 	if (code < ARRAY_SIZE(exception_code))
108 		printf("Unhandled exception: %s\n", exception_code[code]);
109 	else
110 		printf("Unhandled exception code: %ld\n", code);
111 
112 	printf("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
113 	       epc, regs->ra, tval);
114 	/* Print relocation adjustments, but only if gd is initialized */
115 	if (gd && gd->flags & GD_FLG_RELOC)
116 		printf("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n",
117 		       epc - gd->reloc_off, regs->ra - gd->reloc_off);
118 
119 	show_regs(regs);
120 	show_code(epc);
121 	show_efi_loaded_images(epc);
122 	panic("\n");
123 }
124 
interrupt_init(void)125 int interrupt_init(void)
126 {
127 	return 0;
128 }
129 
130 /*
131  * enable interrupts
132  */
enable_interrupts(void)133 void enable_interrupts(void)
134 {
135 }
136 
137 /*
138  * disable interrupts
139  */
disable_interrupts(void)140 int disable_interrupts(void)
141 {
142 	return 0;
143 }
144 
handle_trap(ulong cause,ulong epc,ulong tval,struct pt_regs * regs)145 ulong handle_trap(ulong cause, ulong epc, ulong tval, struct pt_regs *regs)
146 {
147 	ulong is_irq, irq;
148 
149 	/* An UEFI application may have changed gd. Restore U-Boot's gd. */
150 	efi_restore_gd();
151 
152 	is_irq = (cause & MCAUSE_INT);
153 	irq = (cause & ~MCAUSE_INT);
154 
155 	if (is_irq) {
156 		switch (irq) {
157 		case IRQ_M_EXT:
158 		case IRQ_S_EXT:
159 			external_interrupt(0);	/* handle external interrupt */
160 			break;
161 		case IRQ_M_TIMER:
162 		case IRQ_S_TIMER:
163 			timer_interrupt(0);	/* handle timer interrupt */
164 			break;
165 		default:
166 			_exit_trap(cause, epc, tval, regs);
167 			break;
168 		};
169 	} else {
170 		_exit_trap(cause, epc, tval, regs);
171 	}
172 
173 	return epc;
174 }
175 
176 /*
177  *Entry Point for PLIC Interrupt Handler
178  */
external_interrupt(struct pt_regs * regs)179 __attribute__((weak)) void external_interrupt(struct pt_regs *regs)
180 {
181 }
182 
timer_interrupt(struct pt_regs * regs)183 __attribute__((weak)) void timer_interrupt(struct pt_regs *regs)
184 {
185 }
186