* kvm-arm64/psci-1.3: : PSCI v1.3 support, courtesy of David Woodhouse : : Bump KVM's PSCI implementation up to v1.3, with the added bonus of : implementing the SYSTEM_OFF2 call. Like other system-scoped PSCI calls, : this gets relayed to userspace for further processing with a new : KVM_SYSTEM_EVENT_SHUTDOWN flag. : : As an added bonus, implement client-side support for hibernation with : the SYSTEM_OFF2 call. arm64: Use SYSTEM_OFF2 PSCI call to power off for hibernate KVM: arm64: nvhe: Pass through PSCI v1.3 SYSTEM_OFF2 call KVM: selftests: Add test for PSCI SYSTEM_OFF2 KVM: arm64: Add support for PSCI v1.2 and v1.3 KVM: arm64: Add PSCI v1.3 SYSTEM_OFF2 function for hibernation firmware/psci: Add definitions for PSCI v1.3 specification
Unified · Split
| @@ -6855,6 +6855,10 @@ the first `ndata` items (possibly zero) of the data array are valid. · 6854 unmodified lines | ||
| 6855 | 6855 | the guest issued a SYSTEM_RESET2 call according to v1.1 of the PSCI |
| 6856 | 6856 | specification. |
| 6857 | 6857 | |
| 6858 | + - for arm64, data[0] is set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2 | |
| 6859 | + if the guest issued a SYSTEM_OFF2 call according to v1.3 of the PSCI | |
| 6860 | + specification. | |
| 6861 | + | |
| 6858 | 6862 | - for RISC-V, data[0] is set to the value of the second argument of the |
| 6859 | 6863 | ``sbi_system_reset`` call. |
| 6860 | 6864 | |
| @@ -6888,6 +6892,12 @@ either: · 27 unmodified lines | ||
| 6888 | 6892 | - Deny the guest request to suspend the VM. See ARM DEN0022D.b 5.19.2 |
| 6889 | 6893 | "Caller responsibilities" for possible return values. |
| 6890 | 6894 | |
| 6895 | +Hibernation using the PSCI SYSTEM_OFF2 call is enabled when PSCI v1.3 | |
| 6896 | +is enabled. If a guest invokes the PSCI SYSTEM_OFF2 function, KVM will | |
| 6897 | +exit to userspace with the KVM_SYSTEM_EVENT_SHUTDOWN event type and with | |
| 6898 | +data[0] set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2. The only | |
| 6899 | +supported hibernate type for the SYSTEM_OFF2 function is HIBERNATE_OFF. | |
| 6900 | + | |
| 6891 | 6901 | :: |
| 6892 | 6902 | |
| 6893 | 6903 | /* KVM_EXIT_IOAPIC_EOI */ |
| @@ -484,6 +484,12 @@ enum { · 483 unmodified lines | ||
| 484 | 484 | */ |
| 485 | 485 | #define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0) |
| 486 | 486 | |
| 487 | +/* | |
| 488 | + * Shutdown caused by a PSCI v1.3 SYSTEM_OFF2 call. | |
| 489 | + * Valid only when the system event has a type of KVM_SYSTEM_EVENT_SHUTDOWN. | |
| 490 | + */ | |
| 491 | +#define KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2 (1ULL << 0) | |
| 492 | + | |
| 487 | 493 | /* run->fail_entry.hardware_entry_failure_reason codes. */ |
| 488 | 494 | #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) |
| 489 | 495 | |
| @@ -265,6 +265,8 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_ · 264 unmodified lines | ||
| 265 | 265 | case PSCI_1_0_FN_PSCI_FEATURES: |
| 266 | 266 | case PSCI_1_0_FN_SET_SUSPEND_MODE: |
| 267 | 267 | case PSCI_1_1_FN64_SYSTEM_RESET2: |
| 268 | + case PSCI_1_3_FN_SYSTEM_OFF2: | |
| 269 | + case PSCI_1_3_FN64_SYSTEM_OFF2: | |
| 268 | 270 | return psci_forward(host_ctxt); |
| 269 | 271 | case PSCI_1_0_FN64_SYSTEM_SUSPEND: |
| 270 | 272 | return psci_system_suspend(func_id, host_ctxt); |
| @@ -575,6 +575,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) · 574 unmodified lines | ||
| 575 | 575 | case KVM_ARM_PSCI_0_2: |
| 576 | 576 | case KVM_ARM_PSCI_1_0: |
| 577 | 577 | case KVM_ARM_PSCI_1_1: |
| 578 | + case KVM_ARM_PSCI_1_2: | |
| 579 | + case KVM_ARM_PSCI_1_3: | |
| 578 | 580 | if (!wants_02) |
| 579 | 581 | return -EINVAL; |
| 580 | 582 | vcpu->kvm->arch.psci_version = val; |
| @@ -194,6 +194,12 @@ static void kvm_psci_system_off(struct kvm_vcpu *vcpu) · 193 unmodified lines | ||
| 194 | 194 | kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, 0); |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | +static void kvm_psci_system_off2(struct kvm_vcpu *vcpu) | |
| 198 | +{ | |
| 199 | + kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, | |
| 200 | + KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2); | |
| 201 | +} | |
| 202 | + | |
| 197 | 203 | static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) |
| 198 | 204 | { |
| 199 | 205 | kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET, 0); |
| @@ -322,7 +328,7 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) · 122 unmodified lines | ||
| 322 | 328 | |
| 323 | 329 | switch(psci_fn) { |
| 324 | 330 | case PSCI_0_2_FN_PSCI_VERSION: |
| 325 | − val = minor == 0 ? KVM_ARM_PSCI_1_0 : KVM_ARM_PSCI_1_1; | |
| 331 | + val = PSCI_VERSION(1, minor); | |
| 326 | 332 | break; |
| 327 | 333 | case PSCI_1_0_FN_PSCI_FEATURES: |
| 328 | 334 | arg = smccc_get_arg1(vcpu); |
| @@ -358,6 +364,11 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) · 29 unmodified lines | ||
| 358 | 364 | if (minor >= 1) |
| 359 | 365 | val = 0; |
| 360 | 366 | break; |
| 367 | + case PSCI_1_3_FN_SYSTEM_OFF2: | |
| 368 | + case PSCI_1_3_FN64_SYSTEM_OFF2: | |
| 369 | + if (minor >= 3) | |
| 370 | + val = PSCI_1_3_OFF_TYPE_HIBERNATE_OFF; | |
| 371 | + break; | |
| 361 | 372 | } |
| 362 | 373 | break; |
| 363 | 374 | case PSCI_1_0_FN_SYSTEM_SUSPEND: |
| @@ -392,6 +403,33 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) · 28 unmodified lines | ||
| 392 | 403 | break; |
| 393 | 404 | } |
| 394 | 405 | break; |
| 406 | + case PSCI_1_3_FN_SYSTEM_OFF2: | |
| 407 | + kvm_psci_narrow_to_32bit(vcpu); | |
| 408 | + fallthrough; | |
| 409 | + case PSCI_1_3_FN64_SYSTEM_OFF2: | |
| 410 | + if (minor < 3) | |
| 411 | + break; | |
| 412 | + | |
| 413 | + arg = smccc_get_arg1(vcpu); | |
| 414 | + /* | |
| 415 | + * SYSTEM_OFF2 defaults to HIBERNATE_OFF if arg1 is zero. arg2 | |
| 416 | + * must be zero. | |
| 417 | + */ | |
| 418 | + if ((arg && arg != PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) || | |
| 419 | + smccc_get_arg2(vcpu) != 0) { | |
| 420 | + val = PSCI_RET_INVALID_PARAMS; | |
| 421 | + break; | |
| 422 | + } | |
| 423 | + kvm_psci_system_off2(vcpu); | |
| 424 | + /* | |
| 425 | + * We shouldn't be going back to the guest after receiving a | |
| 426 | + * SYSTEM_OFF2 request. Preload a return value of | |
| 427 | + * INTERNAL_FAILURE should userspace ignore the exit and resume | |
| 428 | + * the vCPU. | |
| 429 | + */ | |
| 430 | + val = PSCI_RET_INTERNAL_FAILURE; | |
| 431 | + ret = 0; | |
| 432 | + break; | |
| 395 | 433 | default: |
| 396 | 434 | return kvm_psci_0_2_call(vcpu); |
| 397 | 435 | } |
| @@ -449,6 +487,10 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) · 51 unmodified lines | ||
| 449 | 487 | } |
| 450 | 488 | |
| 451 | 489 | switch (version) { |
| 490 | + case KVM_ARM_PSCI_1_3: | |
| 491 | + return kvm_psci_1_x_call(vcpu, 3); | |
| 492 | + case KVM_ARM_PSCI_1_2: | |
| 493 | + return kvm_psci_1_x_call(vcpu, 2); | |
| 452 | 494 | case KVM_ARM_PSCI_1_1: |
| 453 | 495 | return kvm_psci_1_x_call(vcpu, 1); |
| 454 | 496 | case KVM_ARM_PSCI_1_0: |
| @@ -78,6 +78,7 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void) · 77 unmodified lines | ||
| 78 | 78 | |
| 79 | 79 | static u32 psci_cpu_suspend_feature; |
| 80 | 80 | static bool psci_system_reset2_supported; |
| 81 | +static bool psci_system_off2_hibernate_supported; | |
| 81 | 82 | |
| 82 | 83 | static inline bool psci_has_ext_power_state(void) |
| 83 | 84 | { |
| @@ -333,6 +334,36 @@ static void psci_sys_poweroff(void) · 249 unmodified lines | ||
| 333 | 334 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); |
| 334 | 335 | } |
| 335 | 336 | |
| 337 | +#ifdef CONFIG_HIBERNATION | |
| 338 | +static int psci_sys_hibernate(struct sys_off_data *data) | |
| 339 | +{ | |
| 340 | + /* | |
| 341 | + * If no hibernate type is specified SYSTEM_OFF2 defaults to selecting | |
| 342 | + * HIBERNATE_OFF. | |
| 343 | + * | |
| 344 | + * There are hypervisors in the wild that do not align with the spec and | |
| 345 | + * reject calls that explicitly provide a hibernate type. For | |
| 346 | + * compatibility with these nonstandard implementations, pass 0 as the | |
| 347 | + * type. | |
| 348 | + */ | |
| 349 | + if (system_entering_hibernation()) | |
| 350 | + invoke_psci_fn(PSCI_FN_NATIVE(1_3, SYSTEM_OFF2), 0, 0, 0); | |
| 351 | + return NOTIFY_DONE; | |
| 352 | +} | |
| 353 | + | |
| 354 | +static int __init psci_hibernate_init(void) | |
| 355 | +{ | |
| 356 | + if (psci_system_off2_hibernate_supported) { | |
| 357 | + /* Higher priority than EFI shutdown, but only for hibernate */ | |
| 358 | + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, | |
| 359 | + SYS_OFF_PRIO_FIRMWARE + 2, | |
| 360 | + psci_sys_hibernate, NULL); | |
| 361 | + } | |
| 362 | + return 0; | |
| 363 | +} | |
| 364 | +subsys_initcall(psci_hibernate_init); | |
| 365 | +#endif | |
| 366 | + | |
| 336 | 367 | static int psci_features(u32 psci_func_id) |
| 337 | 368 | { |
| 338 | 369 | return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES, |
| @@ -364,6 +395,7 @@ static const struct { · 25 unmodified lines | ||
| 364 | 395 | PSCI_ID_NATIVE(1_1, SYSTEM_RESET2), |
| 365 | 396 | PSCI_ID(1_1, MEM_PROTECT), |
| 366 | 397 | PSCI_ID_NATIVE(1_1, MEM_PROTECT_CHECK_RANGE), |
| 398 | + PSCI_ID_NATIVE(1_3, SYSTEM_OFF2), | |
| 367 | 399 | }; |
| 368 | 400 | |
| 369 | 401 | static int psci_debugfs_read(struct seq_file *s, void *data) |
| @@ -525,6 +557,18 @@ static void __init psci_init_system_reset2(void) · 155 unmodified lines | ||
| 525 | 557 | psci_system_reset2_supported = true; |
| 526 | 558 | } |
| 527 | 559 | |
| 560 | +static void __init psci_init_system_off2(void) | |
| 561 | +{ | |
| 562 | + int ret; | |
| 563 | + | |
| 564 | + ret = psci_features(PSCI_FN_NATIVE(1_3, SYSTEM_OFF2)); | |
| 565 | + if (ret < 0) | |
| 566 | + return; | |
| 567 | + | |
| 568 | + if (ret & PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) | |
| 569 | + psci_system_off2_hibernate_supported = true; | |
| 570 | +} | |
| 571 | + | |
| 528 | 572 | static void __init psci_init_system_suspend(void) |
| 529 | 573 | { |
| 530 | 574 | int ret; |
| @@ -655,6 +699,7 @@ static int __init psci_probe(void) · 124 unmodified lines | ||
| 655 | 699 | psci_init_cpu_suspend(); |
| 656 | 700 | psci_init_system_suspend(); |
| 657 | 701 | psci_init_system_reset2(); |
| 702 | + psci_init_system_off2(); | |
| 658 | 703 | kvm_init_hyp_services(); |
| 659 | 704 | } |
| 660 | 705 | |
| @@ -14,8 +14,10 @@ · 13 unmodified lines | ||
| 14 | 14 | #define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2) |
| 15 | 15 | #define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0) |
| 16 | 16 | #define KVM_ARM_PSCI_1_1 PSCI_VERSION(1, 1) |
| 17 | +#define KVM_ARM_PSCI_1_2 PSCI_VERSION(1, 2) | |
| 18 | +#define KVM_ARM_PSCI_1_3 PSCI_VERSION(1, 3) | |
| 17 | 19 | |
| 18 | −#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_1 | |
| 20 | +#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_3 | |
| 19 | 21 | |
| 20 | 22 | static inline int kvm_psci_version(struct kvm_vcpu *vcpu) |
| 21 | 23 | { |
| @@ -59,6 +59,7 @@ · 58 unmodified lines | ||
| 59 | 59 | #define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_0_2_FN(18) |
| 60 | 60 | #define PSCI_1_1_FN_MEM_PROTECT PSCI_0_2_FN(19) |
| 61 | 61 | #define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN(20) |
| 62 | +#define PSCI_1_3_FN_SYSTEM_OFF2 PSCI_0_2_FN(21) | |
| 62 | 63 | |
| 63 | 64 | #define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND PSCI_0_2_FN64(12) |
| 64 | 65 | #define PSCI_1_0_FN64_NODE_HW_STATE PSCI_0_2_FN64(13) |
| @@ -68,6 +69,7 @@ · 3 unmodified lines | ||
| 68 | 69 | |
| 69 | 70 | #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18) |
| 70 | 71 | #define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN64(20) |
| 72 | +#define PSCI_1_3_FN64_SYSTEM_OFF2 PSCI_0_2_FN64(21) | |
| 71 | 73 | |
| 72 | 74 | /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ |
| 73 | 75 | #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff |
| @@ -100,6 +102,9 @@ · 26 unmodified lines | ||
| 100 | 102 | #define PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET 0 |
| 101 | 103 | #define PSCI_1_1_RESET_TYPE_VENDOR_START 0x80000000U |
| 102 | 104 | |
| 105 | +/* PSCI v1.3 hibernate type for SYSTEM_OFF2 */ | |
| 106 | +#define PSCI_1_3_OFF_TYPE_HIBERNATE_OFF BIT(0) | |
| 107 | + | |
| 103 | 108 | /* PSCI version decoding (independent of PSCI version) */ |
| 104 | 109 | #define PSCI_VERSION_MAJOR_SHIFT 16 |
| 105 | 110 | #define PSCI_VERSION_MINOR_MASK \ |
| @@ -685,8 +685,11 @@ static void power_down(void) · 684 unmodified lines | ||
| 685 | 685 | } |
| 686 | 686 | fallthrough; |
| 687 | 687 | case HIBERNATION_SHUTDOWN: |
| 688 | − if (kernel_can_power_off()) | |
| 688 | + if (kernel_can_power_off()) { | |
| 689 | + entering_platform_hibernation = true; | |
| 689 | 690 | kernel_power_off(); |
| 691 | + entering_platform_hibernation = false; | |
| 692 | + } | |
| 690 | 693 | break; |
| 691 | 694 | } |
| 692 | 695 | kernel_halt(); |
| @@ -54,6 +54,15 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id) · 53 unmodified lines | ||
| 54 | 54 | return res.a0; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | +static uint64_t psci_system_off2(uint64_t type, uint64_t cookie) | |
| 58 | +{ | |
| 59 | + struct arm_smccc_res res; | |
| 60 | + | |
| 61 | + smccc_hvc(PSCI_1_3_FN64_SYSTEM_OFF2, type, cookie, 0, 0, 0, 0, 0, &res); | |
| 62 | + | |
| 63 | + return res.a0; | |
| 64 | +} | |
| 65 | + | |
| 57 | 66 | static uint64_t psci_features(uint32_t func_id) |
| 58 | 67 | { |
| 59 | 68 | struct arm_smccc_res res; |
| @@ -188,11 +197,94 @@ static void host_test_system_suspend(void) · 128 unmodified lines | ||
| 188 | 197 | kvm_vm_free(vm); |
| 189 | 198 | } |
| 190 | 199 | |
| 200 | +static void guest_test_system_off2(void) | |
| 201 | +{ | |
| 202 | + uint64_t ret; | |
| 203 | + | |
| 204 | + /* assert that SYSTEM_OFF2 is discoverable */ | |
| 205 | + GUEST_ASSERT(psci_features(PSCI_1_3_FN_SYSTEM_OFF2) & | |
| 206 | + PSCI_1_3_OFF_TYPE_HIBERNATE_OFF); | |
| 207 | + GUEST_ASSERT(psci_features(PSCI_1_3_FN64_SYSTEM_OFF2) & | |
| 208 | + PSCI_1_3_OFF_TYPE_HIBERNATE_OFF); | |
| 209 | + | |
| 210 | + /* With non-zero 'cookie' field, it should fail */ | |
| 211 | + ret = psci_system_off2(PSCI_1_3_OFF_TYPE_HIBERNATE_OFF, 1); | |
| 212 | + GUEST_ASSERT(ret == PSCI_RET_INVALID_PARAMS); | |
| 213 | + | |
| 214 | + /* | |
| 215 | + * This would normally never return, so KVM sets the return value | |
| 216 | + * to PSCI_RET_INTERNAL_FAILURE. The test case *does* return, so | |
| 217 | + * that it can test both values for HIBERNATE_OFF. | |
| 218 | + */ | |
| 219 | + ret = psci_system_off2(PSCI_1_3_OFF_TYPE_HIBERNATE_OFF, 0); | |
| 220 | + GUEST_ASSERT(ret == PSCI_RET_INTERNAL_FAILURE); | |
| 221 | + | |
| 222 | + /* | |
| 223 | + * Revision F.b of the PSCI v1.3 specification documents zero as an | |
| 224 | + * alias for HIBERNATE_OFF, since that's the value used in earlier | |
| 225 | + * revisions of the spec and some implementations in the field. | |
| 226 | + */ | |
| 227 | + ret = psci_system_off2(0, 1); | |
| 228 | + GUEST_ASSERT(ret == PSCI_RET_INVALID_PARAMS); | |
| 229 | + | |
| 230 | + ret = psci_system_off2(0, 0); | |
| 231 | + GUEST_ASSERT(ret == PSCI_RET_INTERNAL_FAILURE); | |
| 232 | + | |
| 233 | + GUEST_DONE(); | |
| 234 | +} | |
| 235 | + | |
| 236 | +static void host_test_system_off2(void) | |
| 237 | +{ | |
| 238 | + struct kvm_vcpu *source, *target; | |
| 239 | + struct kvm_mp_state mps; | |
| 240 | + uint64_t psci_version = 0; | |
| 241 | + int nr_shutdowns = 0; | |
| 242 | + struct kvm_run *run; | |
| 243 | + struct ucall uc; | |
| 244 | + | |
| 245 | + setup_vm(guest_test_system_off2, &source, &target); | |
| 246 | + | |
| 247 | + vcpu_get_reg(target, KVM_REG_ARM_PSCI_VERSION, &psci_version); | |
| 248 | + | |
| 249 | + TEST_ASSERT(psci_version >= PSCI_VERSION(1, 3), | |
| 250 | + "Unexpected PSCI version %lu.%lu", | |
| 251 | + PSCI_VERSION_MAJOR(psci_version), | |
| 252 | + PSCI_VERSION_MINOR(psci_version)); | |
| 253 | + | |
| 254 | + vcpu_power_off(target); | |
| 255 | + run = source->run; | |
| 256 | + | |
| 257 | + enter_guest(source); | |
| 258 | + while (run->exit_reason == KVM_EXIT_SYSTEM_EVENT) { | |
| 259 | + TEST_ASSERT(run->system_event.type == KVM_SYSTEM_EVENT_SHUTDOWN, | |
| 260 | + "Unhandled system event: %u (expected: %u)", | |
| 261 | + run->system_event.type, KVM_SYSTEM_EVENT_SHUTDOWN); | |
| 262 | + TEST_ASSERT(run->system_event.ndata >= 1, | |
| 263 | + "Unexpected amount of system event data: %u (expected, >= 1)", | |
| 264 | + run->system_event.ndata); | |
| 265 | + TEST_ASSERT(run->system_event.data[0] & KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2, | |
| 266 | + "PSCI_OFF2 flag not set. Flags %llu (expected %llu)", | |
| 267 | + run->system_event.data[0], KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2); | |
| 268 | + | |
| 269 | + nr_shutdowns++; | |
| 270 | + | |
| 271 | + /* Restart the vCPU */ | |
| 272 | + mps.mp_state = KVM_MP_STATE_RUNNABLE; | |
| 273 | + vcpu_mp_state_set(source, &mps); | |
| 274 | + | |
| 275 | + enter_guest(source); | |
| 276 | + } | |
| 277 | + | |
| 278 | + TEST_ASSERT(get_ucall(source, &uc) == UCALL_DONE, "Guest did not exit cleanly"); | |
| 279 | + TEST_ASSERT(nr_shutdowns == 2, "Two shutdown events were expected, but saw %d", nr_shutdowns); | |
| 280 | +} | |
| 281 | + | |
| 191 | 282 | int main(void) |
| 192 | 283 | { |
| 193 | 284 | TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)); |
| 194 | 285 | |
| 195 | 286 | host_test_cpu_on(); |
| 196 | 287 | host_test_system_suspend(); |
| 288 | + host_test_system_off2(); | |
| 197 | 289 | return 0; |
| 198 | 290 | } |