Merge tag 'kvm-x86-selftests-6.4' of https://github.com/kvm-x86/linux into HEAD
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 26 Apr 2023 19:54:40 +0000 (15:54 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 26 Apr 2023 19:56:01 +0000 (15:56 -0400)
KVM selftests, and an AMX/XCR0 bugfix, for 6.4:

 - Don't advertise XTILE_CFG in KVM_GET_SUPPORTED_CPUID if XTILE_DATA is
   not being reported due to userspace not opting in via prctl()

 - Overhaul the AMX selftests to improve coverage and cleanup the test

 - Misc cleanups

1  2 
arch/x86/kvm/cpuid.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c
tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c

Simple merge
Simple merge
Simple merge
Simple merge
@@@ -35,220 -36,60 +35,221 @@@ union perf_capabilities 
        u64     capabilities;
  };
  
 -static void guest_code(void)
 +/*
 + * The LBR format and most PEBS features are immutable, all other features are
 + * fungible (if supported by the host and KVM).
 + */
 +static const union perf_capabilities immutable_caps = {
 +      .lbr_format = -1,
 +      .pebs_trap  = 1,
 +      .pebs_arch_reg = 1,
 +      .pebs_format = -1,
 +      .pebs_baseline = 1,
 +};
 +
 +static const union perf_capabilities format_caps = {
 +      .lbr_format = -1,
 +      .pebs_format = -1,
 +};
 +
 +static void guest_code(uint64_t current_val)
  {
 -      wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
 +      uint8_t vector;
 +      int i;
 +
 +      vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, current_val);
 +      GUEST_ASSERT_2(vector == GP_VECTOR, current_val, vector);
 +
 +      vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, 0);
 +      GUEST_ASSERT_2(vector == GP_VECTOR, 0, vector);
 +
 +      for (i = 0; i < 64; i++) {
 +              vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES,
 +                                  current_val ^ BIT_ULL(i));
 +              GUEST_ASSERT_2(vector == GP_VECTOR,
 +                             current_val ^ BIT_ULL(i), vector);
 +      }
 +
 +      GUEST_DONE();
  }
  
 -int main(int argc, char *argv[])
 +/*
 + * Verify that guest WRMSRs to PERF_CAPABILITIES #GP regardless of the value
 + * written, that the guest always sees the userspace controlled value, and that
 + * PERF_CAPABILITIES is immutable after KVM_RUN.
 + */
 +static void test_guest_wrmsr_perf_capabilities(union perf_capabilities host_cap)
  {
 -      struct kvm_vm *vm;
        struct kvm_vcpu *vcpu;
 -      int ret;
 -      union perf_capabilities host_cap;
 -      uint64_t val;
 +      struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 +      struct ucall uc;
 +      int r, i;
  
 -      host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
 -      host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);
 +      vm_init_descriptor_tables(vm);
 +      vcpu_init_descriptor_tables(vcpu);
  
 -      /* Create VM */
 -      vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 +      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
  
 -      TEST_REQUIRE(get_kvm_param_bool("enable_pmu"));
 -      TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
 +      vcpu_args_set(vcpu, 1, host_cap.capabilities);
 +      vcpu_run(vcpu);
  
 -      TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
 -      TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
 +      switch (get_ucall(vcpu, &uc)) {
 +      case UCALL_ABORT:
 +              REPORT_GUEST_ASSERT_2(uc, "val = 0x%lx, vector = %lu");
 +              break;
 +      case UCALL_DONE:
 +              break;
 +      default:
 +              TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
 +      }
  
 -      /* testcase 1, set capabilities when we have PDCM bit */
 -      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
 +      ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), host_cap.capabilities);
  
 -      /* check capabilities can be retrieved with KVM_GET_MSR */
 -      ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
 +      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
  
 -      /* check whatever we write with KVM_SET_MSR is _not_ modified */
 -      vcpu_run(vcpu);
 -      ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
 +      r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
 +      TEST_ASSERT(!r, "Post-KVM_RUN write '0' didn't fail");
 +
 +      for (i = 0; i < 64; i++) {
 +              r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
 +                                host_cap.capabilities ^ BIT_ULL(i));
 +              TEST_ASSERT(!r, "Post-KVM_RUN write '0x%llx'didn't fail",
 +                          host_cap.capabilities ^ BIT_ULL(i));
 +      }
 +
 +      kvm_vm_free(vm);
 +}
 +
 +/*
 + * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
 + * enabled, as well as '0' (to disable all features).
 + */
 +static void test_basic_perf_capabilities(union perf_capabilities host_cap)
 +{
 +      struct kvm_vcpu *vcpu;
 +      struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
  
 -      /* testcase 2, check valid LBR formats are accepted */
        vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
 -      ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), 0);
 +      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
 +
 +      kvm_vm_free(vm);
 +}
  
 -      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format);
 -      ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format);
 +static void test_fungible_perf_capabilities(union perf_capabilities host_cap)
 +{
 +      const uint64_t fungible_caps = host_cap.capabilities & ~immutable_caps.capabilities;
 +
 +      struct kvm_vcpu *vcpu;
 +      struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
 +      int bit;
 +
 +      for_each_set_bit(bit, &fungible_caps, 64) {
 +              vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, BIT_ULL(bit));
 +              vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
 +                           host_cap.capabilities & ~BIT_ULL(bit));
 +      }
 +      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
 +
 +      kvm_vm_free(vm);
 +}
 +
 +/*
 + * Verify KVM rejects attempts to set unsupported and/or immutable features in
 + * PERF_CAPABILITIES.  Note, LBR format and PEBS format need to be validated
 + * separately as they are multi-bit values, e.g. toggling or setting a single
 + * bit can generate a false positive without dedicated safeguards.
 + */
 +static void test_immutable_perf_capabilities(union perf_capabilities host_cap)
 +{
 +      const uint64_t reserved_caps = (~host_cap.capabilities |
 +                                      immutable_caps.capabilities) &
 +                                     ~format_caps.capabilities;
 +
 +      struct kvm_vcpu *vcpu;
 +      struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
 +      union perf_capabilities val = host_cap;
 +      int r, bit;
 +
 +      for_each_set_bit(bit, &reserved_caps, 64) {
 +              r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
 +                                host_cap.capabilities ^ BIT_ULL(bit));
 +              TEST_ASSERT(!r, "%s immutable feature 0x%llx (bit %d) didn't fail",
 +                          host_cap.capabilities & BIT_ULL(bit) ? "Setting" : "Clearing",
 +                          BIT_ULL(bit), bit);
 +      }
  
        /*
 -       * Testcase 3, check that an "invalid" LBR format is rejected.  Only an
 -       * exact match of the host's format (and 0/disabled) is allowed.
 +       * KVM only supports the host's native LBR format, as well as '0' (to
 +       * disable LBR support).  Verify KVM rejects all other LBR formats.
         */
 -      for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
 -              if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
 +      for (val.lbr_format = 1; val.lbr_format; val.lbr_format++) {
 +              if (val.lbr_format == host_cap.lbr_format)
 +                      continue;
 +
 +              r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val.capabilities);
 +              TEST_ASSERT(!r, "Bad LBR FMT = 0x%x didn't fail, host = 0x%x",
 +                          val.lbr_format, host_cap.lbr_format);
 +      }
 +
 +      /* Ditto for the PEBS format. */
 +      for (val.pebs_format = 1; val.pebs_format; val.pebs_format++) {
 +              if (val.pebs_format == host_cap.pebs_format)
                        continue;
  
 -              ret = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
 -              TEST_ASSERT(!ret, "Bad LBR FMT = 0x%lx didn't fail", val);
 +              r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val.capabilities);
 +              TEST_ASSERT(!r, "Bad PEBS FMT = 0x%x didn't fail, host = 0x%x",
 +                          val.pebs_format, host_cap.pebs_format);
        }
  
 -      printf("Completed perf capability tests.\n");
        kvm_vm_free(vm);
  }
 +
 +/*
 + * Test that LBR MSRs are writable when LBRs are enabled, and then verify that
 + * disabling the vPMU via CPUID also disables LBR support.  Set bits 2:0 of
 + * LBR_TOS as those bits are writable across all uarch implementations (arch
 + * LBRs will need to poke a different MSR).
 + */
 +static void test_lbr_perf_capabilities(union perf_capabilities host_cap)
 +{
 +      struct kvm_vcpu *vcpu;
 +      struct kvm_vm *vm;
 +      int r;
 +
 +      if (!host_cap.lbr_format)
 +              return;
 +
 +      vm = vm_create_with_one_vcpu(&vcpu, NULL);
 +
 +      vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
 +      vcpu_set_msr(vcpu, MSR_LBR_TOS, 7);
 +
 +      vcpu_clear_cpuid_entry(vcpu, X86_PROPERTY_PMU_VERSION.function);
 +
 +      r = _vcpu_set_msr(vcpu, MSR_LBR_TOS, 7);
 +      TEST_ASSERT(!r, "Writing LBR_TOS should fail after disabling vPMU");
 +
 +      kvm_vm_free(vm);
 +}
 +
 +int main(int argc, char *argv[])
 +{
 +      union perf_capabilities host_cap;
 +
++      TEST_REQUIRE(get_kvm_param_bool("enable_pmu"));
 +      TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
 +
 +      TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
 +      TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
 +
 +      host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
 +
 +      TEST_ASSERT(host_cap.full_width_write,
 +                  "Full-width writes should always be supported");
 +
 +      test_basic_perf_capabilities(host_cap);
 +      test_fungible_perf_capabilities(host_cap);
 +      test_immutable_perf_capabilities(host_cap);
 +      test_guest_wrmsr_perf_capabilities(host_cap);
 +      test_lbr_perf_capabilities(host_cap);
 +}