Skip to content

Commit c345344

Browse files
committed
Merge tag 'kvm-x86-selftests-6.12' of https://github.com/kvm-x86/linux into HEAD
KVM selftests changes for 6.12: - Fix a goof that caused some Hyper-V tests to be skipped when run on bare metal, i.e. NOT in a VM. - Add a regression test for KVM's handling of SHUTDOWN for an SEV-ES guest. - Explicitly include one-off assets in .gitignore. Past Sean was completely wrong about not being able to detect missing .gitignore entries. - Verify userspace single-stepping works when KVM happens to handle a VM-Exit in its fastpath. - Misc cleanups
2 parents 41786cc + c32e028 commit c345344

File tree

12 files changed

+140
-151
lines changed

12 files changed

+140
-151
lines changed

tools/testing/selftests/kvm/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@
55
!*.h
66
!*.S
77
!*.sh
8+
!.gitignore
89
!config
10+
!settings
11+
!Makefile

tools/testing/selftests/kvm/include/kvm_util.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,6 @@ const char *vm_guest_mode_string(uint32_t i);
428428
void kvm_vm_free(struct kvm_vm *vmp);
429429
void kvm_vm_restart(struct kvm_vm *vmp);
430430
void kvm_vm_release(struct kvm_vm *vmp);
431-
int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva,
432-
size_t len);
433431
void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename);
434432
int kvm_memfd_alloc(size_t size, bool hugepages);
435433

tools/testing/selftests/kvm/include/x86_64/hyperv.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@
186186
#define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED \
187187
KVM_X86_CPU_FEATURE(HYPERV_CPUID_ENLIGHTMENT_INFO, 0, EAX, 14)
188188

189+
/* HYPERV_CPUID_NESTED_FEATURES.EAX */
190+
#define HV_X64_NESTED_DIRECT_FLUSH \
191+
KVM_X86_CPU_FEATURE(HYPERV_CPUID_NESTED_FEATURES, 0, EAX, 17)
192+
#define HV_X64_NESTED_GUEST_MAPPING_FLUSH \
193+
KVM_X86_CPU_FEATURE(HYPERV_CPUID_NESTED_FEATURES, 0, EAX, 18)
194+
#define HV_X64_NESTED_MSR_BITMAP \
195+
KVM_X86_CPU_FEATURE(HYPERV_CPUID_NESTED_FEATURES, 0, EAX, 19)
196+
197+
/* HYPERV_CPUID_NESTED_FEATURES.EBX */
198+
#define HV_X64_NESTED_EVMCS1_PERF_GLOBAL_CTRL \
199+
KVM_X86_CPU_FEATURE(HYPERV_CPUID_NESTED_FEATURES, 0, EBX, 0)
200+
189201
/* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */
190202
#define HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING \
191203
KVM_X86_CPU_FEATURE(HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES, 0, EAX, 1)
@@ -343,4 +355,10 @@ struct hyperv_test_pages *vcpu_alloc_hyperv_test_pages(struct kvm_vm *vm,
343355
/* HV_X64_MSR_TSC_INVARIANT_CONTROL bits */
344356
#define HV_INVARIANT_TSC_EXPOSED BIT_ULL(0)
345357

358+
const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void);
359+
const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu);
360+
void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu);
361+
362+
bool kvm_hv_cpu_has(struct kvm_x86_cpu_feature feature);
363+
346364
#endif /* !SELFTEST_KVM_HYPERV_H */

tools/testing/selftests/kvm/include/x86_64/processor.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ extern bool host_cpu_is_intel;
2525
extern bool host_cpu_is_amd;
2626
extern uint64_t guest_tsc_khz;
2727

28+
#ifndef MAX_NR_CPUID_ENTRIES
29+
#define MAX_NR_CPUID_ENTRIES 100
30+
#endif
31+
2832
/* Forced emulation prefix, used to invoke the emulator unconditionally. */
2933
#define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
3034

@@ -908,8 +912,6 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
908912
const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
909913
uint32_t function, uint32_t index);
910914
const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
911-
const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void);
912-
const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu);
913915

914916
static inline uint32_t kvm_cpu_fms(void)
915917
{
@@ -1009,7 +1011,6 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries)
10091011
}
10101012

10111013
void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid);
1012-
void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu);
10131014

10141015
static inline struct kvm_cpuid_entry2 *__vcpu_get_cpuid_entry(struct kvm_vcpu *vcpu,
10151016
uint32_t function,

tools/testing/selftests/kvm/lib/kvm_util.c

Lines changed: 6 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -712,16 +712,13 @@ void kvm_vm_release(struct kvm_vm *vmp)
712712
}
713713

714714
static void __vm_mem_region_delete(struct kvm_vm *vm,
715-
struct userspace_mem_region *region,
716-
bool unlink)
715+
struct userspace_mem_region *region)
717716
{
718717
int ret;
719718

720-
if (unlink) {
721-
rb_erase(&region->gpa_node, &vm->regions.gpa_tree);
722-
rb_erase(&region->hva_node, &vm->regions.hva_tree);
723-
hash_del(&region->slot_node);
724-
}
719+
rb_erase(&region->gpa_node, &vm->regions.gpa_tree);
720+
rb_erase(&region->hva_node, &vm->regions.hva_tree);
721+
hash_del(&region->slot_node);
725722

726723
region->region.memory_size = 0;
727724
vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
@@ -762,7 +759,7 @@ void kvm_vm_free(struct kvm_vm *vmp)
762759

763760
/* Free userspace_mem_regions. */
764761
hash_for_each_safe(vmp->regions.slot_hash, ctr, node, region, slot_node)
765-
__vm_mem_region_delete(vmp, region, false);
762+
__vm_mem_region_delete(vmp, region);
766763

767764
/* Free sparsebit arrays. */
768765
sparsebit_free(&vmp->vpages_valid);
@@ -794,76 +791,6 @@ int kvm_memfd_alloc(size_t size, bool hugepages)
794791
return fd;
795792
}
796793

797-
/*
798-
* Memory Compare, host virtual to guest virtual
799-
*
800-
* Input Args:
801-
* hva - Starting host virtual address
802-
* vm - Virtual Machine
803-
* gva - Starting guest virtual address
804-
* len - number of bytes to compare
805-
*
806-
* Output Args: None
807-
*
808-
* Input/Output Args: None
809-
*
810-
* Return:
811-
* Returns 0 if the bytes starting at hva for a length of len
812-
* are equal the guest virtual bytes starting at gva. Returns
813-
* a value < 0, if bytes at hva are less than those at gva.
814-
* Otherwise a value > 0 is returned.
815-
*
816-
* Compares the bytes starting at the host virtual address hva, for
817-
* a length of len, to the guest bytes starting at the guest virtual
818-
* address given by gva.
819-
*/
820-
int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, vm_vaddr_t gva, size_t len)
821-
{
822-
size_t amt;
823-
824-
/*
825-
* Compare a batch of bytes until either a match is found
826-
* or all the bytes have been compared.
827-
*/
828-
for (uintptr_t offset = 0; offset < len; offset += amt) {
829-
uintptr_t ptr1 = (uintptr_t)hva + offset;
830-
831-
/*
832-
* Determine host address for guest virtual address
833-
* at offset.
834-
*/
835-
uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset);
836-
837-
/*
838-
* Determine amount to compare on this pass.
839-
* Don't allow the comparsion to cross a page boundary.
840-
*/
841-
amt = len - offset;
842-
if ((ptr1 >> vm->page_shift) != ((ptr1 + amt) >> vm->page_shift))
843-
amt = vm->page_size - (ptr1 % vm->page_size);
844-
if ((ptr2 >> vm->page_shift) != ((ptr2 + amt) >> vm->page_shift))
845-
amt = vm->page_size - (ptr2 % vm->page_size);
846-
847-
assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift));
848-
assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift));
849-
850-
/*
851-
* Perform the comparison. If there is a difference
852-
* return that result to the caller, otherwise need
853-
* to continue on looking for a mismatch.
854-
*/
855-
int ret = memcmp((void *)ptr1, (void *)ptr2, amt);
856-
if (ret != 0)
857-
return ret;
858-
}
859-
860-
/*
861-
* No mismatch found. Let the caller know the two memory
862-
* areas are equal.
863-
*/
864-
return 0;
865-
}
866-
867794
static void vm_userspace_mem_region_gpa_insert(struct rb_root *gpa_tree,
868795
struct userspace_mem_region *region)
869796
{
@@ -1270,7 +1197,7 @@ void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa)
12701197
*/
12711198
void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot)
12721199
{
1273-
__vm_mem_region_delete(vm, memslot2region(vm, slot), true);
1200+
__vm_mem_region_delete(vm, memslot2region(vm, slot));
12741201
}
12751202

12761203
void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size,

tools/testing/selftests/kvm/lib/x86_64/hyperv.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,73 @@
88
#include "processor.h"
99
#include "hyperv.h"
1010

11+
const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void)
12+
{
13+
static struct kvm_cpuid2 *cpuid;
14+
int kvm_fd;
15+
16+
if (cpuid)
17+
return cpuid;
18+
19+
cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
20+
kvm_fd = open_kvm_dev_path_or_exit();
21+
22+
kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
23+
24+
close(kvm_fd);
25+
return cpuid;
26+
}
27+
28+
void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu)
29+
{
30+
static struct kvm_cpuid2 *cpuid_full;
31+
const struct kvm_cpuid2 *cpuid_sys, *cpuid_hv;
32+
int i, nent = 0;
33+
34+
if (!cpuid_full) {
35+
cpuid_sys = kvm_get_supported_cpuid();
36+
cpuid_hv = kvm_get_supported_hv_cpuid();
37+
38+
cpuid_full = allocate_kvm_cpuid2(cpuid_sys->nent + cpuid_hv->nent);
39+
if (!cpuid_full) {
40+
perror("malloc");
41+
abort();
42+
}
43+
44+
/* Need to skip KVM CPUID leaves 0x400000xx */
45+
for (i = 0; i < cpuid_sys->nent; i++) {
46+
if (cpuid_sys->entries[i].function >= 0x40000000 &&
47+
cpuid_sys->entries[i].function < 0x40000100)
48+
continue;
49+
cpuid_full->entries[nent] = cpuid_sys->entries[i];
50+
nent++;
51+
}
52+
53+
memcpy(&cpuid_full->entries[nent], cpuid_hv->entries,
54+
cpuid_hv->nent * sizeof(struct kvm_cpuid_entry2));
55+
cpuid_full->nent = nent + cpuid_hv->nent;
56+
}
57+
58+
vcpu_init_cpuid(vcpu, cpuid_full);
59+
}
60+
61+
const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu)
62+
{
63+
struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
64+
65+
vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
66+
67+
return cpuid;
68+
}
69+
70+
bool kvm_hv_cpu_has(struct kvm_x86_cpu_feature feature)
71+
{
72+
if (!kvm_has_cap(KVM_CAP_SYS_HYPERV_CPUID))
73+
return false;
74+
75+
return kvm_cpuid_has(kvm_get_supported_hv_cpuid(), feature);
76+
}
77+
1178
struct hyperv_test_pages *vcpu_alloc_hyperv_test_pages(struct kvm_vm *vm,
1279
vm_vaddr_t *p_hv_pages_gva)
1380
{

tools/testing/selftests/kvm/lib/x86_64/processor.c

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#define KERNEL_DS 0x10
2020
#define KERNEL_TSS 0x18
2121

22-
#define MAX_NR_CPUID_ENTRIES 100
23-
2422
vm_vaddr_t exception_handlers;
2523
bool host_cpu_is_amd;
2624
bool host_cpu_is_intel;
@@ -1193,65 +1191,6 @@ void xen_hypercall(uint64_t nr, uint64_t a0, void *a1)
11931191
GUEST_ASSERT(!__xen_hypercall(nr, a0, a1));
11941192
}
11951193

1196-
const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void)
1197-
{
1198-
static struct kvm_cpuid2 *cpuid;
1199-
int kvm_fd;
1200-
1201-
if (cpuid)
1202-
return cpuid;
1203-
1204-
cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
1205-
kvm_fd = open_kvm_dev_path_or_exit();
1206-
1207-
kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
1208-
1209-
close(kvm_fd);
1210-
return cpuid;
1211-
}
1212-
1213-
void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu)
1214-
{
1215-
static struct kvm_cpuid2 *cpuid_full;
1216-
const struct kvm_cpuid2 *cpuid_sys, *cpuid_hv;
1217-
int i, nent = 0;
1218-
1219-
if (!cpuid_full) {
1220-
cpuid_sys = kvm_get_supported_cpuid();
1221-
cpuid_hv = kvm_get_supported_hv_cpuid();
1222-
1223-
cpuid_full = allocate_kvm_cpuid2(cpuid_sys->nent + cpuid_hv->nent);
1224-
if (!cpuid_full) {
1225-
perror("malloc");
1226-
abort();
1227-
}
1228-
1229-
/* Need to skip KVM CPUID leaves 0x400000xx */
1230-
for (i = 0; i < cpuid_sys->nent; i++) {
1231-
if (cpuid_sys->entries[i].function >= 0x40000000 &&
1232-
cpuid_sys->entries[i].function < 0x40000100)
1233-
continue;
1234-
cpuid_full->entries[nent] = cpuid_sys->entries[i];
1235-
nent++;
1236-
}
1237-
1238-
memcpy(&cpuid_full->entries[nent], cpuid_hv->entries,
1239-
cpuid_hv->nent * sizeof(struct kvm_cpuid_entry2));
1240-
cpuid_full->nent = nent + cpuid_hv->nent;
1241-
}
1242-
1243-
vcpu_init_cpuid(vcpu, cpuid_full);
1244-
}
1245-
1246-
const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu)
1247-
{
1248-
struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
1249-
1250-
vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
1251-
1252-
return cpuid;
1253-
}
1254-
12551194
unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
12561195
{
12571196
const unsigned long num_ht_pages = 12 << (30 - vm->page_shift); /* 12 GiB */

tools/testing/selftests/kvm/x86_64/debug_regs.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@ static void guest_code(void)
4747
/*
4848
* Single step test, covers 2 basic instructions and 2 emulated
4949
*
50-
* Enable interrupts during the single stepping to see that
51-
* pending interrupt we raised is not handled due to KVM_GUESTDBG_BLOCKIRQ
50+
* Enable interrupts during the single stepping to see that pending
51+
* interrupt we raised is not handled due to KVM_GUESTDBG_BLOCKIRQ.
52+
*
53+
* Write MSR_IA32_TSC_DEADLINE to verify that KVM's fastpath handler
54+
* exits to userspace due to single-step being enabled.
5255
*/
5356
asm volatile("ss_start: "
5457
"sti\n\t"
5558
"xor %%eax,%%eax\n\t"
5659
"cpuid\n\t"
57-
"movl $0x1a0,%%ecx\n\t"
58-
"rdmsr\n\t"
60+
"movl $" __stringify(MSR_IA32_TSC_DEADLINE) ", %%ecx\n\t"
61+
"wrmsr\n\t"
5962
"cli\n\t"
6063
: : : "eax", "ebx", "ecx", "edx");
6164

tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ int main(int argc, char *argv[])
242242
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
243243
TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
244244
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS));
245-
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
245+
TEST_REQUIRE(kvm_hv_cpu_has(HV_X64_NESTED_DIRECT_FLUSH));
246246

247247
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
248248

tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int main(int argc, char *argv[])
157157
int stage;
158158

159159
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
160-
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
160+
TEST_REQUIRE(kvm_hv_cpu_has(HV_X64_NESTED_DIRECT_FLUSH));
161161

162162
/* Create VM */
163163
vm = vm_create_with_one_vcpu(&vcpu, guest_code);

0 commit comments

Comments
 (0)