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