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 #if defined(__x86_64__) 31 32 /* steal_time must have 64-byte alignment */ 33 #define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63) 34 35 static void check_status(struct kvm_steal_time *st) 36 { 37 GUEST_ASSERT(!(READ_ONCE(st->version) & 1)); 38 GUEST_ASSERT_EQ(READ_ONCE(st->flags), 0); 39 GUEST_ASSERT_EQ(READ_ONCE(st->preempted), 0); 40 } 41 42 static void guest_code(int cpu) 43 { 44 struct kvm_steal_time *st = st_gva[cpu]; 45 u32 version; 46 47 GUEST_ASSERT_EQ(rdmsr(MSR_KVM_STEAL_TIME), ((u64)st_gva[cpu] | KVM_MSR_ENABLED)); 48 49 memset(st, 0, sizeof(*st)); 50 GUEST_SYNC(0); 51 52 check_status(st); 53 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 54 version = READ_ONCE(st->version); 55 check_status(st); 56 GUEST_SYNC(1); 57 58 check_status(st); 59 GUEST_ASSERT(version < READ_ONCE(st->version)); 60 WRITE_ONCE(guest_stolen_time[cpu], st->steal); 61 check_status(st); 62 GUEST_DONE(); 63 } 64 65 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 66 { 67 return kvm_cpu_has(X86_FEATURE_KVM_STEAL_TIME); 68 } 69 70 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 71 { 72 /* ST_GPA_BASE is identity mapped */ 73 WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], 74 (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 75 76 vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); 77 } 78 79 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 80 { 81 struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 82 83 ksft_print_msg("VCPU%d:\n", vcpu_idx); 84 ksft_print_msg(" steal: %lld\n", st->steal); 85 ksft_print_msg(" version: %d\n", st->version); 86 ksft_print_msg(" flags: %d\n", st->flags); 87 ksft_print_msg(" preempted: %d\n", st->preempted); 88 ksft_print_msg(" u8_pad: %d %d %d\n", 89 st->u8_pad[0], st->u8_pad[1], st->u8_pad[2]); 90 ksft_print_msg(" pad: %d %d %d %d %d %d %d %d %d %d %d\n", 91 st->pad[0], st->pad[1], st->pad[2], st->pad[3], 92 st->pad[4], st->pad[5], st->pad[6], st->pad[7], 93 st->pad[8], st->pad[9], st->pad[10]); 94 } 95 96 static void check_steal_time_uapi(void) 97 { 98 struct kvm_vm *vm; 99 struct kvm_vcpu *vcpu; 100 int ret; 101 102 vm = vm_create_with_one_vcpu(&vcpu, NULL); 103 104 ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, 105 (ulong)ST_GPA_BASE | KVM_STEAL_RESERVED_MASK); 106 TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); 107 108 kvm_vm_free(vm); 109 } 110 111 #elif defined(__aarch64__) 112 113 /* PV_TIME_ST must have 64-byte alignment */ 114 #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) 115 116 #define SMCCC_ARCH_FEATURES 0x80000001 117 #define PV_TIME_FEATURES 0xc5000020 118 #define PV_TIME_ST 0xc5000021 119 120 struct st_time { 121 u32 rev; 122 u32 attr; 123 u64 st_time; 124 }; 125 126 static s64 smccc(u32 func, u64 arg) 127 { 128 struct arm_smccc_res res; 129 130 do_smccc(func, arg, 0, 0, 0, 0, 0, 0, &res); 131 return res.a0; 132 } 133 134 static void check_status(struct st_time *st) 135 { 136 GUEST_ASSERT_EQ(READ_ONCE(st->rev), 0); 137 GUEST_ASSERT_EQ(READ_ONCE(st->attr), 0); 138 } 139 140 static void guest_code(int cpu) 141 { 142 struct st_time *st; 143 s64 status; 144 145 status = smccc(SMCCC_ARCH_FEATURES, PV_TIME_FEATURES); 146 GUEST_ASSERT_EQ(status, 0); 147 status = smccc(PV_TIME_FEATURES, PV_TIME_FEATURES); 148 GUEST_ASSERT_EQ(status, 0); 149 status = smccc(PV_TIME_FEATURES, PV_TIME_ST); 150 GUEST_ASSERT_EQ(status, 0); 151 152 status = smccc(PV_TIME_ST, 0); 153 GUEST_ASSERT_NE(status, -1); 154 GUEST_ASSERT_EQ(status, (ulong)st_gva[cpu]); 155 156 st = (struct st_time *)status; 157 GUEST_SYNC(0); 158 159 check_status(st); 160 WRITE_ONCE(guest_stolen_time[cpu], st->st_time); 161 GUEST_SYNC(1); 162 163 check_status(st); 164 WRITE_ONCE(guest_stolen_time[cpu], st->st_time); 165 GUEST_DONE(); 166 } 167 168 static bool is_steal_time_supported(struct kvm_vcpu *vcpu) 169 { 170 struct kvm_device_attr dev = { 171 .group = KVM_ARM_VCPU_PVTIME_CTRL, 172 .attr = KVM_ARM_VCPU_PVTIME_IPA, 173 }; 174 175 return !__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); 176 } 177 178 static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) 179 { 180 struct kvm_vm *vm = vcpu->vm; 181 u64 st_ipa; 182 183 struct kvm_device_attr dev = { 184 .group = KVM_ARM_VCPU_PVTIME_CTRL, 185 .attr = KVM_ARM_VCPU_PVTIME_IPA, 186 .addr = (u64)&st_ipa, 187 }; 188 189 /* ST_GPA_BASE is identity mapped */ 190 WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); 191 192 st_ipa = (ulong)st_gva[i]; 193 vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); 194 } 195 196 static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) 197 { 198 struct st_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); 199 200 ksft_print_msg("VCPU%d:\n", vcpu_idx); 201 ksft_print_msg(" rev: %d\n", st->rev); 202 ksft_print_msg(" attr: %d\n", st->attr); 203 ksft_print_msg(" st_time: %ld\n", st->st_time); 204 } 205 206 static void check_steal_time_uapi(void) 207 { 208 struct kvm_vm *vm; 209 struct kvm_vcpu *vcpu; 210 u64 st_ipa; 211 int ret; 212 213 vm = vm_create_with_one_vcpu(&vcpu, NULL); 214 215 struct kvm_device_attr dev = { 216 .group = KVM_ARM_VCPU_PVTIME_CTRL, 217 .attr = KVM_ARM_VCPU_PVTIME_IPA, 218 .addr = (u64)&st_ipa, 219 }; 220 221 vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); 222 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, 1, 0); 223 virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, 1); 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 int main(int ac, char **av) 504 { 505 struct kvm_vcpu *vcpus[NR_VCPUS]; 506 struct kvm_vm *vm; 507 pthread_t thread; 508 cpu_set_t cpuset; 509 unsigned int gpages; 510 long stolen_time; 511 long run_delay; 512 bool verbose; 513 int i, cpu; 514 515 verbose = ac > 1 && (!strncmp(av[1], "-v", 3) || !strncmp(av[1], "--verbose", 10)); 516 517 /* Set CPU affinity so we can force preemption of the VCPU */ 518 cpu = pin_self_to_any_cpu(); 519 520 /* Create a VM and an identity mapped memslot for the steal time structure */ 521 vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus); 522 gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * NR_VCPUS); 523 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); 524 virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages); 525 526 ksft_print_header(); 527 TEST_REQUIRE(is_steal_time_supported(vcpus[0])); 528 ksft_set_plan(NR_VCPUS); 529 530 check_steal_time_uapi(); 531 532 /* Run test on each VCPU */ 533 for (i = 0; i < NR_VCPUS; ++i) { 534 steal_time_init(vcpus[i], i); 535 536 vcpu_args_set(vcpus[i], 1, i); 537 538 /* First VCPU run initializes steal-time */ 539 run_vcpu(vcpus[i]); 540 541 /* Second VCPU run, expect guest stolen time to be <= run_delay */ 542 run_vcpu(vcpus[i]); 543 stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]); 544 run_delay = get_run_delay(); 545 TEST_ASSERT(stolen_time <= run_delay, 546 "Expected stolen time <= %ld, got %ld", 547 run_delay, stolen_time); 548 549 /* Steal time from the VCPU. The steal time thread has the same CPU affinity as the VCPUs. */ 550 run_delay = get_run_delay(); 551 kvm_pthread_create(&thread, NULL, do_steal_time, NULL); 552 kvm_pthread_getaffinity(thread, &cpuset); 553 TEST_ASSERT(CPU_COUNT(&cpuset) == 1 && CPU_ISSET(cpu, &cpuset), 554 "Worker failed to inherit parent's CPU affinity"); 555 556 do 557 sched_yield(); 558 while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS); 559 kvm_pthread_join(thread, NULL); 560 run_delay = get_run_delay() - run_delay; 561 TEST_ASSERT(run_delay >= MIN_RUN_DELAY_NS, 562 "Expected run_delay >= %ld, got %ld", 563 MIN_RUN_DELAY_NS, run_delay); 564 565 /* Run VCPU again to confirm stolen time is consistent with run_delay */ 566 run_vcpu(vcpus[i]); 567 stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]) - stolen_time; 568 TEST_ASSERT(stolen_time >= run_delay, 569 "Expected stolen time >= %ld, got %ld", 570 run_delay, stolen_time); 571 572 if (verbose) { 573 ksft_print_msg("VCPU%d: total-stolen-time=%ld test-stolen-time=%ld%s\n", 574 i, guest_stolen_time[i], stolen_time, 575 stolen_time == run_delay ? 576 " (BONUS: guest test-stolen-time even exactly matches test-run_delay)" : ""); 577 steal_time_dump(vm, i); 578 } 579 ksft_test_result_pass("vcpu%d\n", i); 580 } 581 582 /* Print results and exit() accordingly */ 583 ksft_finished(); 584 } 585