1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021, Red Hat Inc.
4  *
5  * Generic tests for KVM CPUID set/get ioctls
6  */
7 #include <asm/kvm_para.h>
8 #include <linux/kvm_para.h>
9 #include <stdint.h>
10 
11 #include "test_util.h"
12 #include "kvm_util.h"
13 #include "processor.h"
14 
15 /* CPUIDs known to differ */
16 struct {
17 	u32 function;
18 	u32 index;
19 } mangled_cpuids[] = {
20 	/*
21 	 * These entries depend on the vCPU's XCR0 register and IA32_XSS MSR,
22 	 * which are not controlled for by this test.
23 	 */
24 	{.function = 0xd, .index = 0},
25 	{.function = 0xd, .index = 1},
26 };
27 
28 static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid)
29 {
30 	int i;
31 	u32 eax, ebx, ecx, edx;
32 
33 	for (i = 0; i < guest_cpuid->nent; i++) {
34 		__cpuid(guest_cpuid->entries[i].function,
35 			guest_cpuid->entries[i].index,
36 			&eax, &ebx, &ecx, &edx);
37 
38 		GUEST_ASSERT(eax == guest_cpuid->entries[i].eax &&
39 			     ebx == guest_cpuid->entries[i].ebx &&
40 			     ecx == guest_cpuid->entries[i].ecx &&
41 			     edx == guest_cpuid->entries[i].edx);
42 	}
43 
44 }
45 
46 static void test_cpuid_40000000(struct kvm_cpuid2 *guest_cpuid)
47 {
48 	u32 eax, ebx, ecx, edx;
49 
50 	cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
51 
52 	GUEST_ASSERT(eax == 0x40000001);
53 }
54 
55 static void guest_main(struct kvm_cpuid2 *guest_cpuid)
56 {
57 	GUEST_SYNC(1);
58 
59 	test_guest_cpuids(guest_cpuid);
60 
61 	GUEST_SYNC(2);
62 
63 	test_cpuid_40000000(guest_cpuid);
64 
65 	GUEST_DONE();
66 }
67 
68 static bool is_cpuid_mangled(const struct kvm_cpuid_entry2 *entrie)
69 {
70 	int i;
71 
72 	for (i = 0; i < sizeof(mangled_cpuids); i++) {
73 		if (mangled_cpuids[i].function == entrie->function &&
74 		    mangled_cpuids[i].index == entrie->index)
75 			return true;
76 	}
77 
78 	return false;
79 }
80 
81 static void compare_cpuids(const struct kvm_cpuid2 *cpuid1,
82 			   const struct kvm_cpuid2 *cpuid2)
83 {
84 	const struct kvm_cpuid_entry2 *e1, *e2;
85 	int i;
86 
87 	TEST_ASSERT(cpuid1->nent == cpuid2->nent,
88 		    "CPUID nent mismatch: %d vs. %d", cpuid1->nent, cpuid2->nent);
89 
90 	for (i = 0; i < cpuid1->nent; i++) {
91 		e1 = &cpuid1->entries[i];
92 		e2 = &cpuid2->entries[i];
93 
94 		TEST_ASSERT(e1->function == e2->function &&
95 			    e1->index == e2->index && e1->flags == e2->flags,
96 			    "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n",
97 			    i, e1->function, e1->index, e1->flags,
98 			    e2->function, e2->index, e2->flags);
99 
100 		if (is_cpuid_mangled(e1))
101 			continue;
102 
103 		TEST_ASSERT(e1->eax == e2->eax && e1->ebx == e2->ebx &&
104 			    e1->ecx == e2->ecx && e1->edx == e2->edx,
105 			    "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x",
106 			    e1->function, e1->index,
107 			    e1->eax, e1->ebx, e1->ecx, e1->edx,
108 			    e2->eax, e2->ebx, e2->ecx, e2->edx);
109 	}
110 }
111 
112 static void run_vcpu(struct kvm_vcpu *vcpu, int stage)
113 {
114 	struct ucall uc;
115 
116 	vcpu_run(vcpu);
117 
118 	switch (get_ucall(vcpu, &uc)) {
119 	case UCALL_SYNC:
120 		TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
121 			    uc.args[1] == stage + 1,
122 			    "Stage %d: Unexpected register values vmexit, got %lx",
123 			    stage + 1, (ulong)uc.args[1]);
124 		return;
125 	case UCALL_DONE:
126 		return;
127 	case UCALL_ABORT:
128 		REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx");
129 	default:
130 		TEST_ASSERT(false, "Unexpected exit: %s",
131 			    exit_reason_str(vcpu->run->exit_reason));
132 	}
133 }
134 
135 struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid)
136 {
137 	int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]);
138 	vm_vaddr_t gva = vm_vaddr_alloc(vm, size, KVM_UTIL_MIN_VADDR);
139 	struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva);
140 
141 	memcpy(guest_cpuids, cpuid, size);
142 
143 	*p_gva = gva;
144 	return guest_cpuids;
145 }
146 
147 static void set_cpuid_after_run(struct kvm_vcpu *vcpu)
148 {
149 	struct kvm_cpuid_entry2 *ent;
150 	int rc;
151 	u32 eax, ebx, x;
152 
153 	/* Setting unmodified CPUID is allowed */
154 	rc = __vcpu_set_cpuid(vcpu);
155 	TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc);
156 
157 	/* Changing CPU features is forbidden */
158 	ent = vcpu_get_cpuid_entry(vcpu, 0x7);
159 	ebx = ent->ebx;
160 	ent->ebx--;
161 	rc = __vcpu_set_cpuid(vcpu);
162 	TEST_ASSERT(rc, "Changing CPU features should fail");
163 	ent->ebx = ebx;
164 
165 	/* Changing MAXPHYADDR is forbidden */
166 	ent = vcpu_get_cpuid_entry(vcpu, 0x80000008);
167 	eax = ent->eax;
168 	x = eax & 0xff;
169 	ent->eax = (eax & ~0xffu) | (x - 1);
170 	rc = __vcpu_set_cpuid(vcpu);
171 	TEST_ASSERT(rc, "Changing MAXPHYADDR should fail");
172 	ent->eax = eax;
173 }
174 
175 int main(void)
176 {
177 	struct kvm_vcpu *vcpu;
178 	vm_vaddr_t cpuid_gva;
179 	struct kvm_vm *vm;
180 	int stage;
181 
182 	vm = vm_create_with_one_vcpu(&vcpu, guest_main);
183 
184 	compare_cpuids(kvm_get_supported_cpuid(), vcpu->cpuid);
185 
186 	vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid);
187 
188 	vcpu_args_set(vcpu, 1, cpuid_gva);
189 
190 	for (stage = 0; stage < 3; stage++)
191 		run_vcpu(vcpu, stage);
192 
193 	set_cpuid_after_run(vcpu);
194 
195 	kvm_vm_free(vm);
196 }
197