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