diff --git a/hypervisor/arch/x86/guest/vcpuid.c b/hypervisor/arch/x86/guest/vcpuid.c index 0621aac78..25bec2b97 100644 --- a/hypervisor/arch/x86/guest/vcpuid.c +++ b/hypervisor/arch/x86/guest/vcpuid.c @@ -467,9 +467,14 @@ static void guest_cpuid_01h(struct acrn_vcpu *vcpu, uint32_t *eax, uint32_t *ebx *ecx &= ~CPUID_ECX_PCID; } - /* if guest disabed monitor/mwait, clear cpuid.01h[3] */ - if ((guest_ia32_misc_enable & MSR_IA32_MISC_ENABLE_MONITOR_ENA) == 0UL) { - *ecx &= ~CPUID_ECX_MONITOR; + /* guest monitor/mwait is supported only if it is allowed('vm_mwait_cap' is true) + * and MSR_IA32_MISC_ENABLE_MONITOR_ENA bit of guest MSR_IA32_MISC_ENABLE is set, + * else clear cpuid.01h[3]. + */ + *ecx &= ~CPUID_ECX_MONITOR; + if (vcpu->vm->arch_vm.vm_mwait_cap && + ((guest_ia32_misc_enable & MSR_IA32_MISC_ENABLE_MONITOR_ENA) != 0UL)) { + *ecx |= CPUID_ECX_MONITOR; } *ecx &= ~CPUID_ECX_OSXSAVE; diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 3a9de2b0f..e22690b27 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -535,6 +535,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v spinlock_init(&vm->arch_vm.iwkey_backup_lock); vm->arch_vm.vlapic_mode = VM_VLAPIC_XAPIC; + vm->arch_vm.vm_mwait_cap = has_monitor_cap(); vm->intr_inject_delay_delta = 0UL; vm->nr_emul_mmio_regions = 0U; vm->vcpuid_entry_nr = 0U; diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 84e564e1a..bae2bff2c 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -707,7 +707,7 @@ static void set_guest_ia32_misc_enalbe(struct acrn_vcpu *vcpu, uint64_t v) { uint32_t eax, ebx = 0U, ecx = 0U, edx = 0U; bool update_vmsr = true; - uint64_t msr_value; + /* According to SDM Vol4 2.1 & Vol 3A 4.1.4, * EFER.NXE should be cleared if guest disable XD in IA32_MISC_ENABLE */ @@ -716,13 +716,9 @@ static void set_guest_ia32_misc_enalbe(struct acrn_vcpu *vcpu, uint64_t v) } /* Handle MISC_ENABLE_MONITOR_ENA - * If has_monitor_cap() retrn true, this means the feature is enabed on host. - * HV will use monitor/mwait. - * - if guest try to set this bit, do nothing since it is already enabled - * - if guest try to clear this bit, not allow to disable in physcial MSR, - * just clear the corresponding bit in vcpuid. - * If has_monitor_cap() retrn false, this means the feature is not enabled on host. - * HV will not use monitor/mwait. Allow guest to change the bit to physcial MSR + * - if guest try to set this bit, do nothing. + * - if guest try to clear this bit, MISC_ENABLE_MONITOR_ENA bit of guest MSR_IA32_MISC_ENABLE + * shall be cleared. */ if (((v ^ vcpu_get_guest_msr(vcpu, MSR_IA32_MISC_ENABLE)) & MSR_IA32_MISC_ENABLE_MONITOR_ENA) != 0UL) { eax = 1U; @@ -733,15 +729,11 @@ static void set_guest_ia32_misc_enalbe(struct acrn_vcpu *vcpu, uint64_t v) if ((ecx & CPUID_ECX_SSE3) == 0U) { vcpu_inject_gp(vcpu, 0U); update_vmsr = false; - } else if ((!has_monitor_cap()) && (!is_apl_platform())) { - msr_value = msr_read(MSR_IA32_MISC_ENABLE) & ~MSR_IA32_MISC_ENABLE_MONITOR_ENA; - msr_value |= v & MSR_IA32_MISC_ENABLE_MONITOR_ENA; - /* This will not change the return value of has_monitor_cap() since the feature values - * are cached when platform init. - */ - msr_write(MSR_IA32_MISC_ENABLE, msr_value); + } else if (vcpu->vm->arch_vm.vm_mwait_cap) { + /* guest cpuid.01H will be updated when guest executes 'cpuid' with leaf 01H */ + v &= ~MSR_IA32_MISC_ENABLE_MONITOR_ENA; } else { - /* Not allow to change MISC_ENABLE_MONITOR_ENA in MSR */ + update_vmsr = false; } } diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 9d5d320c0..d8e922398 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -130,6 +130,7 @@ struct vm_arch { struct iwkey iwkey_backup; /* reference to virtual platform to come here (as needed) */ + bool vm_mwait_cap; } __aligned(PAGE_SIZE); struct acrn_vm {