aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-11-10 11:55:28 -0500
committerTom Rini <trini@konsulko.com>2023-11-10 11:55:28 -0500
commit277ad71dd1bd83c51d6b626212aa7936325fe88b (patch)
tree2f648c488a6e102c7182c551058d63ac464e1124
parent298de41f0c560eddc8d12281f1a2b01f8ad79351 (diff)
parent926720127ebda496e04100478b283fdaabb02a0b (diff)
downloadu-boot-277ad71dd1bd83c51d6b626212aa7936325fe88b.zip
u-boot-277ad71dd1bd83c51d6b626212aa7936325fe88b.tar.gz
u-boot-277ad71dd1bd83c51d6b626212aa7936325fe88b.tar.bz2
Merge branch '2023-11-10-improve-semihosting-armv6' into next
To quote the author: This series has a few fixes for semihosting on ARMv6 and older CPUs. The first two patches address problems regarding the stack pointer and link register. U-Boot runs in supervisor mode, so taking a software interrupt will clobber sp/lr. I think we really should run in system mode, since it has separate sp/lr registers. To quote ARM DDI 0100I: > The remaining mode is System mode, which is not entered by any > exception and has exactly the same registers available as User mode. > However, it is a privileged mode and is therefore not subject to the > User mode restrictions. It is intended for use by operating system > tasks that need access to system resources, but wish to avoid using > the additional registers associated with the exception modes. Avoiding > such use ensures that the task state is not corrupted by the > occurrence of any exception. However, the processor mode has been supervisor for such a long time (since relocation got introduced) that I would rather not touch it.
-rw-r--r--arch/arm/lib/interrupts.c31
-rw-r--r--arch/arm/lib/semihosting.S6
-rw-r--r--arch/arm/lib/vectors.S21
-rw-r--r--lib/Kconfig4
4 files changed, 59 insertions, 3 deletions
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 6dc27d1..9961472 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/semihosting.S b/arch/arm/lib/semihosting.S
index 393aade..6e1691a 100644
--- a/arch/arm/lib/semihosting.S
+++ b/arch/arm/lib/semihosting.S
@@ -18,11 +18,17 @@ ENTRY(smh_trap)
#elif defined(CONFIG_SYS_THUMB_BUILD)
svc #0xab
#else
+#if CONFIG_SYS_ARM_ARCH < 7
+ /* Before the ARMv7 exception model, svc (swi) clobbers lr */
+ mov r2, lr
+#endif
svc #0x123456
#endif
#if defined(CONFIG_ARM64)
ret
+#elif CONFIG_SYS_ARM_ARCH < 7
+ bx r2
#else
bx lr
#endif
diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S
index 7cf7d16..843f9b9 100644
--- a/arch/arm/lib/vectors.S
+++ b/arch/arm/lib/vectors.S
@@ -240,6 +240,18 @@ IRQ_STACK_START_IN:
movs pc, lr @ jump to next instruction & switch modes.
.endm
+ .macro get_bad_stack_swi
+ sub r13, r13, #4 @ space on current stack for scratch reg.
+ str r0, [r13] @ save R0's value.
+ ldr r0, IRQ_STACK_START_IN @ get data regions start
+ str lr, [r0] @ save caller lr in position 0 of saved stack
+ mrs lr, spsr @ get the spsr
+ str lr, [r0, #4] @ save spsr in position 1 of saved stack
+ ldr lr, [r0] @ restore lr
+ ldr r0, [r13] @ restore r0
+ add r13, r13, #4 @ pop stack entry
+ .endm
+
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
@@ -260,9 +272,16 @@ undefined_instruction:
.align 5
software_interrupt:
- get_bad_stack
+ 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 1add546..da19613 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