mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior
Add a quirk for KVM's behavior of emulating intercepted MONITOR/MWAIT instructions a NOPs regardless of whether or not they are supported in guest CPUID. KVM's current behavior was likely motiviated by a certain fruity operating system that expects MONITOR/MWAIT to be supported unconditionally and blindly executes MONITOR/MWAIT without first checking CPUID. And because KVM does NOT advertise MONITOR/MWAIT to userspace, that's effectively the default setup for any VMM that regurgitates KVM_GET_SUPPORTED_CPUID to KVM_SET_CPUID2. Note, this quirk interacts with KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT. The behavior is actually desirable, as userspace VMMs that want to unconditionally hide MONITOR/MWAIT from the guest can leave the MISC_ENABLE quirk enabled. Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20220608224516.3788274-2-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									ff81a90f45
								
							
						
					
					
						commit
						bfbcc81bb8
					
				
					 4 changed files with 35 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -7522,6 +7522,19 @@ The valid bits in cap.args[0] are:
 | 
			
		|||
                                    hypercall instructions. Executing the
 | 
			
		||||
                                    incorrect hypercall instruction will
 | 
			
		||||
                                    generate a #UD within the guest.
 | 
			
		||||
 | 
			
		||||
KVM_X86_QUIRK_MWAIT_NEVER_FAULTS    By default, KVM emulates MONITOR/MWAIT (if
 | 
			
		||||
                                    they are intercepted) as NOPs regardless of
 | 
			
		||||
                                    whether or not MONITOR/MWAIT are supported
 | 
			
		||||
                                    according to guest CPUID.  When this quirk
 | 
			
		||||
                                    is disabled and KVM_X86_DISABLE_EXITS_MWAIT
 | 
			
		||||
                                    is not set (MONITOR/MWAIT are intercepted),
 | 
			
		||||
                                    KVM will inject a #UD on MONITOR/MWAIT if
 | 
			
		||||
                                    they're unsupported per guest CPUID.  Note,
 | 
			
		||||
                                    KVM will modify MONITOR/MWAIT support in
 | 
			
		||||
                                    guest CPUID on writes to MISC_ENABLE if
 | 
			
		||||
                                    KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is
 | 
			
		||||
                                    disabled.
 | 
			
		||||
=================================== ============================================
 | 
			
		||||
 | 
			
		||||
7.32 KVM_CAP_MAX_VCPU_ID
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2076,6 +2076,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
 | 
			
		|||
	 KVM_X86_QUIRK_LAPIC_MMIO_HOLE |	\
 | 
			
		||||
	 KVM_X86_QUIRK_OUT_7E_INC_RIP |		\
 | 
			
		||||
	 KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT |	\
 | 
			
		||||
	 KVM_X86_QUIRK_FIX_HYPERCALL_INSN)
 | 
			
		||||
	 KVM_X86_QUIRK_FIX_HYPERCALL_INSN |	\
 | 
			
		||||
	 KVM_X86_QUIRK_MWAIT_NEVER_FAULTS)
 | 
			
		||||
 | 
			
		||||
#endif /* _ASM_X86_KVM_HOST_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -439,6 +439,7 @@ struct kvm_sync_regs {
 | 
			
		|||
#define KVM_X86_QUIRK_OUT_7E_INC_RIP		(1 << 3)
 | 
			
		||||
#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT	(1 << 4)
 | 
			
		||||
#define KVM_X86_QUIRK_FIX_HYPERCALL_INSN	(1 << 5)
 | 
			
		||||
#define KVM_X86_QUIRK_MWAIT_NEVER_FAULTS	(1 << 6)
 | 
			
		||||
 | 
			
		||||
#define KVM_STATE_NESTED_FORMAT_VMX	0
 | 
			
		||||
#define KVM_STATE_NESTED_FORMAT_SVM	1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2036,13 +2036,6 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu)
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(kvm_emulate_invd);
 | 
			
		||||
 | 
			
		||||
int kvm_emulate_mwait(struct kvm_vcpu *vcpu)
 | 
			
		||||
{
 | 
			
		||||
	pr_warn_once("kvm: MWAIT instruction emulated as NOP!\n");
 | 
			
		||||
	return kvm_emulate_as_nop(vcpu);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(kvm_emulate_mwait);
 | 
			
		||||
 | 
			
		||||
int kvm_handle_invalid_op(struct kvm_vcpu *vcpu)
 | 
			
		||||
{
 | 
			
		||||
	kvm_queue_exception(vcpu, UD_VECTOR);
 | 
			
		||||
| 
						 | 
				
			
			@ -2050,10 +2043,25 @@ int kvm_handle_invalid_op(struct kvm_vcpu *vcpu)
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(kvm_handle_invalid_op);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn)
 | 
			
		||||
{
 | 
			
		||||
	if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) &&
 | 
			
		||||
	    !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT))
 | 
			
		||||
		return kvm_handle_invalid_op(vcpu);
 | 
			
		||||
 | 
			
		||||
	pr_warn_once("kvm: %s instruction emulated as NOP!\n", insn);
 | 
			
		||||
	return kvm_emulate_as_nop(vcpu);
 | 
			
		||||
}
 | 
			
		||||
int kvm_emulate_mwait(struct kvm_vcpu *vcpu)
 | 
			
		||||
{
 | 
			
		||||
	return kvm_emulate_monitor_mwait(vcpu, "MWAIT");
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(kvm_emulate_mwait);
 | 
			
		||||
 | 
			
		||||
int kvm_emulate_monitor(struct kvm_vcpu *vcpu)
 | 
			
		||||
{
 | 
			
		||||
	pr_warn_once("kvm: MONITOR instruction emulated as NOP!\n");
 | 
			
		||||
	return kvm_emulate_as_nop(vcpu);
 | 
			
		||||
	return kvm_emulate_monitor_mwait(vcpu, "MONITOR");
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(kvm_emulate_monitor);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3884,8 +3892,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 | 
			
		|||
		if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
 | 
			
		||||
			return kvm_pmu_get_msr(vcpu, msr_info);
 | 
			
		||||
		/*
 | 
			
		||||
		 * Userspace is allowed to read MSRs that KVM reports in
 | 
			
		||||
		 * KVM_GET_MSR_INDEX_LIST, even if an MSR isn't fully supported.
 | 
			
		||||
		 * Userspace is allowed to read MSRs that KVM reports as
 | 
			
		||||
		 * to-be-saved, even if an MSR isn't fully supported.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!msr_info->host_initiated)
 | 
			
		||||
			return 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue