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