linux/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * VMX-pmu related msrs test
   4 *
   5 * Copyright (C) 2021 Intel Corporation
   6 *
   7 * Test to check the effect of various CPUID settings
   8 * on the MSR_IA32_PERF_CAPABILITIES MSR, and check that
   9 * whatever we write with KVM_SET_MSR is _not_ modified
  10 * in the guest and test it can be retrieved with KVM_GET_MSR.
  11 *
  12 * Test to check that invalid LBR formats are rejected.
  13 */
  14
  15#define _GNU_SOURCE /* for program_invocation_short_name */
  16#include <sys/ioctl.h>
  17
  18#include "kvm_util.h"
  19#include "vmx.h"
  20
  21#define VCPU_ID       0
  22
  23#define X86_FEATURE_PDCM        (1<<15)
  24#define PMU_CAP_FW_WRITES       (1ULL << 13)
  25#define PMU_CAP_LBR_FMT         0x3f
  26
  27union cpuid10_eax {
  28        struct {
  29                unsigned int version_id:8;
  30                unsigned int num_counters:8;
  31                unsigned int bit_width:8;
  32                unsigned int mask_length:8;
  33        } split;
  34        unsigned int full;
  35};
  36
  37union perf_capabilities {
  38        struct {
  39                u64     lbr_format:6;
  40                u64     pebs_trap:1;
  41                u64     pebs_arch_reg:1;
  42                u64     pebs_format:4;
  43                u64     smm_freeze:1;
  44                u64     full_width_write:1;
  45                u64 pebs_baseline:1;
  46                u64     perf_metrics:1;
  47                u64     pebs_output_pt_available:1;
  48                u64     anythread_deprecated:1;
  49        };
  50        u64     capabilities;
  51};
  52
  53static void guest_code(void)
  54{
  55        wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
  56}
  57
  58int main(int argc, char *argv[])
  59{
  60        struct kvm_cpuid2 *cpuid;
  61        struct kvm_cpuid_entry2 *entry_1_0;
  62        struct kvm_cpuid_entry2 *entry_a_0;
  63        bool pdcm_supported = false;
  64        struct kvm_vm *vm;
  65        int ret;
  66        union cpuid10_eax eax;
  67        union perf_capabilities host_cap;
  68
  69        host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
  70        host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);
  71
  72        /* Create VM */
  73        vm = vm_create_default(VCPU_ID, 0, guest_code);
  74        cpuid = kvm_get_supported_cpuid();
  75
  76        if (kvm_get_cpuid_max_basic() >= 0xa) {
  77                entry_1_0 = kvm_get_supported_cpuid_index(1, 0);
  78                entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0);
  79                pdcm_supported = entry_1_0 && !!(entry_1_0->ecx & X86_FEATURE_PDCM);
  80                eax.full = entry_a_0->eax;
  81        }
  82        if (!pdcm_supported) {
  83                print_skip("MSR_IA32_PERF_CAPABILITIES is not supported by the vCPU");
  84                exit(KSFT_SKIP);
  85        }
  86        if (!eax.split.version_id) {
  87                print_skip("PMU is not supported by the vCPU");
  88                exit(KSFT_SKIP);
  89        }
  90
  91        /* testcase 1, set capabilities when we have PDCM bit */
  92        vcpu_set_cpuid(vm, VCPU_ID, cpuid);
  93        vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
  94
  95        /* check capabilities can be retrieved with KVM_GET_MSR */
  96        ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
  97
  98        /* check whatever we write with KVM_SET_MSR is _not_ modified */
  99        vcpu_run(vm, VCPU_ID);
 100        ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
 101
 102        /* testcase 2, check valid LBR formats are accepted */
 103        vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0);
 104        ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0);
 105
 106        vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format);
 107        ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format);
 108
 109        /* testcase 3, check invalid LBR format is rejected */
 110        ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
 111        TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
 112
 113        /* testcase 4, set capabilities when we don't have PDCM bit */
 114        entry_1_0->ecx &= ~X86_FEATURE_PDCM;
 115        vcpu_set_cpuid(vm, VCPU_ID, cpuid);
 116        ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
 117        TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
 118
 119        /* testcase 5, set capabilities when we don't have PMU version bits */
 120        entry_1_0->ecx |= X86_FEATURE_PDCM;
 121        eax.split.version_id = 0;
 122        entry_1_0->ecx = eax.full;
 123        vcpu_set_cpuid(vm, VCPU_ID, cpuid);
 124        ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
 125        TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
 126
 127        vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0);
 128        ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0);
 129
 130        kvm_vm_free(vm);
 131}
 132