1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2013
4  * David Feng <fenghua@phytium.com.cn>
5  */
6 
7 #include <common.h>
8 #include <asm/esr.h>
9 #include <asm/global_data.h>
10 #include <asm/ptrace.h>
11 #include <irq_func.h>
12 #include <linux/compiler.h>
13 #include <efi_loader.h>
14 #include <semihosting.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
interrupt_init(void)18 int interrupt_init(void)
19 {
20 	enable_interrupts();
21 
22 	return 0;
23 }
24 
enable_interrupts(void)25 void enable_interrupts(void)
26 {
27 	return;
28 }
29 
disable_interrupts(void)30 int disable_interrupts(void)
31 {
32 	return 0;
33 }
34 
show_efi_loaded_images(struct pt_regs * regs)35 static void show_efi_loaded_images(struct pt_regs *regs)
36 {
37 	efi_print_image_infos((void *)regs->elr);
38 }
39 
dump_far(unsigned long esr)40 static void dump_far(unsigned long esr)
41 {
42 	unsigned long el, far;
43 
44 	switch ((esr >> 26) & 0b111111) {
45 	case 0x20:
46 	case 0x21:
47 	case 0x24:
48 	case 0x25:
49 	case 0x22:
50 	case 0x34:
51 	case 0x35:
52 		break;
53 	default:
54 		return;
55 	}
56 
57 	asm("mrs	%0, CurrentEl": "=r" (el));
58 
59 	switch (el >> 2) {
60 	case 1:
61 		asm("mrs	%0, FAR_EL1": "=r" (far));
62 		break;
63 	case 2:
64 		asm("mrs	%0, FAR_EL2": "=r" (far));
65 		break;
66 	default:
67 		/* don't print anything to make output pretty */
68 		return;
69 	}
70 
71 	printf(", far 0x%lx", far);
72 }
73 
dump_instr(struct pt_regs * regs)74 static void dump_instr(struct pt_regs *regs)
75 {
76 	u32 *addr = (u32 *)(regs->elr & ~3UL);
77 	int i;
78 
79 	printf("Code: ");
80 	for (i = -4; i < 1; i++)
81 		printf(i == 0 ? "(%08x) " : "%08x ", addr[i]);
82 	printf("\n");
83 }
84 
show_regs(struct pt_regs * regs)85 void show_regs(struct pt_regs *regs)
86 {
87 	int i;
88 
89 	if (gd->flags & GD_FLG_RELOC)
90 		printf("elr: %016lx lr : %016lx (reloc)\n",
91 		       regs->elr - gd->reloc_off,
92 		       regs->regs[30] - gd->reloc_off);
93 	printf("elr: %016lx lr : %016lx\n", regs->elr, regs->regs[30]);
94 
95 	for (i = 0; i < 29; i += 2)
96 		printf("x%-2d: %016lx x%-2d: %016lx\n",
97 		       i, regs->regs[i], i+1, regs->regs[i+1]);
98 	printf("\n");
99 	dump_instr(regs);
100 }
101 
102 /*
103  * Try to "emulate" a semihosting call in the event that we don't have a
104  * debugger attached.
105  */
smh_emulate_trap(struct pt_regs * regs)106 static bool smh_emulate_trap(struct pt_regs *regs)
107 {
108 	int size;
109 
110 	if (ESR_ELx_EC(regs->esr) != ESR_ELx_EC_UNKNOWN)
111 		return false;
112 
113 	if (regs->spsr & PSR_MODE32_BIT) {
114 		if (regs->spsr & PSR_AA32_T_BIT) {
115 			u16 *insn = (u16 *)ALIGN_DOWN(regs->elr, 2);
116 
117 			if (*insn != SMH_T32_SVC && *insn != SMH_T32_HLT)
118 				return false;
119 			size = 2;
120 		} else {
121 			u32 *insn = (u32 *)ALIGN_DOWN(regs->elr, 4);
122 
123 			if (*insn != SMH_A32_SVC && *insn != SMH_A32_HLT)
124 				return false;
125 			size = 4;
126 		}
127 	} else {
128 		u32 *insn = (u32 *)ALIGN_DOWN(regs->elr, 4);
129 
130 		if (*insn != SMH_A64_HLT)
131 			return false;
132 		size = 4;
133 	}
134 
135 	/* Avoid future semihosting calls */
136 	disable_semihosting();
137 
138 	/* Just pretend the call failed */
139 	regs->regs[0] = -1;
140 	regs->elr += size;
141 	return true;
142 }
143 
144 /*
145  * do_bad_sync handles the impossible case in the Synchronous Abort vector.
146  */
do_bad_sync(struct pt_regs * pt_regs)147 void do_bad_sync(struct pt_regs *pt_regs)
148 {
149 	efi_restore_gd();
150 	printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08lx\n",
151 	       pt_regs->esr);
152 	show_regs(pt_regs);
153 	show_efi_loaded_images(pt_regs);
154 	panic("Resetting CPU ...\n");
155 }
156 
157 /*
158  * do_bad_irq handles the impossible case in the Irq vector.
159  */
do_bad_irq(struct pt_regs * pt_regs)160 void do_bad_irq(struct pt_regs *pt_regs)
161 {
162 	efi_restore_gd();
163 	printf("Bad mode in \"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
164 	show_regs(pt_regs);
165 	show_efi_loaded_images(pt_regs);
166 	panic("Resetting CPU ...\n");
167 }
168 
169 /*
170  * do_bad_fiq handles the impossible case in the Fiq vector.
171  */
do_bad_fiq(struct pt_regs * pt_regs)172 void do_bad_fiq(struct pt_regs *pt_regs)
173 {
174 	efi_restore_gd();
175 	printf("Bad mode in \"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
176 	show_regs(pt_regs);
177 	show_efi_loaded_images(pt_regs);
178 	panic("Resetting CPU ...\n");
179 }
180 
181 /*
182  * do_bad_error handles the impossible case in the Error vector.
183  */
do_bad_error(struct pt_regs * pt_regs)184 void do_bad_error(struct pt_regs *pt_regs)
185 {
186 	efi_restore_gd();
187 	printf("Bad mode in \"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
188 	show_regs(pt_regs);
189 	show_efi_loaded_images(pt_regs);
190 	panic("Resetting CPU ...\n");
191 }
192 
193 /*
194  * do_sync handles the Synchronous Abort exception.
195  */
do_sync(struct pt_regs * pt_regs)196 void do_sync(struct pt_regs *pt_regs)
197 {
198 	if (CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) &&
199 	    smh_emulate_trap(pt_regs))
200 		return;
201 	efi_restore_gd();
202 	printf("\"Synchronous Abort\" handler, esr 0x%08lx", pt_regs->esr);
203 	dump_far(pt_regs->esr);
204 	printf("\n");
205 	show_regs(pt_regs);
206 	show_efi_loaded_images(pt_regs);
207 	panic("Resetting CPU ...\n");
208 }
209 
210 /*
211  * do_irq handles the Irq exception.
212  */
do_irq(struct pt_regs * pt_regs)213 void do_irq(struct pt_regs *pt_regs)
214 {
215 	efi_restore_gd();
216 	printf("\"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
217 	show_regs(pt_regs);
218 	show_efi_loaded_images(pt_regs);
219 	panic("Resetting CPU ...\n");
220 }
221 
222 /*
223  * do_fiq handles the Fiq exception.
224  */
do_fiq(struct pt_regs * pt_regs)225 void do_fiq(struct pt_regs *pt_regs)
226 {
227 	efi_restore_gd();
228 	printf("\"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
229 	show_regs(pt_regs);
230 	show_efi_loaded_images(pt_regs);
231 	panic("Resetting CPU ...\n");
232 }
233 
234 /*
235  * do_error handles the Error exception.
236  * Errors are more likely to be processor specific,
237  * it is defined with weak attribute and can be redefined
238  * in processor specific code.
239  */
do_error(struct pt_regs * pt_regs)240 void __weak do_error(struct pt_regs *pt_regs)
241 {
242 	efi_restore_gd();
243 	printf("\"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
244 	show_regs(pt_regs);
245 	show_efi_loaded_images(pt_regs);
246 	panic("Resetting CPU ...\n");
247 }
248