ACPI: APEI: Fix integer overflow in ghes_estatus_pool_init()
[sfrench/cifs-2.6.git] / tools / testing / selftests / kvm / aarch64 / psci_test.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * psci_cpu_on_test - Test that the observable state of a vCPU targeted by the
4  * CPU_ON PSCI call matches what the caller requested.
5  *
6  * Copyright (c) 2021 Google LLC.
7  *
8  * This is a regression test for a race between KVM servicing the PSCI call and
9  * userspace reading the vCPUs registers.
10  */
11
12 #define _GNU_SOURCE
13
14 #include <linux/psci.h>
15
16 #include "kvm_util.h"
17 #include "processor.h"
18 #include "test_util.h"
19
20 #define CPU_ON_ENTRY_ADDR 0xfeedf00dul
21 #define CPU_ON_CONTEXT_ID 0xdeadc0deul
22
23 static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr,
24                             uint64_t context_id)
25 {
26         struct arm_smccc_res res;
27
28         smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id,
29                   0, 0, 0, 0, &res);
30
31         return res.a0;
32 }
33
34 static uint64_t psci_affinity_info(uint64_t target_affinity,
35                                    uint64_t lowest_affinity_level)
36 {
37         struct arm_smccc_res res;
38
39         smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level,
40                   0, 0, 0, 0, 0, &res);
41
42         return res.a0;
43 }
44
45 static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id)
46 {
47         struct arm_smccc_res res;
48
49         smccc_hvc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id,
50                   0, 0, 0, 0, 0, &res);
51
52         return res.a0;
53 }
54
55 static uint64_t psci_features(uint32_t func_id)
56 {
57         struct arm_smccc_res res;
58
59         smccc_hvc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res);
60
61         return res.a0;
62 }
63
64 static void vcpu_power_off(struct kvm_vcpu *vcpu)
65 {
66         struct kvm_mp_state mp_state = {
67                 .mp_state = KVM_MP_STATE_STOPPED,
68         };
69
70         vcpu_mp_state_set(vcpu, &mp_state);
71 }
72
73 static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source,
74                                struct kvm_vcpu **target)
75 {
76         struct kvm_vcpu_init init;
77         struct kvm_vm *vm;
78
79         vm = vm_create(2);
80         ucall_init(vm, NULL);
81
82         vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
83         init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);
84
85         *source = aarch64_vcpu_add(vm, 0, &init, guest_code);
86         *target = aarch64_vcpu_add(vm, 1, &init, guest_code);
87
88         return vm;
89 }
90
91 static void enter_guest(struct kvm_vcpu *vcpu)
92 {
93         struct ucall uc;
94
95         vcpu_run(vcpu);
96         if (get_ucall(vcpu, &uc) == UCALL_ABORT)
97                 REPORT_GUEST_ASSERT(uc);
98 }
99
100 static void assert_vcpu_reset(struct kvm_vcpu *vcpu)
101 {
102         uint64_t obs_pc, obs_x0;
103
104         vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc), &obs_pc);
105         vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.regs[0]), &obs_x0);
106
107         TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR,
108                     "unexpected target cpu pc: %lx (expected: %lx)",
109                     obs_pc, CPU_ON_ENTRY_ADDR);
110         TEST_ASSERT(obs_x0 == CPU_ON_CONTEXT_ID,
111                     "unexpected target context id: %lx (expected: %lx)",
112                     obs_x0, CPU_ON_CONTEXT_ID);
113 }
114
115 static void guest_test_cpu_on(uint64_t target_cpu)
116 {
117         uint64_t target_state;
118
119         GUEST_ASSERT(!psci_cpu_on(target_cpu, CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID));
120
121         do {
122                 target_state = psci_affinity_info(target_cpu, 0);
123
124                 GUEST_ASSERT((target_state == PSCI_0_2_AFFINITY_LEVEL_ON) ||
125                              (target_state == PSCI_0_2_AFFINITY_LEVEL_OFF));
126         } while (target_state != PSCI_0_2_AFFINITY_LEVEL_ON);
127
128         GUEST_DONE();
129 }
130
131 static void host_test_cpu_on(void)
132 {
133         struct kvm_vcpu *source, *target;
134         uint64_t target_mpidr;
135         struct kvm_vm *vm;
136         struct ucall uc;
137
138         vm = setup_vm(guest_test_cpu_on, &source, &target);
139
140         /*
141          * make sure the target is already off when executing the test.
142          */
143         vcpu_power_off(target);
144
145         vcpu_get_reg(target, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr);
146         vcpu_args_set(source, 1, target_mpidr & MPIDR_HWID_BITMASK);
147         enter_guest(source);
148
149         if (get_ucall(source, &uc) != UCALL_DONE)
150                 TEST_FAIL("Unhandled ucall: %lu", uc.cmd);
151
152         assert_vcpu_reset(target);
153         kvm_vm_free(vm);
154 }
155
156 static void guest_test_system_suspend(void)
157 {
158         uint64_t ret;
159
160         /* assert that SYSTEM_SUSPEND is discoverable */
161         GUEST_ASSERT(!psci_features(PSCI_1_0_FN_SYSTEM_SUSPEND));
162         GUEST_ASSERT(!psci_features(PSCI_1_0_FN64_SYSTEM_SUSPEND));
163
164         ret = psci_system_suspend(CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID);
165         GUEST_SYNC(ret);
166 }
167
168 static void host_test_system_suspend(void)
169 {
170         struct kvm_vcpu *source, *target;
171         struct kvm_run *run;
172         struct kvm_vm *vm;
173
174         vm = setup_vm(guest_test_system_suspend, &source, &target);
175         vm_enable_cap(vm, KVM_CAP_ARM_SYSTEM_SUSPEND, 0);
176
177         vcpu_power_off(target);
178         run = source->run;
179
180         enter_guest(source);
181
182         TEST_ASSERT(run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
183                     "Unhandled exit reason: %u (%s)",
184                     run->exit_reason, exit_reason_str(run->exit_reason));
185         TEST_ASSERT(run->system_event.type == KVM_SYSTEM_EVENT_SUSPEND,
186                     "Unhandled system event: %u (expected: %u)",
187                     run->system_event.type, KVM_SYSTEM_EVENT_SUSPEND);
188
189         kvm_vm_free(vm);
190 }
191
192 int main(void)
193 {
194         TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SYSTEM_SUSPEND));
195
196         host_test_cpu_on();
197         host_test_system_suspend();
198         return 0;
199 }