]> Git Repo - J-u-boot.git/blobdiff - arch/arm/lib/interrupts.c
arm: clean up v7 and v8 linker scripts for bss_start/end
[J-u-boot.git] / arch / arm / lib / interrupts.c
index 066c172bb32420ed51553fee64e9845984bcdbad..9961472f69f76098faf61fc4b04faf6c6f22d7dc 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2003
  * Texas Instruments <www.ti.com>
  *
  * (C) Copyright 2004
  * Philippe Robin, ARM Ltd. <[email protected]>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <cpu_func.h>
+#include <efi_loader.h>
+#include <irq_func.h>
+#include <semihosting.h>
+#include <asm/global_data.h>
 #include <asm/proc-armv/ptrace.h>
+#include <asm/ptrace.h>
 #include <asm/u-boot-arm.h>
-#include <efi_loader.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int interrupt_init (void)
+int interrupt_init(void)
 {
        /*
         * setup up stacks if necessary
         */
        IRQ_STACK_START_IN = gd->irq_sp + 8;
 
+       enable_interrupts();
+
        return 0;
 }
 
-void enable_interrupts (void)
+void enable_interrupts(void)
 {
        return;
 }
-int disable_interrupts (void)
+int disable_interrupts(void)
 {
        return 0;
 }
@@ -48,7 +54,36 @@ int disable_interrupts (void)
 void bad_mode (void)
 {
        panic ("Resetting CPU ...\n");
-       reset_cpu (0);
+       reset_cpu();
+}
+
+static void show_efi_loaded_images(struct pt_regs *regs)
+{
+       efi_print_image_infos((void *)instruction_pointer(regs));
+}
+
+static void dump_instr(struct pt_regs *regs)
+{
+       unsigned long addr = instruction_pointer(regs);
+       const int thumb = thumb_mode(regs);
+       const int width = thumb ? 4 : 8;
+       int i;
+
+       if (thumb)
+               addr &= ~1L;
+       else
+               addr &= ~3L;
+       printf("Code: ");
+       for (i = -4; i < 1 + !!thumb; i++) {
+               unsigned int val;
+
+               if (thumb)
+                       val = ((u16 *)addr)[i];
+               else
+                       val = ((u32 *)addr)[i];
+               printf(i == 0 ? "(%0*x) " : "%0*x ", width, val);
+       }
+       printf("\n");
 }
 
 void show_regs (struct pt_regs *regs)
@@ -91,21 +126,63 @@ void show_regs (struct pt_regs *regs)
                fast_interrupts_enabled (regs) ? "on" : "off",
                processor_modes[processor_mode (regs)],
                thumb_mode (regs) ? " (T)" : "");
+       dump_instr(regs);
+}
+
+/* fixup PC to point to the instruction leading to the exception */
+static inline void fixup_pc(struct pt_regs *regs, int offset)
+{
+       uint32_t pc = instruction_pointer(regs) + offset;
+       regs->ARM_pc = pc | (regs->ARM_pc & PCMASK);
+}
+
+/*
+ * Try to "emulate" a semihosting call in the event that we don't have a
+ * debugger attached.
+ */
+static bool smh_emulate_trap(struct pt_regs *regs)
+{
+       if (regs->ARM_cpsr & T_BIT) {
+               u16 *insn = (u16 *)(regs->ARM_pc - 2);
+
+               if (*insn != SMH_T32_SVC)
+                       return false;
+       } else {
+               u32 *insn = (u32 *)(regs->ARM_pc - 4);
+
+               if (*insn != SMH_A32_SVC)
+                       return false;
+       }
+
+       /* Avoid future semihosting calls */
+       disable_semihosting();
+
+       /* Just pretend the call failed */
+       regs->ARM_r0 = -1;
+       return true;
 }
 
 void do_undefined_instruction (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("undefined instruction\n");
+       fixup_pc(pt_regs, -4);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
 void do_software_interrupt (struct pt_regs *pt_regs)
 {
+       if (CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK) &&
+           smh_emulate_trap(pt_regs))
+               return;
+
        efi_restore_gd();
        printf ("software interrupt\n");
+       fixup_pc(pt_regs, -4);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
@@ -113,7 +190,9 @@ void do_prefetch_abort (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("prefetch abort\n");
+       fixup_pc(pt_regs, -8);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
@@ -121,7 +200,9 @@ void do_data_abort (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("data abort\n");
+       fixup_pc(pt_regs, -8);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
@@ -129,7 +210,9 @@ void do_not_used (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("not used\n");
+       fixup_pc(pt_regs, -8);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
@@ -137,7 +220,9 @@ void do_fiq (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("fast interrupt request\n");
+       fixup_pc(pt_regs, -8);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
 
@@ -145,6 +230,8 @@ void do_irq (struct pt_regs *pt_regs)
 {
        efi_restore_gd();
        printf ("interrupt request\n");
+       fixup_pc(pt_regs, -8);
        show_regs (pt_regs);
+       show_efi_loaded_images(pt_regs);
        bad_mode ();
 }
This page took 0.037878 seconds and 4 git commands to generate.