Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020, Google LLC.
0004  *
0005  * Tests for KVM paravirtual feature disablement
0006  */
0007 #include <asm/kvm_para.h>
0008 #include <linux/kvm_para.h>
0009 #include <stdint.h>
0010 
0011 #include "test_util.h"
0012 #include "kvm_util.h"
0013 #include "processor.h"
0014 
0015 struct msr_data {
0016     uint32_t idx;
0017     const char *name;
0018 };
0019 
0020 #define TEST_MSR(msr) { .idx = msr, .name = #msr }
0021 #define UCALL_PR_MSR 0xdeadbeef
0022 #define PR_MSR(msr) ucall(UCALL_PR_MSR, 1, msr)
0023 
0024 /*
0025  * KVM paravirtual msrs to test. Expect a #GP if any of these msrs are read or
0026  * written, as the KVM_CPUID_FEATURES leaf is cleared.
0027  */
0028 static struct msr_data msrs_to_test[] = {
0029     TEST_MSR(MSR_KVM_SYSTEM_TIME),
0030     TEST_MSR(MSR_KVM_SYSTEM_TIME_NEW),
0031     TEST_MSR(MSR_KVM_WALL_CLOCK),
0032     TEST_MSR(MSR_KVM_WALL_CLOCK_NEW),
0033     TEST_MSR(MSR_KVM_ASYNC_PF_EN),
0034     TEST_MSR(MSR_KVM_STEAL_TIME),
0035     TEST_MSR(MSR_KVM_PV_EOI_EN),
0036     TEST_MSR(MSR_KVM_POLL_CONTROL),
0037     TEST_MSR(MSR_KVM_ASYNC_PF_INT),
0038     TEST_MSR(MSR_KVM_ASYNC_PF_ACK),
0039 };
0040 
0041 static void test_msr(struct msr_data *msr)
0042 {
0043     uint64_t ignored;
0044     uint8_t vector;
0045 
0046     PR_MSR(msr);
0047 
0048     vector = rdmsr_safe(msr->idx, &ignored);
0049     GUEST_ASSERT_1(vector == GP_VECTOR, vector);
0050 
0051     vector = wrmsr_safe(msr->idx, 0);
0052     GUEST_ASSERT_1(vector == GP_VECTOR, vector);
0053 }
0054 
0055 struct hcall_data {
0056     uint64_t nr;
0057     const char *name;
0058 };
0059 
0060 #define TEST_HCALL(hc) { .nr = hc, .name = #hc }
0061 #define UCALL_PR_HCALL 0xdeadc0de
0062 #define PR_HCALL(hc) ucall(UCALL_PR_HCALL, 1, hc)
0063 
0064 /*
0065  * KVM hypercalls to test. Expect -KVM_ENOSYS when called, as the corresponding
0066  * features have been cleared in KVM_CPUID_FEATURES.
0067  */
0068 static struct hcall_data hcalls_to_test[] = {
0069     TEST_HCALL(KVM_HC_KICK_CPU),
0070     TEST_HCALL(KVM_HC_SEND_IPI),
0071     TEST_HCALL(KVM_HC_SCHED_YIELD),
0072 };
0073 
0074 static void test_hcall(struct hcall_data *hc)
0075 {
0076     uint64_t r;
0077 
0078     PR_HCALL(hc);
0079     r = kvm_hypercall(hc->nr, 0, 0, 0, 0);
0080     GUEST_ASSERT(r == -KVM_ENOSYS);
0081 }
0082 
0083 static void guest_main(void)
0084 {
0085     int i;
0086 
0087     for (i = 0; i < ARRAY_SIZE(msrs_to_test); i++) {
0088         test_msr(&msrs_to_test[i]);
0089     }
0090 
0091     for (i = 0; i < ARRAY_SIZE(hcalls_to_test); i++) {
0092         test_hcall(&hcalls_to_test[i]);
0093     }
0094 
0095     GUEST_DONE();
0096 }
0097 
0098 static void pr_msr(struct ucall *uc)
0099 {
0100     struct msr_data *msr = (struct msr_data *)uc->args[0];
0101 
0102     pr_info("testing msr: %s (%#x)\n", msr->name, msr->idx);
0103 }
0104 
0105 static void pr_hcall(struct ucall *uc)
0106 {
0107     struct hcall_data *hc = (struct hcall_data *)uc->args[0];
0108 
0109     pr_info("testing hcall: %s (%lu)\n", hc->name, hc->nr);
0110 }
0111 
0112 static void enter_guest(struct kvm_vcpu *vcpu)
0113 {
0114     struct kvm_run *run = vcpu->run;
0115     struct ucall uc;
0116 
0117     while (true) {
0118         vcpu_run(vcpu);
0119         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0120                 "unexpected exit reason: %u (%s)",
0121                 run->exit_reason, exit_reason_str(run->exit_reason));
0122 
0123         switch (get_ucall(vcpu, &uc)) {
0124         case UCALL_PR_MSR:
0125             pr_msr(&uc);
0126             break;
0127         case UCALL_PR_HCALL:
0128             pr_hcall(&uc);
0129             break;
0130         case UCALL_ABORT:
0131             REPORT_GUEST_ASSERT_1(uc, "vector = %lu");
0132             return;
0133         case UCALL_DONE:
0134             return;
0135         }
0136     }
0137 }
0138 
0139 int main(void)
0140 {
0141     struct kvm_vcpu *vcpu;
0142     struct kvm_vm *vm;
0143 
0144     TEST_REQUIRE(kvm_has_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID));
0145 
0146     vm = vm_create_with_one_vcpu(&vcpu, guest_main);
0147 
0148     vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1);
0149 
0150     vcpu_clear_cpuid_entry(vcpu, KVM_CPUID_FEATURES);
0151 
0152     vm_init_descriptor_tables(vm);
0153     vcpu_init_descriptor_tables(vcpu);
0154 
0155     enter_guest(vcpu);
0156     kvm_vm_free(vm);
0157 }