Test KVM's newly-added support for the SYSTEM_SUSPEND PSCI call. Since
it is ABI that the vCPUs remain runnable after a system exit (i.e. a VMM
can blissfully ignore this exit), assert that the exiting vCPU is reset
at the requested entrypoint.

Signed-off-by: Oliver Upton <[email protected]>
---
 .../selftests/kvm/aarch64/psci_cpu_on_test.c  | 110 +++++++++++++-----
 1 file changed, 84 insertions(+), 26 deletions(-)

diff --git a/tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c 
b/tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c
index 9c22374fc0f5..b08b006cc4b4 100644
--- a/tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c
+++ b/tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c
@@ -54,7 +54,21 @@ static uint64_t psci_affinity_info(uint64_t target_affinity,
        return x0;
 }
 
-static void guest_main(uint64_t target_cpu)
+static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id)
+{
+       register uint64_t x0 asm("x0") = PSCI_1_0_FN64_SYSTEM_SUSPEND;
+       register uint64_t x1 asm("x1") = entry_addr;
+       register uint64_t x2 asm("x2") = context_id;
+
+       asm volatile("hvc #0"
+                    : "=r"(x0)
+                    : "r"(x0), "r"(x1), "r"(x2)
+                    : "memory");
+
+       return x0;
+}
+
+static void guest_test_cpu_on(uint64_t target_cpu)
 {
        GUEST_ASSERT(!psci_cpu_on(target_cpu, CPU_ON_ENTRY_ADDR, 
CPU_ON_CONTEXT_ID));
        uint64_t target_state;
@@ -69,52 +83,96 @@ static void guest_main(uint64_t target_cpu)
        GUEST_DONE();
 }
 
+static void guest_test_system_suspend(uint64_t target_cpu)
+{
+       psci_system_suspend(CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID);
+
+       /* should never be reached */
+       GUEST_ASSERT(0);
+}
+
+static void guest_main(uint64_t target_cpu)
+{
+       guest_test_cpu_on(target_cpu);
+       guest_test_system_suspend(target_cpu);
+}
+
 int main(void)
 {
+       struct kvm_mp_state target_mp_state = { .mp_state = 
KVM_MP_STATE_STOPPED };
        uint64_t target_mpidr, obs_pc, obs_x0;
+       struct kvm_enable_cap cap = {0};
+       uint32_t vcpu_to_test = -1;
        struct kvm_vcpu_init init;
        struct kvm_vm *vm;
        struct ucall uc;
+       int i;
+
+       if (!kvm_check_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)) {
+               print_skip("KVM_CAP_ARM_SYSTEM_SUSPEND not supported");
+               exit(KSFT_SKIP);
+       }
 
        vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
        kvm_vm_elf_load(vm, program_invocation_name);
        ucall_init(vm, NULL);
 
+       cap.cap = KVM_CAP_ARM_SYSTEM_SUSPEND;
+       vm_enable_cap(vm, &cap);
+
        vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
        init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);
 
        aarch64_vcpu_add_default(vm, VCPU_ID_SOURCE, &init, guest_main);
-
-       /*
-        * make sure the target is already off when executing the test.
-        */
-       init.features[0] |= (1 << KVM_ARM_VCPU_POWER_OFF);
        aarch64_vcpu_add_default(vm, VCPU_ID_TARGET, &init, guest_main);
 
        get_reg(vm, VCPU_ID_TARGET, ARM64_SYS_REG(MPIDR_EL1), &target_mpidr);
        vcpu_args_set(vm, VCPU_ID_SOURCE, 1, target_mpidr & MPIDR_HWID_BITMASK);
-       vcpu_run(vm, VCPU_ID_SOURCE);
-
-       switch (get_ucall(vm, VCPU_ID_SOURCE, &uc)) {
-       case UCALL_DONE:
-               break;
-       case UCALL_ABORT:
-               TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__,
-                         uc.args[1]);
-               break;
-       default:
-               TEST_FAIL("Unhandled ucall: %lu", uc.cmd);
-       }
 
-       get_reg(vm, VCPU_ID_TARGET, ARM64_CORE_REG(regs.pc), &obs_pc);
-       get_reg(vm, VCPU_ID_TARGET, ARM64_CORE_REG(regs.regs[0]), &obs_x0);
+       for (i = 0; i < 2; i++) {
+               struct kvm_run *run = vcpu_state(vm, VCPU_ID_SOURCE);
+
+               /*
+                * make sure the target is already off when executing the test.
+                */
+               vcpu_set_mp_state(vm, VCPU_ID_TARGET, &target_mp_state);
+               vcpu_run(vm, VCPU_ID_SOURCE);
+               switch (run->exit_reason) {
+               case KVM_EXIT_MMIO:
+                       switch (get_ucall(vm, VCPU_ID_SOURCE, &uc)) {
+                       case UCALL_DONE:
+                               vcpu_to_test = VCPU_ID_TARGET;
+                               break;
+                       case UCALL_ABORT:
+                               TEST_FAIL("%s at %s:%ld", (const char 
*)uc.args[0], __FILE__,
+                                         uc.args[1]);
+                               break;
+                       default:
+                               TEST_FAIL("Unhandled ucall: %lu", uc.cmd);
+                       }
+                       break;
+               case KVM_EXIT_SYSTEM_EVENT:
+                       TEST_ASSERT(run->system_event.type == 
KVM_SYSTEM_EVENT_SUSPEND,
+                                   "unhandled system event: %u (expected: %u)",
+                                   run->system_event.type, 
KVM_SYSTEM_EVENT_SUSPEND);
+                       vcpu_to_test = VCPU_ID_SOURCE;
+                       break;
+               default:
+                       TEST_FAIL("unhandled exit reason: %u (%s)",
+                                 run->exit_reason, 
exit_reason_str(run->exit_reason));
+               }
+
+               get_reg(vm, vcpu_to_test, ARM64_CORE_REG(regs.pc), &obs_pc);
+               get_reg(vm, vcpu_to_test, ARM64_CORE_REG(regs.regs[0]), 
&obs_x0);
+
+               TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR,
+                           "unexpected target cpu pc: %lx (expected: %lx)",
+                           obs_pc, CPU_ON_ENTRY_ADDR);
+               TEST_ASSERT(obs_x0 == CPU_ON_CONTEXT_ID,
+                           "unexpected target context id: %lx (expected: %lx)",
+                           obs_x0, CPU_ON_CONTEXT_ID);
 
-       TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR,
-                   "unexpected target cpu pc: %lx (expected: %lx)",
-                   obs_pc, CPU_ON_ENTRY_ADDR);
-       TEST_ASSERT(obs_x0 == CPU_ON_CONTEXT_ID,
-                   "unexpected target context id: %lx (expected: %lx)",
-                   obs_x0, CPU_ON_CONTEXT_ID);
+       }
 
        kvm_vm_free(vm);
        return 0;
-- 
2.33.0.rc2.250.ged5fa647cd-goog

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to