selftests: kvm/x86: Verify the pmu event filter matches the correct event
authorAaron Lewis <aaronlewis@google.com>
Tue, 17 May 2022 05:12:38 +0000 (05:12 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 20 May 2022 11:06:55 +0000 (07:06 -0400)
Add a test to demonstrate that when the guest programs an event select
it is matched correctly in the pmu event filter and not inadvertently
filtered.  This could happen on AMD if the high nybble[1] in the event
select gets truncated away only leaving the bottom byte[2] left for
matching.

This is a contrived example used for the convenience of demonstrating
this issue, however, this can be applied to event selects 0x28A (OC
Mode Switch) and 0x08A (L1 BTB Correction), where 0x08A could end up
being denied when the event select was only set up to deny 0x28A.

[1] bits 35:32 in the event select register and bits 11:8 in the event
    select.
[2] bits 7:0 in the event select register and bits 7:0 in the event
    select.

Signed-off-by: Aaron Lewis <aaronlewis@google.com>
Message-Id: <20220517051238.2566934-3-aaronlewis@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c

index 30c1a58..93d7757 100644 (file)
@@ -281,6 +281,22 @@ static uint64_t test_with_filter(struct kvm_vm *vm,
        return run_vm_to_sync(vm);
 }
 
+static void test_amd_deny_list(struct kvm_vm *vm)
+{
+       uint64_t event = EVENT(0x1C2, 0);
+       struct kvm_pmu_event_filter *f;
+       uint64_t count;
+
+       f = create_pmu_event_filter(&event, 1, KVM_PMU_EVENT_DENY);
+       count = test_with_filter(vm, f);
+
+       free(f);
+       if (count != NUM_BRANCHES)
+               pr_info("%s: Branch instructions retired = %lu (expected %u)\n",
+                       __func__, count, NUM_BRANCHES);
+       TEST_ASSERT(count, "Allowed PMU event is not counting");
+}
+
 static void test_member_deny_list(struct kvm_vm *vm)
 {
        struct kvm_pmu_event_filter *f = event_filter(KVM_PMU_EVENT_DENY);
@@ -463,6 +479,9 @@ int main(int argc, char *argv[])
                exit(KSFT_SKIP);
        }
 
+       if (use_amd_pmu())
+               test_amd_deny_list(vm);
+
        test_without_filter(vm);
        test_member_deny_list(vm);
        test_member_allow_list(vm);