History

Merge branch kvm-arm64/psci-1.3 into kvmarm/next

* 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

Oliver Upton committed 2 years ago

Commit 7ccd6152 parents 2865463 3e251af10 files · +212 −3Browse files

Unified · Split

10 files
  1. Documentation/virt/kvm/api.rst +10 −0
  2. arch/arm64/include/uapi/asm/kvm.h +6 −0
  3. arch/arm64/kvm/hyp/nvhe/psci-relay.c +2 −0
  4. arch/arm64/kvm/hypercalls.c +2 −0
  5. arch/arm64/kvm/psci.c +43 −1
  6. drivers/firmware/psci/psci.c +45 −0
  7. include/kvm/arm_psci.h +3 −1
  8. include/uapi/linux/psci.h +5 −0
  9. kernel/power/hibernate.c +4 −1
  10. tools/testing/selftests/kvm/aarch64/psci_test.c +92 −0
Documentation/virt/kvm/api.rst+10−0
@@ -6855,6 +6855,10 @@ the first `ndata` items (possibly zero) of the data array are valid. · 6854 unmodified lines
68556855 the guest issued a SYSTEM_RESET2 call according to v1.1 of the PSCI
68566856 specification.
68576857
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+
68586862 - for RISC-V, data[0] is set to the value of the second argument of the
68596863 ``sbi_system_reset`` call.
68606864
@@ -6888,6 +6892,12 @@ either: · 27 unmodified lines
68886892 - Deny the guest request to suspend the VM. See ARM DEN0022D.b 5.19.2
68896893 "Caller responsibilities" for possible return values.
68906894
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+
68916901 ::
68926902
68936903 /* KVM_EXIT_IOAPIC_EOI */
arch/arm64/include/uapi/asm/kvm.h+6−0
@@ -484,6 +484,12 @@ enum { · 483 unmodified lines
484484 */
485485 #define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0)
486486
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+
487493 /* run->fail_entry.hardware_entry_failure_reason codes. */
488494 #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0)
489495
arch/arm64/kvm/hyp/nvhe/psci-relay.c+2−0
@@ -265,6 +265,8 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_ · 264 unmodified lines
265265 case PSCI_1_0_FN_PSCI_FEATURES:
266266 case PSCI_1_0_FN_SET_SUSPEND_MODE:
267267 case PSCI_1_1_FN64_SYSTEM_RESET2:
268+ case PSCI_1_3_FN_SYSTEM_OFF2:
269+ case PSCI_1_3_FN64_SYSTEM_OFF2:
268270 return psci_forward(host_ctxt);
269271 case PSCI_1_0_FN64_SYSTEM_SUSPEND:
270272 return psci_system_suspend(func_id, host_ctxt);
arch/arm64/kvm/hypercalls.c+2−0
@@ -575,6 +575,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) · 574 unmodified lines
575575 case KVM_ARM_PSCI_0_2:
576576 case KVM_ARM_PSCI_1_0:
577577 case KVM_ARM_PSCI_1_1:
578+ case KVM_ARM_PSCI_1_2:
579+ case KVM_ARM_PSCI_1_3:
578580 if (!wants_02)
579581 return -EINVAL;
580582 vcpu->kvm->arch.psci_version = val;
arch/arm64/kvm/psci.c+43−1
@@ -194,6 +194,12 @@ static void kvm_psci_system_off(struct kvm_vcpu *vcpu) · 193 unmodified lines
194194 kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, 0);
195195 }
196196
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+
197203 static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
198204 {
199205 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
322328
323329 switch(psci_fn) {
324330 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);
326332 break;
327333 case PSCI_1_0_FN_PSCI_FEATURES:
328334 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
358364 if (minor >= 1)
359365 val = 0;
360366 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;
361372 }
362373 break;
363374 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
392403 break;
393404 }
394405 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;
395433 default:
396434 return kvm_psci_0_2_call(vcpu);
397435 }
@@ -449,6 +487,10 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) · 51 unmodified lines
449487 }
450488
451489 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);
452494 case KVM_ARM_PSCI_1_1:
453495 return kvm_psci_1_x_call(vcpu, 1);
454496 case KVM_ARM_PSCI_1_0:
drivers/firmware/psci/psci.c+45−0
@@ -78,6 +78,7 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void) · 77 unmodified lines
7878
7979 static u32 psci_cpu_suspend_feature;
8080 static bool psci_system_reset2_supported;
81+static bool psci_system_off2_hibernate_supported;
8182
8283 static inline bool psci_has_ext_power_state(void)
8384 {
@@ -333,6 +334,36 @@ static void psci_sys_poweroff(void) · 249 unmodified lines
333334 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
334335 }
335336
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+
336367 static int psci_features(u32 psci_func_id)
337368 {
338369 return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES,
@@ -364,6 +395,7 @@ static const struct { · 25 unmodified lines
364395 PSCI_ID_NATIVE(1_1, SYSTEM_RESET2),
365396 PSCI_ID(1_1, MEM_PROTECT),
366397 PSCI_ID_NATIVE(1_1, MEM_PROTECT_CHECK_RANGE),
398+ PSCI_ID_NATIVE(1_3, SYSTEM_OFF2),
367399 };
368400
369401 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
525557 psci_system_reset2_supported = true;
526558 }
527559
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+
528572 static void __init psci_init_system_suspend(void)
529573 {
530574 int ret;
@@ -655,6 +699,7 @@ static int __init psci_probe(void) · 124 unmodified lines
655699 psci_init_cpu_suspend();
656700 psci_init_system_suspend();
657701 psci_init_system_reset2();
702+ psci_init_system_off2();
658703 kvm_init_hyp_services();
659704 }
660705
include/kvm/arm_psci.h+3−1
@@ -14,8 +14,10 @@ · 13 unmodified lines
1414 #define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2)
1515 #define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0)
1616 #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)
1719
18−#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_1
20+#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_3
1921
2022 static inline int kvm_psci_version(struct kvm_vcpu *vcpu)
2123 {
include/uapi/linux/psci.h+5−0
@@ -59,6 +59,7 @@ · 58 unmodified lines
5959 #define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_0_2_FN(18)
6060 #define PSCI_1_1_FN_MEM_PROTECT PSCI_0_2_FN(19)
6161 #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)
6263
6364 #define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND PSCI_0_2_FN64(12)
6465 #define PSCI_1_0_FN64_NODE_HW_STATE PSCI_0_2_FN64(13)
@@ -68,6 +69,7 @@ · 3 unmodified lines
6869
6970 #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18)
7071 #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)
7173
7274 /* PSCI v0.2 power state encoding for CPU_SUSPEND function */
7375 #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff
@@ -100,6 +102,9 @@ · 26 unmodified lines
100102 #define PSCI_1_1_RESET_TYPE_SYSTEM_WARM_RESET 0
101103 #define PSCI_1_1_RESET_TYPE_VENDOR_START 0x80000000U
102104
105+/* PSCI v1.3 hibernate type for SYSTEM_OFF2 */
106+#define PSCI_1_3_OFF_TYPE_HIBERNATE_OFF BIT(0)
107+
103108 /* PSCI version decoding (independent of PSCI version) */
104109 #define PSCI_VERSION_MAJOR_SHIFT 16
105110 #define PSCI_VERSION_MINOR_MASK \
kernel/power/hibernate.c+4−1
@@ -685,8 +685,11 @@ static void power_down(void) · 684 unmodified lines
685685 }
686686 fallthrough;
687687 case HIBERNATION_SHUTDOWN:
688− if (kernel_can_power_off())
688+ if (kernel_can_power_off()) {
689+ entering_platform_hibernation = true;
689690 kernel_power_off();
691+ entering_platform_hibernation = false;
692+ }
690693 break;
691694 }
692695 kernel_halt();
tools/testing/selftests/kvm/aarch64/psci_test.c+92−0
@@ -54,6 +54,15 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id) · 53 unmodified lines
5454 return res.a0;
5555 }
5656
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+
5766 static uint64_t psci_features(uint32_t func_id)
5867 {
5968 struct arm_smccc_res res;
@@ -188,11 +197,94 @@ static void host_test_system_suspend(void) · 128 unmodified lines
188197 kvm_vm_free(vm);
189198 }
190199
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+
191282 int main(void)
192283 {
193284 TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SYSTEM_SUSPEND));
194285
195286 host_test_cpu_on();
196287 host_test_system_suspend();
288+ host_test_system_off2();
197289 return 0;
198290 }