Skip to content

Commit a8f0655

Browse files
ptosioupton
authored andcommitted
KVM: arm64: Fix clobbered ELR in sync abort/SError
When the hypervisor receives a SError or synchronous exception (EL2h) while running with the __kvm_hyp_vector and if ELR_EL2 doesn't point to an extable entry, it panics indirectly by overwriting ELR with the address of a panic handler in order for the asm routine it returns to to ERET into the handler. However, this clobbers ELR_EL2 for the handler itself. As a result, hyp_panic(), when retrieving what it believes to be the PC where the exception happened, actually ends up reading the address of the panic handler that called it! This results in an erroneous and confusing panic message where the source of any synchronous exception (e.g. BUG() or kCFI) appears to be __guest_exit_panic, making it hard to locate the actual BRK instruction. Therefore, store the original ELR_EL2 in the per-CPU kvm_hyp_ctxt and point the sysreg to a routine that first restores it to its previous value before running __guest_exit_panic. Fixes: 7db2153 ("KVM: arm64: Restore hyp when panicking in guest context") Signed-off-by: Pierre-Clément Tosi <[email protected]> Acked-by: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 83a7eef commit a8f0655

File tree

3 files changed

+12
-2
lines changed

3 files changed

+12
-2
lines changed

arch/arm64/kernel/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ int main(void)
128128
DEFINE(VCPU_FAULT_DISR, offsetof(struct kvm_vcpu, arch.fault.disr_el1));
129129
DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
130130
DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_cpu_context, regs));
131+
DEFINE(CPU_ELR_EL2, offsetof(struct kvm_cpu_context, sys_regs[ELR_EL2]));
131132
DEFINE(CPU_RGSR_EL1, offsetof(struct kvm_cpu_context, sys_regs[RGSR_EL1]));
132133
DEFINE(CPU_GCR_EL1, offsetof(struct kvm_cpu_context, sys_regs[GCR_EL1]));
133134
DEFINE(CPU_APIAKEYLO_EL1, offsetof(struct kvm_cpu_context, sys_regs[APIAKEYLO_EL1]));

arch/arm64/kvm/hyp/entry.S

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ alternative_else_nop_endif
8383
eret
8484
sb
8585

86+
SYM_INNER_LABEL(__guest_exit_restore_elr_and_panic, SYM_L_GLOBAL)
87+
// x2-x29,lr: vcpu regs
88+
// vcpu x0-x1 on the stack
89+
90+
adr_this_cpu x0, kvm_hyp_ctxt, x1
91+
ldr x0, [x0, #CPU_ELR_EL2]
92+
msr elr_el2, x0
93+
8694
SYM_INNER_LABEL(__guest_exit_panic, SYM_L_GLOBAL)
8795
// x2-x29,lr: vcpu regs
8896
// vcpu x0-x1 on the stack

arch/arm64/kvm/hyp/include/hyp/switch.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
693693

694694
static inline void __kvm_unexpected_el2_exception(void)
695695
{
696-
extern char __guest_exit_panic[];
696+
extern char __guest_exit_restore_elr_and_panic[];
697697
unsigned long addr, fixup;
698698
struct kvm_exception_table_entry *entry, *end;
699699
unsigned long elr_el2 = read_sysreg(elr_el2);
@@ -715,7 +715,8 @@ static inline void __kvm_unexpected_el2_exception(void)
715715
}
716716

717717
/* Trigger a panic after restoring the hyp context. */
718-
write_sysreg(__guest_exit_panic, elr_el2);
718+
this_cpu_ptr(&kvm_hyp_ctxt)->sys_regs[ELR_EL2] = elr_el2;
719+
write_sysreg(__guest_exit_restore_elr_and_panic, elr_el2);
719720
}
720721

721722
#endif /* __ARM64_KVM_HYP_SWITCH_H__ */

0 commit comments

Comments
 (0)