On 21/03/17 22:47, 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. > > Signed-off-by: Tyler Baicar <tbaicar@xxxxxxxxxxxxxx> > --- > arch/arm/include/asm/kvm_arm.h | 10 +++++++++ > arch/arm/include/asm/system_misc.h | 5 +++++ > arch/arm/kvm/mmu.c | 41 ++++++++++++++++++++++++++++++------ > arch/arm64/include/asm/kvm_arm.h | 10 +++++++++ > arch/arm64/include/asm/system_misc.h | 2 ++ > arch/arm64/mm/fault.c | 19 +++++++++++++++-- > drivers/acpi/apei/ghes.c | 13 ++++++------ > include/acpi/ghes.h | 2 +- > 8 files changed, 86 insertions(+), 16 deletions(-) > > diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h > index a3f0b3d..ebf020b 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) > +#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) > diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h > index a3d61ad..ea45d94 100644 > --- a/arch/arm/include/asm/system_misc.h > +++ b/arch/arm/include/asm/system_misc.h > @@ -24,4 +24,9 @@ > > #endif /* !__ASSEMBLY__ */ > > +static inline int handle_guest_sea(unsigned long addr, unsigned int esr) > +{ > + return -1; > +} > + Shouldn't this be in the #ifndef __ASSEMBLY__ block? The assembler is definitely going to barf on that... > #endif /* __ASM_ARM_SYSTEM_MISC_H */ > diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c > index 962616f..105b6ab 100644 > --- a/arch/arm/kvm/mmu.c > +++ b/arch/arm/kvm/mmu.c > @@ -29,6 +29,7 @@ > #include <asm/kvm_asm.h> > #include <asm/kvm_emulate.h> > #include <asm/virt.h> > +#include <asm/system_misc.h> > > #include "trace.h" > > @@ -1406,6 +1407,24 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) > kvm_set_pfn_accessed(pfn); > } > > +static bool is_abort_synchronous(unsigned long fault_status) { > + switch (fault_status) { > + case FSC_SEA: > + case FSC_SEA_TTW0: > + case FSC_SEA_TTW1: > + case FSC_SEA_TTW2: > + case FSC_SEA_TTW3: > + case FSC_SECC: > + case FSC_SECC_TTW0: > + case FSC_SECC_TTW1: > + case FSC_SECC_TTW2: > + case FSC_SECC_TTW3: > + return true; > + default: > + return false; > + } > +} > + > /** > * kvm_handle_guest_abort - handles all 2nd stage aborts > * @vcpu: the VCPU pointer > @@ -1426,23 +1445,31 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run) > unsigned long hva; > bool is_iabt, write_fault, writable; > gfn_t gfn; > - int ret, idx; > + int ret, idx, sea_status = 1; > + > + /* Check the stage-2 fault is trans. fault or write fault */ > + fault_status = kvm_vcpu_trap_get_fault_type(vcpu); > + > + fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); > + > + /* 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)) > + sea_status = handle_guest_sea((unsigned long)fault_ipa, > + kvm_vcpu_get_hsr(vcpu)); > > is_iabt = kvm_vcpu_trap_is_iabt(vcpu); > - if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) { > + if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu)) && sea_status) { > kvm_inject_vabt(vcpu); > return 1; > } > > - fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); > - > trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu), > kvm_vcpu_get_hfar(vcpu), fault_ipa); > > - /* 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) { > + fault_status != FSC_ACCESS && sea_status) { > 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/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h > index 6e99978..61d694c 100644 > --- a/arch/arm64/include/asm/kvm_arm.h > +++ b/arch/arm64/include/asm/kvm_arm.h > @@ -204,6 +204,16 @@ > #define FSC_FAULT ESR_ELx_FSC_FAULT > #define FSC_ACCESS ESR_ELx_FSC_ACCESS > #define FSC_PERM ESR_ELx_FSC_PERM > +#define FSC_SEA ESR_ELx_FSC_EXTABT > +#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) > +#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 (~UL(0xf)) > diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h > index bc81243..5b2cecd 100644 > --- a/arch/arm64/include/asm/system_misc.h > +++ b/arch/arm64/include/asm/system_misc.h > @@ -58,4 +58,6 @@ void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int, > > #endif /* __ASSEMBLY__ */ > > +int handle_guest_sea(unsigned long addr, unsigned int esr); Same remark here. > + > #endif /* __ASM_SYSTEM_MISC_H */ > diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c > index f7372ce..ee96307 100644 > --- a/arch/arm64/mm/fault.c > +++ b/arch/arm64/mm/fault.c > @@ -497,6 +497,7 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) > static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > { > struct siginfo info; > + int ret = 0; > > pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", > fault_name(esr), esr, addr); > @@ -508,7 +509,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > */ > if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > nmi_enter(); > - ghes_notify_sea(); > + ret = ghes_notify_sea(); > nmi_exit(); > } > > @@ -521,7 +522,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > info.si_addr = (void __user *)addr; > arm64_notify_die("", regs, &info, esr); > > - return 0; > + return ret; > } > > static const struct fault_info { > @@ -603,6 +604,20 @@ 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) > +{ > + int ret = -ENOENT; > + > + if(IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > + ret = ghes_notify_sea(); > + } > + > + return ret; > +} > + > +/* > * Dispatch a data abort to the relevant handler. > */ > asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, > diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c > index 230b095..81eabc6 100644 > --- a/drivers/acpi/apei/ghes.c > +++ b/drivers/acpi/apei/ghes.c > @@ -810,17 +810,18 @@ static int ghes_notify_sci(struct notifier_block *this, > #ifdef CONFIG_ACPI_APEI_SEA > static LIST_HEAD(ghes_sea); > > -void ghes_notify_sea(void) > +int ghes_notify_sea(void) > { > struct ghes *ghes; > + int ret = -ENOENT; > > - /* > - * synchronize_rcu() will wait for nmi_exit(), so no need to > - * rcu_read_lock(). > - */ > + rcu_read_lock(); > list_for_each_entry_rcu(ghes, &ghes_sea, list) { > - ghes_proc(ghes); > + if(!ghes_proc(ghes)) > + ret = 0; > } > + rcu_read_unlock(); > + return ret; > } > > static void ghes_sea_add(struct ghes *ghes) > diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h > index 18bc935..2a727dc 100644 > --- a/include/acpi/ghes.h > +++ b/include/acpi/ghes.h > @@ -99,6 +99,6 @@ static inline void *acpi_hest_generic_data_payload(struct acpi_hest_generic_data > gdata + 1; > } > > -void ghes_notify_sea(void); > +int ghes_notify_sea(void); > > #endif /* GHES_H */ > Otherwise, the KVM changes look good to me. Assuming you fix the two nits above: Acked-by: Marc Zyngier <marc.zyngier@xxxxxxx> Thanks, M. -- Jazz is not dead. It just smells funny...