diff options
author | Sean Anderson | 2023-10-27 16:40:15 -0400 |
---|---|---|
committer | Tom Rini | 2023-11-10 12:52:33 -0500 |
commit | 47cfdb2192b1f8cb5061bde53fcce562afaeadf2 (patch) | |
tree | 83379c53e7d1821b8351db5dec24f1835f11c526 | |
parent | 6ef83ab6be8978ab85a7d8967e9585ddf5f2bbbd (diff) |
arm: semihosting: Support semihosting fallback on 32-bit ARM
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>
-rw-r--r-- | arch/arm/lib/interrupts.c | 31 | ||||
-rw-r--r-- | arch/arm/lib/vectors.S | 7 | ||||
-rw-r--r-- | 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 0c3afae8f52..9ae846ea5f7 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -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 |