[PATCH 3/3] arm: semihosting: Support semihosting fallback on 32-bit ARM

Sean Anderson sean.anderson at seco.com
Fri Oct 27 22:40:15 CEST 2023


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 at seco.com>
---

 arch/arm/lib/interrupts.c | 31 +++++++++++++++++++++++++++++++
 arch/arm/lib/vectors.S    |  7 +++++++
 lib/Kconfig               |  4 ++--
 3 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 6dc27d1d589..9961472f69f 100644
--- a/arch/arm/lib/interrupts.c
+++ b/arch/arm/lib/interrupts.c
@@ -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);
diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S
index fe8ca403ac9..843f9b9c281 100644
--- a/arch/arm/lib/vectors.S
+++ b/arch/arm/lib/vectors.S
@@ -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:
diff --git a/lib/Kconfig b/lib/Kconfig
index f6ca559897e..3cabb07bfd6 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -93,7 +93,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
@@ -116,7 +116,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
-- 
2.35.1.1320.gc452695387.dirty



More information about the U-Boot mailing list