Hi Tyler,

On 06/03/17 20:45, Tyler Baicar wrote:
> Currently external aborts are unsupported by the guest abort
> handling. Add handling for SEAs so that the host kernel reports
> SEAs which occur in the guest kernel.

> diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
> index e22089f..a1a3dff 100644
> --- a/arch/arm/include/asm/kvm_arm.h
> +++ b/arch/arm/include/asm/kvm_arm.h
> @@ -187,6 +187,16 @@
>  #define FSC_FAULT    (0x04)
>  #define FSC_ACCESS   (0x08)
>  #define FSC_PERM     (0x0c)
> +#define FSC_SEA              (0x10)
> +#define FSC_SEA_TTW0 (0x14)
> +#define FSC_SEA_TTW1 (0x15)
> +#define FSC_SEA_TTW2 (0x16)
> +#define FSC_SEA_TTW3 (0x17)
> +#define FSC_SECC     (0x18)
> +#define FSC_SECC_TTW0        (0x1c)

aarch32 doesn't have either of these 'TW0' values, it's an unused encoding.
(However ...)

> +#define FSC_SECC_TTW1        (0x1d)
> +#define FSC_SECC_TTW2        (0x1e)
> +#define FSC_SECC_TTW3        (0x1f)
>  
>  /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
>  #define HPFAR_MASK   (~0xf)

>  #endif /* __ASM_ARM_SYSTEM_MISC_H */
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index a5265ed..f3608c9 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -1444,8 +1463,21 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, 
> struct kvm_run *run)
>  
>       /* Check the stage-2 fault is trans. fault or write fault */
>       fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
> -     if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
> -         fault_status != FSC_ACCESS) {
> +
> +     /* The host kernel will handle the synchronous external abort. There
> +      * is no need to pass the error into the guest.
> +      */
> +     if (is_abort_synchronous(fault_status)) {
> +             if(handle_guest_sea((unsigned long)fault_ipa,
> +                                 kvm_vcpu_get_hsr(vcpu))) {


... Looking further up in this function:
>       is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
>       if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
>               kvm_inject_vabt(vcpu);
>               return 1;
>       }

... so external data aborts will have already been 'claimed' by kvm and dealt
with, and we already have a helper for spotting external aborts. (sorry I didn't
spot it earlier).

We need to do the handle_guest_sea() before this code.

kvm_inject_vabt() makes an SError interrupt pending for the guest. This makes a
synchronous error asynchronous as the guest may have SError interrupts masked.

I guess this was the best that could be done at the time of (4055710baca8
"arm/arm64: KVM: Inject virtual abort when guest exits on external abort"), but
in the light of this firmware-first handling, I'm not sure its the right thing
to do.

Is it possible for handle_guest_sea() to return whether it actually found any
work to do? If there was none I think we should keep this kvm_inject_vabt() as
it is the existing behaviour.


> +                     kvm_err("Failed to handle guest SEA, FSC: EC=%#x 
> xFSC=%#lx ESR_EL2=%#lx\n",
> +                             kvm_vcpu_trap_get_class(vcpu),
> +                             (unsigned long)kvm_vcpu_trap_get_fault(vcpu),
> +                             (unsigned long)kvm_vcpu_get_hsr(vcpu));
> +                     return -EFAULT;
> +             }
> +     } else if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
> +                fault_status != FSC_ACCESS) {
>               kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
>                       kvm_vcpu_trap_get_class(vcpu),
>                       (unsigned long)kvm_vcpu_trap_get_fault(vcpu),


> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index b2d57fc..31c5171 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -602,6 +602,24 @@ static const char *fault_name(unsigned int esr)
>  }
>  
>  /*
> + * Handle Synchronous External Aborts that occur in a guest kernel.
> + */
> +int handle_guest_sea(unsigned long addr, unsigned int esr)
> +{
> +     /*
> +      * synchronize_rcu() will wait for nmi_exit(), so no need to
> +      * rcu_read_lock().
> +      */

This comment has a life of its own! Given we don't always call ghes_notify_sea()
when we interrupted un-interruptable code its not always true. I think the
rcu_read_{,un}lock() should go against the list walk (so it looks like the
examples), and ditch the comment!


> +     if(IS_ENABLED(ACPI_APEI_SEA)) {
> +             rcu_read_lock();
> +             ghes_notify_sea();
> +             rcu_read_unlock();
> +     }
> +
> +     return 0;
> +}
> +
> +/*
>   * Dispatch a data abort to the relevant handler.
>   */
>  asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int 
> esr,
> 


Thanks,

James

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to