[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.6] arm64: handle async aborts delivered while at EL2



commit 5f85ab0eb8bbf0fa56523424cc0a54d35ea69e80
Author:     Wei Chen <Wei.Chen@xxxxxxx>
AuthorDate: Tue Nov 29 16:12:05 2016 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Nov 29 16:12:05 2016 +0100

    arm64: handle async aborts delivered while at EL2
    
    If EL1 generates an asynchronous abort and then traps into EL2
    (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 EL2, 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
    EL1 -> EL2 swich paths. If we catched such asynchronous abort in
    checking window, the hyp_error 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@xxxxxxx>
    Reviewed-by: Julien Grall <julien.grall@xxxxxxx>
    Acked-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
    master commit: 36008800e81bc061cce1fd204a0b638f9dc61c70
    master date: 2016-11-29 15:58:57 +0100
---
 xen/arch/arm/arm64/entry.S | 123 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S
index 0ed0073..1840659 100644
--- a/xen/arch/arm/arm64/entry.S
+++ b/xen/arch/arm/arm64/entry.S
@@ -173,6 +173,43 @@ hyp_error_invalid:
         entry   hyp=1
         invalid BAD_ERROR
 
+hyp_error:
+        /*
+         * Only two possibilities:
+         * 1) Either we come from the exit path, having just unmasked
+         *    PSTATE.A: change the return code to an EL2 fault, and
+         *    carry on, as we're already in a sane state to handle it.
+         * 2) Or we come from anywhere else, and that's a bug: we panic.
+         */
+        entry   hyp=1
+        msr     daifclr, #2
+
+        /*
+         * The ELR_EL2 may be modified by an interrupt, so we have to use the
+         * saved value in cpu_user_regs to check whether we come from 1) or
+         * not.
+         */
+        ldr     x0, [sp, #UREGS_PC]
+        adr     x1, abort_guest_exit_start
+        cmp     x0, x1
+        adr     x1, abort_guest_exit_end
+        ccmp    x0, x1, #4, ne
+        mov     x0, sp
+        mov     x1, #BAD_ERROR
+
+        /*
+         * Not equal, the exception come from 2). It's a bug, we have to
+         * panic the hypervisor.
+         */
+        b.ne    do_bad_mode
+
+        /*
+         * Otherwise, the exception come from 1). It happened because of
+         * the guest. Crash this guest.
+         */
+        bl      do_trap_guest_error
+        exit    hyp=1
+
 /* Traps taken in Current EL with SP_ELx */
 hyp_sync:
         entry   hyp=1
@@ -189,15 +226,29 @@ hyp_irq:
 
 guest_sync:
         entry   hyp=0, compat=0
+        bl      check_pending_vserror
+        /*
+         * If x0 is Non-zero, a vSError took place, the initial exception
+         * doesn't have any significance to be handled. Exit ASAP
+         */
+        cbnz    x0, 1f
         msr     daifclr, #2
         mov     x0, sp
         bl      do_trap_hypervisor
+1:
         exit    hyp=0, compat=0
 
 guest_irq:
         entry   hyp=0, compat=0
+        bl      check_pending_vserror
+        /*
+         * If x0 is Non-zero, a vSError took place, the initial exception
+         * doesn't have any significance to be handled. Exit ASAP
+         */
+        cbnz    x0, 1f
         mov     x0, sp
         bl      do_trap_irq
+1:
         exit    hyp=0, compat=0
 
 guest_fiq_invalid:
@@ -213,15 +264,29 @@ guest_error:
 
 guest_sync_compat:
         entry   hyp=0, compat=1
+        bl      check_pending_vserror
+        /*
+         * If x0 is Non-zero, a vSError took place, the initial exception
+         * doesn't have any significance to be handled. Exit ASAP
+         */
+        cbnz    x0, 1f
         msr     daifclr, #2
         mov     x0, sp
         bl      do_trap_hypervisor
+1:
         exit    hyp=0, compat=1
 
 guest_irq_compat:
         entry   hyp=0, compat=1
+        bl      check_pending_vserror
+        /*
+         * If x0 is Non-zero, a vSError took place, the initial exception
+         * doesn't have any significance to be handled. Exit ASAP
+         */
+        cbnz    x0, 1f
         mov     x0, sp
         bl      do_trap_irq
+1:
         exit    hyp=0, compat=1
 
 guest_fiq_invalid_compat:
@@ -270,6 +335,62 @@ return_from_trap:
         eret
 
 /*
+ * This function is used to check pending virtual SError in the gap of
+ * EL1 -> EL2 world switch.
+ * The x0 register will be used to indicate the results of detection.
+ * x0 -- Non-zero indicates a pending virtual SError took place.
+ * x0 -- Zero indicates no pending virtual SError took place.
+ */
+check_pending_vserror:
+        /*
+         * Save elr_el2 to check whether the pending SError exception takes
+         * place while we are doing this sync exception.
+         */
+        mrs     x0, elr_el2
+
+        /* Synchronize against in-flight ld/st */
+        dsb     sy
+
+        /*
+         * Unmask PSTATE asynchronous abort bit. If there is a pending
+         * SError, the EL2 error exception will happen after PSTATE.A
+         * is cleared.
+         */
+        msr     daifclr, #4
+
+        /*
+         * This is our single instruction exception window. A pending
+         * SError is guaranteed to occur at the earliest when we unmask
+         * it, and at the latest just after the ISB.
+         *
+         * If a pending SError occurs, the program will jump to EL2 error
+         * exception handler, and the elr_el2 will be set to
+         * abort_guest_exit_start or abort_guest_exit_end.
+         */
+abort_guest_exit_start:
+
+        isb
+
+abort_guest_exit_end:
+        /* Mask PSTATE asynchronous abort bit, close the checking window. */
+        msr     daifset, #4
+
+        /*
+         * Compare elr_el2 and the saved value to check whether we are
+         * returning from a valid exception caused by pending SError.
+         */
+        mrs     x1, elr_el2
+        cmp     x0, x1
+
+        /*
+         * Not equal, the pending SError exception took place, set
+         * x0 to non-zero.
+         */
+        cset    x0, ne
+
+        ret
+
+/*
  * Exception vectors.
  */
         .macro  ventry  label
@@ -287,7 +408,7 @@ ENTRY(hyp_traps_vector)
         ventry  hyp_sync                        // Synchronous EL2h
         ventry  hyp_irq                         // IRQ EL2h
         ventry  hyp_fiq_invalid                 // FIQ EL2h
-        ventry  hyp_error_invalid               // Error EL2h
+        ventry  hyp_error                       // Error EL2h
 
         ventry  guest_sync                      // Synchronous 64-bit EL0/EL1
         ventry  guest_irq                       // IRQ 64-bit EL0/EL1
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.6

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.