switch (msr) {
        case MSR_CORE_PERF_GLOBAL_STATUS:
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
                msr_info->data = pmu->global_status;
                break;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
        case MSR_CORE_PERF_GLOBAL_CTRL:
                msr_info->data = pmu->global_ctrl;
                break;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
        case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
                msr_info->data = 0;
                break;
        u64 data = msr_info->data;
        u64 diff;
 
+       /*
+        * Note, AMD ignores writes to reserved bits and read-only PMU MSRs,
+        * whereas Intel generates #GP on attempts to write reserved/RO MSRs.
+        */
        switch (msr) {
        case MSR_CORE_PERF_GLOBAL_STATUS:
                if (!msr_info->host_initiated)
                        return 1; /* RO MSR */
+               fallthrough;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
+               /* Per PPR, Read-only MSR. Writes are ignored. */
+               if (!msr_info->host_initiated)
+                       break;
 
                if (data & pmu->global_status_mask)
                        return 1;
 
                pmu->global_status = data;
                break;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
+               data &= ~pmu->global_ctrl_mask;
+               fallthrough;
        case MSR_CORE_PERF_GLOBAL_CTRL:
                if (!kvm_valid_perf_global_ctrl(pmu, data))
                        return 1;
                 */
                if (data & pmu->global_status_mask)
                        return 1;
-
+               fallthrough;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
                if (!msr_info->host_initiated)
                        pmu->global_status &= ~data;
                break;
 
        return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx & ~(3u << 30));
 }
 
-static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
-{
-       /* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough.  */
-       return false;
-}
-
 static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
        return pmc;
 }
 
+static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+       struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+       switch (msr) {
+       case MSR_K7_EVNTSEL0 ... MSR_K7_PERFCTR3:
+               return pmu->version > 0;
+       case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5:
+               return guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE);
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
+       case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
+               return pmu->version > 1;
+       default:
+               if (msr > MSR_F15H_PERF_CTR5 &&
+                   msr < MSR_F15H_PERF_CTL0 + 2 * pmu->nr_arch_gp_counters)
+                       return pmu->version > 1;
+               break;
+       }
+
+       return amd_msr_idx_to_pmc(vcpu, msr);
+}
+
 static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
 static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+       union cpuid_0x80000022_ebx ebx;
 
-       if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE))
+       pmu->version = 1;
+       if (guest_cpuid_has(vcpu, X86_FEATURE_PERFMON_V2)) {
+               pmu->version = 2;
+               /*
+                * Note, PERFMON_V2 is also in 0x80000022.0x0, i.e. the guest
+                * CPUID entry is guaranteed to be non-NULL.
+                */
+               BUILD_BUG_ON(x86_feature_cpuid(X86_FEATURE_PERFMON_V2).function != 0x80000022 ||
+                            x86_feature_cpuid(X86_FEATURE_PERFMON_V2).index);
+               ebx.full = kvm_find_cpuid_entry_index(vcpu, 0x80000022, 0)->ebx;
+               pmu->nr_arch_gp_counters = ebx.split.num_core_pmc;
+       } else if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE)) {
                pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS_CORE;
-       else
+       } else {
                pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
+       }
 
        pmu->nr_arch_gp_counters = min_t(unsigned int, pmu->nr_arch_gp_counters,
                                         kvm_pmu_cap.num_counters_gp);
 
+       if (pmu->version > 1) {
+               pmu->global_ctrl_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1);
+               pmu->global_status_mask = pmu->global_ctrl_mask;
+       }
+
        pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
        pmu->reserved_bits = 0xfffffff000280000ull;
        pmu->raw_event_mask = AMD64_RAW_EVENT_MASK;
-       pmu->version = 1;
        /* not applicable to AMD; but clean them to prevent any fall out */
        pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
        pmu->nr_arch_fixed_counters = 0;
-       pmu->global_status = 0;
        bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
 }
 
                pmc_stop_counter(pmc);
                pmc->counter = pmc->prev_counter = pmc->eventsel = 0;
        }
+
+       pmu->global_ctrl = pmu->global_status = 0;
 }
 
 struct kvm_pmu_ops amd_pmu_ops __initdata = {
 
        MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
        MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
        MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
+
+       MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
+       MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
+       MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
 };
 
 static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_base) +
                    kvm_pmu_cap.num_counters_fixed)
                        return;
                break;
+       case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
+       case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
+               if (!kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
+                       return;
+               break;
        case MSR_IA32_XFD:
        case MSR_IA32_XFD_ERR:
                if (!kvm_cpu_cap_has(X86_FEATURE_XFD))