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