blob: 125dc0bb390bb1fa4404d0f892572b4424c700b9 [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
7#include <common.h>
Sean Anderson064c8572022-03-22 16:59:31 -04008#include <asm/esr.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Simon Glass6b9f0102020-05-10 11:40:06 -060010#include <asm/ptrace.h>
Simon Glass9b61c7c2019-11-14 12:57:41 -070011#include <irq_func.h>
David Feng85fd5f12013-12-14 11:47:35 +080012#include <linux/compiler.h>
Alexander Graf58177862016-03-04 01:10:06 +010013#include <efi_loader.h>
Sean Anderson064c8572022-03-22 16:59:31 -040014#include <semihosting.h>
David Feng85fd5f12013-12-14 11:47:35 +080015
Peng Fanc3c9b332017-11-28 10:08:08 +080016DECLARE_GLOBAL_DATA_PTR;
David Feng85fd5f12013-12-14 11:47:35 +080017
18int interrupt_init(void)
19{
Ovidiu Panait8998e712020-04-20 10:31:44 +030020 enable_interrupts();
21
David Feng85fd5f12013-12-14 11:47:35 +080022 return 0;
23}
24
25void enable_interrupts(void)
26{
27 return;
28}
29
30int disable_interrupts(void)
31{
32 return 0;
33}
34
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +020035static void show_efi_loaded_images(struct pt_regs *regs)
36{
37 efi_print_image_infos((void *)regs->elr);
38}
39
Pavel Skripkin23c722d2023-04-02 19:27:34 +030040static 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
Heinrich Schuchardt11efc1a2019-09-12 19:09:26 +020074static 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
David Feng85fd5f12013-12-14 11:47:35 +080085void show_regs(struct pt_regs *regs)
86{
87 int i;
88
Karl Beldanb33ccd12018-02-20 23:30:08 +000089 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
David Feng85fd5f12013-12-14 11:47:35 +080095 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");
Heinrich Schuchardt11efc1a2019-09-12 19:09:26 +020099 dump_instr(regs);
David Feng85fd5f12013-12-14 11:47:35 +0800100}
101
102/*
Sean Anderson064c8572022-03-22 16:59:31 -0400103 * Try to "emulate" a semihosting call in the event that we don't have a
104 * debugger attached.
105 */
106static 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/*
David Feng85fd5f12013-12-14 11:47:35 +0800145 * do_bad_sync handles the impossible case in the Synchronous Abort vector.
146 */
Sean Anderson2d755492022-03-22 17:17:35 -0400147void do_bad_sync(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800148{
Alexander Graf58177862016-03-04 01:10:06 +0100149 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400150 printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08lx\n",
151 pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800152 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200153 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800154 panic("Resetting CPU ...\n");
155}
156
157/*
158 * do_bad_irq handles the impossible case in the Irq vector.
159 */
Sean Anderson2d755492022-03-22 17:17:35 -0400160void do_bad_irq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800161{
Alexander Graf58177862016-03-04 01:10:06 +0100162 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400163 printf("Bad mode in \"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800164 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200165 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800166 panic("Resetting CPU ...\n");
167}
168
169/*
170 * do_bad_fiq handles the impossible case in the Fiq vector.
171 */
Sean Anderson2d755492022-03-22 17:17:35 -0400172void do_bad_fiq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800173{
Alexander Graf58177862016-03-04 01:10:06 +0100174 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400175 printf("Bad mode in \"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800176 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200177 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800178 panic("Resetting CPU ...\n");
179}
180
181/*
182 * do_bad_error handles the impossible case in the Error vector.
183 */
Sean Anderson2d755492022-03-22 17:17:35 -0400184void do_bad_error(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800185{
Alexander Graf58177862016-03-04 01:10:06 +0100186 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400187 printf("Bad mode in \"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800188 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200189 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800190 panic("Resetting CPU ...\n");
191}
192
193/*
194 * do_sync handles the Synchronous Abort exception.
195 */
Sean Anderson2d755492022-03-22 17:17:35 -0400196void do_sync(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800197{
Sean Anderson064c8572022-03-22 16:59:31 -0400198 if (CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) &&
199 smh_emulate_trap(pt_regs))
200 return;
Alexander Graf58177862016-03-04 01:10:06 +0100201 efi_restore_gd();
Pavel Skripkin23c722d2023-04-02 19:27:34 +0300202 printf("\"Synchronous Abort\" handler, esr 0x%08lx", pt_regs->esr);
203 dump_far(pt_regs->esr);
204 printf("\n");
David Feng85fd5f12013-12-14 11:47:35 +0800205 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200206 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800207 panic("Resetting CPU ...\n");
208}
209
210/*
211 * do_irq handles the Irq exception.
212 */
Sean Anderson2d755492022-03-22 17:17:35 -0400213void do_irq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800214{
Alexander Graf58177862016-03-04 01:10:06 +0100215 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400216 printf("\"Irq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800217 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200218 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800219 panic("Resetting CPU ...\n");
220}
221
222/*
223 * do_fiq handles the Fiq exception.
224 */
Sean Anderson2d755492022-03-22 17:17:35 -0400225void do_fiq(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800226{
Alexander Graf58177862016-03-04 01:10:06 +0100227 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400228 printf("\"Fiq\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800229 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200230 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800231 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 */
Sean Anderson2d755492022-03-22 17:17:35 -0400240void __weak do_error(struct pt_regs *pt_regs)
David Feng85fd5f12013-12-14 11:47:35 +0800241{
Alexander Graf58177862016-03-04 01:10:06 +0100242 efi_restore_gd();
Sean Anderson2d755492022-03-22 17:17:35 -0400243 printf("\"Error\" handler, esr 0x%08lx\n", pt_regs->esr);
David Feng85fd5f12013-12-14 11:47:35 +0800244 show_regs(pt_regs);
Heinrich Schuchardtb7c0c382019-04-04 22:06:25 +0200245 show_efi_loaded_images(pt_regs);
David Feng85fd5f12013-12-14 11:47:35 +0800246 panic("Resetting CPU ...\n");
247}