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