KVM: Move "exit due to NMI" handling into vmx_complete_interrupts()

From: Gleb Natapov
Date: Mon May 11 2009 - 06:35:55 EST


To save us one reading of VM_EXIT_INTR_INFO.

Signed-off-by: Gleb Natapov <gleb@xxxxxxxxxx>
Signed-off-by: Avi Kivity <avi@xxxxxxxxxx>

Regards
Stefan Lippers-Hollmann

> From: Andi Kleen <ak@xxxxxxxxxxxxxxx>
>
> commit a0861c02a981c943573478ea13b29b1fb958ee5b upstream.
>
> VT-x needs an explicit MC vector intercept to handle machine checks in the
> hyper visor.
>
> It also has a special option to catch machine checks that happen
> during VT entry.
>
> Do these interceptions and forward them to the Linux machine check
> handler. Make it always look like user space is interrupted because
> the machine check handler treats kernel/user space differently.
>
> Thanks to Jiang Yunhong for help and testing.
>
> Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
> Signed-off-by: Huang Ying <ying.huang@xxxxxxxxx>
> Signed-off-by: Avi Kivity <avi@xxxxxxxxxx>
> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
>
> ---
> arch/x86/include/asm/vmx.h | 1
> arch/x86/kernel/cpu/mcheck/mce_64.c | 1
> arch/x86/kvm/vmx.c | 50 ++++++++++++++++++++++++++++++++++--
> 3 files changed, 50 insertions(+), 2 deletions(-)

--

> --- a/arch/x86/include/asm/vmx.h
> +++ b/arch/x86/include/asm/vmx.h
> @@ -247,6 +247,7 @@ enum vmcs_field {
> #define EXIT_REASON_MSR_READ 31
> #define EXIT_REASON_MSR_WRITE 32
> #define EXIT_REASON_MWAIT_INSTRUCTION 36
> +#define EXIT_REASON_MCE_DURING_VMENTRY 41
> #define EXIT_REASON_TPR_BELOW_THRESHOLD 43
> #define EXIT_REASON_APIC_ACCESS 44
> #define EXIT_REASON_EPT_VIOLATION 48
> --- a/arch/x86/kernel/cpu/mcheck/mce_64.c
> +++ b/arch/x86/kernel/cpu/mcheck/mce_64.c
> @@ -420,6 +420,7 @@ void do_machine_check(struct pt_regs * r
> out2:
> atomic_dec(&mce_entry);
> }
> +EXPORT_SYMBOL_GPL(do_machine_check);
>
> #ifdef CONFIG_X86_MCE_INTEL
> /***
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -32,6 +32,7 @@
> #include <asm/desc.h>
> #include <asm/vmx.h>
> #include <asm/virtext.h>
> +#include <asm/mce.h>
>
> #define __ex(x) __kvm_handle_fault_on_reboot(x)
>
> @@ -97,6 +98,7 @@ struct vcpu_vmx {
> int soft_vnmi_blocked;
> ktime_t entry_time;
> s64 vnmi_blocked_time;
> + u32 exit_reason;
> };
>
> static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
> @@ -213,6 +215,13 @@ static inline int is_external_interrupt(
> == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
> }
>
> +static inline int is_machine_check(u32 intr_info)
> +{
> + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
> + INTR_INFO_VALID_MASK)) ==
> + (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK);
> +}
> +
> static inline int cpu_has_vmx_msr_bitmap(void)
> {
> return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS);
> @@ -478,7 +487,7 @@ static void update_exception_bitmap(stru
> {
> u32 eb;
>
> - eb = (1u << PF_VECTOR) | (1u << UD_VECTOR);
> + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR);
> if (!vcpu->fpu_active)
> eb |= 1u << NM_VECTOR;
> if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
> @@ -2585,6 +2594,31 @@ static int handle_rmode_exception(struct
> return 0;
> }
>
> +/*
> + * Trigger machine check on the host. We assume all the MSRs are already set up
> + * by the CPU and that we still run on the same CPU as the MCE occurred on.
> + * We pass a fake environment to the machine check handler because we want
> + * the guest to be always treated like user space, no matter what context
> + * it used internally.
> + */
> +static void kvm_machine_check(void)
> +{
> +#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_64)
> + struct pt_regs regs = {
> + .cs = 3, /* Fake ring 3 no matter what the guest ran on */
> + .flags = X86_EFLAGS_IF,
> + };
> +
> + do_machine_check(&regs, 0);
> +#endif
> +}
> +
> +static int handle_machine_check(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
> +{
> + /* already handled by vcpu_run */
> + return 1;
> +}
> +
> static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> @@ -2596,6 +2630,9 @@ static int handle_exception(struct kvm_v
> vect_info = vmx->idt_vectoring_info;
> intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
>
> + if (is_machine_check(intr_info))
> + return handle_machine_check(vcpu, kvm_run);
> +
> if ((vect_info & VECTORING_INFO_VALID_MASK) &&
> !is_page_fault(intr_info))
> printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
> @@ -3150,6 +3187,7 @@ static int (*kvm_vmx_exit_handlers[])(st
> [EXIT_REASON_WBINVD] = handle_wbinvd,
> [EXIT_REASON_TASK_SWITCH] = handle_task_switch,
> [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
> + [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check,
> };
>
> static const int kvm_vmx_max_exit_handlers =
> @@ -3161,8 +3199,8 @@ static const int kvm_vmx_max_exit_handle
> */
> static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
> {
> - u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> + u32 exit_reason = vmx->exit_reason;
> u32 vectoring_info = vmx->idt_vectoring_info;
>
> KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)kvm_rip_read(vcpu),
> @@ -3512,6 +3550,14 @@ static void vmx_vcpu_run(struct kvm_vcpu
>
> intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
>
> + vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
> +
> + /* Handle machine checks before interrupts are enabled */
> + if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
> + || (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI
> + && is_machine_check(exit_intr_info)))
> + kvm_machine_check();
> +
> /* We need to handle NMIs before interrupts are enabled */
> if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
> (intr_info & INTR_INFO_VALID_MASK)) {
>
>
> Patches currently in stable-queue which might be from ak@xxxxxxxxxxxxxxx are
>
> queue-2.6.30/kvm-add-vt-x-machine-check-support.patch
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/