1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * arch_timer.c - Tests the aarch64 timer IRQ functionality 4 * 5 * The test validates both the virtual and physical timer IRQs using 6 * CVAL and TVAL registers. This consitutes the four stages in the test. 7 * The guest's main thread configures the timer interrupt for a stage 8 * and waits for it to fire, with a timeout equal to the timer period. 9 * It asserts that the timeout doesn't exceed the timer period. 10 * 11 * On the other hand, upon receipt of an interrupt, the guest's interrupt 12 * handler validates the interrupt by checking if the architectural state 13 * is in compliance with the specifications. 14 * 15 * The test provides command-line options to configure the timer's 16 * period (-p), number of vCPUs (-n), and iterations per stage (-i). 17 * To stress-test the timer stack even more, an option to migrate the 18 * vCPUs across pCPUs (-m), at a particular rate, is also provided. 19 * 20 * Copyright (c) 2021, Google LLC. 21 */ 22 23 #define _GNU_SOURCE 24 25 #include <stdlib.h> 26 #include <pthread.h> 27 #include <linux/kvm.h> 28 #include <linux/sizes.h> 29 #include <linux/bitmap.h> 30 #include <sys/sysinfo.h> 31 32 #include "kvm_util.h" 33 #include "processor.h" 34 #include "delay.h" 35 #include "arch_timer.h" 36 #include "gic.h" 37 #include "vgic.h" 38 39 #define NR_VCPUS_DEF 4 40 #define NR_TEST_ITERS_DEF 5 41 #define TIMER_TEST_PERIOD_MS_DEF 10 42 #define TIMER_TEST_ERR_MARGIN_US 100 43 #define TIMER_TEST_MIGRATION_FREQ_MS 2 44 45 struct test_args { 46 int nr_vcpus; 47 int nr_iter; 48 int timer_period_ms; 49 int migration_freq_ms; 50 struct kvm_arm_counter_offset offset; 51 }; 52 53 static struct test_args test_args = { 54 .nr_vcpus = NR_VCPUS_DEF, 55 .nr_iter = NR_TEST_ITERS_DEF, 56 .timer_period_ms = TIMER_TEST_PERIOD_MS_DEF, 57 .migration_freq_ms = TIMER_TEST_MIGRATION_FREQ_MS, 58 .offset = { .reserved = 1 }, 59 }; 60 61 #define msecs_to_usecs(msec) ((msec) * 1000LL) 62 63 #define GICD_BASE_GPA 0x8000000ULL 64 #define GICR_BASE_GPA 0x80A0000ULL 65 66 enum guest_stage { 67 GUEST_STAGE_VTIMER_CVAL = 1, 68 GUEST_STAGE_VTIMER_TVAL, 69 GUEST_STAGE_PTIMER_CVAL, 70 GUEST_STAGE_PTIMER_TVAL, 71 GUEST_STAGE_MAX, 72 }; 73 74 /* Shared variables between host and guest */ 75 struct test_vcpu_shared_data { 76 int nr_iter; 77 enum guest_stage guest_stage; 78 uint64_t xcnt; 79 }; 80 81 static struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; 82 static pthread_t pt_vcpu_run[KVM_MAX_VCPUS]; 83 static struct test_vcpu_shared_data vcpu_shared_data[KVM_MAX_VCPUS]; 84 85 static int vtimer_irq, ptimer_irq; 86 87 static unsigned long *vcpu_done_map; 88 static pthread_mutex_t vcpu_done_map_lock; 89 90 static void 91 guest_configure_timer_action(struct test_vcpu_shared_data *shared_data) 92 { 93 switch (shared_data->guest_stage) { 94 case GUEST_STAGE_VTIMER_CVAL: 95 timer_set_next_cval_ms(VIRTUAL, test_args.timer_period_ms); 96 shared_data->xcnt = timer_get_cntct(VIRTUAL); 97 timer_set_ctl(VIRTUAL, CTL_ENABLE); 98 break; 99 case GUEST_STAGE_VTIMER_TVAL: 100 timer_set_next_tval_ms(VIRTUAL, test_args.timer_period_ms); 101 shared_data->xcnt = timer_get_cntct(VIRTUAL); 102 timer_set_ctl(VIRTUAL, CTL_ENABLE); 103 break; 104 case GUEST_STAGE_PTIMER_CVAL: 105 timer_set_next_cval_ms(PHYSICAL, test_args.timer_period_ms); 106 shared_data->xcnt = timer_get_cntct(PHYSICAL); 107 timer_set_ctl(PHYSICAL, CTL_ENABLE); 108 break; 109 case GUEST_STAGE_PTIMER_TVAL: 110 timer_set_next_tval_ms(PHYSICAL, test_args.timer_period_ms); 111 shared_data->xcnt = timer_get_cntct(PHYSICAL); 112 timer_set_ctl(PHYSICAL, CTL_ENABLE); 113 break; 114 default: 115 GUEST_ASSERT(0); 116 } 117 } 118 119 static void guest_validate_irq(unsigned int intid, 120 struct test_vcpu_shared_data *shared_data) 121 { 122 enum guest_stage stage = shared_data->guest_stage; 123 uint64_t xcnt = 0, xcnt_diff_us, cval = 0; 124 unsigned long xctl = 0; 125 unsigned int timer_irq = 0; 126 unsigned int accessor; 127 128 if (intid == IAR_SPURIOUS) 129 return; 130 131 switch (stage) { 132 case GUEST_STAGE_VTIMER_CVAL: 133 case GUEST_STAGE_VTIMER_TVAL: 134 accessor = VIRTUAL; 135 timer_irq = vtimer_irq; 136 break; 137 case GUEST_STAGE_PTIMER_CVAL: 138 case GUEST_STAGE_PTIMER_TVAL: 139 accessor = PHYSICAL; 140 timer_irq = ptimer_irq; 141 break; 142 default: 143 GUEST_ASSERT(0); 144 return; 145 } 146 147 xctl = timer_get_ctl(accessor); 148 if ((xctl & CTL_IMASK) || !(xctl & CTL_ENABLE)) 149 return; 150 151 timer_set_ctl(accessor, CTL_IMASK); 152 xcnt = timer_get_cntct(accessor); 153 cval = timer_get_cval(accessor); 154 155 xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt); 156 157 /* Make sure we are dealing with the correct timer IRQ */ 158 GUEST_ASSERT_2(intid == timer_irq, intid, timer_irq); 159 160 /* Basic 'timer condition met' check */ 161 GUEST_ASSERT_3(xcnt >= cval, xcnt, cval, xcnt_diff_us); 162 GUEST_ASSERT_1(xctl & CTL_ISTATUS, xctl); 163 164 WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); 165 } 166 167 static void guest_irq_handler(struct ex_regs *regs) 168 { 169 unsigned int intid = gic_get_and_ack_irq(); 170 uint32_t cpu = guest_get_vcpuid(); 171 struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 172 173 guest_validate_irq(intid, shared_data); 174 175 gic_set_eoi(intid); 176 } 177 178 static void guest_run_stage(struct test_vcpu_shared_data *shared_data, 179 enum guest_stage stage) 180 { 181 uint32_t irq_iter, config_iter; 182 183 shared_data->guest_stage = stage; 184 shared_data->nr_iter = 0; 185 186 for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { 187 /* Setup the next interrupt */ 188 guest_configure_timer_action(shared_data); 189 190 /* Setup a timeout for the interrupt to arrive */ 191 udelay(msecs_to_usecs(test_args.timer_period_ms) + 192 TIMER_TEST_ERR_MARGIN_US); 193 194 irq_iter = READ_ONCE(shared_data->nr_iter); 195 GUEST_ASSERT_2(config_iter + 1 == irq_iter, 196 config_iter + 1, irq_iter); 197 } 198 } 199 200 static void guest_code(void) 201 { 202 uint32_t cpu = guest_get_vcpuid(); 203 struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; 204 205 local_irq_disable(); 206 207 gic_init(GIC_V3, test_args.nr_vcpus, 208 (void *)GICD_BASE_GPA, (void *)GICR_BASE_GPA); 209 210 timer_set_ctl(VIRTUAL, CTL_IMASK); 211 timer_set_ctl(PHYSICAL, CTL_IMASK); 212 213 gic_irq_enable(vtimer_irq); 214 gic_irq_enable(ptimer_irq); 215 local_irq_enable(); 216 217 guest_run_stage(shared_data, GUEST_STAGE_VTIMER_CVAL); 218 guest_run_stage(shared_data, GUEST_STAGE_VTIMER_TVAL); 219 guest_run_stage(shared_data, GUEST_STAGE_PTIMER_CVAL); 220 guest_run_stage(shared_data, GUEST_STAGE_PTIMER_TVAL); 221 222 GUEST_DONE(); 223 } 224 225 static void *test_vcpu_run(void *arg) 226 { 227 unsigned int vcpu_idx = (unsigned long)arg; 228 struct ucall uc; 229 struct kvm_vcpu *vcpu = vcpus[vcpu_idx]; 230 struct kvm_vm *vm = vcpu->vm; 231 struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpu_idx]; 232 233 vcpu_run(vcpu); 234 235 /* Currently, any exit from guest is an indication of completion */ 236 pthread_mutex_lock(&vcpu_done_map_lock); 237 __set_bit(vcpu_idx, vcpu_done_map); 238 pthread_mutex_unlock(&vcpu_done_map_lock); 239 240 switch (get_ucall(vcpu, &uc)) { 241 case UCALL_SYNC: 242 case UCALL_DONE: 243 break; 244 case UCALL_ABORT: 245 sync_global_from_guest(vm, *shared_data); 246 REPORT_GUEST_ASSERT_N(uc, "values: %lu, %lu; %lu, vcpu %u; stage; %u; iter: %u", 247 GUEST_ASSERT_ARG(uc, 0), 248 GUEST_ASSERT_ARG(uc, 1), 249 GUEST_ASSERT_ARG(uc, 2), 250 vcpu_idx, 251 shared_data->guest_stage, 252 shared_data->nr_iter); 253 break; 254 default: 255 TEST_FAIL("Unexpected guest exit\n"); 256 } 257 258 return NULL; 259 } 260 261 static uint32_t test_get_pcpu(void) 262 { 263 uint32_t pcpu; 264 unsigned int nproc_conf; 265 cpu_set_t online_cpuset; 266 267 nproc_conf = get_nprocs_conf(); 268 sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset); 269 270 /* Randomly find an available pCPU to place a vCPU on */ 271 do { 272 pcpu = rand() % nproc_conf; 273 } while (!CPU_ISSET(pcpu, &online_cpuset)); 274 275 return pcpu; 276 } 277 278 static int test_migrate_vcpu(unsigned int vcpu_idx) 279 { 280 int ret; 281 cpu_set_t cpuset; 282 uint32_t new_pcpu = test_get_pcpu(); 283 284 CPU_ZERO(&cpuset); 285 CPU_SET(new_pcpu, &cpuset); 286 287 pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); 288 289 ret = pthread_setaffinity_np(pt_vcpu_run[vcpu_idx], 290 sizeof(cpuset), &cpuset); 291 292 /* Allow the error where the vCPU thread is already finished */ 293 TEST_ASSERT(ret == 0 || ret == ESRCH, 294 "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d\n", 295 vcpu_idx, new_pcpu, ret); 296 297 return ret; 298 } 299 300 static void *test_vcpu_migration(void *arg) 301 { 302 unsigned int i, n_done; 303 bool vcpu_done; 304 305 do { 306 usleep(msecs_to_usecs(test_args.migration_freq_ms)); 307 308 for (n_done = 0, i = 0; i < test_args.nr_vcpus; i++) { 309 pthread_mutex_lock(&vcpu_done_map_lock); 310 vcpu_done = test_bit(i, vcpu_done_map); 311 pthread_mutex_unlock(&vcpu_done_map_lock); 312 313 if (vcpu_done) { 314 n_done++; 315 continue; 316 } 317 318 test_migrate_vcpu(i); 319 } 320 } while (test_args.nr_vcpus != n_done); 321 322 return NULL; 323 } 324 325 static void test_run(struct kvm_vm *vm) 326 { 327 pthread_t pt_vcpu_migration; 328 unsigned int i; 329 int ret; 330 331 pthread_mutex_init(&vcpu_done_map_lock, NULL); 332 vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus); 333 TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap\n"); 334 335 for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) { 336 ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run, 337 (void *)(unsigned long)i); 338 TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread\n", i); 339 } 340 341 /* Spawn a thread to control the vCPU migrations */ 342 if (test_args.migration_freq_ms) { 343 srand(time(NULL)); 344 345 ret = pthread_create(&pt_vcpu_migration, NULL, 346 test_vcpu_migration, NULL); 347 TEST_ASSERT(!ret, "Failed to create the migration pthread\n"); 348 } 349 350 351 for (i = 0; i < test_args.nr_vcpus; i++) 352 pthread_join(pt_vcpu_run[i], NULL); 353 354 if (test_args.migration_freq_ms) 355 pthread_join(pt_vcpu_migration, NULL); 356 357 bitmap_free(vcpu_done_map); 358 } 359 360 static void test_init_timer_irq(struct kvm_vm *vm) 361 { 362 /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ 363 vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, 364 KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); 365 vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, 366 KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); 367 368 sync_global_to_guest(vm, ptimer_irq); 369 sync_global_to_guest(vm, vtimer_irq); 370 371 pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq); 372 } 373 374 static int gic_fd; 375 376 static struct kvm_vm *test_vm_create(void) 377 { 378 struct kvm_vm *vm; 379 unsigned int i; 380 int nr_vcpus = test_args.nr_vcpus; 381 382 vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); 383 384 vm_init_descriptor_tables(vm); 385 vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handler); 386 387 if (!test_args.offset.reserved) { 388 if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET)) 389 vm_ioctl(vm, KVM_ARM_SET_COUNTER_OFFSET, &test_args.offset); 390 else 391 TEST_FAIL("no support for global offset\n"); 392 } 393 394 for (i = 0; i < nr_vcpus; i++) 395 vcpu_init_descriptor_tables(vcpus[i]); 396 397 test_init_timer_irq(vm); 398 gic_fd = vgic_v3_setup(vm, nr_vcpus, 64, GICD_BASE_GPA, GICR_BASE_GPA); 399 __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3"); 400 401 /* Make all the test's cmdline args visible to the guest */ 402 sync_global_to_guest(vm, test_args); 403 404 return vm; 405 } 406 407 static void test_vm_cleanup(struct kvm_vm *vm) 408 { 409 close(gic_fd); 410 kvm_vm_free(vm); 411 } 412 413 static void test_print_help(char *name) 414 { 415 pr_info("Usage: %s [-h] [-n nr_vcpus] [-i iterations] [-p timer_period_ms]\n", 416 name); 417 pr_info("\t-n: Number of vCPUs to configure (default: %u; max: %u)\n", 418 NR_VCPUS_DEF, KVM_MAX_VCPUS); 419 pr_info("\t-i: Number of iterations per stage (default: %u)\n", 420 NR_TEST_ITERS_DEF); 421 pr_info("\t-p: Periodicity (in ms) of the guest timer (default: %u)\n", 422 TIMER_TEST_PERIOD_MS_DEF); 423 pr_info("\t-m: Frequency (in ms) of vCPUs to migrate to different pCPU. 0 to turn off (default: %u)\n", 424 TIMER_TEST_MIGRATION_FREQ_MS); 425 pr_info("\t-o: Counter offset (in counter cycles, default: 0)\n"); 426 pr_info("\t-h: print this help screen\n"); 427 } 428 429 static bool parse_args(int argc, char *argv[]) 430 { 431 int opt; 432 433 while ((opt = getopt(argc, argv, "hn:i:p:m:o:")) != -1) { 434 switch (opt) { 435 case 'n': 436 test_args.nr_vcpus = atoi_positive("Number of vCPUs", optarg); 437 if (test_args.nr_vcpus > KVM_MAX_VCPUS) { 438 pr_info("Max allowed vCPUs: %u\n", 439 KVM_MAX_VCPUS); 440 goto err; 441 } 442 break; 443 case 'i': 444 test_args.nr_iter = atoi_positive("Number of iterations", optarg); 445 break; 446 case 'p': 447 test_args.timer_period_ms = atoi_positive("Periodicity", optarg); 448 break; 449 case 'm': 450 test_args.migration_freq_ms = atoi_non_negative("Frequency", optarg); 451 break; 452 case 'o': 453 test_args.offset.counter_offset = strtol(optarg, NULL, 0); 454 test_args.offset.reserved = 0; 455 break; 456 case 'h': 457 default: 458 goto err; 459 } 460 } 461 462 return true; 463 464 err: 465 test_print_help(argv[0]); 466 return false; 467 } 468 469 int main(int argc, char *argv[]) 470 { 471 struct kvm_vm *vm; 472 473 if (!parse_args(argc, argv)) 474 exit(KSFT_SKIP); 475 476 __TEST_REQUIRE(!test_args.migration_freq_ms || get_nprocs() >= 2, 477 "At least two physical CPUs needed for vCPU migration"); 478 479 vm = test_vm_create(); 480 test_run(vm); 481 test_vm_cleanup(vm); 482 483 return 0; 484 } 485