Skip to content

Commit 72be5aa

Browse files
dwmw2oupton
authored andcommitted
KVM: selftests: Add test for PSCI SYSTEM_OFF2
Signed-off-by: David Woodhouse <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 8be82d5 commit 72be5aa

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

tools/testing/selftests/kvm/aarch64/psci_test.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id)
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)
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
}

0 commit comments

Comments
 (0)