]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
arm: semihosting: Support semihosting fallback on 32-bit ARM
authorSean Anderson <sean.anderson@seco.com>
Fri, 27 Oct 2023 20:40:15 +0000 (16:40 -0400)
committerTom Rini <trini@konsulko.com>
Fri, 10 Nov 2023 17:52:33 +0000 (12:52 -0500)
Add support for a semihosting fallback on 32-bit ARM. The assembly is
lightly adapted from the irq return code, except there is no offset
since lr already points to the correct instruction. The C side is mostly
like ARM64, except we have fewer cases to deal with.

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
arch/arm/lib/interrupts.c
arch/arm/lib/vectors.S
lib/Kconfig

index 6dc27d1d589adddbc69dca0e6347ee7755255b89..9961472f69f76098faf61fc4b04faf6c6f22d7dc 100644 (file)
@@ -22,6 +22,7 @@
 #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>
@@ -135,6 +136,32 @@ static inline void fixup_pc(struct pt_regs *regs, int 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();
@@ -147,6 +174,10 @@ void do_undefined_instruction (struct pt_regs *pt_regs)
 
 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);
index fe8ca403ac9ec043e61d7899d81224567649f5ee..843f9b9c281c9d5cf67aa01b08d5583677bfe222 100644 (file)
@@ -275,6 +275,13 @@ software_interrupt:
        get_bad_stack_swi
        bad_save_user_regs
        bl      do_software_interrupt
+#if CONFIG_IS_ENABLED(SEMIHOSTING_FALLBACK)
+       ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
+       mov     r0, r0
+       ldr     lr, [sp, #S_PC]                 @ Get PC
+       add     sp, sp, #S_FRAME_SIZE
+       movs    pc, lr          @ return & move spsr_svc into cpsr
+#endif
 
        .align  5
 prefetch_abort:
index 0c3afae8f52a41adeba876904fdd7f843fb630c1..9ae846ea5f75d1891f211242457e09a8ade67125 100644 (file)
@@ -100,7 +100,7 @@ config SEMIHOSTING
 
 config SEMIHOSTING_FALLBACK
        bool "Recover gracefully when semihosting fails"
-       depends on SEMIHOSTING && (ARM64 || RISCV)
+       depends on SEMIHOSTING
        default y
        help
          Normally, if U-Boot makes a semihosting call and no debugger is
@@ -123,7 +123,7 @@ config SPL_SEMIHOSTING
 
 config SPL_SEMIHOSTING_FALLBACK
        bool "Recover gracefully when semihosting fails in SPL"
-       depends on SPL_SEMIHOSTING && (ARM64 || RISCV)
+       depends on SPL_SEMIHOSTING
        select ARMV8_SPL_EXCEPTION_VECTORS if ARM64
        default y
        help