blob: b3024ba514ec363bfc3b957df203fc784278037e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
David Feng85fd5f12013-12-14 11:47:35 +08002/*
3 * (C) Copyright 2013
4 * David Feng <fenghua@phytium.com.cn>
David Feng85fd5f12013-12-14 11:47:35 +08005 */
6
Sean Anderson064c8572022-03-22 16:59:31 -04007#include <asm/esr.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06008#include <asm/global_data.h>
Simon Glass6b9f0102020-05-10 11:40:06 -06009#include <asm/ptrace.h>
Simon Glass9b61c7c2019-11-14 12:57:41 -070010#include <irq_func.h>
David Feng85fd5f12013-12-14 11:47:35 +080011#include <linux/compiler.h>
Alexander Graf58177862016-03-04 01:10:06 +010012#include <efi_loader.h>
Sean Anderson064c8572022-03-22 16:59:31 -040013#include <semihosting.h>
David Feng85fd5f12013-12-14 11:47:35 +080014
Peng Fanc3c9b332017-11-28 10:08:08 +080015DECLARE_GLOBAL_DATA_PTR;
David Feng85fd5f12013-12-14 11:47:35 +080016
17int interrupt_init(void)
18{
Ovidiu Panait8998e712020-04-20 10:31:44 +030019 enable_interrupts();
20
David Feng85fd5f12013-12-14 11:47:35 +080021 return 0;
22}
23
24void enable_interrupts(void)
25{
26 return;
27}
28
29int disable_interrupts(void)
30{
31 return 0;
32}
33
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +020034static void show_efi_loaded_images(struct pt_regs *regs)
35{
36 efi_print_image_infos((void *)regs->elr);
37}
38
Pavel Skripkin23c722d2023-04-02 19:27:34 +030039static 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
Heinrich Schuchardt11efc1a2019-09-12 19:09:26 +020073static 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
David Feng85fd5f12013-12-14 11:47:35 +080084void show_regs(struct pt_regs *regs)
85{
86 int i;
87
Karl Beldanb33ccd12018-02-20 23:30:08 +000088 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
David Feng85fd5f12013-12-14 11:47:35 +080094 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");
Heinrich Schuchardt11efc1a2019-09-12 19:09:26 +020098 dump_instr(regs);
David Feng85fd5f12013-12-14 11:47:35 +080099}
100
101/*
Sean Anderson064c8572022-03-22 16:59:31 -0400102 * Try to "emulate" a semihosting call in the event that we don't have a
103 * debugger attached.
104 */
105static 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/*
David Feng85fd5f12013-12-14 11:47:35 +0800144 * do_bad_sync handles the impossible case in the Synchronous Abort vector.
145 */
Sean Anderson2d755492022-03-22 17:17:35 -0400146void do_bad_sync(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800147{
Alexander Graf58177862016-03-04 01:10:06 +0100148 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400149 printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08lx\n",
150 pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800151 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200152 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800153 panic("Resetting CPU ...\n");
154}
155
156/*
157 * do_bad_irq handles the impossible case in the Irq vector.
158 */
Sean Anderson2d755492022-03-22 17:17:35 -0400159void do_bad_irq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800160{
Alexander Graf58177862016-03-04 01:10:06 +0100161 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400162 printf("Bad mode in \"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800163 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200164 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800165 panic("Resetting CPU ...\n");
166}
167
168/*
169 * do_bad_fiq handles the impossible case in the Fiq vector.
170 */
Sean Anderson2d755492022-03-22 17:17:35 -0400171void do_bad_fiq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800172{
Alexander Graf58177862016-03-04 01:10:06 +0100173 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400174 printf("Bad mode in \"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800175 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200176 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800177 panic("Resetting CPU ...\n");
178}
179
180/*
181 * do_bad_error handles the impossible case in the Error vector.
182 */
Sean Anderson2d755492022-03-22 17:17:35 -0400183void do_bad_error(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800184{
Alexander Graf58177862016-03-04 01:10:06 +0100185 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400186 printf("Bad mode in \"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800187 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200188 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800189 panic("Resetting CPU ...\n");
190}
191
192/*
193 * do_sync handles the Synchronous Abort exception.
194 */
Sean Anderson2d755492022-03-22 17:17:35 -0400195void do_sync(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800196{
Sean Anderson064c8572022-03-22 16:59:31 -0400197 if (CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) &&
198 smh_emulate_trap(pt_regs))
199 return;
Alexander Graf58177862016-03-04 01:10:06 +0100200 efi_restore_gd();
Pavel Skripkin23c722d2023-04-02 19:27:34 +0300201 printf("\"Synchronous Abort\" handler, esr 0x%08lx", pt_regs->esr);
202 dump_far(pt_regs->esr);
203 printf("\n");
David Feng85fd5f12013-12-14 11:47:35 +0800204 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200205 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800206 panic("Resetting CPU ...\n");
207}
208
209/*
210 * do_irq handles the Irq exception.
211 */
Sean Anderson2d755492022-03-22 17:17:35 -0400212void do_irq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800213{
Alexander Graf58177862016-03-04 01:10:06 +0100214 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400215 printf("\"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800216 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200217 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800218 panic("Resetting CPU ...\n");
219}
220
221/*
222 * do_fiq handles the Fiq exception.
223 */
Sean Anderson2d755492022-03-22 17:17:35 -0400224void do_fiq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800225{
Alexander Graf58177862016-03-04 01:10:06 +0100226 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400227 printf("\"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800228 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200229 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800230 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 */
Sean Anderson2d755492022-03-22 17:17:35 -0400239void __weak do_error(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800240{
Alexander Graf58177862016-03-04 01:10:06 +0100241 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400242 printf("\"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800243 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200244 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800245 panic("Resetting CPU ...\n");
246}