Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: Add PSCI v1.3 SYSTEM_OFF2 function for hibernation

The PSCI v1.3 specification adds support for a SYSTEM_OFF2 function
which is analogous to ACPI S4 state. This will allow hosting
environments to determine that a guest is hibernated rather than just
powered off, and ensure that they preserve the virtual environment
appropriately to allow the guest to resume safely (or bump the
hardware_signature in the FACS to trigger a clean reboot instead).

This feature is safe to enable unconditionally (in a subsequent commit)
because it is exposed to userspace through the existing
KVM_SYSTEM_EVENT_SHUTDOWN event, just with an additional flag which
userspace can use to know that the instance intended hibernation instead
of a plain power-off.

As with SYSTEM_RESET2, there is only one type available (in this case
HIBERNATE_OFF), and it is not explicitly reported to userspace through
the event; userspace can get it from the registers if it cares).

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
Link: https://lore.kernel.org/r/20241019172459.2241939-3-dwmw2@infradead.org
[oliver: slight cleanup of comments]
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>

authored by

David Woodhouse and committed by
Oliver Upton
97413cea 2f2d4695

+54
+10
Documentation/virt/kvm/api.rst
··· 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 ··· 6891 6887 6892 6888 - Deny the guest request to suspend the VM. See ARM DEN0022D.b 5.19.2 6893 6889 "Caller responsibilities" for possible return values. 6890 + 6891 + Hibernation using the PSCI SYSTEM_OFF2 call is enabled when PSCI v1.3 6892 + is enabled. If a guest invokes the PSCI SYSTEM_OFF2 function, KVM will 6893 + exit to userspace with the KVM_SYSTEM_EVENT_SHUTDOWN event type and with 6894 + data[0] set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2. The only 6895 + supported hibernate type for the SYSTEM_OFF2 function is HIBERNATE_OFF. 6894 6896 6895 6897 :: 6896 6898
+6
arch/arm64/include/uapi/asm/kvm.h
··· 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
+38
arch/arm64/kvm/psci.c
··· 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); ··· 364 358 if (minor >= 1) 365 359 val = 0; 366 360 break; 361 + case PSCI_1_3_FN_SYSTEM_OFF2: 362 + case PSCI_1_3_FN64_SYSTEM_OFF2: 363 + if (minor >= 3) 364 + val = PSCI_1_3_OFF_TYPE_HIBERNATE_OFF; 365 + break; 367 366 } 368 367 break; 369 368 case PSCI_1_0_FN_SYSTEM_SUSPEND: ··· 402 391 val = PSCI_RET_INVALID_PARAMS; 403 392 break; 404 393 } 394 + break; 395 + case PSCI_1_3_FN_SYSTEM_OFF2: 396 + kvm_psci_narrow_to_32bit(vcpu); 397 + fallthrough; 398 + case PSCI_1_3_FN64_SYSTEM_OFF2: 399 + if (minor < 3) 400 + break; 401 + 402 + arg = smccc_get_arg1(vcpu); 403 + /* 404 + * SYSTEM_OFF2 defaults to HIBERNATE_OFF if arg1 is zero. arg2 405 + * must be zero. 406 + */ 407 + if ((arg && arg != PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) || 408 + smccc_get_arg2(vcpu) != 0) { 409 + val = PSCI_RET_INVALID_PARAMS; 410 + break; 411 + } 412 + kvm_psci_system_off2(vcpu); 413 + /* 414 + * We shouldn't be going back to the guest after receiving a 415 + * SYSTEM_OFF2 request. Preload a return value of 416 + * INTERNAL_FAILURE should userspace ignore the exit and resume 417 + * the vCPU. 418 + */ 419 + val = PSCI_RET_INTERNAL_FAILURE; 420 + ret = 0; 405 421 break; 406 422 default: 407 423 return kvm_psci_0_2_call(vcpu);