[PATCH V13 10/10] arm/arm64: KVM: add guest SEA support
Baicar, Tyler
tbaicar at codeaurora.org
Tue Mar 28 09:35:22 PDT 2017
Hello Marc,
On 3/24/2017 8:03 AM, Marc Zyngier wrote:
> 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 at codeaurora.org>
>> ---
>> 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...
I will move this in the next patch set.
>> #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.
Same 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 at arm.com>
Thanks!
Tyler
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
More information about the linux-arm-kernel
mailing list