arm32: handle async aborts delivered while at HYP

If guest generates an asynchronous abort and then traps into HYP
(by HVC or IRQ) before the abort has been delivered, the hypervisor
could not catch it, because the PSTATE.A bit is masked all the time
in hypervisor. So this asynchronous abort may be slipped to next
running guest with PSTATE.A bit unmasked.

In order to avoid this, it is necessary to take the abort at HYP, by
clearing the PSTATE.A bit. In this patch, we unmask the PSTATE.A bit
to open a window to catch guest-generated asynchronous abort in all
Guest -> HYP switch paths. If we caught such asynchronous abort in
checking window, the HYP data abort exception will be triggered and
the abort source guest will be crashed.

This is part of XSA-201.

Signed-off-by: Wei Chen <Wei.Chen@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
This commit is contained in:
Wei Chen authored and Jan Beulich committed 2016-11-29 15:59:55 +01:00
1 parent f8c6a9334b
commit 6aaff7b407
4 files changed
+72 -1

No files matched your search

+55
View File
@@ -42,6 +42,61 @@ save_guest_regs:
SAVE_BANKED(fiq)
SAVE_ONE_BANKED(R8_fiq); SAVE_ONE_BANKED(R9_fiq); SAVE_ONE_BANKED(R10_fiq)
SAVE_ONE_BANKED(R11_fiq); SAVE_ONE_BANKED(R12_fiq);
/*
* Start to check pending virtual abort in the gap of Guest -> HYP
* world switch.
*
* Save ELR_hyp to check whether the pending virtual abort exception
* takes place while we are doing this trap exception.
*/
mrs r1, ELR_hyp
/*
* Force loads and stores to complete before unmasking asynchronous
* aborts and forcing the delivery of the exception.
*/
dsb sy
/*
* Unmask asynchronous abort bit. If there is a pending asynchronous
* abort, the data_abort exception will happen after A bit is cleared.
*/
cpsie a
/*
* This is our single instruction exception window. A pending
* asynchronous abort is guaranteed to occur at the earliest when we
* unmask it, and at the latest just after the ISB.
*
* If a pending abort occurs, the program will jump to data_abort
* exception handler, and the ELR_hyp will be set to
* abort_guest_exit_start or abort_guest_exit_end.
*/
.global abort_guest_exit_start
abort_guest_exit_start:
isb
.global abort_guest_exit_end
abort_guest_exit_end:
/* Mask CPSR asynchronous abort bit, close the checking window. */
cpsid a
/*
* Compare ELR_hyp and the saved value to check whether we are
* returning from a valid exception caused by pending virtual
* abort.
*/
mrs r2, ELR_hyp
cmp r1, r2
/*
* Not equal, the pending virtual abort exception took place, the
* initial exception does not have any significance to be handled.
* Exit ASAP.
*/
bne return_from_trap
mov pc, lr
#define DEFINE_TRAP_ENTRY(trap) \
+4 -1
View File
@@ -63,7 +63,10 @@ asmlinkage void do_trap_prefetch_abort(struct cpu_user_regs *regs)
asmlinkage void do_trap_data_abort(struct cpu_user_regs *regs)
{
do_unexpected_trap("Data Abort", regs);
if ( VABORT_GEN_BY_GUEST(regs) )
do_trap_guest_error(regs);
else
do_unexpected_trap("Data Abort", regs);
}
/*
+11
View File
@@ -55,6 +55,17 @@ struct cpu_user_regs
uint32_t pad1; /* Doubleword-align the user half of the frame */
};
/* Functions for pending virtual abort checking window. */
void abort_guest_exit_start(void);
void abort_guest_exit_end(void);
#define VABORT_GEN_BY_GUEST(r) \
( \
( (unsigned long)abort_guest_exit_start == (r)->pc ) || \
( (unsigned long)abort_guest_exit_end == (r)->pc ) \
)
#endif
/* Layout as used in assembly, with src/dest registers mixed in */
+2
View File
@@ -690,6 +690,8 @@ void vcpu_regs_user_to_hyp(struct vcpu *vcpu,
int call_smc(register_t function_id, register_t arg0, register_t arg1,
register_t arg2);
void do_trap_guest_error(struct cpu_user_regs *regs);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARM_PROCESSOR_H */
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.