xref: /linux/tools/testing/selftests/kvm/get-reg-list.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Check for KVM_GET_REG_LIST regressions.
4  *
5  * Copyright (C) 2020, Red Hat, Inc.
6  *
7  * When attempting to migrate from a host with an older kernel to a host
8  * with a newer kernel we allow the newer kernel on the destination to
9  * list new registers with get-reg-list. We assume they'll be unused, at
10  * least until the guest reboots, and so they're relatively harmless.
11  * However, if the destination host with the newer kernel is missing
12  * registers which the source host with the older kernel has, then that's
13  * a regression in get-reg-list. This test checks for that regression by
14  * checking the current list against a blessed list. We should never have
15  * missing registers, but if new ones appear then they can probably be
16  * added to the blessed list. A completely new blessed list can be created
17  * by running the test with the --list command line argument.
18  *
19  * The blessed list should be created from the oldest possible kernel.
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include "kvm_util.h"
28 #include "test_util.h"
29 #include "processor.h"
30 
31 static struct kvm_reg_list *reg_list;
32 static __u64 *blessed_reg, blessed_n;
33 
34 extern struct vcpu_reg_list *vcpu_configs[];
35 extern int vcpu_configs_n;
36 
37 #define for_each_reg(i)								\
38 	for ((i) = 0; (i) < reg_list->n; ++(i))
39 
40 #define for_each_reg_filtered(i)						\
41 	for_each_reg(i)								\
42 		if (!filter_reg(reg_list->reg[i]))
43 
44 #define for_each_missing_reg(i)							\
45 	for ((i) = 0; (i) < blessed_n; ++(i))					\
46 		if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i]))	\
47 			if (check_supported_reg(vcpu, blessed_reg[i]))
48 
49 #define for_each_new_reg(i)							\
50 	for_each_reg_filtered(i)						\
51 		if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
52 
53 #define for_each_present_blessed_reg(i)						\
54 	for_each_reg(i)								\
55 		if (find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
56 
config_name(struct vcpu_reg_list * c)57 static const char *config_name(struct vcpu_reg_list *c)
58 {
59 	struct vcpu_reg_sublist *s;
60 	int len = 0;
61 
62 	if (c->name)
63 		return c->name;
64 
65 	for_each_sublist(c, s)
66 		len += strlen(s->name) + 1;
67 
68 	c->name = malloc(len);
69 
70 	len = 0;
71 	for_each_sublist(c, s) {
72 		if (!strcmp(s->name, "base"))
73 			continue;
74 		if (len)
75 			c->name[len++] = '+';
76 		strcpy(c->name + len, s->name);
77 		len += strlen(s->name);
78 	}
79 	c->name[len] = '\0';
80 
81 	return c->name;
82 }
83 
check_supported_reg(struct kvm_vcpu * vcpu,__u64 reg)84 bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg)
85 {
86 	return true;
87 }
88 
filter_reg(__u64 reg)89 bool __weak filter_reg(__u64 reg)
90 {
91 	return false;
92 }
93 
find_reg(__u64 regs[],__u64 nr_regs,__u64 reg)94 static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg)
95 {
96 	int i;
97 
98 	for (i = 0; i < nr_regs; ++i)
99 		if (reg == regs[i])
100 			return true;
101 	return false;
102 }
103 
print_reg(const char * prefix,__u64 id)104 void __weak print_reg(const char *prefix, __u64 id)
105 {
106 	printf("\t0x%llx,\n", id);
107 }
108 
check_reject_set(int err)109 bool __weak check_reject_set(int err)
110 {
111 	return true;
112 }
113 
finalize_vcpu(struct kvm_vcpu * vcpu,struct vcpu_reg_list * c)114 void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
115 {
116 }
117 
118 #ifdef __aarch64__
prepare_vcpu_init(struct vcpu_reg_list * c,struct kvm_vcpu_init * init)119 static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init)
120 {
121 	struct vcpu_reg_sublist *s;
122 
123 	for_each_sublist(c, s)
124 		if (s->capability)
125 			init->features[s->feature / 32] |= 1 << (s->feature % 32);
126 }
127 
vcpu_config_get_vcpu(struct vcpu_reg_list * c,struct kvm_vm * vm)128 static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
129 {
130 	struct kvm_vcpu_init init = { .target = -1, };
131 	struct kvm_vcpu *vcpu;
132 
133 	prepare_vcpu_init(c, &init);
134 	vcpu = __vm_vcpu_add(vm, 0);
135 	aarch64_vcpu_setup(vcpu, &init);
136 
137 	return vcpu;
138 }
139 #else
vcpu_config_get_vcpu(struct vcpu_reg_list * c,struct kvm_vm * vm)140 static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
141 {
142 	return __vm_vcpu_add(vm, 0);
143 }
144 #endif
145 
check_supported(struct vcpu_reg_list * c)146 static void check_supported(struct vcpu_reg_list *c)
147 {
148 	struct vcpu_reg_sublist *s;
149 
150 	for_each_sublist(c, s) {
151 		if (!s->capability)
152 			continue;
153 
154 		__TEST_REQUIRE(kvm_has_cap(s->capability),
155 			       "%s: %s not available, skipping tests",
156 			       config_name(c), s->name);
157 	}
158 }
159 
160 static bool print_list;
161 static bool print_filtered;
162 
run_test(struct vcpu_reg_list * c)163 static void run_test(struct vcpu_reg_list *c)
164 {
165 	int new_regs = 0, missing_regs = 0, i, n;
166 	int failed_get = 0, failed_set = 0, failed_reject = 0;
167 	int skipped_set = 0;
168 	struct kvm_vcpu *vcpu;
169 	struct kvm_vm *vm;
170 	struct vcpu_reg_sublist *s;
171 
172 	check_supported(c);
173 
174 	vm = vm_create_barebones();
175 	vcpu = vcpu_config_get_vcpu(c, vm);
176 	finalize_vcpu(vcpu, c);
177 
178 	reg_list = vcpu_get_reg_list(vcpu);
179 
180 	if (print_list || print_filtered) {
181 		putchar('\n');
182 		for_each_reg(i) {
183 			__u64 id = reg_list->reg[i];
184 			if ((print_list && !filter_reg(id)) ||
185 			    (print_filtered && filter_reg(id)))
186 				print_reg(config_name(c), id);
187 		}
188 		putchar('\n');
189 		return;
190 	}
191 
192 	for_each_sublist(c, s)
193 		blessed_n += s->regs_n;
194 	blessed_reg = calloc(blessed_n, sizeof(__u64));
195 
196 	n = 0;
197 	for_each_sublist(c, s) {
198 		for (i = 0; i < s->regs_n; ++i)
199 			blessed_reg[n++] = s->regs[i];
200 	}
201 
202 	/*
203 	 * We only test that we can get the register and then write back the
204 	 * same value. Some registers may allow other values to be written
205 	 * back, but others only allow some bits to be changed, and at least
206 	 * for ID registers set will fail if the value does not exactly match
207 	 * what was returned by get. If registers that allow other values to
208 	 * be written need to have the other values tested, then we should
209 	 * create a new set of tests for those in a new independent test
210 	 * executable.
211 	 *
212 	 * Only do the get/set tests on present, blessed list registers,
213 	 * since we don't know the capabilities of any new registers.
214 	 */
215 	for_each_present_blessed_reg(i) {
216 		uint8_t addr[2048 / 8];
217 		struct kvm_one_reg reg = {
218 			.id = reg_list->reg[i],
219 			.addr = (__u64)&addr,
220 		};
221 		bool reject_reg = false, skip_reg = false;
222 		int ret;
223 
224 		ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr);
225 		if (ret) {
226 			printf("%s: Failed to get ", config_name(c));
227 			print_reg(config_name(c), reg.id);
228 			putchar('\n');
229 			++failed_get;
230 		}
231 
232 		for_each_sublist(c, s) {
233 			/* rejects_set registers are rejected for set operation */
234 			if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) {
235 				reject_reg = true;
236 				ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
237 				if (ret != -1 || !check_reject_set(errno)) {
238 					printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno);
239 					print_reg(config_name(c), reg.id);
240 					putchar('\n');
241 					++failed_reject;
242 				}
243 				break;
244 			}
245 
246 			/* skips_set registers are skipped for set operation */
247 			if (s->skips_set && find_reg(s->skips_set, s->skips_set_n, reg.id)) {
248 				skip_reg = true;
249 				++skipped_set;
250 				break;
251 			}
252 		}
253 
254 		if (!reject_reg && !skip_reg) {
255 			ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
256 			if (ret) {
257 				printf("%s: Failed to set ", config_name(c));
258 				print_reg(config_name(c), reg.id);
259 				putchar('\n');
260 				++failed_set;
261 			}
262 		}
263 	}
264 
265 	for_each_new_reg(i)
266 		++new_regs;
267 
268 	for_each_missing_reg(i)
269 		++missing_regs;
270 
271 	if (new_regs || missing_regs) {
272 		n = 0;
273 		for_each_reg_filtered(i)
274 			++n;
275 
276 		printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n);
277 		printf("%s: Number registers:         %5lld (includes %lld filtered registers)\n",
278 		       config_name(c), reg_list->n, reg_list->n - n);
279 	}
280 
281 	if (new_regs) {
282 		printf("\n%s: There are %d new registers.\n"
283 		       "Consider adding them to the blessed reg "
284 		       "list with the following lines:\n\n", config_name(c), new_regs);
285 		for_each_new_reg(i)
286 			print_reg(config_name(c), reg_list->reg[i]);
287 		putchar('\n');
288 	}
289 
290 	if (missing_regs) {
291 		printf("\n%s: There are %d missing registers.\n"
292 		       "The following lines are missing registers:\n\n", config_name(c), missing_regs);
293 		for_each_missing_reg(i)
294 			print_reg(config_name(c), blessed_reg[i]);
295 		putchar('\n');
296 	}
297 
298 	TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject,
299 		    "%s: There are %d missing registers; %d registers failed get; "
300 		    "%d registers failed set; %d registers failed reject; %d registers skipped set",
301 		    config_name(c), missing_regs, failed_get, failed_set, failed_reject, skipped_set);
302 
303 	pr_info("%s: PASS\n", config_name(c));
304 	blessed_n = 0;
305 	free(blessed_reg);
306 	free(reg_list);
307 	kvm_vm_free(vm);
308 }
309 
help(void)310 static void help(void)
311 {
312 	struct vcpu_reg_list *c;
313 	int i;
314 
315 	printf(
316 	"\n"
317 	"usage: get-reg-list [--config=<selection>] [--list] [--list-filtered]\n\n"
318 	" --config=<selection>        Used to select a specific vcpu configuration for the test/listing\n"
319 	"                             '<selection>' may be\n");
320 
321 	for (i = 0; i < vcpu_configs_n; ++i) {
322 		c = vcpu_configs[i];
323 		printf(
324 	"                               '%s'\n", config_name(c));
325 	}
326 
327 	printf(
328 	"\n"
329 	" --list                      Print the register list rather than test it (requires --config)\n"
330 	" --list-filtered             Print registers that would normally be filtered out (requires --config)\n"
331 	"\n"
332 	);
333 }
334 
parse_config(const char * config)335 static struct vcpu_reg_list *parse_config(const char *config)
336 {
337 	struct vcpu_reg_list *c = NULL;
338 	int i;
339 
340 	if (config[8] != '=')
341 		help(), exit(1);
342 
343 	for (i = 0; i < vcpu_configs_n; ++i) {
344 		c = vcpu_configs[i];
345 		if (strcmp(config_name(c), &config[9]) == 0)
346 			break;
347 	}
348 
349 	if (i == vcpu_configs_n)
350 		help(), exit(1);
351 
352 	return c;
353 }
354 
main(int ac,char ** av)355 int main(int ac, char **av)
356 {
357 	struct vcpu_reg_list *c, *sel = NULL;
358 	int i, ret = 0;
359 	pid_t pid;
360 
361 	for (i = 1; i < ac; ++i) {
362 		if (strncmp(av[i], "--config", 8) == 0)
363 			sel = parse_config(av[i]);
364 		else if (strcmp(av[i], "--list") == 0)
365 			print_list = true;
366 		else if (strcmp(av[i], "--list-filtered") == 0)
367 			print_filtered = true;
368 		else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0)
369 			help(), exit(0);
370 		else
371 			help(), exit(1);
372 	}
373 
374 	if (print_list || print_filtered) {
375 		/*
376 		 * We only want to print the register list of a single config.
377 		 */
378 		if (!sel)
379 			help(), exit(1);
380 	}
381 
382 	for (i = 0; i < vcpu_configs_n; ++i) {
383 		c = vcpu_configs[i];
384 		if (sel && c != sel)
385 			continue;
386 
387 		pid = fork();
388 
389 		if (!pid) {
390 			run_test(c);
391 			exit(0);
392 		} else {
393 			int wstatus;
394 			pid_t wpid = wait(&wstatus);
395 			TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return");
396 			if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP)
397 				ret = KSFT_FAIL;
398 		}
399 	}
400 
401 	return ret;
402 }
403