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 | |
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 | |
84 | bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg) |
85 | { |
86 | return true; |
87 | } |
88 | |
89 | bool __weak filter_reg(__u64 reg) |
90 | { |
91 | return false; |
92 | } |
93 | |
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 | |
104 | void __weak print_reg(const char *prefix, __u64 id) |
105 | { |
106 | printf("\t0x%llx,\n" , id); |
107 | } |
108 | |
109 | bool __weak check_reject_set(int err) |
110 | { |
111 | return true; |
112 | } |
113 | |
114 | void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) |
115 | { |
116 | } |
117 | |
118 | #ifdef __aarch64__ |
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 | |
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 |
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 | |
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 | |
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, ®); |
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, ®); |
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 | |
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 | |
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 | |
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(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 | |