1 // SPDX-License-Identifier: GPL-2.0
3 * Check for KVM_GET_REG_LIST regressions.
5 * Copyright (C) 2020, Red Hat, Inc.
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.
19 * The blessed list should be created from the oldest possible kernel.
25 #include <sys/types.h>
28 #include "test_util.h"
29 #include "processor.h"
31 static struct kvm_reg_list
*reg_list
;
32 static __u64
*blessed_reg
, blessed_n
;
34 extern struct vcpu_reg_list
*vcpu_configs
[];
35 extern int vcpu_configs_n
;
37 #define for_each_reg(i) \
38 for ((i) = 0; (i) < reg_list->n; ++(i))
40 #define for_each_reg_filtered(i) \
42 if (!filter_reg(reg_list->reg[i]))
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]))
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]))
53 #define for_each_present_blessed_reg(i) \
55 if (find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
57 static const char *config_name(struct vcpu_reg_list
*c
)
59 struct vcpu_reg_sublist
*s
;
65 for_each_sublist(c
, s
)
66 len
+= strlen(s
->name
) + 1;
68 c
->name
= malloc(len
);
71 for_each_sublist(c
, s
) {
72 if (!strcmp(s
->name
, "base"))
76 strcpy(c
->name
+ len
, s
->name
);
77 len
+= strlen(s
->name
);
84 bool __weak
check_supported_reg(struct kvm_vcpu
*vcpu
, __u64 reg
)
89 bool __weak
filter_reg(__u64 reg
)
94 static bool find_reg(__u64 regs
[], __u64 nr_regs
, __u64 reg
)
98 for (i
= 0; i
< nr_regs
; ++i
)
104 void __weak
print_reg(const char *prefix
, __u64 id
)
106 printf("\t0x%llx,\n", id
);
109 bool __weak
check_reject_set(int err
)
114 void __weak
finalize_vcpu(struct kvm_vcpu
*vcpu
, struct vcpu_reg_list
*c
)
119 static void prepare_vcpu_init(struct vcpu_reg_list
*c
, struct kvm_vcpu_init
*init
)
121 struct vcpu_reg_sublist
*s
;
123 for_each_sublist(c
, s
)
125 init
->features
[s
->feature
/ 32] |= 1 << (s
->feature
% 32);
128 static struct kvm_vcpu
*vcpu_config_get_vcpu(struct vcpu_reg_list
*c
, struct kvm_vm
*vm
)
130 struct kvm_vcpu_init init
= { .target
= -1, };
131 struct kvm_vcpu
*vcpu
;
133 prepare_vcpu_init(c
, &init
);
134 vcpu
= __vm_vcpu_add(vm
, 0);
135 aarch64_vcpu_setup(vcpu
, &init
);
140 static struct kvm_vcpu
*vcpu_config_get_vcpu(struct vcpu_reg_list
*c
, struct kvm_vm
*vm
)
142 return __vm_vcpu_add(vm
, 0);
146 static void check_supported(struct vcpu_reg_list
*c
)
148 struct vcpu_reg_sublist
*s
;
150 for_each_sublist(c
, s
) {
154 __TEST_REQUIRE(kvm_has_cap(s
->capability
),
155 "%s: %s not available, skipping tests",
156 config_name(c
), s
->name
);
160 static bool print_list
;
161 static bool print_filtered
;
163 static void run_test(struct vcpu_reg_list
*c
)
165 int new_regs
= 0, missing_regs
= 0, i
, n
;
166 int failed_get
= 0, failed_set
= 0, failed_reject
= 0;
168 struct kvm_vcpu
*vcpu
;
170 struct vcpu_reg_sublist
*s
;
174 vm
= vm_create_barebones();
175 vcpu
= vcpu_config_get_vcpu(c
, vm
);
176 finalize_vcpu(vcpu
, c
);
178 reg_list
= vcpu_get_reg_list(vcpu
);
180 if (print_list
|| print_filtered
) {
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
);
192 for_each_sublist(c
, s
)
193 blessed_n
+= s
->regs_n
;
194 blessed_reg
= calloc(blessed_n
, sizeof(__u64
));
197 for_each_sublist(c
, s
) {
198 for (i
= 0; i
< s
->regs_n
; ++i
)
199 blessed_reg
[n
++] = s
->regs
[i
];
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
212 * Only do the get/set tests on present, blessed list registers,
213 * since we don't know the capabilities of any new registers.
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
,
221 bool reject_reg
= false, skip_reg
= false;
224 ret
= __vcpu_get_reg(vcpu
, reg_list
->reg
[i
], &addr
);
226 printf("%s: Failed to get ", config_name(c
));
227 print_reg(config_name(c
), reg
.id
);
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
)) {
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
);
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
)) {
254 if (!reject_reg
&& !skip_reg
) {
255 ret
= __vcpu_ioctl(vcpu
, KVM_SET_ONE_REG
, ®
);
257 printf("%s: Failed to set ", config_name(c
));
258 print_reg(config_name(c
), reg
.id
);
268 for_each_missing_reg(i
)
271 if (new_regs
|| missing_regs
) {
273 for_each_reg_filtered(i
)
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
);
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
);
286 print_reg(config_name(c
), reg_list
->reg
[i
]);
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
]);
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
);
303 pr_info("%s: PASS\n", config_name(c
));
310 static void help(void)
312 struct vcpu_reg_list
*c
;
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");
321 for (i
= 0; i
< vcpu_configs_n
; ++i
) {
324 " '%s'\n", config_name(c
));
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"
335 static struct vcpu_reg_list
*parse_config(const char *config
)
337 struct vcpu_reg_list
*c
= NULL
;
340 if (config
[8] != '=')
343 for (i
= 0; i
< vcpu_configs_n
; ++i
) {
345 if (strcmp(config_name(c
), &config
[9]) == 0)
349 if (i
== vcpu_configs_n
)
355 int main(int ac
, char **av
)
357 struct vcpu_reg_list
*c
, *sel
= NULL
;
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)
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)
374 if (print_list
|| print_filtered
) {
376 * We only want to print the register list of a single config.
382 for (i
= 0; i
< vcpu_configs_n
; ++i
) {
394 pid_t wpid
= wait(&wstatus
);
395 TEST_ASSERT(wpid
== pid
&& WIFEXITED(wstatus
), "wait: Unexpected return");
396 if (WEXITSTATUS(wstatus
) && WEXITSTATUS(wstatus
) != KSFT_SKIP
)