1*17da79e0SAndrew Jones // SPDX-License-Identifier: GPL-2.0 2*17da79e0SAndrew Jones /* 3*17da79e0SAndrew Jones * Check for KVM_GET_REG_LIST regressions. 4*17da79e0SAndrew Jones * 5*17da79e0SAndrew Jones * Copyright (C) 2020, Red Hat, Inc. 6*17da79e0SAndrew Jones * 7*17da79e0SAndrew Jones * When attempting to migrate from a host with an older kernel to a host 8*17da79e0SAndrew Jones * with a newer kernel we allow the newer kernel on the destination to 9*17da79e0SAndrew Jones * list new registers with get-reg-list. We assume they'll be unused, at 10*17da79e0SAndrew Jones * least until the guest reboots, and so they're relatively harmless. 11*17da79e0SAndrew Jones * However, if the destination host with the newer kernel is missing 12*17da79e0SAndrew Jones * registers which the source host with the older kernel has, then that's 13*17da79e0SAndrew Jones * a regression in get-reg-list. This test checks for that regression by 14*17da79e0SAndrew Jones * checking the current list against a blessed list. We should never have 15*17da79e0SAndrew Jones * missing registers, but if new ones appear then they can probably be 16*17da79e0SAndrew Jones * added to the blessed list. A completely new blessed list can be created 17*17da79e0SAndrew Jones * by running the test with the --list command line argument. 18*17da79e0SAndrew Jones * 19*17da79e0SAndrew Jones * The blessed list should be created from the oldest possible kernel. 20*17da79e0SAndrew Jones */ 21*17da79e0SAndrew Jones #include <stdio.h> 22*17da79e0SAndrew Jones #include <stdlib.h> 23*17da79e0SAndrew Jones #include <string.h> 24*17da79e0SAndrew Jones #include <unistd.h> 25*17da79e0SAndrew Jones #include <sys/types.h> 26*17da79e0SAndrew Jones #include <sys/wait.h> 27*17da79e0SAndrew Jones #include "kvm_util.h" 28*17da79e0SAndrew Jones #include "test_util.h" 29*17da79e0SAndrew Jones #include "processor.h" 30*17da79e0SAndrew Jones 31*17da79e0SAndrew Jones static struct kvm_reg_list *reg_list; 32*17da79e0SAndrew Jones static __u64 *blessed_reg, blessed_n; 33*17da79e0SAndrew Jones 34*17da79e0SAndrew Jones extern struct vcpu_reg_list *vcpu_configs[]; 35*17da79e0SAndrew Jones extern int vcpu_configs_n; 36*17da79e0SAndrew Jones 37*17da79e0SAndrew Jones #define for_each_sublist(c, s) \ 38*17da79e0SAndrew Jones for ((s) = &(c)->sublists[0]; (s)->regs; ++(s)) 39*17da79e0SAndrew Jones 40*17da79e0SAndrew Jones #define for_each_reg(i) \ 41*17da79e0SAndrew Jones for ((i) = 0; (i) < reg_list->n; ++(i)) 42*17da79e0SAndrew Jones 43*17da79e0SAndrew Jones #define for_each_reg_filtered(i) \ 44*17da79e0SAndrew Jones for_each_reg(i) \ 45*17da79e0SAndrew Jones if (!filter_reg(reg_list->reg[i])) 46*17da79e0SAndrew Jones 47*17da79e0SAndrew Jones #define for_each_missing_reg(i) \ 48*17da79e0SAndrew Jones for ((i) = 0; (i) < blessed_n; ++(i)) \ 49*17da79e0SAndrew Jones if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) \ 50*17da79e0SAndrew Jones if (check_supported_reg(vcpu, blessed_reg[i])) 51*17da79e0SAndrew Jones 52*17da79e0SAndrew Jones #define for_each_new_reg(i) \ 53*17da79e0SAndrew Jones for_each_reg_filtered(i) \ 54*17da79e0SAndrew Jones if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) 55*17da79e0SAndrew Jones 56*17da79e0SAndrew Jones static const char *config_name(struct vcpu_reg_list *c) 57*17da79e0SAndrew Jones { 58*17da79e0SAndrew Jones struct vcpu_reg_sublist *s; 59*17da79e0SAndrew Jones int len = 0; 60*17da79e0SAndrew Jones 61*17da79e0SAndrew Jones if (c->name) 62*17da79e0SAndrew Jones return c->name; 63*17da79e0SAndrew Jones 64*17da79e0SAndrew Jones for_each_sublist(c, s) 65*17da79e0SAndrew Jones len += strlen(s->name) + 1; 66*17da79e0SAndrew Jones 67*17da79e0SAndrew Jones c->name = malloc(len); 68*17da79e0SAndrew Jones 69*17da79e0SAndrew Jones len = 0; 70*17da79e0SAndrew Jones for_each_sublist(c, s) { 71*17da79e0SAndrew Jones if (!strcmp(s->name, "base")) 72*17da79e0SAndrew Jones continue; 73*17da79e0SAndrew Jones strcat(c->name + len, s->name); 74*17da79e0SAndrew Jones len += strlen(s->name) + 1; 75*17da79e0SAndrew Jones c->name[len - 1] = '+'; 76*17da79e0SAndrew Jones } 77*17da79e0SAndrew Jones c->name[len - 1] = '\0'; 78*17da79e0SAndrew Jones 79*17da79e0SAndrew Jones return c->name; 80*17da79e0SAndrew Jones } 81*17da79e0SAndrew Jones 82*17da79e0SAndrew Jones bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg) 83*17da79e0SAndrew Jones { 84*17da79e0SAndrew Jones return true; 85*17da79e0SAndrew Jones } 86*17da79e0SAndrew Jones 87*17da79e0SAndrew Jones bool __weak filter_reg(__u64 reg) 88*17da79e0SAndrew Jones { 89*17da79e0SAndrew Jones return false; 90*17da79e0SAndrew Jones } 91*17da79e0SAndrew Jones 92*17da79e0SAndrew Jones static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg) 93*17da79e0SAndrew Jones { 94*17da79e0SAndrew Jones int i; 95*17da79e0SAndrew Jones 96*17da79e0SAndrew Jones for (i = 0; i < nr_regs; ++i) 97*17da79e0SAndrew Jones if (reg == regs[i]) 98*17da79e0SAndrew Jones return true; 99*17da79e0SAndrew Jones return false; 100*17da79e0SAndrew Jones } 101*17da79e0SAndrew Jones 102*17da79e0SAndrew Jones void __weak print_reg(const char *prefix, __u64 id) 103*17da79e0SAndrew Jones { 104*17da79e0SAndrew Jones printf("\t0x%llx,\n", id); 105*17da79e0SAndrew Jones } 106*17da79e0SAndrew Jones 107*17da79e0SAndrew Jones static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) 108*17da79e0SAndrew Jones { 109*17da79e0SAndrew Jones struct vcpu_reg_sublist *s; 110*17da79e0SAndrew Jones 111*17da79e0SAndrew Jones for_each_sublist(c, s) 112*17da79e0SAndrew Jones if (s->capability) 113*17da79e0SAndrew Jones init->features[s->feature / 32] |= 1 << (s->feature % 32); 114*17da79e0SAndrew Jones } 115*17da79e0SAndrew Jones 116*17da79e0SAndrew Jones static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) 117*17da79e0SAndrew Jones { 118*17da79e0SAndrew Jones struct vcpu_reg_sublist *s; 119*17da79e0SAndrew Jones int feature; 120*17da79e0SAndrew Jones 121*17da79e0SAndrew Jones for_each_sublist(c, s) { 122*17da79e0SAndrew Jones if (s->finalize) { 123*17da79e0SAndrew Jones feature = s->feature; 124*17da79e0SAndrew Jones vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); 125*17da79e0SAndrew Jones } 126*17da79e0SAndrew Jones } 127*17da79e0SAndrew Jones } 128*17da79e0SAndrew Jones 129*17da79e0SAndrew Jones static void check_supported(struct vcpu_reg_list *c) 130*17da79e0SAndrew Jones { 131*17da79e0SAndrew Jones struct vcpu_reg_sublist *s; 132*17da79e0SAndrew Jones 133*17da79e0SAndrew Jones for_each_sublist(c, s) { 134*17da79e0SAndrew Jones if (!s->capability) 135*17da79e0SAndrew Jones continue; 136*17da79e0SAndrew Jones 137*17da79e0SAndrew Jones __TEST_REQUIRE(kvm_has_cap(s->capability), 138*17da79e0SAndrew Jones "%s: %s not available, skipping tests\n", 139*17da79e0SAndrew Jones config_name(c), s->name); 140*17da79e0SAndrew Jones } 141*17da79e0SAndrew Jones } 142*17da79e0SAndrew Jones 143*17da79e0SAndrew Jones static bool print_list; 144*17da79e0SAndrew Jones static bool print_filtered; 145*17da79e0SAndrew Jones 146*17da79e0SAndrew Jones static void run_test(struct vcpu_reg_list *c) 147*17da79e0SAndrew Jones { 148*17da79e0SAndrew Jones struct kvm_vcpu_init init = { .target = -1, }; 149*17da79e0SAndrew Jones int new_regs = 0, missing_regs = 0, i, n; 150*17da79e0SAndrew Jones int failed_get = 0, failed_set = 0, failed_reject = 0; 151*17da79e0SAndrew Jones struct kvm_vcpu *vcpu; 152*17da79e0SAndrew Jones struct kvm_vm *vm; 153*17da79e0SAndrew Jones struct vcpu_reg_sublist *s; 154*17da79e0SAndrew Jones 155*17da79e0SAndrew Jones check_supported(c); 156*17da79e0SAndrew Jones 157*17da79e0SAndrew Jones vm = vm_create_barebones(); 158*17da79e0SAndrew Jones prepare_vcpu_init(c, &init); 159*17da79e0SAndrew Jones vcpu = __vm_vcpu_add(vm, 0); 160*17da79e0SAndrew Jones aarch64_vcpu_setup(vcpu, &init); 161*17da79e0SAndrew Jones finalize_vcpu(vcpu, c); 162*17da79e0SAndrew Jones 163*17da79e0SAndrew Jones reg_list = vcpu_get_reg_list(vcpu); 164*17da79e0SAndrew Jones 165*17da79e0SAndrew Jones if (print_list || print_filtered) { 166*17da79e0SAndrew Jones putchar('\n'); 167*17da79e0SAndrew Jones for_each_reg(i) { 168*17da79e0SAndrew Jones __u64 id = reg_list->reg[i]; 169*17da79e0SAndrew Jones if ((print_list && !filter_reg(id)) || 170*17da79e0SAndrew Jones (print_filtered && filter_reg(id))) 171*17da79e0SAndrew Jones print_reg(config_name(c), id); 172*17da79e0SAndrew Jones } 173*17da79e0SAndrew Jones putchar('\n'); 174*17da79e0SAndrew Jones return; 175*17da79e0SAndrew Jones } 176*17da79e0SAndrew Jones 177*17da79e0SAndrew Jones /* 178*17da79e0SAndrew Jones * We only test that we can get the register and then write back the 179*17da79e0SAndrew Jones * same value. Some registers may allow other values to be written 180*17da79e0SAndrew Jones * back, but others only allow some bits to be changed, and at least 181*17da79e0SAndrew Jones * for ID registers set will fail if the value does not exactly match 182*17da79e0SAndrew Jones * what was returned by get. If registers that allow other values to 183*17da79e0SAndrew Jones * be written need to have the other values tested, then we should 184*17da79e0SAndrew Jones * create a new set of tests for those in a new independent test 185*17da79e0SAndrew Jones * executable. 186*17da79e0SAndrew Jones */ 187*17da79e0SAndrew Jones for_each_reg(i) { 188*17da79e0SAndrew Jones uint8_t addr[2048 / 8]; 189*17da79e0SAndrew Jones struct kvm_one_reg reg = { 190*17da79e0SAndrew Jones .id = reg_list->reg[i], 191*17da79e0SAndrew Jones .addr = (__u64)&addr, 192*17da79e0SAndrew Jones }; 193*17da79e0SAndrew Jones bool reject_reg = false; 194*17da79e0SAndrew Jones int ret; 195*17da79e0SAndrew Jones 196*17da79e0SAndrew Jones ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); 197*17da79e0SAndrew Jones if (ret) { 198*17da79e0SAndrew Jones printf("%s: Failed to get ", config_name(c)); 199*17da79e0SAndrew Jones print_reg(config_name(c), reg.id); 200*17da79e0SAndrew Jones putchar('\n'); 201*17da79e0SAndrew Jones ++failed_get; 202*17da79e0SAndrew Jones } 203*17da79e0SAndrew Jones 204*17da79e0SAndrew Jones /* rejects_set registers are rejected after KVM_ARM_VCPU_FINALIZE */ 205*17da79e0SAndrew Jones for_each_sublist(c, s) { 206*17da79e0SAndrew Jones if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { 207*17da79e0SAndrew Jones reject_reg = true; 208*17da79e0SAndrew Jones ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); 209*17da79e0SAndrew Jones if (ret != -1 || errno != EPERM) { 210*17da79e0SAndrew Jones printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); 211*17da79e0SAndrew Jones print_reg(config_name(c), reg.id); 212*17da79e0SAndrew Jones putchar('\n'); 213*17da79e0SAndrew Jones ++failed_reject; 214*17da79e0SAndrew Jones } 215*17da79e0SAndrew Jones break; 216*17da79e0SAndrew Jones } 217*17da79e0SAndrew Jones } 218*17da79e0SAndrew Jones 219*17da79e0SAndrew Jones if (!reject_reg) { 220*17da79e0SAndrew Jones ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); 221*17da79e0SAndrew Jones if (ret) { 222*17da79e0SAndrew Jones printf("%s: Failed to set ", config_name(c)); 223*17da79e0SAndrew Jones print_reg(config_name(c), reg.id); 224*17da79e0SAndrew Jones putchar('\n'); 225*17da79e0SAndrew Jones ++failed_set; 226*17da79e0SAndrew Jones } 227*17da79e0SAndrew Jones } 228*17da79e0SAndrew Jones } 229*17da79e0SAndrew Jones 230*17da79e0SAndrew Jones for_each_sublist(c, s) 231*17da79e0SAndrew Jones blessed_n += s->regs_n; 232*17da79e0SAndrew Jones blessed_reg = calloc(blessed_n, sizeof(__u64)); 233*17da79e0SAndrew Jones 234*17da79e0SAndrew Jones n = 0; 235*17da79e0SAndrew Jones for_each_sublist(c, s) { 236*17da79e0SAndrew Jones for (i = 0; i < s->regs_n; ++i) 237*17da79e0SAndrew Jones blessed_reg[n++] = s->regs[i]; 238*17da79e0SAndrew Jones } 239*17da79e0SAndrew Jones 240*17da79e0SAndrew Jones for_each_new_reg(i) 241*17da79e0SAndrew Jones ++new_regs; 242*17da79e0SAndrew Jones 243*17da79e0SAndrew Jones for_each_missing_reg(i) 244*17da79e0SAndrew Jones ++missing_regs; 245*17da79e0SAndrew Jones 246*17da79e0SAndrew Jones if (new_regs || missing_regs) { 247*17da79e0SAndrew Jones n = 0; 248*17da79e0SAndrew Jones for_each_reg_filtered(i) 249*17da79e0SAndrew Jones ++n; 250*17da79e0SAndrew Jones 251*17da79e0SAndrew Jones printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n); 252*17da79e0SAndrew Jones printf("%s: Number registers: %5lld (includes %lld filtered registers)\n", 253*17da79e0SAndrew Jones config_name(c), reg_list->n, reg_list->n - n); 254*17da79e0SAndrew Jones } 255*17da79e0SAndrew Jones 256*17da79e0SAndrew Jones if (new_regs) { 257*17da79e0SAndrew Jones printf("\n%s: There are %d new registers.\n" 258*17da79e0SAndrew Jones "Consider adding them to the blessed reg " 259*17da79e0SAndrew Jones "list with the following lines:\n\n", config_name(c), new_regs); 260*17da79e0SAndrew Jones for_each_new_reg(i) 261*17da79e0SAndrew Jones print_reg(config_name(c), reg_list->reg[i]); 262*17da79e0SAndrew Jones putchar('\n'); 263*17da79e0SAndrew Jones } 264*17da79e0SAndrew Jones 265*17da79e0SAndrew Jones if (missing_regs) { 266*17da79e0SAndrew Jones printf("\n%s: There are %d missing registers.\n" 267*17da79e0SAndrew Jones "The following lines are missing registers:\n\n", config_name(c), missing_regs); 268*17da79e0SAndrew Jones for_each_missing_reg(i) 269*17da79e0SAndrew Jones print_reg(config_name(c), blessed_reg[i]); 270*17da79e0SAndrew Jones putchar('\n'); 271*17da79e0SAndrew Jones } 272*17da79e0SAndrew Jones 273*17da79e0SAndrew Jones TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject, 274*17da79e0SAndrew Jones "%s: There are %d missing registers; " 275*17da79e0SAndrew Jones "%d registers failed get; %d registers failed set; %d registers failed reject", 276*17da79e0SAndrew Jones config_name(c), missing_regs, failed_get, failed_set, failed_reject); 277*17da79e0SAndrew Jones 278*17da79e0SAndrew Jones pr_info("%s: PASS\n", config_name(c)); 279*17da79e0SAndrew Jones blessed_n = 0; 280*17da79e0SAndrew Jones free(blessed_reg); 281*17da79e0SAndrew Jones free(reg_list); 282*17da79e0SAndrew Jones kvm_vm_free(vm); 283*17da79e0SAndrew Jones } 284*17da79e0SAndrew Jones 285*17da79e0SAndrew Jones static void help(void) 286*17da79e0SAndrew Jones { 287*17da79e0SAndrew Jones struct vcpu_reg_list *c; 288*17da79e0SAndrew Jones int i; 289*17da79e0SAndrew Jones 290*17da79e0SAndrew Jones printf( 291*17da79e0SAndrew Jones "\n" 292*17da79e0SAndrew Jones "usage: get-reg-list [--config=<selection>] [--list] [--list-filtered]\n\n" 293*17da79e0SAndrew Jones " --config=<selection> Used to select a specific vcpu configuration for the test/listing\n" 294*17da79e0SAndrew Jones " '<selection>' may be\n"); 295*17da79e0SAndrew Jones 296*17da79e0SAndrew Jones for (i = 0; i < vcpu_configs_n; ++i) { 297*17da79e0SAndrew Jones c = vcpu_configs[i]; 298*17da79e0SAndrew Jones printf( 299*17da79e0SAndrew Jones " '%s'\n", config_name(c)); 300*17da79e0SAndrew Jones } 301*17da79e0SAndrew Jones 302*17da79e0SAndrew Jones printf( 303*17da79e0SAndrew Jones "\n" 304*17da79e0SAndrew Jones " --list Print the register list rather than test it (requires --config)\n" 305*17da79e0SAndrew Jones " --list-filtered Print registers that would normally be filtered out (requires --config)\n" 306*17da79e0SAndrew Jones "\n" 307*17da79e0SAndrew Jones ); 308*17da79e0SAndrew Jones } 309*17da79e0SAndrew Jones 310*17da79e0SAndrew Jones static struct vcpu_reg_list *parse_config(const char *config) 311*17da79e0SAndrew Jones { 312*17da79e0SAndrew Jones struct vcpu_reg_list *c = NULL; 313*17da79e0SAndrew Jones int i; 314*17da79e0SAndrew Jones 315*17da79e0SAndrew Jones if (config[8] != '=') 316*17da79e0SAndrew Jones help(), exit(1); 317*17da79e0SAndrew Jones 318*17da79e0SAndrew Jones for (i = 0; i < vcpu_configs_n; ++i) { 319*17da79e0SAndrew Jones c = vcpu_configs[i]; 320*17da79e0SAndrew Jones if (strcmp(config_name(c), &config[9]) == 0) 321*17da79e0SAndrew Jones break; 322*17da79e0SAndrew Jones } 323*17da79e0SAndrew Jones 324*17da79e0SAndrew Jones if (i == vcpu_configs_n) 325*17da79e0SAndrew Jones help(), exit(1); 326*17da79e0SAndrew Jones 327*17da79e0SAndrew Jones return c; 328*17da79e0SAndrew Jones } 329*17da79e0SAndrew Jones 330*17da79e0SAndrew Jones int main(int ac, char **av) 331*17da79e0SAndrew Jones { 332*17da79e0SAndrew Jones struct vcpu_reg_list *c, *sel = NULL; 333*17da79e0SAndrew Jones int i, ret = 0; 334*17da79e0SAndrew Jones pid_t pid; 335*17da79e0SAndrew Jones 336*17da79e0SAndrew Jones for (i = 1; i < ac; ++i) { 337*17da79e0SAndrew Jones if (strncmp(av[i], "--config", 8) == 0) 338*17da79e0SAndrew Jones sel = parse_config(av[i]); 339*17da79e0SAndrew Jones else if (strcmp(av[i], "--list") == 0) 340*17da79e0SAndrew Jones print_list = true; 341*17da79e0SAndrew Jones else if (strcmp(av[i], "--list-filtered") == 0) 342*17da79e0SAndrew Jones print_filtered = true; 343*17da79e0SAndrew Jones else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0) 344*17da79e0SAndrew Jones help(), exit(0); 345*17da79e0SAndrew Jones else 346*17da79e0SAndrew Jones help(), exit(1); 347*17da79e0SAndrew Jones } 348*17da79e0SAndrew Jones 349*17da79e0SAndrew Jones if (print_list || print_filtered) { 350*17da79e0SAndrew Jones /* 351*17da79e0SAndrew Jones * We only want to print the register list of a single config. 352*17da79e0SAndrew Jones */ 353*17da79e0SAndrew Jones if (!sel) 354*17da79e0SAndrew Jones help(), exit(1); 355*17da79e0SAndrew Jones } 356*17da79e0SAndrew Jones 357*17da79e0SAndrew Jones for (i = 0; i < vcpu_configs_n; ++i) { 358*17da79e0SAndrew Jones c = vcpu_configs[i]; 359*17da79e0SAndrew Jones if (sel && c != sel) 360*17da79e0SAndrew Jones continue; 361*17da79e0SAndrew Jones 362*17da79e0SAndrew Jones pid = fork(); 363*17da79e0SAndrew Jones 364*17da79e0SAndrew Jones if (!pid) { 365*17da79e0SAndrew Jones run_test(c); 366*17da79e0SAndrew Jones exit(0); 367*17da79e0SAndrew Jones } else { 368*17da79e0SAndrew Jones int wstatus; 369*17da79e0SAndrew Jones pid_t wpid = wait(&wstatus); 370*17da79e0SAndrew Jones TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return"); 371*17da79e0SAndrew Jones if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP) 372*17da79e0SAndrew Jones ret = KSFT_FAIL; 373*17da79e0SAndrew Jones } 374*17da79e0SAndrew Jones } 375*17da79e0SAndrew Jones 376*17da79e0SAndrew Jones return ret; 377*17da79e0SAndrew Jones } 378