This leaves hanging the question of if we should clean-up KVM_HAVE_MCE_INJECTION? It is poisoned to avoid entering generic code. Signed-off-by: Alex Bennée --- docs/specs/acpi_hest_ghes.rst | 3 ++- include/accel/kvm/cpu-ops.h | 6 ++++++ include/system/kvm.h | 2 -- target/i386/kvm/kvm_i386.h | 1 + accel/kvm/kvm-all.c | 19 ++++++++++++++++--- target/arm/kvm.c | 3 ++- target/i386/kvm/kvm-cpu.c | 1 + target/i386/kvm/kvm.c | 2 +- 8 files changed, 29 insertions(+), 8 deletions(-) diff --git a/docs/specs/acpi_hest_ghes.rst b/docs/specs/acpi_hest_ghes.rst index aaf7b1ad11a..dfb319dc3b4 100644 --- a/docs/specs/acpi_hest_ghes.rst +++ b/docs/specs/acpi_hest_ghes.rst @@ -114,5 +114,6 @@ Design Details kernel, on receiving notification, guest APEI driver could read the CPER error and take appropriate action. -(11) kvm_arch_on_sigbus_vcpu() reports RAS errors via a SEA notifications, + +(11) The KVMCPUops::on_sigbus_vcpu callback reports RAS errors via a SEA notifications, when a SIGBUS event is triggered. diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h index c2ae74f2b87..d43bc845ad5 100644 --- a/include/accel/kvm/cpu-ops.h +++ b/include/accel/kvm/cpu-ops.h @@ -101,6 +101,11 @@ struct kvm_run; * execution should stop. * Returns true to stop the VM, or false to dump state * and continue. If NULL, defaults to true. + * @on_sigbus_vcpu: Optional callback executed when a SIGBUS signal is received + * to inject an architecture-specific hardware memory error + * (e.g. MCE on x86 or SEA on ARM) into the guest. + * May be NULL if the target does not support hardware error + * injection. */ typedef struct KVMCPUOps { int (*pre_create_vcpu)(CPUState *cpu, Error **errp); @@ -122,6 +127,7 @@ typedef struct KVMCPUOps { GdbBreakpointType type); void (*remove_all_hw_breakpoints)(CPUState *cpu); bool (*stop_on_emulation_error)(CPUState *cpu); + void (*on_sigbus_vcpu)(CPUState *cpu, int code, void *addr); } KVMCPUOps; #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu" diff --git a/include/system/kvm.h b/include/system/kvm.h index 719ae1c71fb..98ef937eff1 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -352,8 +352,6 @@ bool kvm_vcpu_id_is_valid(int vcpu_id); /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ unsigned long kvm_vcpu_id(CPUState *cpu); -void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); - void kvm_arch_init_irq_routing(KVMState *s); int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 9d4be604443..88aa0699c28 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -52,6 +52,7 @@ int x86_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len, GdbBreakpointType type); void x86_kvm_remove_all_hw_breakpoints(CPUState *cs); bool x86_kvm_stop_on_emulation_error(CPUState *cs); +void x86_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr); void kvm_arch_after_reset_vcpu(X86CPU *cpu); void kvm_arch_do_init_vcpu(X86CPU *cs); uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function, diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 62ebb3458c8..5189cdc6a01 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3535,8 +3535,10 @@ int kvm_cpu_exec(CPUState *cpu) #ifdef KVM_HAVE_MCE_INJECTION if (unlikely(have_sigbus_pending)) { bql_lock(); - kvm_arch_on_sigbus_vcpu(cpu, pending_sigbus_code, + if (ops->on_sigbus_vcpu) { + ops->on_sigbus_vcpu(cpu, pending_sigbus_code, pending_sigbus_addr); + } have_sigbus_pending = false; bql_unlock(); } @@ -4080,6 +4082,11 @@ void kvm_init_cpu_signals(CPUState *cpu) int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { #ifdef KVM_HAVE_MCE_INJECTION + const KVMCPUOps *ops = kvm_get_cpu_ops(cpu); + + if (!ops || !ops->on_sigbus_vcpu) { + return 1; + } if (have_sigbus_pending) { return 1; } @@ -4097,13 +4104,19 @@ int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) int kvm_on_sigbus(int code, void *addr) { #ifdef KVM_HAVE_MCE_INJECTION + const KVMCPUOps *ops; + /* Action required MCE kills the process if SIGBUS is blocked. Because * that's what happens in the I/O thread, where we handle MCE via signalfd, * we can only get action optional here. */ assert(code != BUS_MCEERR_AR); - kvm_arch_on_sigbus_vcpu(first_cpu, code, addr); - return 0; + ops = kvm_get_cpu_ops(first_cpu); + if (ops && ops->on_sigbus_vcpu) { + ops->on_sigbus_vcpu(first_cpu, code, addr); + return 0; + } + return 1; #else return 1; #endif diff --git a/target/arm/kvm.c b/target/arm/kvm.c index ed99699098c..563b331a7cf 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -2486,7 +2486,7 @@ static int arm_kvm_get_registers(CPUState *cs, Error **errp) return ret; } -void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) +static void arm_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr) { ram_addr_t ram_addr; hwaddr paddr; @@ -2656,6 +2656,7 @@ static const KVMCPUOps arm_kvm_cpu_ops = { .insert_hw_breakpoint = arm_kvm_insert_hw_breakpoint, .remove_hw_breakpoint = arm_kvm_remove_hw_breakpoint, .remove_all_hw_breakpoints = arm_kvm_remove_all_hw_breakpoints, + .on_sigbus_vcpu = arm_kvm_on_sigbus_vcpu, }; static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data) diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index c9340183eaf..e876ec6b794 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -252,6 +252,7 @@ static const KVMCPUOps x86_kvm_cpu_ops = { .remove_hw_breakpoint = x86_kvm_remove_hw_breakpoint, .remove_all_hw_breakpoints = x86_kvm_remove_all_hw_breakpoints, .stop_on_emulation_error = x86_kvm_stop_on_emulation_error, + .on_sigbus_vcpu = x86_kvm_on_sigbus_vcpu, }; static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index e419af944cb..26d30629272 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -767,7 +767,7 @@ static void hardware_memory_error(void *host_addr) exit(1); } -void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) +void x86_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr) { X86CPU *cpu = X86_CPU(c); CPUX86State *env = &cpu->env; -- 2.47.3