1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020, Google LLC.
5 * Tests for KVM paravirtual feature disablement
7 #include <asm/kvm_para.h>
8 #include <linux/kvm_para.h>
11 #include "test_util.h"
13 #include "processor.h"
15 extern unsigned char rdmsr_start
;
16 extern unsigned char rdmsr_end
;
18 static u64
do_rdmsr(u32 idx
)
22 asm volatile("rdmsr_start: rdmsr;"
27 return (((u64
) hi
) << 32) | lo
;
30 extern unsigned char wrmsr_start
;
31 extern unsigned char wrmsr_end
;
33 static void do_wrmsr(u32 idx
, u64 val
)
40 asm volatile("wrmsr_start: wrmsr;"
42 : : "a"(lo
), "c"(idx
), "d"(hi
));
47 static void guest_gp_handler(struct ex_regs
*regs
)
49 unsigned char *rip
= (unsigned char *)regs
->rip
;
52 r
= rip
== &rdmsr_start
;
53 w
= rip
== &wrmsr_start
;
59 regs
->rip
= (uint64_t)&rdmsr_end
;
61 regs
->rip
= (uint64_t)&wrmsr_end
;
69 #define TEST_MSR(msr) { .idx = msr, .name = #msr }
70 #define UCALL_PR_MSR 0xdeadbeef
71 #define PR_MSR(msr) ucall(UCALL_PR_MSR, 1, msr)
74 * KVM paravirtual msrs to test. Expect a #GP if any of these msrs are read or
75 * written, as the KVM_CPUID_FEATURES leaf is cleared.
77 static struct msr_data msrs_to_test
[] = {
78 TEST_MSR(MSR_KVM_SYSTEM_TIME
),
79 TEST_MSR(MSR_KVM_SYSTEM_TIME_NEW
),
80 TEST_MSR(MSR_KVM_WALL_CLOCK
),
81 TEST_MSR(MSR_KVM_WALL_CLOCK_NEW
),
82 TEST_MSR(MSR_KVM_ASYNC_PF_EN
),
83 TEST_MSR(MSR_KVM_STEAL_TIME
),
84 TEST_MSR(MSR_KVM_PV_EOI_EN
),
85 TEST_MSR(MSR_KVM_POLL_CONTROL
),
86 TEST_MSR(MSR_KVM_ASYNC_PF_INT
),
87 TEST_MSR(MSR_KVM_ASYNC_PF_ACK
),
90 static void test_msr(struct msr_data
*msr
)
94 GUEST_ASSERT(READ_ONCE(nr_gp
) == 1);
97 do_wrmsr(msr
->idx
, 0);
98 GUEST_ASSERT(READ_ONCE(nr_gp
) == 1);
107 #define TEST_HCALL(hc) { .nr = hc, .name = #hc }
108 #define UCALL_PR_HCALL 0xdeadc0de
109 #define PR_HCALL(hc) ucall(UCALL_PR_HCALL, 1, hc)
112 * KVM hypercalls to test. Expect -KVM_ENOSYS when called, as the corresponding
113 * features have been cleared in KVM_CPUID_FEATURES.
115 static struct hcall_data hcalls_to_test
[] = {
116 TEST_HCALL(KVM_HC_KICK_CPU
),
117 TEST_HCALL(KVM_HC_SEND_IPI
),
118 TEST_HCALL(KVM_HC_SCHED_YIELD
),
121 static void test_hcall(struct hcall_data
*hc
)
126 r
= kvm_hypercall(hc
->nr
, 0, 0, 0, 0);
127 GUEST_ASSERT(r
== -KVM_ENOSYS
);
130 static void guest_main(void)
134 for (i
= 0; i
< ARRAY_SIZE(msrs_to_test
); i
++) {
135 test_msr(&msrs_to_test
[i
]);
138 for (i
= 0; i
< ARRAY_SIZE(hcalls_to_test
); i
++) {
139 test_hcall(&hcalls_to_test
[i
]);
145 static void clear_kvm_cpuid_features(struct kvm_cpuid2
*cpuid
)
147 struct kvm_cpuid_entry2 ent
= {0};
149 ent
.function
= KVM_CPUID_FEATURES
;
150 TEST_ASSERT(set_cpuid(cpuid
, &ent
),
151 "failed to clear KVM_CPUID_FEATURES leaf");
154 static void pr_msr(struct ucall
*uc
)
156 struct msr_data
*msr
= (struct msr_data
*)uc
->args
[0];
158 pr_info("testing msr: %s (%#x)\n", msr
->name
, msr
->idx
);
161 static void pr_hcall(struct ucall
*uc
)
163 struct hcall_data
*hc
= (struct hcall_data
*)uc
->args
[0];
165 pr_info("testing hcall: %s (%lu)\n", hc
->name
, hc
->nr
);
168 static void handle_abort(struct ucall
*uc
)
170 TEST_FAIL("%s at %s:%ld", (const char *)uc
->args
[0],
171 __FILE__
, uc
->args
[1]);
176 static void enter_guest(struct kvm_vm
*vm
)
182 run
= vcpu_state(vm
, VCPU_ID
);
185 r
= _vcpu_run(vm
, VCPU_ID
);
186 TEST_ASSERT(!r
, "vcpu_run failed: %d\n", r
);
187 TEST_ASSERT(run
->exit_reason
== KVM_EXIT_IO
,
188 "unexpected exit reason: %u (%s)",
189 run
->exit_reason
, exit_reason_str(run
->exit_reason
));
191 switch (get_ucall(vm
, VCPU_ID
, &uc
)) {
209 struct kvm_enable_cap cap
= {0};
210 struct kvm_cpuid2
*best
;
213 if (!kvm_check_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID
)) {
214 print_skip("KVM_CAP_ENFORCE_PV_FEATURE_CPUID not supported");
218 vm
= vm_create_default(VCPU_ID
, 0, guest_main
);
220 cap
.cap
= KVM_CAP_ENFORCE_PV_FEATURE_CPUID
;
222 vcpu_enable_cap(vm
, VCPU_ID
, &cap
);
224 best
= kvm_get_supported_cpuid();
225 clear_kvm_cpuid_features(best
);
226 vcpu_set_cpuid(vm
, VCPU_ID
, best
);
228 vm_init_descriptor_tables(vm
);
229 vcpu_init_descriptor_tables(vm
, VCPU_ID
);
230 vm_handle_exception(vm
, GP_VECTOR
, guest_gp_handler
);