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