1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * steal/stolen time test 4 * 5 * Copyright (C) 2020, Red Hat, Inc. 6 */ 7 #include <stdio.h> 8 #include <time.h> 9 #include <sched.h> 10 #include <pthread.h> 11 #include <linux/kernel.h> 12 #include <asm/kvm.h> 13 #ifdef __riscv 14 #include "sbi.h" 15 #else 16 #include <asm/kvm_para.h> 17 #endif 18 19 #include "test_util.h" 20 #include "kvm_util.h" 21 #include "processor.h" 22 #include "ucall_common.h" 23 24 #define NR_VCPUS 4 25 #define ST_GPA_BASE (1 << 30) 26 27 static void *st_gva[NR_VCPUS]; 28 static u64 guest_stolen_time[NR_VCPUS]; 29 30 static struct kvm_vm *vm_create_steal_time(u32 nr_vcpus, void *guest_code, 31 struct kvm_vcpu *vcpus[]); 32 33 #if defined(__x86_64__) 34 35 /* steal_time must have 64-byte alignment */ 36 #define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63) 37 38 static void check_status(struct kvm_steal_time *st) 39 { 40 GUEST_ASSERT(!(READ_ONCE(st->version) & 1)); 41 GUEST_ASSERT_EQ(READ_ONCE(st->flags), 0); 42 GUEST_ASSERT_EQ(READ_ONCE(st->preempted), 0); 43 } 44 45 static void guest_code(int cpu) 46 { 47 struct kvm_steal_time *st = st_gva[cpu]; 48 u32 version; 49 50 GUEST_ASSERT_EQ(rdmsr(MSR_KVM_STEAL_TIME), ((u64)st_gva[cpu] | KVM_MSR_ENABLED)); 51 52 memset(st, 0, sizeof(*st)); 53 GUEST_SYNC(0); 54 55 check_status(st); 56 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 57 version = READ_ONCE(st->version); 58 check_status(st); 59 GUEST_SYNC(1); 60 61 check_status(st); 62 GUEST_ASSERT(version < READ_ONCE(st->version)); 63 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 64 check_status(st); 65 GUEST_DONE(); 66 } 67 68 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 69 { 70 return kvm_cpu_has(X86_FEATURE_KVM_STEAL_TIME); 71 } 72 73 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 74 { 75 /* ST_GPA_BASE is identity mapped */ 76 WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], 77 (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 78 79 vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); 80 } 81 82 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 83 { 84 struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 85 86 ksft_print_msg("VCPU%d:\n", vcpu_idx); 87 ksft_print_msg(" steal: %lld\n", st->steal); 88 ksft_print_msg(" version: %d\n", st->version); 89 ksft_print_msg(" flags: %d\n", st->flags); 90 ksft_print_msg(" preempted: %d\n", st->preempted); 91 ksft_print_msg(" u8_pad: %d %d %d\n", 92 st->u8_pad[0], st->u8_pad[1], st->u8_pad[2]); 93 ksft_print_msg(" pad: %d %d %d %d %d %d %d %d %d %d %d\n", 94 st->pad[0], st->pad[1], st->pad[2], st->pad[3], 95 st->pad[4], st->pad[5], st->pad[6], st->pad[7], 96 st->pad[8], st->pad[9], st->pad[10]); 97 } 98 99 static void check_steal_time_uapi(void) 100 { 101 struct kvm_vm *vm; 102 struct kvm_vcpu *vcpu; 103 int ret; 104 105 vm = vm_create_with_one_vcpu(&vcpu, NULL); 106 107 ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, 108 (ulong)ST_GPA_BASE | KVM_STEAL_RESERVED_MASK); 109 TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); 110 111 kvm_vm_free(vm); 112 } 113 114 #elif defined(__aarch64__) 115 116 /* PV_TIME_ST must have 64-byte alignment */ 117 #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) 118 119 #define SMCCC_ARCH_FEATURES 0x80000001 120 #define PV_TIME_FEATURES 0xc5000020 121 #define PV_TIME_ST 0xc5000021 122 123 struct st_time { 124 u32 rev; 125 u32 attr; 126 u64 st_time; 127 }; 128 129 static s64 smccc(u32 func, u64 arg) 130 { 131 struct arm_smccc_res res; 132 133 do_smccc(func, arg, 0, 0, 0, 0, 0, 0, &res); 134 return res.a0; 135 } 136 137 static void check_status(struct st_time *st) 138 { 139 GUEST_ASSERT_EQ(READ_ONCE(st->rev), 0); 140 GUEST_ASSERT_EQ(READ_ONCE(st->attr), 0); 141 } 142 143 static void guest_code(int cpu) 144 { 145 struct st_time *st; 146 s64 status; 147 148 status = smccc(SMCCC_ARCH_FEATURES, PV_TIME_FEATURES); 149 GUEST_ASSERT_EQ(status, 0); 150 status = smccc(PV_TIME_FEATURES, PV_TIME_FEATURES); 151 GUEST_ASSERT_EQ(status, 0); 152 status = smccc(PV_TIME_FEATURES, PV_TIME_ST); 153 GUEST_ASSERT_EQ(status, 0); 154 155 status = smccc(PV_TIME_ST, 0); 156 GUEST_ASSERT_NE(status, -1); 157 GUEST_ASSERT_EQ(status, (ulong)st_gva[cpu]); 158 159 st = (struct st_time *)status; 160 GUEST_SYNC(0); 161 162 check_status(st); 163 WRITE_ONCE(guest_stolen_time[cpu], st->st_time); 164 GUEST_SYNC(1); 165 166 check_status(st); 167 WRITE_ONCE(guest_stolen_time[cpu], st->st_time); 168 GUEST_DONE(); 169 } 170 171 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 172 { 173 struct kvm_device_attr dev = { 174 .group = KVM_ARM_VCPU_PVTIME_CTRL, 175 .attr = KVM_ARM_VCPU_PVTIME_IPA, 176 }; 177 178 return !__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); 179 } 180 181 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 182 { 183 struct kvm_vm *vm = vcpu->vm; 184 u64 st_ipa; 185 186 struct kvm_device_attr dev = { 187 .group = KVM_ARM_VCPU_PVTIME_CTRL, 188 .attr = KVM_ARM_VCPU_PVTIME_IPA, 189 .addr = (u64)&st_ipa, 190 }; 191 192 /* ST_GPA_BASE is identity mapped */ 193 WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 194 195 st_ipa = (ulong)st_gva[i]; 196 vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); 197 } 198 199 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 200 { 201 struct st_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 202 203 ksft_print_msg("VCPU%d:\n", vcpu_idx); 204 ksft_print_msg(" rev: %d\n", st->rev); 205 ksft_print_msg(" attr: %d\n", st->attr); 206 ksft_print_msg(" st_time: %ld\n", st->st_time); 207 } 208 209 static void check_steal_time_uapi(void) 210 { 211 struct kvm_vm *vm; 212 struct kvm_vcpu *vcpu; 213 u64 st_ipa; 214 int ret; 215 216 struct kvm_device_attr dev = { 217 .group = KVM_ARM_VCPU_PVTIME_CTRL, 218 .attr = KVM_ARM_VCPU_PVTIME_IPA, 219 .addr = (u64)&st_ipa, 220 }; 221 222 vm = vm_create_steal_time(1, NULL, &vcpu); 223 vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); 224 225 st_ipa = (ulong)ST_GPA_BASE | 1; 226 ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); 227 TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); 228 229 st_ipa = (ulong)ST_GPA_BASE; 230 vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); 231 232 ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); 233 TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST"); 234 235 kvm_vm_free(vm); 236 } 237 238 #elif defined(__riscv) 239 240 /* SBI STA shmem must have 64-byte alignment */ 241 #define STEAL_TIME_SIZE ((sizeof(struct sta_struct) + 63) & ~63) 242 243 static gpa_t st_gpa[NR_VCPUS]; 244 245 struct sta_struct { 246 u32 sequence; 247 u32 flags; 248 u64 steal; 249 u8 preempted; 250 u8 pad[47]; 251 } __packed; 252 253 static void sta_set_shmem(gpa_t gpa, unsigned long flags) 254 { 255 unsigned long lo = (unsigned long)gpa; 256 #if __riscv_xlen == 32 257 unsigned long hi = (unsigned long)(gpa >> 32); 258 #else 259 unsigned long hi = gpa == -1 ? -1 : 0; 260 #endif 261 struct sbiret ret = sbi_ecall(SBI_EXT_STA, 0, lo, hi, flags, 0, 0, 0); 262 263 GUEST_ASSERT(ret.value == 0 && ret.error == 0); 264 } 265 266 static void check_status(struct sta_struct *st) 267 { 268 GUEST_ASSERT(!(READ_ONCE(st->sequence) & 1)); 269 GUEST_ASSERT(READ_ONCE(st->flags) == 0); 270 GUEST_ASSERT(READ_ONCE(st->preempted) == 0); 271 } 272 273 static void guest_code(int cpu) 274 { 275 struct sta_struct *st = st_gva[cpu]; 276 u32 sequence; 277 long out_val = 0; 278 bool probe; 279 280 probe = guest_sbi_probe_extension(SBI_EXT_STA, &out_val); 281 GUEST_ASSERT(probe && out_val == 1); 282 283 sta_set_shmem(st_gpa[cpu], 0); 284 GUEST_SYNC(0); 285 286 check_status(st); 287 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 288 sequence = READ_ONCE(st->sequence); 289 check_status(st); 290 GUEST_SYNC(1); 291 292 check_status(st); 293 GUEST_ASSERT(sequence < READ_ONCE(st->sequence)); 294 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 295 check_status(st); 296 GUEST_DONE(); 297 } 298 299 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 300 { 301 u64 id = RISCV_SBI_EXT_REG(KVM_RISCV_SBI_EXT_STA); 302 unsigned long enabled = vcpu_get_reg(vcpu, id); 303 304 TEST_ASSERT(enabled == 0 || enabled == 1, "Expected boolean result"); 305 306 return enabled; 307 } 308 309 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 310 { 311 /* ST_GPA_BASE is identity mapped */ 312 WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 313 WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gpa[i], addr_gva2gpa(vcpu->vm, (gva_t)st_gva[i])); 314 } 315 316 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 317 { 318 struct sta_struct *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 319 int i; 320 321 pr_info("VCPU%d:\n", vcpu_idx); 322 pr_info(" sequence: %d\n", st->sequence); 323 pr_info(" flags: %d\n", st->flags); 324 pr_info(" steal: %"PRIu64"\n", st->steal); 325 pr_info(" preempted: %d\n", st->preempted); 326 pr_info(" pad: "); 327 for (i = 0; i < 47; ++i) 328 pr_info("%d", st->pad[i]); 329 pr_info("\n"); 330 } 331 332 static void check_steal_time_uapi(void) 333 { 334 struct kvm_vm *vm; 335 struct kvm_vcpu *vcpu; 336 struct kvm_one_reg reg; 337 u64 shmem; 338 int ret; 339 340 vm = vm_create_with_one_vcpu(&vcpu, NULL); 341 342 reg.id = KVM_REG_RISCV | 343 KVM_REG_SIZE_ULONG | 344 KVM_REG_RISCV_SBI_STATE | 345 KVM_REG_RISCV_SBI_STA | 346 KVM_REG_RISCV_SBI_STA_REG(shmem_lo); 347 reg.addr = (u64)&shmem; 348 349 shmem = ST_GPA_BASE + 1; 350 ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); 351 TEST_ASSERT(ret == -1 && errno == EINVAL, 352 "misaligned STA shmem returns -EINVAL"); 353 354 shmem = ST_GPA_BASE; 355 ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); 356 TEST_ASSERT(ret == 0, 357 "aligned STA shmem succeeds"); 358 359 shmem = INVALID_GPA; 360 ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); 361 TEST_ASSERT(ret == 0, 362 "all-ones for STA shmem succeeds"); 363 364 kvm_vm_free(vm); 365 } 366 367 #elif defined(__loongarch__) 368 369 /* steal_time must have 64-byte alignment */ 370 #define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63) 371 #define KVM_STEAL_PHYS_VALID BIT_ULL(0) 372 373 struct kvm_steal_time { 374 __u64 steal; 375 __u32 version; 376 __u32 flags; 377 __u8 preempted; 378 __u8 pad[47]; 379 }; 380 381 static void check_status(struct kvm_steal_time *st) 382 { 383 GUEST_ASSERT(!(READ_ONCE(st->version) & 1)); 384 GUEST_ASSERT_EQ(READ_ONCE(st->flags), 0); 385 GUEST_ASSERT_EQ(READ_ONCE(st->preempted), 0); 386 } 387 388 static void guest_code(int cpu) 389 { 390 u32 version; 391 struct kvm_steal_time *st = st_gva[cpu]; 392 393 memset(st, 0, sizeof(*st)); 394 GUEST_SYNC(0); 395 396 check_status(st); 397 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 398 version = READ_ONCE(st->version); 399 check_status(st); 400 GUEST_SYNC(1); 401 402 check_status(st); 403 GUEST_ASSERT(version < READ_ONCE(st->version)); 404 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 405 check_status(st); 406 GUEST_DONE(); 407 } 408 409 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 410 { 411 int err; 412 u64 val; 413 struct kvm_device_attr attr = { 414 .group = KVM_LOONGARCH_VCPU_CPUCFG, 415 .attr = CPUCFG_KVM_FEATURE, 416 .addr = (u64)&val, 417 }; 418 419 err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr); 420 if (err) 421 return false; 422 423 err = __vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &attr); 424 if (err) 425 return false; 426 427 return val & BIT(KVM_FEATURE_STEAL_TIME); 428 } 429 430 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 431 { 432 int err; 433 u64 st_gpa; 434 struct kvm_vm *vm = vcpu->vm; 435 struct kvm_device_attr attr = { 436 .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, 437 .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, 438 .addr = (u64)&st_gpa, 439 }; 440 441 /* ST_GPA_BASE is identity mapped */ 442 WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 443 444 err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr); 445 TEST_ASSERT(err == 0, "No PV stealtime Feature"); 446 447 st_gpa = (unsigned long)st_gva[i] | KVM_STEAL_PHYS_VALID; 448 err = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr); 449 TEST_ASSERT(err == 0, "Fail to set PV stealtime GPA"); 450 } 451 452 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 453 { 454 struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 455 456 ksft_print_msg("VCPU%d:\n", vcpu_idx); 457 ksft_print_msg(" steal: %lld\n", st->steal); 458 ksft_print_msg(" flags: %d\n", st->flags); 459 ksft_print_msg(" version: %d\n", st->version); 460 ksft_print_msg(" preempted: %d\n", st->preempted); 461 } 462 463 static void check_steal_time_uapi(void) 464 { 465 466 } 467 #endif 468 469 static void *do_steal_time(void *arg) 470 { 471 struct timespec ts, stop; 472 473 clock_gettime(CLOCK_MONOTONIC, &ts); 474 stop = timespec_add_ns(ts, MIN_RUN_DELAY_NS); 475 476 while (1) { 477 clock_gettime(CLOCK_MONOTONIC, &ts); 478 if (timespec_to_ns(timespec_sub(ts, stop)) >= 0) 479 break; 480 } 481 482 return NULL; 483 } 484 485 static void run_vcpu(struct kvm_vcpu *vcpu) 486 { 487 struct ucall uc; 488 489 vcpu_run(vcpu); 490 491 switch (get_ucall(vcpu, &uc)) { 492 case UCALL_SYNC: 493 case UCALL_DONE: 494 break; 495 case UCALL_ABORT: 496 REPORT_GUEST_ASSERT(uc); 497 default: 498 TEST_ASSERT(false, "Unexpected exit: %s", 499 exit_reason_str(vcpu->run->exit_reason)); 500 } 501 } 502 503 static struct kvm_vm *vm_create_steal_time(u32 nr_vcpus, void *guest_code, 504 struct kvm_vcpu *vcpus[]) 505 { 506 unsigned int gpages; 507 struct kvm_vm *vm; 508 509 /* Create a VM and an identity mapped memslot for the steal time structure */ 510 vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); 511 gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * nr_vcpus); 512 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); 513 virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages); 514 515 return vm; 516 } 517 518 int main(int ac, char **av) 519 { 520 struct kvm_vcpu *vcpus[NR_VCPUS]; 521 struct kvm_vm *vm; 522 pthread_t thread; 523 cpu_set_t cpuset; 524 long stolen_time; 525 long run_delay; 526 bool verbose; 527 int i, cpu; 528 529 verbose = ac > 1 && (!strncmp(av[1], "-v", 3) || !strncmp(av[1], "--verbose", 10)); 530 531 /* Set CPU affinity so we can force preemption of the VCPU */ 532 cpu = pin_self_to_any_cpu(); 533 534 vm = vm_create_steal_time(NR_VCPUS, guest_code, vcpus); 535 536 ksft_print_header(); 537 TEST_REQUIRE(is_steal_time_supported(vcpus[0])); 538 ksft_set_plan(NR_VCPUS); 539 540 check_steal_time_uapi(); 541 542 /* Run test on each VCPU */ 543 for (i = 0; i < NR_VCPUS; ++i) { 544 steal_time_init(vcpus[i], i); 545 546 vcpu_args_set(vcpus[i], 1, i); 547 548 /* First VCPU run initializes steal-time */ 549 run_vcpu(vcpus[i]); 550 551 /* Second VCPU run, expect guest stolen time to be <= run_delay */ 552 run_vcpu(vcpus[i]); 553 stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]); 554 run_delay = get_run_delay(); 555 TEST_ASSERT(stolen_time <= run_delay, 556 "Expected stolen time <= %ld, got %ld", 557 run_delay, stolen_time); 558 559 /* Steal time from the VCPU. The steal time thread has the same CPU affinity as the VCPUs. */ 560 run_delay = get_run_delay(); 561 kvm_pthread_create(&thread, NULL, do_steal_time, NULL); 562 kvm_pthread_getaffinity(thread, &cpuset); 563 TEST_ASSERT(CPU_COUNT(&cpuset) == 1 && CPU_ISSET(cpu, &cpuset), 564 "Worker failed to inherit parent's CPU affinity"); 565 566 do 567 sched_yield(); 568 while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS); 569 kvm_pthread_join(thread, NULL); 570 run_delay = get_run_delay() - run_delay; 571 TEST_ASSERT(run_delay >= MIN_RUN_DELAY_NS, 572 "Expected run_delay >= %ld, got %ld", 573 MIN_RUN_DELAY_NS, run_delay); 574 575 /* Run VCPU again to confirm stolen time is consistent with run_delay */ 576 run_vcpu(vcpus[i]); 577 stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]) - stolen_time; 578 TEST_ASSERT(stolen_time >= run_delay, 579 "Expected stolen time >= %ld, got %ld", 580 run_delay, stolen_time); 581 582 if (verbose) { 583 ksft_print_msg("VCPU%d: total-stolen-time=%ld test-stolen-time=%ld%s\n", 584 i, guest_stolen_time[i], stolen_time, 585 stolen_time == run_delay ? 586 " (BONUS: guest test-stolen-time even exactly matches test-run_delay)" : ""); 587 steal_time_dump(vm, i); 588 } 589 ksft_test_result_pass("vcpu%d\n", i); 590 } 591 592 /* Print results and exit() accordingly */ 593 ksft_finished(); 594 } 595