[RFC PATCH 5/5] Fix PC adjustment logic in exception handlers

Jim Posen jim.posen at gmail.com
Mon Oct 25 01:58:08 CEST 2021


The link register is at a different offset depending on processor
mode, so ensure it applies the correct adjustment.

Signed-off-by: Jim Posen <jim.posen at gmail.com>
---

 arch/arm/include/asm/u-boot-arm.h | 14 +++++++-------
 arch/arm/lib/interrupts.c         | 26 +++++++++++++-------------
 arch/arm/lib/vectors.S            |  4 +++-
 3 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index 0b93cc48c5..6ebefa7c86 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -41,17 +41,17 @@ int	board_init(void);
 struct pt_regs;
 
 void bad_mode(void);
-void do_undefined_instruction(struct pt_regs *pt_regs);
-void do_software_interrupt(struct pt_regs *pt_regs);
-void do_prefetch_abort(struct pt_regs *pt_regs);
-void do_data_abort(struct pt_regs *pt_regs);
-void do_not_used(struct pt_regs *pt_regs);
+void do_undefined_instruction(struct pt_regs *pt_regs, bool hyp_mode);
+void do_software_interrupt(struct pt_regs *pt_regs, bool hyp_mode);
+void do_prefetch_abort(struct pt_regs *pt_regs, bool hyp_mode);
+void do_data_abort(struct pt_regs *pt_regs, bool hyp_mode);
+void do_not_used(struct pt_regs *pt_regs, bool hyp_mode);
 #ifdef CONFIG_ARM64
 void do_fiq(struct pt_regs *pt_regs, unsigned int esr);
 void do_irq(struct pt_regs *pt_regs, unsigned int esr);
 #else
-void do_fiq(struct pt_regs *pt_regs);
-void do_irq(struct pt_regs *pt_regswq);
+void do_fiq(struct pt_regs *pt_regs, bool hyp_mode);
+void do_irq(struct pt_regs *pt_regswq, bool hyp_mode);
 #endif
 
 void reset_misc(void);
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 6dc27d1d58..498401cdc5 100644
--- a/arch/arm/lib/interrupts.c
+++ b/arch/arm/lib/interrupts.c
@@ -135,17 +135,17 @@ static inline void fixup_pc(struct pt_regs *regs, int offset)
 	regs->ARM_pc = pc | (regs->ARM_pc & PCMASK);
 }
 
-void do_undefined_instruction (struct pt_regs *pt_regs)
+void do_undefined_instruction(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("undefined instruction\n");
-	fixup_pc(pt_regs, -4);
+	fixup_pc(pt_regs, hyp_mode ? 0 : thumb_mode(regs) ? -2 : -4);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
 }
 
-void do_software_interrupt (struct pt_regs *pt_regs)
+void do_software_interrupt(struct pt_regs *pt_regs, bool _hyp_mode)
 {
 	efi_restore_gd();
 	printf ("software interrupt\n");
@@ -155,51 +155,51 @@ void do_software_interrupt (struct pt_regs *pt_regs)
 	bad_mode ();
 }
 
-void do_prefetch_abort (struct pt_regs *pt_regs)
+void do_prefetch_abort(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("prefetch abort\n");
-	fixup_pc(pt_regs, -8);
+	fixup_pc(pt_regs, hyp_mode ? 0 : -4);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
 }
 
-void do_data_abort (struct pt_regs *pt_regs)
+void do_data_abort(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("data abort\n");
-	fixup_pc(pt_regs, -8);
+	fixup_pc(pt_regs, hyp_mode ? 0 : -8);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
 }
 
-void do_not_used (struct pt_regs *pt_regs)
+void do_not_used(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("not used\n");
-	fixup_pc(pt_regs, -8);
+	fixup_pc(pt_regs, hyp_mode ? 0 : -8);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
 }
 
-void do_fiq (struct pt_regs *pt_regs)
+void do_fiq(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("fast interrupt request\n");
-	fixup_pc(pt_regs, -8);
+	fixup_pc(pt_regs, hyp_mode ? 0 : -4);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
 }
 
-void do_irq (struct pt_regs *pt_regs)
+void do_irq(struct pt_regs *pt_regs, bool hyp_mode)
 {
 	efi_restore_gd();
 	printf ("interrupt request\n");
-	fixup_pc(pt_regs, -8);
+	fixup_pc(pt_regs, hyp_mode ? 0 : -4);
 	show_regs (pt_regs);
 	show_efi_loaded_images(pt_regs);
 	bad_mode ();
diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S
index a36e3b7a43..dff2155dad 100644
--- a/arch/arm/lib/vectors.S
+++ b/arch/arm/lib/vectors.S
@@ -239,6 +239,7 @@ IRQ_STACK_START_IN:
 	mov	r1, lr
 	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
 	mov	r0, sp		@ save current stack into r0 (param register)
+	mov	r1, #0      @ set r1 param to 0, not hypervisor mode
 	.endm
 
 	.macro get_bad_stack
@@ -321,7 +322,8 @@ fiq:
 	str	r1, [sp, #S_PC]
 	str	r2, [sp, #S_PSR]
 	str	r0, [sp, #S_OLD_R0]
-	mov	r0, sp
+	mov	r0, sp		@ set r0 param to struct pt_regs on stack
+	mov	r1, #1      @ set r1 param to 1, hypervisor mode
 	.endm
 
 hyp_undefined_instruction:
-- 
2.25.1



More information about the U-Boot mailing list