return evmcs_unsupported_ctrls[ctrl_type][evmcs_rev];
 }
 
-void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
+static bool evmcs_has_perf_global_ctrl(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+
+       /*
+        * PERF_GLOBAL_CTRL has a quirk where some Windows guests may fail to
+        * boot if a PV CPUID feature flag is not also set.  Treat the fields
+        * as unsupported if the flag is not set in guest CPUID.  This should
+        * be called only for guest accesses, and all guest accesses should be
+        * gated on Hyper-V being enabled and initialized.
+        */
+       if (WARN_ON_ONCE(!hv_vcpu))
+               return false;
+
+       return hv_vcpu->cpuid_cache.nested_ebx & HV_X64_NESTED_EVMCS1_PERF_GLOBAL_CTRL;
+}
+
+void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        u32 ctl_low = (u32)*pdata;
        u32 ctl_high = (u32)(*pdata >> 32);
+       u32 unsupported_ctrls;
 
        /*
         * Hyper-V 2016 and 2019 try using these features even when eVMCS
        switch (msr_index) {
        case MSR_IA32_VMX_EXIT_CTLS:
        case MSR_IA32_VMX_TRUE_EXIT_CTLS:
-               ctl_high &= ~evmcs_get_unsupported_ctls(EVMCS_EXIT_CTRLS);
+               unsupported_ctrls = evmcs_get_unsupported_ctls(EVMCS_EXIT_CTRLS);
+               if (!evmcs_has_perf_global_ctrl(vcpu))
+                       unsupported_ctrls |= VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
+               ctl_high &= ~unsupported_ctrls;
                break;
        case MSR_IA32_VMX_ENTRY_CTLS:
        case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
-               ctl_high &= ~evmcs_get_unsupported_ctls(EVMCS_ENTRY_CTRLS);
+               unsupported_ctrls = evmcs_get_unsupported_ctls(EVMCS_ENTRY_CTRLS);
+               if (!evmcs_has_perf_global_ctrl(vcpu))
+                       unsupported_ctrls |= VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
+               ctl_high &= ~unsupported_ctrls;
                break;
        case MSR_IA32_VMX_PROCBASED_CTLS2:
                ctl_high &= ~evmcs_get_unsupported_ctls(EVMCS_2NDEXEC);
 
  *     PLE_GAP                         = 0x00004020,
  *     PLE_WINDOW                      = 0x00004022,
  *     VMX_PREEMPTION_TIMER_VALUE      = 0x0000482E,
- *      GUEST_IA32_PERF_GLOBAL_CTRL     = 0x00002808,
- *      HOST_IA32_PERF_GLOBAL_CTRL      = 0x00002c04,
  *
  * Currently unsupported in KVM:
  *     GUEST_IA32_RTIT_CTL             = 0x00002814,
         SECONDARY_EXEC_TSC_SCALING |                                   \
         SECONDARY_EXEC_PAUSE_LOOP_EXITING)
 #define EVMCS1_UNSUPPORTED_VMEXIT_CTRL                                 \
-       (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |                           \
-        VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
-#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
+       (VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
+#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (0)
 #define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
 
 struct evmcs_field {
 uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
 int nested_enable_evmcs(struct kvm_vcpu *vcpu,
                        uint16_t *vmcs_version);
-void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata);
+void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
 
 #endif /* __KVM_X86_VMX_EVMCS_H */