2017-08-18 13:49:56

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 0/7] Add RAS virtualization support to SEA/SEI notification type

In the firmware-first RAS solution, corrupt data is detected in a
memory location when guest OS application software executing at EL0
or guest OS kernel El1 software are reading from the memory. The
memory node records errors in an error record accessible using
system registers.

Because SCR_EL3.EA is 1, then CPU will trap to El3 firmware, EL3
firmware records the error to APEI table through reading system
register.

Because the error was taken from a lower Exception leve, if the
exception is SEA/SEI and HCR_EL2.TEA/HCR_EL2.AMO is 1, firmware
sets ESR_EL2/FAR_El to fake a exception trap to EL2, then
transfers to hypervisor.

Hypervisor calls the momory failure to deal with this error, momory
failure read the APEI table and decide whether it needs to deliver
SIGBUS signal to user space, the advantage of using SIGBUS signal
to notify user space is that it can be compatible Non-Kvm users.

Dongjiu Geng (5):
acpi: apei: Add SEI notification type support for ARMv8
support user space to query RAS extension feature
arm64: kvm: route synchronous external abort exceptions to el2
KVM: arm/arm64: Allow get exception syndrome and
arm64: kvm: handle SEI notification and inject virtual SError

James Morse (1):
KVM: arm64: Save ESR_EL2 on guest SError

Xie XiuQi (1):
arm64: cpufeature: Detect CPU RAS Extentions

arch/arm/include/asm/kvm_host.h | 2 ++
arch/arm/kvm/guest.c | 5 +++
arch/arm64/Kconfig | 16 ++++++++++
arch/arm64/include/asm/barrier.h | 1 +
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/kvm_arm.h | 2 ++
arch/arm64/include/asm/kvm_emulate.h | 17 ++++++++++
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/include/asm/sysreg.h | 5 +++
arch/arm64/include/asm/system_misc.h | 1 +
arch/arm64/include/uapi/asm/kvm.h | 5 +++
arch/arm64/kernel/cpufeature.c | 13 ++++++++
arch/arm64/kernel/process.c | 3 ++
arch/arm64/kvm/guest.c | 48 +++++++++++++++++++++++++++++
arch/arm64/kvm/handle_exit.c | 21 +++++++++++--
arch/arm64/kvm/hyp/switch.c | 29 +++++++++++++++--
arch/arm64/kvm/reset.c | 3 ++
arch/arm64/mm/fault.c | 21 +++++++++++--
drivers/acpi/apei/Kconfig | 15 +++++++++
drivers/acpi/apei/ghes.c | 60 +++++++++++++++++++++++-------------
include/acpi/ghes.h | 2 +-
include/uapi/linux/kvm.h | 3 ++
virt/kvm/arm/arm.c | 7 +++++
23 files changed, 254 insertions(+), 30 deletions(-)

--
2.14.0


2017-08-18 13:49:40

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 2/7] KVM: arm64: Save ESR_EL2 on guest SError

From: James Morse <[email protected]>

When we exit a guest due to an SError the vcpu fault info isn't updated
with the ESR. Today this is only done for traps.

The v8.2 RAS Extensions define ISS values for SError. Update the vcpu's
fault_info with the ESR on SError so that handle_exit() can determine
if this was a RAS SError and decode its severity.

Signed-off-by: James Morse <[email protected]>
---
arch/arm64/kvm/hyp/switch.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 945e79c641c4..c6f17c7675ad 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -226,13 +226,20 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar)
return true;
}

+static void __hyp_text __populate_fault_info_esr(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
+}
+
static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
{
- u64 esr = read_sysreg_el2(esr);
- u8 ec = ESR_ELx_EC(esr);
+ u8 ec;
+ u64 esr;
u64 hpfar, far;

- vcpu->arch.fault.esr_el2 = esr;
+ __populate_fault_info_esr(vcpu);
+ esr = vcpu->arch.fault.esr_el2;
+ ec = ESR_ELx_EC(esr);

if (ec != ESR_ELx_EC_DABT_LOW && ec != ESR_ELx_EC_IABT_LOW)
return true;
@@ -321,6 +328,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
*/
if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
goto again;
+ else if (ARM_EXCEPTION_CODE(exit_code) == ARM_EXCEPTION_EL1_SERROR)
+ __populate_fault_info_esr(vcpu);

if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
exit_code == ARM_EXCEPTION_TRAP) {
--
2.14.0

2017-08-18 13:49:50

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 1/7] arm64: cpufeature: Detect CPU RAS Extentions

From: Xie XiuQi <[email protected]>

ARM's v8.2 Extentions add support for Reliability, Availability and
Serviceability (RAS). On CPUs with these extensions system software
can use additional barriers to isolate errors and determine if faults
are pending.

Add cpufeature detection and a barrier in the context-switch code.
There is no need to use alternatives for this as CPUs that don't
support this feature will treat the instruction as a nop.

Platform level RAS support may require additional firmware support.

Signed-off-by: Xie XiuQi <[email protected]>
[Rebased, added esb and config option, reworded commit message]
Signed-off-by: James Morse <[email protected]>
---
arch/arm64/Kconfig | 16 ++++++++++++++++
arch/arm64/include/asm/barrier.h | 1 +
arch/arm64/include/asm/cpucaps.h | 3 ++-
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kernel/cpufeature.c | 13 +++++++++++++
arch/arm64/kernel/process.c | 3 +++
6 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index dfd908630631..4d87aa963d83 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -960,6 +960,22 @@ config ARM64_UAO
regular load/store instructions if the cpu does not implement the
feature.

+config ARM64_RAS_EXTN
+ bool "Enable support for RAS CPU Extensions"
+ default y
+ help
+ CPUs that support the Reliability, Availability and Serviceability
+ (RAS) Extensions, part of ARMv8.2 are able to track faults and
+ errors, classify them and report them to software.
+
+ On CPUs with these extensions system software can use additional
+ barriers to determine if faults are pending and read the
+ classification from a new set of registers.
+
+ Selecting this feature will allow the kernel to use these barriers
+ and access the new registers if the system supports the extension.
+ Platform RAS features may additionally depend on firmware support.
+
endmenu

config ARM64_MODULE_CMODEL_LARGE
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 0fe7e43b7fbc..8b0a0eb67625 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -30,6 +30,7 @@
#define isb() asm volatile("isb" : : : "memory")
#define dmb(opt) asm volatile("dmb " #opt : : : "memory")
#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
+#define esb() asm volatile("hint #16" : : : "memory")

#define mb() dsb(sy)
#define rmb() dsb(ld)
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 8d2272c6822c..f93bf77f1f74 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -39,7 +39,8 @@
#define ARM64_WORKAROUND_QCOM_FALKOR_E1003 18
#define ARM64_WORKAROUND_858921 19
#define ARM64_WORKAROUND_CAVIUM_30115 20
+#define ARM64_HAS_RAS_EXTN 21

-#define ARM64_NCAPS 21
+#define ARM64_NCAPS 22

#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 248339e4aaf5..35b786b43ee4 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -331,6 +331,7 @@
#define ID_AA64ISAR1_JSCVT_SHIFT 12

/* id_aa64pfr0 */
+#define ID_AA64PFR0_RAS_SHIFT 28
#define ID_AA64PFR0_GIC_SHIFT 24
#define ID_AA64PFR0_ASIMD_SHIFT 20
#define ID_AA64PFR0_FP_SHIFT 16
@@ -339,6 +340,7 @@
#define ID_AA64PFR0_EL1_SHIFT 4
#define ID_AA64PFR0_EL0_SHIFT 0

+#define ID_AA64PFR0_RAS_V1 0x1
#define ID_AA64PFR0_FP_NI 0xf
#define ID_AA64PFR0_FP_SUPPORTED 0x0
#define ID_AA64PFR0_ASIMD_NI 0xf
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9f9e0064c8c1..a807ab55ee10 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -124,6 +124,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
};

static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_RAS_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
@@ -888,6 +889,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.min_field_value = 0,
.matches = has_no_fpsimd,
},
+#ifdef CONFIG_ARM64_RAS_EXTN
+ {
+ .desc = "RAS Extension Support",
+ .capability = ARM64_HAS_RAS_EXTN,
+ .def_scope = SCOPE_SYSTEM,
+ .matches = has_cpuid_feature,
+ .sys_reg = SYS_ID_AA64PFR0_EL1,
+ .sign = FTR_UNSIGNED,
+ .field_pos = ID_AA64PFR0_RAS_SHIFT,
+ .min_field_value = ID_AA64PFR0_RAS_V1,
+ },
+#endif /* CONFIG_ARM64_RAS_EXTN */
{},
};

diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 659ae8094ed5..2def5ce75867 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -363,6 +363,9 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
*/
dsb(ish);

+ /* Deliver any pending SError from prev */
+ esb();
+
/* the actual thread switch */
last = cpu_switch_to(prev, next);

--
2.14.0

2017-08-18 13:49:58

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 7/7] arm64: kvm: handle SEI notification and inject virtual SError

After receive SError, KVM firstly call memory failure to
deal with the Error. If memory failure wants user space to
handle it, it will notify user space. This patch adds support
to userspace that injects virtual SError with specified
syndrome. This syndrome value will be set to the VSESR_EL2.
VSESR_EL2 is a new RAS extensions register which provides the
syndrome value reported to software on taking a virtual SError
interrupt exception.

Signed-off-by: Dongjiu Geng <[email protected]>
Signed-off-by: Quanming Wu <[email protected]>
---
arch/arm/include/asm/kvm_host.h | 2 ++
arch/arm/kvm/guest.c | 5 +++++
arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/include/asm/sysreg.h | 3 +++
arch/arm64/include/asm/system_misc.h | 1 +
arch/arm64/kvm/guest.c | 13 +++++++++++++
arch/arm64/kvm/handle_exit.c | 21 +++++++++++++++++++--
arch/arm64/kvm/hyp/switch.c | 14 ++++++++++++++
include/uapi/linux/kvm.h | 2 ++
virt/kvm/arm/arm.c | 7 +++++++
11 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 127e2dd2e21c..bdb6ea690257 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -244,6 +244,8 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
int exception_index);

+int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome);
+
static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
unsigned long hyp_stack_ptr,
unsigned long vector_ptr)
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784ebbfd6..c23df72d9bec 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -248,6 +248,11 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return -EINVAL;
}

+int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome)
+{
+ return 0;
+}
+
int __attribute_const__ kvm_target_cpu(void)
{
switch (read_cpuid_part()) {
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 47983db27de2..74213bd539dc 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -155,6 +155,16 @@ static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
return vcpu->arch.fault.esr_el2;
}

+static inline u32 kvm_vcpu_get_vsesr(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.fault.vsesr_el2;
+}
+
+static inline void kvm_vcpu_set_vsesr(struct kvm_vcpu *vcpu, unsigned long val)
+{
+ vcpu->arch.fault.vsesr_el2 = val;
+}
+
static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
{
u32 esr = kvm_vcpu_get_hsr(vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index d68630007b14..57b011261597 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -88,6 +88,7 @@ struct kvm_vcpu_fault_info {
u32 esr_el2; /* Hyp Syndrom Register */
u64 far_el2; /* Hyp Fault Address Register */
u64 hpfar_el2; /* Hyp IPA Fault Address Register */
+ u32 vsesr_el2; /* Virtual SError Exception Syndrome Register */
};

/*
@@ -381,6 +382,7 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr);
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr);
+int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome);

static inline void __cpu_init_stage2(void)
{
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 35b786b43ee4..06059eef0f5d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -86,6 +86,9 @@
#define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4)
#define REG_PSTATE_UAO_IMM sys_reg(0, 0, 4, 0, 3)

+/* virtual SError exception syndrome register in armv8.2 */
+#define REG_VSESR_EL2 sys_reg(3, 4, 5, 2, 3)
+
#define SET_PSTATE_PAN(x) __emit_inst(0xd5000000 | REG_PSTATE_PAN_IMM | \
(!!x)<<8 | 0x1f)
#define SET_PSTATE_UAO(x) __emit_inst(0xd5000000 | REG_PSTATE_UAO_IMM | \
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index 07aa8e3c5630..7d07aeb02bc4 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -57,6 +57,7 @@ extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
})

int handle_guest_sea(phys_addr_t addr, unsigned int esr);
+int handle_guest_sei(phys_addr_t addr, unsigned int esr);

#endif /* __ASSEMBLY__ */

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index cb383c310f18..3cbe91e76c0e 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -312,6 +312,19 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return -EINVAL;
}

+int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome)
+{
+ u64 reg = *syndrome;
+
+ if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && reg)
+ /* set vsesr_el2[24:0] with value that user space specified */
+ kvm_vcpu_set_vsesr(vcpu, reg & ESR_ELx_ISS_MASK);
+
+ /* inject virtual system Error or asynchronous abort */
+ kvm_inject_vabt(vcpu);
+ return 0;
+}
+
int __attribute_const__ kvm_target_cpu(void)
{
unsigned long implementor = read_cpuid_implementor();
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 17d8a1677a0b..7ddeff30c7b9 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -28,6 +28,7 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_psci.h>
+#include <asm/system_misc.h>

#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -178,6 +179,22 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
return arm_exit_handlers[hsr_ec];
}

+static int kvm_handle_guest_sei(struct kvm_vcpu *vcpu)
+{
+ unsigned long fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+
+ if (handle_guest_sei((unsigned long)fault_ipa,
+ kvm_vcpu_get_hsr(vcpu))) {
+ kvm_err("Failed to handle guest SEI, 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));
+
+ kvm_inject_vabt(vcpu);
+ }
+ return 0;
+}
+
/*
* Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
* proper exit to userspace.
@@ -201,7 +218,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
*vcpu_pc(vcpu) -= adj;
}

- kvm_inject_vabt(vcpu);
+ kvm_handle_guest_sei(vcpu);
return 1;
}

@@ -211,7 +228,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
case ARM_EXCEPTION_IRQ:
return 1;
case ARM_EXCEPTION_EL1_SERROR:
- kvm_inject_vabt(vcpu);
+ kvm_handle_guest_sei(vcpu);
return 1;
case ARM_EXCEPTION_TRAP:
/*
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index c6f17c7675ad..a73346141cf3 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -42,6 +42,13 @@ bool __hyp_text __fpsimd_enabled(void)
return __fpsimd_is_enabled()();
}

+static void __hyp_text __sysreg_set_vsesr(struct kvm_vcpu *vcpu)
+{
+ if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) &&
+ (vcpu->arch.hcr_el2 & HCR_VSE))
+ write_sysreg_s(vcpu->arch.fault.vsesr_el2, REG_VSESR_EL2);
+}
+
static void __hyp_text __activate_traps_vhe(void)
{
u64 val;
@@ -86,6 +93,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
isb();
}
write_sysreg(val, hcr_el2);
+
+ /*
+ * If the virtual SError interrupt is taken to EL1 using AArch64,
+ * then VSESR_EL2 provides the syndrome value reported in ESR_EL1.
+ */
+ __sysreg_set_vsesr(vcpu);
+
/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
write_sysreg(1 << 15, hstr_el2);
/*
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 5a2a338cae57..d3fa4c60c9dc 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1356,6 +1356,8 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_S390_CMMA_MIGRATION */
#define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
#define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
+#define KVM_ARM_SEI _IO(KVMIO, 0xb10)
+

#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index a39a1e161e63..dbaaf206ace2 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1022,6 +1022,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
return -EFAULT;
return kvm_arm_vcpu_has_attr(vcpu, &attr);
}
+ case KVM_ARM_SEI: {
+ u64 syndrome;
+
+ if (copy_from_user(&syndrome, argp, sizeof(syndrome)))
+ return -EFAULT;
+ return kvm_vcpu_ioctl_sei(vcpu, &syndrome);
+ }
default:
return -EINVAL;
}
--
2.14.0

2017-08-18 13:49:53

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 5/7] arm64: kvm: route synchronous external abort exceptions to el2

ARMv8.2 adds a new bit HCR_EL2.TEA which controls to
route synchronous external aborts to EL2, and add a
trap control bit HCR_EL2.TERR which will control to
trap all Non-secure EL1&0 error record accesses to EL2.

This patch will enable the two bits for the guest OS.
when an synchronous abort is generated in the guest OS,
it will trap to EL3 firmware, firmware will be according
to the HCR_EL2.TEA to decide to jump to hypervisor or host
OS. In the guest OS, RAS error record access will trap to
EL2.

Signed-off-by: Dongjiu Geng <[email protected]>
---
arch/arm64/include/asm/kvm_arm.h | 2 ++
arch/arm64/include/asm/kvm_emulate.h | 7 +++++++
2 files changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 61d694c2eae5..1188272003c4 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,8 @@
#include <asm/types.h>

/* Hyp Configuration Register (HCR) bits */
+#define HCR_TEA (UL(1) << 37)
+#define HCR_TERR (UL(1) << 36)
#define HCR_E2H (UL(1) << 34)
#define HCR_ID (UL(1) << 33)
#define HCR_CD (UL(1) << 32)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index fe39e6841326..47983db27de2 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -47,6 +47,13 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
if (is_kernel_in_hyp_mode())
vcpu->arch.hcr_el2 |= HCR_E2H;
+ if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
+ /* route synchronous external abort exceptions to EL2 */
+ vcpu->arch.hcr_el2 |= HCR_TEA;
+ /* trap error record accesses */
+ vcpu->arch.hcr_el2 |= HCR_TERR;
+ }
+
if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
vcpu->arch.hcr_el2 &= ~HCR_RW;
}
--
2.14.0

2017-08-18 13:51:08

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 4/7] support user space to query RAS extension feature

In armv8.2 RAS extension, it adds virtual SError exception
syndrome registeri(VSESR_EL2), user space will specify that
value. so user space will check whether CPU feature has RAS
extension. if has, it will specify the virtual SError syndrome
value. Otherwise, it will not set. This patch adds this support

Signed-off-by: Dongjiu Geng <[email protected]>
---
arch/arm64/kvm/reset.c | 3 +++
include/uapi/linux/kvm.h | 1 +
2 files changed, 4 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 3256b9228e75..b7313ee028e9 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ARM_PMU_V3:
r = kvm_arm_support_pmu_v3();
break;
+ case KVM_CAP_ARM_RAS_EXTENSION:
+ r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
+ break;
case KVM_CAP_SET_GUEST_DEBUG:
case KVM_CAP_VCPU_ATTRIBUTES:
r = 1;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6cd63c18708a..5a2a338cae57 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -929,6 +929,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_PPC_SMT_POSSIBLE 147
#define KVM_CAP_HYPERV_SYNIC2 148
#define KVM_CAP_HYPERV_VP_INDEX 149
+#define KVM_CAP_ARM_RAS_EXTENSION 150

#ifdef KVM_CAP_IRQ_ROUTING

--
2.14.0

2017-08-18 13:51:38

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 3/7] acpi: apei: Add SEI notification type support for ARMv8

ARMV8.2 requires implementation of the RAS extension, in
this extension it adds SEI(SError Interrupt) notification
type, this patch addes a new GHES error source handling
function for SEI. Because this error source parse and handling
method are similar with the SEA. so use one function to handle
them.

In current code logic, The two functions ghes_sea_add() and
ghes_sea_remove() are only called when CONFIG_ACPI_APEI_SEA
and CONFIG_ACPI_APEI_SEI are defined. If not, it will return
errors in the ghes_probe() and do not continue, so remove the
useless code that handling CONFIG_ACPI_APEI_SEA and
CONFIG_ACPI_APEI_SEI do not defined.

Expose one API ghes_notify_sex() to external, external modules
can call this exposed APIs to parse and handling the SEA/SEI.

Signed-off-by: Dongjiu Geng <[email protected]>
---
arch/arm64/mm/fault.c | 21 +++++++++++++++--
drivers/acpi/apei/Kconfig | 15 ++++++++++++
drivers/acpi/apei/ghes.c | 60 ++++++++++++++++++++++++++++++-----------------
include/acpi/ghes.h | 2 +-
4 files changed, 74 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 2509e4fe6992..0aa92a69c280 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -585,7 +585,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
if (interrupts_enabled(regs))
nmi_enter();

- ret = ghes_notify_sea();
+ ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEA);

if (interrupts_enabled(regs))
nmi_exit();
@@ -682,7 +682,24 @@ int handle_guest_sea(phys_addr_t addr, unsigned int esr)
int ret = -ENOENT;

if (IS_ENABLED(CONFIG_ACPI_APEI_SEA))
- ret = ghes_notify_sea();
+ ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEA);
+
+ return ret;
+}
+
+/*
+ * Handle SError interrupt that occur in a guest kernel.
+ *
+ * The return value will be zero if the SEI was successfully handled
+ * and non-zero if there was an error processing the error or there was
+ * no error to process.
+ */
+int handle_guest_sei(phys_addr_t addr, unsigned int esr)
+{
+ int ret = -ENOENT;
+
+ if (IS_ENABLED(CONFIG_ACPI_APEI_SEI))
+ ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEI);

return ret;
}
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index de14d49a5c90..556370c763ec 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -54,6 +54,21 @@ config ACPI_APEI_SEA
option allows the OS to look for such hardware error record, and
take appropriate action.

+config ACPI_APEI_SEI
+ bool "APEI Asynchronous SError Interrupt logging/recovering support"
+ depends on ARM64 && ACPI_APEI_GHES
+ default y
+ help
+ This option should be enabled if the system supports
+ firmware first handling of SEI (asynchronous SError interrupt).
+
+ SEI happens with invalid instruction access or asynchronous exceptions
+ on ARMv8 systems. If a system supports firmware first handling of SEI,
+ the platform analyzes and handles hardware error notifications from
+ SEI, and it may then form a HW error record for the OS to parse and
+ handle. This option allows the OS to look for such hardware error
+ record, and take appropriate action.
+
config ACPI_APEI_MEMORY_FAILURE
bool "APEI memory error recovering support"
depends on ACPI_APEI && MEMORY_FAILURE
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index d661d452b238..705738aa48b8 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -813,20 +813,21 @@ static struct notifier_block ghes_notifier_hed = {
.notifier_call = ghes_notify_hed,
};

-#ifdef CONFIG_ACPI_APEI_SEA
static LIST_HEAD(ghes_sea);
+static LIST_HEAD(ghes_sei);

/*
* Return 0 only if one of the SEA error sources successfully reported an error
* record sent from the firmware.
*/
-int ghes_notify_sea(void)
+
+int ghes_handle_sex(struct list_head *head)
{
struct ghes *ghes;
int ret = -ENOENT;

rcu_read_lock();
- list_for_each_entry_rcu(ghes, &ghes_sea, list) {
+ list_for_each_entry_rcu(ghes, head, list) {
if (!ghes_proc(ghes))
ret = 0;
}
@@ -834,33 +835,41 @@ int ghes_notify_sea(void)
return ret;
}

-static void ghes_sea_add(struct ghes *ghes)
+int ghes_notify_sex(u8 type)
+{
+ if (type == ACPI_HEST_NOTIFY_SEA)
+ return ghes_handle_sex(&ghes_sea);
+ else if (type == ACPI_HEST_NOTIFY_SEI)
+ return ghes_handle_sex(&ghes_sei);
+
+ return -ENOENT;
+}
+
+/*
+ * This function is only called when the CONFIG_HAVE_ACPI_APEI_SEA or
+ * CONFIG_HAVE_ACPI_APEI_SEA is enabled. when disabled, it will return
+ * error in the ghes_probe
+ */
+static void ghes_sex_add(struct ghes *ghes)
{
+ u8 notify_type = ghes->generic->notify.type;
+
mutex_lock(&ghes_list_mutex);
- list_add_rcu(&ghes->list, &ghes_sea);
+ if (notify_type == ACPI_HEST_NOTIFY_SEA)
+ list_add_rcu(&ghes->list, &ghes_sea);
+ else if (notify_type == ACPI_HEST_NOTIFY_SEI)
+ list_add_rcu(&ghes->list, &ghes_sei);
+
mutex_unlock(&ghes_list_mutex);
}

-static void ghes_sea_remove(struct ghes *ghes)
+static void ghes_sex_remove(struct ghes *ghes)
{
mutex_lock(&ghes_list_mutex);
list_del_rcu(&ghes->list);
mutex_unlock(&ghes_list_mutex);
synchronize_rcu();
}
-#else /* CONFIG_ACPI_APEI_SEA */
-static inline void ghes_sea_add(struct ghes *ghes)
-{
- pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
- ghes->generic->header.source_id);
-}
-
-static inline void ghes_sea_remove(struct ghes *ghes)
-{
- pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
- ghes->generic->header.source_id);
-}
-#endif /* CONFIG_ACPI_APEI_SEA */

#ifdef CONFIG_HAVE_ACPI_APEI_NMI
/*
@@ -1107,6 +1116,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
goto err;
}
break;
+ case ACPI_HEST_NOTIFY_SEI:
+ if (!IS_ENABLED(CONFIG_ACPI_APEI_SEI)) {
+ pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEI is not supported!\n",
+ generic->header.source_id);
+ goto err;
+ }
+ break;
case ACPI_HEST_NOTIFY_NMI:
if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
@@ -1176,7 +1192,8 @@ static int ghes_probe(struct platform_device *ghes_dev)
break;

case ACPI_HEST_NOTIFY_SEA:
- ghes_sea_add(ghes);
+ case ACPI_HEST_NOTIFY_SEI:
+ ghes_sex_add(ghes);
break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_add(ghes);
@@ -1229,7 +1246,8 @@ static int ghes_remove(struct platform_device *ghes_dev)
break;

case ACPI_HEST_NOTIFY_SEA:
- ghes_sea_remove(ghes);
+ case ACPI_HEST_NOTIFY_SEI:
+ ghes_sex_remove(ghes);
break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_remove(ghes);
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 9061c5c743b3..41cbce1bc926 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -118,6 +118,6 @@ static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
(void *)section - (void *)(estatus + 1) < estatus->data_length; \
section = acpi_hest_get_next(section))

-int ghes_notify_sea(void);
+int ghes_notify_sex(u8 type);

#endif /* GHES_H */
--
2.14.0

2017-08-18 13:49:38

by Dongjiu Geng

[permalink] [raw]
Subject: [PATCH v5 6/7] KVM: arm64: Allow get exception information from userspace

when userspace gets SIGBUS signal, it does not know whether
this is a synchronous external abort or SError, so needs
to get the exception syndrome. so this patch allows userspace
can get this values. For syndrome, only give userspace
syndrome EC and ISS.

Now we move the synchronous external abort injection logic to
userspace, when userspace injects the SEA exception to guest
OS, it needs to specify the far_el1 value, so this patch give
the exception virtual address to user space.

Signed-off-by: Dongjiu Geng <[email protected]>
Signed-off-by: Quanming Wu <[email protected]>
---
arch/arm64/include/uapi/asm/kvm.h | 5 +++++
arch/arm64/kvm/guest.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)

diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 9f3ca24bbcc6..514261f682b8 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -181,6 +181,11 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0

+/* AArch64 fault registers */
+#define KVM_REG_ARM64_FAULT (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM64_FAULT_ESR_EC_ISS (0)
+#define KVM_REG_ARM64_FAULT_FAR (1)
+
#define ARM64_SYS_REG_SHIFT_MASK(x,n) \
(((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \
KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657dd207..cb383c310f18 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -128,6 +128,38 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
out:
return err;
}
+static int get_fault_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+ u32 ec, value;
+ u32 id = reg->id & ~(KVM_REG_ARCH_MASK |
+ KVM_REG_SIZE_MASK | KVM_REG_ARM64_FAULT);
+
+ switch (id) {
+ case KVM_REG_ARM64_FAULT_ESR_EC_ISS:
+ /* The user space needs to know the fault exception
+ * class field
+ */
+ ec = kvm_vcpu_get_hsr(vcpu) & ESR_ELx_EC_MASK;
+ value = ec | (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISS_MASK);
+
+ if (copy_to_user(uaddr, &value, KVM_REG_SIZE(reg->id)) != 0)
+ return -EFAULT;
+ break;
+ case KVM_REG_ARM64_FAULT_FAR:
+ /* when user space injects synchronized abort, it needs
+ * to inject the fault address.
+ */
+ if (copy_to_user(uaddr, &(vcpu->arch.fault.far_el2),
+ KVM_REG_SIZE(reg->id)) != 0)
+ return -EFAULT;
+ break;
+ default:
+ return -ENOENT;
+ }
+ return 0;
+}
+

int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
@@ -243,6 +275,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
return get_core_reg(vcpu, reg);

+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM64_FAULT)
+ return get_fault_reg(vcpu, reg);
+
if (is_timer_reg(reg->id))
return get_timer_reg(vcpu, reg);

--
2.14.0

2017-08-21 21:08:38

by Christoffer Dall

[permalink] [raw]
Subject: Re: [PATCH v5 4/7] support user space to query RAS extension feature

On Fri, Aug 18, 2017 at 10:11:54PM +0800, Dongjiu Geng wrote:

You should put KVM and arm64 in the subject here.

> In armv8.2 RAS extension, it adds virtual SError exception
> syndrome registeri(VSESR_EL2), user space will specify that
> value. so user space will check whether CPU feature has RAS
> extension. if has, it will specify the virtual SError syndrome
> value. Otherwise, it will not set. This patch adds this support
>
> Signed-off-by: Dongjiu Geng <[email protected]>
> ---
> arch/arm64/kvm/reset.c | 3 +++
> include/uapi/linux/kvm.h | 1 +
> 2 files changed, 4 insertions(+)
>
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 3256b9228e75..b7313ee028e9 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
> case KVM_CAP_ARM_PMU_V3:
> r = kvm_arm_support_pmu_v3();
> break;
> + case KVM_CAP_ARM_RAS_EXTENSION:
> + r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
> + break;
> case KVM_CAP_SET_GUEST_DEBUG:
> case KVM_CAP_VCPU_ATTRIBUTES:
> r = 1;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6cd63c18708a..5a2a338cae57 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -929,6 +929,7 @@ struct kvm_ppc_resize_hpt {
> #define KVM_CAP_PPC_SMT_POSSIBLE 147
> #define KVM_CAP_HYPERV_SYNIC2 148
> #define KVM_CAP_HYPERV_VP_INDEX 149
> +#define KVM_CAP_ARM_RAS_EXTENSION 150
>
> #ifdef KVM_CAP_IRQ_ROUTING
>
> --
> 2.14.0
>

Thanks,
-Christoffer

2017-08-22 01:25:21

by Dongjiu Geng

[permalink] [raw]
Subject: Re: [PATCH v5 4/7] support user space to query RAS extension feature

Christoffer,
Thanks for the review.

On 2017/8/22 5:08, Christoffer Dall wrote:
> On Fri, Aug 18, 2017 at 10:11:54PM +0800, Dongjiu Geng wrote:
>
> You should put KVM and arm64 in the subject here.
I will update it in the next version.


>
>> In armv8.2 RAS extension, it adds virtual SError exception
>> syndrome registeri(VSESR_EL2), user space will specify that
>> value. so user space will check whether CPU feature has RAS
>> extension. if has, it will specify the virtual SError syndrome
>> value. Otherwise, it will not set. This patch adds this support
>>
>> Signed-off-by: Dongjiu Geng <[email protected]>
>> ---
>> arch/arm64/kvm/reset.c | 3 +++
>> include/uapi/linux/kvm.h | 1 +
>> 2 files changed, 4 insertions(+)
>>
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 3256b9228e75..b7313ee028e9 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>> case KVM_CAP_ARM_PMU_V3:
>> r = kvm_arm_support_pmu_v3();
>> break;
>> + case KVM_CAP_ARM_RAS_EXTENSION:
>> + r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
>> + break;
>> case KVM_CAP_SET_GUEST_DEBUG:
>> case KVM_CAP_VCPU_ATTRIBUTES:
>> r = 1;
>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> index 6cd63c18708a..5a2a338cae57 100644
>> --- a/include/uapi/linux/kvm.h
>> +++ b/include/uapi/linux/kvm.h
>> @@ -929,6 +929,7 @@ struct kvm_ppc_resize_hpt {
>> #define KVM_CAP_PPC_SMT_POSSIBLE 147
>> #define KVM_CAP_HYPERV_SYNIC2 148
>> #define KVM_CAP_HYPERV_VP_INDEX 149
>> +#define KVM_CAP_ARM_RAS_EXTENSION 150
>>
>> #ifdef KVM_CAP_IRQ_ROUTING
>>
>> --
>> 2.14.0
>>
>
> Thanks,
> -Christoffer
>
> .
>

2017-08-22 07:55:15

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 0/7] Add RAS virtualization support to SEA/SEI notification type

On Fri, 18 Aug 2017 22:11:50 +0800
Dongjiu Geng <[email protected]> wrote:

> In the firmware-first RAS solution, corrupt data is detected in a
> memory location when guest OS application software executing at EL0
> or guest OS kernel El1 software are reading from the memory. The
> memory node records errors in an error record accessible using
> system registers.
>
> Because SCR_EL3.EA is 1, then CPU will trap to El3 firmware, EL3
> firmware records the error to APEI table through reading system
> register.
>
> Because the error was taken from a lower Exception leve, if the

leve -> level

> exception is SEA/SEI and HCR_EL2.TEA/HCR_EL2.AMO is 1, firmware
> sets ESR_EL2/FAR_El to fake a exception trap to EL2, then
> transfers to hypervisor.
>
> Hypervisor calls the momory failure to deal with this error, momory

momory -> memory

memory failure -> memory failure function? Or callback perhaps?

> failure read the APEI table and decide whether it needs to deliver
> SIGBUS signal to user space, the advantage of using SIGBUS signal
> to notify user space is that it can be compatible Non-Kvm users.

Seems like a good description to me. Thanks.

Jonathan

>
> Dongjiu Geng (5):
> acpi: apei: Add SEI notification type support for ARMv8
> support user space to query RAS extension feature
> arm64: kvm: route synchronous external abort exceptions to el2
> KVM: arm/arm64: Allow get exception syndrome and
> arm64: kvm: handle SEI notification and inject virtual SError
>
> James Morse (1):
> KVM: arm64: Save ESR_EL2 on guest SError
>
> Xie XiuQi (1):
> arm64: cpufeature: Detect CPU RAS Extentions
>
> arch/arm/include/asm/kvm_host.h | 2 ++
> arch/arm/kvm/guest.c | 5 +++
> arch/arm64/Kconfig | 16 ++++++++++
> arch/arm64/include/asm/barrier.h | 1 +
> arch/arm64/include/asm/cpucaps.h | 3 +-
> arch/arm64/include/asm/kvm_arm.h | 2 ++
> arch/arm64/include/asm/kvm_emulate.h | 17 ++++++++++
> arch/arm64/include/asm/kvm_host.h | 2 ++
> arch/arm64/include/asm/sysreg.h | 5 +++
> arch/arm64/include/asm/system_misc.h | 1 +
> arch/arm64/include/uapi/asm/kvm.h | 5 +++
> arch/arm64/kernel/cpufeature.c | 13 ++++++++
> arch/arm64/kernel/process.c | 3 ++
> arch/arm64/kvm/guest.c | 48 +++++++++++++++++++++++++++++
> arch/arm64/kvm/handle_exit.c | 21 +++++++++++--
> arch/arm64/kvm/hyp/switch.c | 29 +++++++++++++++--
> arch/arm64/kvm/reset.c | 3 ++
> arch/arm64/mm/fault.c | 21 +++++++++++--
> drivers/acpi/apei/Kconfig | 15 +++++++++
> drivers/acpi/apei/ghes.c | 60 +++++++++++++++++++++++-------------
> include/acpi/ghes.h | 2 +-
> include/uapi/linux/kvm.h | 3 ++
> virt/kvm/arm/arm.c | 7 +++++
> 23 files changed, 254 insertions(+), 30 deletions(-)
>

2017-08-22 07:56:00

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 1/7] arm64: cpufeature: Detect CPU RAS Extentions

On Fri, 18 Aug 2017 22:11:51 +0800
Dongjiu Geng <[email protected]> wrote:

> From: Xie XiuQi <[email protected]>
>
> ARM's v8.2 Extentions add support for Reliability, Availability and
> Serviceability (RAS). On CPUs with these extensions system software

extensions, system software

> can use additional barriers to isolate errors and determine if faults
> are pending.
>
> Add cpufeature detection and a barrier in the context-switch code.
> There is no need to use alternatives for this as CPUs that don't
> support this feature will treat the instruction as a nop.
>
> Platform level RAS support may require additional firmware support.
>
> Signed-off-by: Xie XiuQi <[email protected]>
> [Rebased, added esb and config option, reworded commit message]
> Signed-off-by: James Morse <[email protected]>
> ---
> arch/arm64/Kconfig | 16 ++++++++++++++++
> arch/arm64/include/asm/barrier.h | 1 +
> arch/arm64/include/asm/cpucaps.h | 3 ++-
> arch/arm64/include/asm/sysreg.h | 2 ++
> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++
> arch/arm64/kernel/process.c | 3 +++
> 6 files changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index dfd908630631..4d87aa963d83 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -960,6 +960,22 @@ config ARM64_UAO
> regular load/store instructions if the cpu does not implement the
> feature.
>
> +config ARM64_RAS_EXTN
> + bool "Enable support for RAS CPU Extensions"
> + default y
> + help
> + CPUs that support the Reliability, Availability and Serviceability
> + (RAS) Extensions, part of ARMv8.2 are able to track faults and
> + errors, classify them and report them to software.
> +
> + On CPUs with these extensions system software can use additional
> + barriers to determine if faults are pending and read the
> + classification from a new set of registers.
> +
> + Selecting this feature will allow the kernel to use these barriers
> + and access the new registers if the system supports the extension.
> + Platform RAS features may additionally depend on firmware support.
> +
> endmenu
>
> config ARM64_MODULE_CMODEL_LARGE
> diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
> index 0fe7e43b7fbc..8b0a0eb67625 100644
> --- a/arch/arm64/include/asm/barrier.h
> +++ b/arch/arm64/include/asm/barrier.h
> @@ -30,6 +30,7 @@
> #define isb() asm volatile("isb" : : : "memory")
> #define dmb(opt) asm volatile("dmb " #opt : : : "memory")
> #define dsb(opt) asm volatile("dsb " #opt : : : "memory")
> +#define esb() asm volatile("hint #16" : : : "memory")
>
> #define mb() dsb(sy)
> #define rmb() dsb(ld)
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index 8d2272c6822c..f93bf77f1f74 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -39,7 +39,8 @@
> #define ARM64_WORKAROUND_QCOM_FALKOR_E1003 18
> #define ARM64_WORKAROUND_858921 19
> #define ARM64_WORKAROUND_CAVIUM_30115 20
> +#define ARM64_HAS_RAS_EXTN 21
>
> -#define ARM64_NCAPS 21
> +#define ARM64_NCAPS 22
>
> #endif /* __ASM_CPUCAPS_H */
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 248339e4aaf5..35b786b43ee4 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -331,6 +331,7 @@
> #define ID_AA64ISAR1_JSCVT_SHIFT 12
>
> /* id_aa64pfr0 */
> +#define ID_AA64PFR0_RAS_SHIFT 28
> #define ID_AA64PFR0_GIC_SHIFT 24
> #define ID_AA64PFR0_ASIMD_SHIFT 20
> #define ID_AA64PFR0_FP_SHIFT 16
> @@ -339,6 +340,7 @@
> #define ID_AA64PFR0_EL1_SHIFT 4
> #define ID_AA64PFR0_EL0_SHIFT 0
>
> +#define ID_AA64PFR0_RAS_V1 0x1
> #define ID_AA64PFR0_FP_NI 0xf
> #define ID_AA64PFR0_FP_SUPPORTED 0x0
> #define ID_AA64PFR0_ASIMD_NI 0xf
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 9f9e0064c8c1..a807ab55ee10 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -124,6 +124,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
> };
>
> static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
> + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_RAS_SHIFT, 4, 0),
> ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
> S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
> S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
> @@ -888,6 +889,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
> .min_field_value = 0,
> .matches = has_no_fpsimd,
> },
> +#ifdef CONFIG_ARM64_RAS_EXTN
> + {
> + .desc = "RAS Extension Support",
> + .capability = ARM64_HAS_RAS_EXTN,
> + .def_scope = SCOPE_SYSTEM,
> + .matches = has_cpuid_feature,
> + .sys_reg = SYS_ID_AA64PFR0_EL1,
> + .sign = FTR_UNSIGNED,
> + .field_pos = ID_AA64PFR0_RAS_SHIFT,
> + .min_field_value = ID_AA64PFR0_RAS_V1,
> + },
> +#endif /* CONFIG_ARM64_RAS_EXTN */
> {},
> };
>
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index 659ae8094ed5..2def5ce75867 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -363,6 +363,9 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
> */
> dsb(ish);
>
> + /* Deliver any pending SError from prev */
> + esb();
> +
> /* the actual thread switch */
> last = cpu_switch_to(prev, next);
>

2017-08-22 07:59:01

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 3/7] acpi: apei: Add SEI notification type support for ARMv8

On Fri, 18 Aug 2017 22:11:53 +0800
Dongjiu Geng <[email protected]> wrote:

> ARMV8.2 requires implementation of the RAS extension, in
> this extension it adds SEI(SError Interrupt) notification
> type, this patch addes a new GHES error source handling
> function for SEI. Because this error source parse and handling
> method are similar with the SEA. so use one function to handle
> them.

Because the error source parsing and handling methods are similar
to that for the SEA, use one function to handle both.

>
> In current code logic, The two functions ghes_sea_add() and

No capital after ,

> ghes_sea_remove() are only called when CONFIG_ACPI_APEI_SEA
> and CONFIG_ACPI_APEI_SEI are defined. If not, it will return
> errors in the ghes_probe() and do not continue, so remove the
> useless code that handling CONFIG_ACPI_APEI_SEA and
> CONFIG_ACPI_APEI_SEI do not defined.

If not, it will return errors in the ghes_probe() and not contiue.
Hence, remove the unnecessary handling when CONFIG_ACPI_APEI_SEA
and CONFIG_ACPI_APEI_SEI are not defined.

>
> Expose one API ghes_notify_sex() to external, external modules
> can call this exposed APIs to parse and handling the SEA/SEI.

Expose one API ghes_notify_sec() to external users. External modules...
>
> Signed-off-by: Dongjiu Geng <[email protected]>

Some really trivial suggestions inline. Feel free to ignore them as
they are a matter of personal taste.

Jonathan

> ---
> arch/arm64/mm/fault.c | 21 +++++++++++++++--
> drivers/acpi/apei/Kconfig | 15 ++++++++++++
> drivers/acpi/apei/ghes.c | 60 ++++++++++++++++++++++++++++++-----------------
> include/acpi/ghes.h | 2 +-
> 4 files changed, 74 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 2509e4fe6992..0aa92a69c280 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -585,7 +585,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
> if (interrupts_enabled(regs))
> nmi_enter();
>
> - ret = ghes_notify_sea();
> + ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEA);
>
> if (interrupts_enabled(regs))
> nmi_exit();
> @@ -682,7 +682,24 @@ int handle_guest_sea(phys_addr_t addr, unsigned int esr)
> int ret = -ENOENT;
>
> if (IS_ENABLED(CONFIG_ACPI_APEI_SEA))
> - ret = ghes_notify_sea();
> + ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEA);
> +
> + return ret;
> +}
> +
> +/*
> + * Handle SError interrupt that occur in a guest kernel.
> + *
> + * The return value will be zero if the SEI was successfully handled
> + * and non-zero if there was an error processing the error or there was
> + * no error to process.
> + */
> +int handle_guest_sei(phys_addr_t addr, unsigned int esr)
> +{
> + int ret = -ENOENT;
> +
> + if (IS_ENABLED(CONFIG_ACPI_APEI_SEI))
> + ret = ghes_notify_sex(ACPI_HEST_NOTIFY_SEI);
>
> return ret;
> }
> diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
> index de14d49a5c90..556370c763ec 100644
> --- a/drivers/acpi/apei/Kconfig
> +++ b/drivers/acpi/apei/Kconfig
> @@ -54,6 +54,21 @@ config ACPI_APEI_SEA
> option allows the OS to look for such hardware error record, and
> take appropriate action.
>
> +config ACPI_APEI_SEI
> + bool "APEI Asynchronous SError Interrupt logging/recovering support"
> + depends on ARM64 && ACPI_APEI_GHES
> + default y
> + help
> + This option should be enabled if the system supports
> + firmware first handling of SEI (asynchronous SError interrupt).
> +
> + SEI happens with invalid instruction access or asynchronous exceptions
> + on ARMv8 systems. If a system supports firmware first handling of SEI,
> + the platform analyzes and handles hardware error notifications from
> + SEI, and it may then form a HW error record for the OS to parse and
> + handle. This option allows the OS to look for such hardware error
> + record, and take appropriate action.
> +
> config ACPI_APEI_MEMORY_FAILURE
> bool "APEI memory error recovering support"
> depends on ACPI_APEI && MEMORY_FAILURE
> diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
> index d661d452b238..705738aa48b8 100644
> --- a/drivers/acpi/apei/ghes.c
> +++ b/drivers/acpi/apei/ghes.c
> @@ -813,20 +813,21 @@ static struct notifier_block ghes_notifier_hed = {
> .notifier_call = ghes_notify_hed,
> };
>
> -#ifdef CONFIG_ACPI_APEI_SEA
> static LIST_HEAD(ghes_sea);
> +static LIST_HEAD(ghes_sei);
>
> /*
> * Return 0 only if one of the SEA error sources successfully reported an error
> * record sent from the firmware.
> */
> -int ghes_notify_sea(void)
> +
> +int ghes_handle_sex(struct list_head *head)
> {
> struct ghes *ghes;
> int ret = -ENOENT;
>
> rcu_read_lock();
> - list_for_each_entry_rcu(ghes, &ghes_sea, list) {
> + list_for_each_entry_rcu(ghes, head, list) {
> if (!ghes_proc(ghes))
> ret = 0;
> }
> @@ -834,33 +835,41 @@ int ghes_notify_sea(void)
> return ret;
> }
>
> -static void ghes_sea_add(struct ghes *ghes)
> +int ghes_notify_sex(u8 type)
> +{
> + if (type == ACPI_HEST_NOTIFY_SEA)
> + return ghes_handle_sex(&ghes_sea);
> + else if (type == ACPI_HEST_NOTIFY_SEI)

No real need for the else. If there is potential that additional
elements may be added in here in future, it might be best to go
straight to a switch statement.


> + return ghes_handle_sex(&ghes_sei);
> +
> + return -ENOENT;
> +}
> +
> +/*
> + * This function is only called when the CONFIG_HAVE_ACPI_APEI_SEA or
> + * CONFIG_HAVE_ACPI_APEI_SEA is enabled. when disabled, it will return
> + * error in the ghes_probe
> + */
> +static void ghes_sex_add(struct ghes *ghes)
> {
> + u8 notify_type = ghes->generic->notify.type;
> +
> mutex_lock(&ghes_list_mutex);
> - list_add_rcu(&ghes->list, &ghes_sea);
> + if (notify_type == ACPI_HEST_NOTIFY_SEA)
> + list_add_rcu(&ghes->list, &ghes_sea);
> + else if (notify_type == ACPI_HEST_NOTIFY_SEI)
> + list_add_rcu(&ghes->list, &ghes_sei);

Again, perhaps a switch statement would be slightly cleaner?

> +
> mutex_unlock(&ghes_list_mutex);
> }
>
> -static void ghes_sea_remove(struct ghes *ghes)
> +static void ghes_sex_remove(struct ghes *ghes)
> {
> mutex_lock(&ghes_list_mutex);
> list_del_rcu(&ghes->list);
> mutex_unlock(&ghes_list_mutex);
> synchronize_rcu();
> }
> -#else /* CONFIG_ACPI_APEI_SEA */
> -static inline void ghes_sea_add(struct ghes *ghes)
> -{
> - pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
> - ghes->generic->header.source_id);
> -}
> -
> -static inline void ghes_sea_remove(struct ghes *ghes)
> -{
> - pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
> - ghes->generic->header.source_id);
> -}
> -#endif /* CONFIG_ACPI_APEI_SEA */
>
> #ifdef CONFIG_HAVE_ACPI_APEI_NMI
> /*
> @@ -1107,6 +1116,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
> goto err;
> }
> break;
> + case ACPI_HEST_NOTIFY_SEI:
> + if (!IS_ENABLED(CONFIG_ACPI_APEI_SEI)) {
> + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEI is not supported!\n",
> + generic->header.source_id);
> + goto err;
> + }
> + break;
> case ACPI_HEST_NOTIFY_NMI:
> if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
> pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
> @@ -1176,7 +1192,8 @@ static int ghes_probe(struct platform_device *ghes_dev)
> break;
>
> case ACPI_HEST_NOTIFY_SEA:
> - ghes_sea_add(ghes);
> + case ACPI_HEST_NOTIFY_SEI:
> + ghes_sex_add(ghes);
> break;
> case ACPI_HEST_NOTIFY_NMI:
> ghes_nmi_add(ghes);
> @@ -1229,7 +1246,8 @@ static int ghes_remove(struct platform_device *ghes_dev)
> break;
>
> case ACPI_HEST_NOTIFY_SEA:
> - ghes_sea_remove(ghes);
> + case ACPI_HEST_NOTIFY_SEI:
> + ghes_sex_remove(ghes);
> break;
> case ACPI_HEST_NOTIFY_NMI:
> ghes_nmi_remove(ghes);
> diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
> index 9061c5c743b3..41cbce1bc926 100644
> --- a/include/acpi/ghes.h
> +++ b/include/acpi/ghes.h
> @@ -118,6 +118,6 @@ static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
> (void *)section - (void *)(estatus + 1) < estatus->data_length; \
> section = acpi_hest_get_next(section))
>
> -int ghes_notify_sea(void);
> +int ghes_notify_sex(u8 type);
>
> #endif /* GHES_H */

2017-08-22 07:59:24

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 6/7] KVM: arm64: Allow get exception information from userspace

On Fri, 18 Aug 2017 22:11:56 +0800
Dongjiu Geng <[email protected]> wrote:

> when userspace gets SIGBUS signal, it does not know whether
> this is a synchronous external abort or SError, so needs
> to get the exception syndrome. so this patch allows userspace
> can get this values. For syndrome, only give userspace
> syndrome EC and ISS.
>
> Now we move the synchronous external abort injection logic to
> userspace, when userspace injects the SEA exception to guest
> OS, it needs to specify the far_el1 value, so this patch give
> the exception virtual address to user space.
>
> Signed-off-by: Dongjiu Geng <[email protected]>
> Signed-off-by: Quanming Wu <[email protected]>

A couple of really trivial formatting points inline.

> ---
> arch/arm64/include/uapi/asm/kvm.h | 5 +++++
> arch/arm64/kvm/guest.c | 35 +++++++++++++++++++++++++++++++++++
> 2 files changed, 40 insertions(+)
>
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9f3ca24bbcc6..514261f682b8 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -181,6 +181,11 @@ struct kvm_arch_memory_slot {
> #define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
> #define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
>
> +/* AArch64 fault registers */
> +#define KVM_REG_ARM64_FAULT (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
> +#define KVM_REG_ARM64_FAULT_ESR_EC_ISS (0)
> +#define KVM_REG_ARM64_FAULT_FAR (1)
> +
> #define ARM64_SYS_REG_SHIFT_MASK(x,n) \
> (((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \
> KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 5c7f657dd207..cb383c310f18 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -128,6 +128,38 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> out:
> return err;
> }
> +static int get_fault_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> + void __user *uaddr = (void __user *)(unsigned long)reg->addr;
> + u32 ec, value;
> + u32 id = reg->id & ~(KVM_REG_ARCH_MASK |
> + KVM_REG_SIZE_MASK | KVM_REG_ARM64_FAULT);
> +
> + switch (id) {
> + case KVM_REG_ARM64_FAULT_ESR_EC_ISS:
> + /* The user space needs to know the fault exception
> + * class field
> + */

The rest of this file uses the multiline comment syntax
/*
* The user...
*/

> + ec = kvm_vcpu_get_hsr(vcpu) & ESR_ELx_EC_MASK;
> + value = ec | (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISS_MASK);
Same as

value = kvm_vpcu_get_hsr(vcpu) & (ESR_ELx_EC_MASK | ESR_ELx_ISS_MASK);

?

> +
> + if (copy_to_user(uaddr, &value, KVM_REG_SIZE(reg->id)) != 0)
> + return -EFAULT;
> + break;
> + case KVM_REG_ARM64_FAULT_FAR:
> + /* when user space injects synchronized abort, it needs
> + * to inject the fault address.
> + */

Again, multiline comment syntax.

> + if (copy_to_user(uaddr, &(vcpu->arch.fault.far_el2),
> + KVM_REG_SIZE(reg->id)) != 0)
> + return -EFAULT;
> + break;
> + default:
> + return -ENOENT;
> + }
> + return 0;
> +}
> +
>
> int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> {
> @@ -243,6 +275,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> return get_core_reg(vcpu, reg);
>
> + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM64_FAULT)
> + return get_fault_reg(vcpu, reg);
> +
> if (is_timer_reg(reg->id))
> return get_timer_reg(vcpu, reg);
>

2017-08-22 07:59:34

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 7/7] arm64: kvm: handle SEI notification and inject virtual SError

On Fri, 18 Aug 2017 22:11:57 +0800
Dongjiu Geng <[email protected]> wrote:

> After receive SError, KVM firstly call memory failure to
> deal with the Error. If memory failure wants user space to
> handle it, it will notify user space. This patch adds support
> to userspace that injects virtual SError with specified
> syndrome. This syndrome value will be set to the VSESR_EL2.
> VSESR_EL2 is a new RAS extensions register which provides the
> syndrome value reported to software on taking a virtual SError
> interrupt exception.
>
> Signed-off-by: Dongjiu Geng <[email protected]>
> Signed-off-by: Quanming Wu <[email protected]>

Content seems fine, some real nitpicks inline.

> ---
> arch/arm/include/asm/kvm_host.h | 2 ++
> arch/arm/kvm/guest.c | 5 +++++
> arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
> arch/arm64/include/asm/kvm_host.h | 2 ++
> arch/arm64/include/asm/sysreg.h | 3 +++
> arch/arm64/include/asm/system_misc.h | 1 +
> arch/arm64/kvm/guest.c | 13 +++++++++++++
> arch/arm64/kvm/handle_exit.c | 21 +++++++++++++++++++--
> arch/arm64/kvm/hyp/switch.c | 14 ++++++++++++++
> include/uapi/linux/kvm.h | 2 ++
> virt/kvm/arm/arm.c | 7 +++++++
> 11 files changed, 78 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 127e2dd2e21c..bdb6ea690257 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -244,6 +244,8 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
> int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
> int exception_index);
>
> +int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome);
> +
> static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> unsigned long hyp_stack_ptr,
> unsigned long vector_ptr)
> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
> index 1e0784ebbfd6..c23df72d9bec 100644
> --- a/arch/arm/kvm/guest.c
> +++ b/arch/arm/kvm/guest.c
> @@ -248,6 +248,11 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
> return -EINVAL;
> }
>

Perhaps a comment here on why the stub doesn't do anything?
Obvious in the context of this patch, but perhaps not when someone is looking
at this out of context.

> +int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome)
> +{
> + return 0;
> +}
> +
> int __attribute_const__ kvm_target_cpu(void)
> {
> switch (read_cpuid_part()) {
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 47983db27de2..74213bd539dc 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -155,6 +155,16 @@ static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
> return vcpu->arch.fault.esr_el2;
> }
>
> +static inline u32 kvm_vcpu_get_vsesr(const struct kvm_vcpu *vcpu)
> +{
> + return vcpu->arch.fault.vsesr_el2;
> +}
> +
> +static inline void kvm_vcpu_set_vsesr(struct kvm_vcpu *vcpu, unsigned long val)
> +{
> + vcpu->arch.fault.vsesr_el2 = val;
> +}
> +
> static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
> {
> u32 esr = kvm_vcpu_get_hsr(vcpu);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index d68630007b14..57b011261597 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -88,6 +88,7 @@ struct kvm_vcpu_fault_info {
> u32 esr_el2; /* Hyp Syndrom Register */
> u64 far_el2; /* Hyp Fault Address Register */
> u64 hpfar_el2; /* Hyp IPA Fault Address Register */
> + u32 vsesr_el2; /* Virtual SError Exception Syndrome Register */
> };
>
> /*
> @@ -381,6 +382,7 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
> struct kvm_device_attr *attr);
> int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
> struct kvm_device_attr *attr);
> +int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome);
>
> static inline void __cpu_init_stage2(void)
> {
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 35b786b43ee4..06059eef0f5d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -86,6 +86,9 @@
> #define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4)
> #define REG_PSTATE_UAO_IMM sys_reg(0, 0, 4, 0, 3)
>
> +/* virtual SError exception syndrome register in armv8.2 */
> +#define REG_VSESR_EL2 sys_reg(3, 4, 5, 2, 3)
> +
> #define SET_PSTATE_PAN(x) __emit_inst(0xd5000000 | REG_PSTATE_PAN_IMM | \
> (!!x)<<8 | 0x1f)
> #define SET_PSTATE_UAO(x) __emit_inst(0xd5000000 | REG_PSTATE_UAO_IMM | \
> diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
> index 07aa8e3c5630..7d07aeb02bc4 100644
> --- a/arch/arm64/include/asm/system_misc.h
> +++ b/arch/arm64/include/asm/system_misc.h
> @@ -57,6 +57,7 @@ extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
> })
>
> int handle_guest_sea(phys_addr_t addr, unsigned int esr);
> +int handle_guest_sei(phys_addr_t addr, unsigned int esr);
>
> #endif /* __ASSEMBLY__ */
>
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index cb383c310f18..3cbe91e76c0e 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -312,6 +312,19 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
> return -EINVAL;
> }
>
> +int kvm_vcpu_ioctl_sei(struct kvm_vcpu *vcpu, u64 *syndrome)
> +{
> + u64 reg = *syndrome;
> +
> + if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && reg)
> + /* set vsesr_el2[24:0] with value that user space specified */
> + kvm_vcpu_set_vsesr(vcpu, reg & ESR_ELx_ISS_MASK);
> +
> + /* inject virtual system Error or asynchronous abort */
> + kvm_inject_vabt(vcpu);

Nitpick, but blank line here would make it ever so slightly more readable.

> + return 0;
> +}
> +
> int __attribute_const__ kvm_target_cpu(void)
> {
> unsigned long implementor = read_cpuid_implementor();
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index 17d8a1677a0b..7ddeff30c7b9 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -28,6 +28,7 @@
> #include <asm/kvm_emulate.h>
> #include <asm/kvm_mmu.h>
> #include <asm/kvm_psci.h>
> +#include <asm/system_misc.h>
>
> #define CREATE_TRACE_POINTS
> #include "trace.h"
> @@ -178,6 +179,22 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
> return arm_exit_handlers[hsr_ec];
> }
>
> +static int kvm_handle_guest_sei(struct kvm_vcpu *vcpu)
> +{
> + unsigned long fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
> +
> + if (handle_guest_sei((unsigned long)fault_ipa,
> + kvm_vcpu_get_hsr(vcpu))) {
> + kvm_err("Failed to handle guest SEI, 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));
> +
> + kvm_inject_vabt(vcpu);
> + }

Again, ever so slightly more readable with a blank line here.

> + return 0;
> +}
> +
> /*
> * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
> * proper exit to userspace.
> @@ -201,7 +218,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
> *vcpu_pc(vcpu) -= adj;
> }
>
> - kvm_inject_vabt(vcpu);
> + kvm_handle_guest_sei(vcpu);
> return 1;
> }
>
> @@ -211,7 +228,7 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
> case ARM_EXCEPTION_IRQ:
> return 1;
> case ARM_EXCEPTION_EL1_SERROR:
> - kvm_inject_vabt(vcpu);
> + kvm_handle_guest_sei(vcpu);
> return 1;
> case ARM_EXCEPTION_TRAP:
> /*
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index c6f17c7675ad..a73346141cf3 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -42,6 +42,13 @@ bool __hyp_text __fpsimd_enabled(void)
> return __fpsimd_is_enabled()();
> }
>
> +static void __hyp_text __sysreg_set_vsesr(struct kvm_vcpu *vcpu)
> +{
> + if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) &&
> + (vcpu->arch.hcr_el2 & HCR_VSE))
> + write_sysreg_s(vcpu->arch.fault.vsesr_el2, REG_VSESR_EL2);
> +}
> +
> static void __hyp_text __activate_traps_vhe(void)
> {
> u64 val;
> @@ -86,6 +93,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> isb();
> }
> write_sysreg(val, hcr_el2);
> +
> + /*
> + * If the virtual SError interrupt is taken to EL1 using AArch64,
> + * then VSESR_EL2 provides the syndrome value reported in ESR_EL1.
> + */
> + __sysreg_set_vsesr(vcpu);
> +
> /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> write_sysreg(1 << 15, hstr_el2);
> /*
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 5a2a338cae57..d3fa4c60c9dc 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1356,6 +1356,8 @@ struct kvm_s390_ucas_mapping {
> /* Available with KVM_CAP_S390_CMMA_MIGRATION */
> #define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
> #define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
> +#define KVM_ARM_SEI _IO(KVMIO, 0xb10)
> +
>
> #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
> #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index a39a1e161e63..dbaaf206ace2 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -1022,6 +1022,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> return -EFAULT;
> return kvm_arm_vcpu_has_attr(vcpu, &attr);
> }
> + case KVM_ARM_SEI: {
> + u64 syndrome;
> +
> + if (copy_from_user(&syndrome, argp, sizeof(syndrome)))
> + return -EFAULT;
> + return kvm_vcpu_ioctl_sei(vcpu, &syndrome);
> + }
> default:
> return -EINVAL;
> }

2017-08-22 08:00:57

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH v5 4/7] support user space to query RAS extension feature

On Fri, 18 Aug 2017 22:11:54 +0800
Dongjiu Geng <[email protected]> wrote:

> In armv8.2 RAS extension, it adds virtual SError exception
> syndrome registeri(VSESR_EL2), user space will specify that
> value. so user space will check whether CPU feature has RAS
> extension. if has, it will specify the virtual SError syndrome
> value. Otherwise, it will not set. This patch adds this support

In the armv8.2 RAS extension, a virtual SError exception syndrome
registeri(VSESR_EL) is added. This value may be specified from userspace.
Userspace will want to check if the CPU has the RAS extension.
If it has, it wil specify the virtual SError syndrome value, otherwise
it will not be set. This patch adds support for querying the availability
of this extension.

Code is fine.
>
> Signed-off-by: Dongjiu Geng <[email protected]>
> ---
> arch/arm64/kvm/reset.c | 3 +++
> include/uapi/linux/kvm.h | 1 +
> 2 files changed, 4 insertions(+)
>
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 3256b9228e75..b7313ee028e9 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
> case KVM_CAP_ARM_PMU_V3:
> r = kvm_arm_support_pmu_v3();
> break;
> + case KVM_CAP_ARM_RAS_EXTENSION:
> + r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
> + break;
> case KVM_CAP_SET_GUEST_DEBUG:
> case KVM_CAP_VCPU_ATTRIBUTES:
> r = 1;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6cd63c18708a..5a2a338cae57 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -929,6 +929,7 @@ struct kvm_ppc_resize_hpt {
> #define KVM_CAP_PPC_SMT_POSSIBLE 147
> #define KVM_CAP_HYPERV_SYNIC2 148
> #define KVM_CAP_HYPERV_VP_INDEX 149
> +#define KVM_CAP_ARM_RAS_EXTENSION 150
>
> #ifdef KVM_CAP_IRQ_ROUTING
>

2017-08-23 02:08:49

by Dongjiu Geng

[permalink] [raw]
Subject: Re: [PATCH v5 0/7] Add RAS virtualization support to SEA/SEI notification type

Jonathan,
Thanks for the review, will correct the typo issue in the next patch version.


On 2017/8/22 15:54, Jonathan Cameron wrote:
> On Fri, 18 Aug 2017 22:11:50 +0800
> Dongjiu Geng <[email protected]> wrote:
>
>> In the firmware-first RAS solution, corrupt data is detected in a
>> memory location when guest OS application software executing at EL0
>> or guest OS kernel El1 software are reading from the memory. The
>> memory node records errors in an error record accessible using
>> system registers.
>>
>> Because SCR_EL3.EA is 1, then CPU will trap to El3 firmware, EL3
>> firmware records the error to APEI table through reading system
>> register.
>>
>> Because the error was taken from a lower Exception leve, if the
>
> leve -> level
>
>> exception is SEA/SEI and HCR_EL2.TEA/HCR_EL2.AMO is 1, firmware
>> sets ESR_EL2/FAR_El to fake a exception trap to EL2, then
>> transfers to hypervisor.
>>
>> Hypervisor calls the momory failure to deal with this error, momory
>
> momory -> memory
>
> memory failure -> memory failure function? Or callback perhaps?
>
>> failure read the APEI table and decide whether it needs to deliver
>> SIGBUS signal to user space, the advantage of using SIGBUS signal
>> to notify user space is that it can be compatible Non-Kvm users.
>
> Seems like a good description to me. Thanks.
>
> Jonathan
>
>>
>> Dongjiu Geng (5):
>> acpi: apei: Add SEI notification type support for ARMv8
>> support user space to query RAS extension feature
>> arm64: kvm: route synchronous external abort exceptions to el2
>> KVM: arm/arm64: Allow get exception syndrome and
>> arm64: kvm: handle SEI notification and inject virtual SError
>>
>> James Morse (1):
>> KVM: arm64: Save ESR_EL2 on guest SError
>>
>> Xie XiuQi (1):
>> arm64: cpufeature: Detect CPU RAS Extentions
>>
>> arch/arm/include/asm/kvm_host.h | 2 ++
>> arch/arm/kvm/guest.c | 5 +++
>> arch/arm64/Kconfig | 16 ++++++++++
>> arch/arm64/include/asm/barrier.h | 1 +
>> arch/arm64/include/asm/cpucaps.h | 3 +-
>> arch/arm64/include/asm/kvm_arm.h | 2 ++
>> arch/arm64/include/asm/kvm_emulate.h | 17 ++++++++++
>> arch/arm64/include/asm/kvm_host.h | 2 ++
>> arch/arm64/include/asm/sysreg.h | 5 +++
>> arch/arm64/include/asm/system_misc.h | 1 +
>> arch/arm64/include/uapi/asm/kvm.h | 5 +++
>> arch/arm64/kernel/cpufeature.c | 13 ++++++++
>> arch/arm64/kernel/process.c | 3 ++
>> arch/arm64/kvm/guest.c | 48 +++++++++++++++++++++++++++++
>> arch/arm64/kvm/handle_exit.c | 21 +++++++++++--
>> arch/arm64/kvm/hyp/switch.c | 29 +++++++++++++++--
>> arch/arm64/kvm/reset.c | 3 ++
>> arch/arm64/mm/fault.c | 21 +++++++++++--
>> drivers/acpi/apei/Kconfig | 15 +++++++++
>> drivers/acpi/apei/ghes.c | 60 +++++++++++++++++++++++-------------
>> include/acpi/ghes.h | 2 +-
>> include/uapi/linux/kvm.h | 3 ++
>> virt/kvm/arm/arm.c | 7 +++++
>> 23 files changed, 254 insertions(+), 30 deletions(-)
>>
>
>
> .
>