Commit | Line | Data |
---|---|---|
b25d4cb4 JF |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Test for s390x CPU resets | |
4 | * | |
5 | * Copyright (C) 2020, IBM | |
6 | */ | |
7 | ||
8 | #include <stdio.h> | |
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
11 | #include <sys/ioctl.h> | |
12 | ||
13 | #include "test_util.h" | |
14 | #include "kvm_util.h" | |
b1edf7f1 | 15 | #include "kselftest.h" |
b25d4cb4 | 16 | |
b2ff728b PM |
17 | #define LOCAL_IRQS 32 |
18 | ||
371dfb2e SC |
19 | #define ARBITRARY_NON_ZERO_VCPU_ID 3 |
20 | ||
21 | struct kvm_s390_irq buf[ARBITRARY_NON_ZERO_VCPU_ID + LOCAL_IRQS]; | |
b25d4cb4 | 22 | |
b0435a12 | 23 | static uint8_t regs_null[512]; |
b25d4cb4 | 24 | |
b25d4cb4 JF |
25 | static void guest_code_initial(void) |
26 | { | |
41cbed5b CB |
27 | /* set several CRs to "safe" value */ |
28 | unsigned long cr2_59 = 0x10; /* enable guarded storage */ | |
29 | unsigned long cr8_63 = 0x1; /* monitor mask = 1 */ | |
30 | unsigned long cr10 = 1; /* PER START */ | |
31 | unsigned long cr11 = -1; /* PER END */ | |
32 | ||
b25d4cb4 JF |
33 | |
34 | /* Dirty registers */ | |
35 | asm volatile ( | |
41cbed5b CB |
36 | " lghi 2,0x11\n" /* Round toward 0 */ |
37 | " sfpc 2\n" /* set fpc to !=0 */ | |
38 | " lctlg 2,2,%0\n" | |
39 | " lctlg 8,8,%1\n" | |
40 | " lctlg 10,10,%2\n" | |
41 | " lctlg 11,11,%3\n" | |
3203a017 CB |
42 | /* now clobber some general purpose regs */ |
43 | " llihh 0,0xffff\n" | |
44 | " llihl 1,0x5555\n" | |
45 | " llilh 2,0xaaaa\n" | |
46 | " llill 3,0x0000\n" | |
47 | /* now clobber a floating point reg */ | |
48 | " lghi 4,0x1\n" | |
49 | " cdgbr 0,4\n" | |
50 | /* now clobber an access reg */ | |
51 | " sar 9,4\n" | |
52 | /* We embed diag 501 here to control register content */ | |
53 | " diag 0,0,0x501\n" | |
54 | : | |
55 | : "m" (cr2_59), "m" (cr8_63), "m" (cr10), "m" (cr11) | |
56 | /* no clobber list as this should not return */ | |
57 | ); | |
b25d4cb4 JF |
58 | } |
59 | ||
371dfb2e | 60 | static void test_one_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t value) |
b25d4cb4 | 61 | { |
b25d4cb4 JF |
62 | uint64_t eval_reg; |
63 | ||
768e9a61 | 64 | vcpu_get_reg(vcpu, id, &eval_reg); |
53362fe9 | 65 | TEST_ASSERT(eval_reg == value, "value == 0x%lx", value); |
b25d4cb4 JF |
66 | } |
67 | ||
371dfb2e | 68 | static void assert_noirq(struct kvm_vcpu *vcpu) |
b2ff728b PM |
69 | { |
70 | struct kvm_s390_irq_state irq_state; | |
71 | int irqs; | |
72 | ||
73 | irq_state.len = sizeof(buf); | |
74 | irq_state.buf = (unsigned long)buf; | |
768e9a61 | 75 | irqs = __vcpu_ioctl(vcpu, KVM_S390_GET_IRQ_STATE, &irq_state); |
b2ff728b PM |
76 | /* |
77 | * irqs contains the number of retrieved interrupts. Any interrupt | |
78 | * (notably, the emergency call interrupt we have injected) should | |
79 | * be cleared by the resets, so this should be 0. | |
80 | */ | |
a38125f1 | 81 | TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d", errno); |
b2ff728b PM |
82 | TEST_ASSERT(!irqs, "IRQ pending"); |
83 | } | |
84 | ||
371dfb2e | 85 | static void assert_clear(struct kvm_vcpu *vcpu) |
b25d4cb4 | 86 | { |
371dfb2e | 87 | struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; |
b25d4cb4 JF |
88 | struct kvm_sregs sregs; |
89 | struct kvm_regs regs; | |
90 | struct kvm_fpu fpu; | |
91 | ||
768e9a61 | 92 | vcpu_regs_get(vcpu, ®s); |
b25d4cb4 JF |
93 | TEST_ASSERT(!memcmp(®s.gprs, regs_null, sizeof(regs.gprs)), "grs == 0"); |
94 | ||
768e9a61 | 95 | vcpu_sregs_get(vcpu, &sregs); |
b25d4cb4 JF |
96 | TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0"); |
97 | ||
768e9a61 | 98 | vcpu_fpu_get(vcpu, &fpu); |
b25d4cb4 | 99 | TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0"); |
b0435a12 CB |
100 | |
101 | /* sync regs */ | |
102 | TEST_ASSERT(!memcmp(sync_regs->gprs, regs_null, sizeof(sync_regs->gprs)), | |
103 | "gprs0-15 == 0 (sync_regs)"); | |
104 | ||
105 | TEST_ASSERT(!memcmp(sync_regs->acrs, regs_null, sizeof(sync_regs->acrs)), | |
106 | "acrs0-15 == 0 (sync_regs)"); | |
107 | ||
108 | TEST_ASSERT(!memcmp(sync_regs->vrs, regs_null, sizeof(sync_regs->vrs)), | |
109 | "vrs0-15 == 0 (sync_regs)"); | |
b25d4cb4 JF |
110 | } |
111 | ||
371dfb2e | 112 | static void assert_initial_noclear(struct kvm_vcpu *vcpu) |
3203a017 | 113 | { |
371dfb2e SC |
114 | struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; |
115 | ||
3203a017 CB |
116 | TEST_ASSERT(sync_regs->gprs[0] == 0xffff000000000000UL, |
117 | "gpr0 == 0xffff000000000000 (sync_regs)"); | |
118 | TEST_ASSERT(sync_regs->gprs[1] == 0x0000555500000000UL, | |
119 | "gpr1 == 0x0000555500000000 (sync_regs)"); | |
120 | TEST_ASSERT(sync_regs->gprs[2] == 0x00000000aaaa0000UL, | |
121 | "gpr2 == 0x00000000aaaa0000 (sync_regs)"); | |
122 | TEST_ASSERT(sync_regs->gprs[3] == 0x0000000000000000UL, | |
123 | "gpr3 == 0x0000000000000000 (sync_regs)"); | |
124 | TEST_ASSERT(sync_regs->fprs[0] == 0x3ff0000000000000UL, | |
125 | "fpr0 == 0f1 (sync_regs)"); | |
126 | TEST_ASSERT(sync_regs->acrs[9] == 1, "ar9 == 1 (sync_regs)"); | |
127 | } | |
128 | ||
371dfb2e | 129 | static void assert_initial(struct kvm_vcpu *vcpu) |
b25d4cb4 | 130 | { |
371dfb2e | 131 | struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; |
b25d4cb4 JF |
132 | struct kvm_sregs sregs; |
133 | struct kvm_fpu fpu; | |
134 | ||
b0435a12 | 135 | /* KVM_GET_SREGS */ |
768e9a61 | 136 | vcpu_sregs_get(vcpu, &sregs); |
b0435a12 CB |
137 | TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0 (KVM_GET_SREGS)"); |
138 | TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, | |
139 | "cr14 == 0xC2000000 (KVM_GET_SREGS)"); | |
b25d4cb4 | 140 | TEST_ASSERT(!memcmp(&sregs.crs[1], regs_null, sizeof(sregs.crs[1]) * 12), |
b0435a12 CB |
141 | "cr1-13 == 0 (KVM_GET_SREGS)"); |
142 | TEST_ASSERT(sregs.crs[15] == 0, "cr15 == 0 (KVM_GET_SREGS)"); | |
143 | ||
144 | /* sync regs */ | |
145 | TEST_ASSERT(sync_regs->crs[0] == 0xE0UL, "cr0 == 0xE0 (sync_regs)"); | |
146 | TEST_ASSERT(sync_regs->crs[14] == 0xC2000000UL, | |
147 | "cr14 == 0xC2000000 (sync_regs)"); | |
148 | TEST_ASSERT(!memcmp(&sync_regs->crs[1], regs_null, 8 * 12), | |
149 | "cr1-13 == 0 (sync_regs)"); | |
150 | TEST_ASSERT(sync_regs->crs[15] == 0, "cr15 == 0 (sync_regs)"); | |
151 | TEST_ASSERT(sync_regs->fpc == 0, "fpc == 0 (sync_regs)"); | |
152 | TEST_ASSERT(sync_regs->todpr == 0, "todpr == 0 (sync_regs)"); | |
153 | TEST_ASSERT(sync_regs->cputm == 0, "cputm == 0 (sync_regs)"); | |
154 | TEST_ASSERT(sync_regs->ckc == 0, "ckc == 0 (sync_regs)"); | |
155 | TEST_ASSERT(sync_regs->pp == 0, "pp == 0 (sync_regs)"); | |
156 | TEST_ASSERT(sync_regs->gbea == 1, "gbea == 1 (sync_regs)"); | |
157 | ||
158 | /* kvm_run */ | |
371dfb2e SC |
159 | TEST_ASSERT(vcpu->run->psw_addr == 0, "psw_addr == 0 (kvm_run)"); |
160 | TEST_ASSERT(vcpu->run->psw_mask == 0, "psw_mask == 0 (kvm_run)"); | |
b25d4cb4 | 161 | |
768e9a61 | 162 | vcpu_fpu_get(vcpu, &fpu); |
b25d4cb4 JF |
163 | TEST_ASSERT(!fpu.fpc, "fpc == 0"); |
164 | ||
371dfb2e SC |
165 | test_one_reg(vcpu, KVM_REG_S390_GBEA, 1); |
166 | test_one_reg(vcpu, KVM_REG_S390_PP, 0); | |
167 | test_one_reg(vcpu, KVM_REG_S390_TODPR, 0); | |
168 | test_one_reg(vcpu, KVM_REG_S390_CPU_TIMER, 0); | |
169 | test_one_reg(vcpu, KVM_REG_S390_CLOCK_COMP, 0); | |
b25d4cb4 JF |
170 | } |
171 | ||
371dfb2e | 172 | static void assert_normal_noclear(struct kvm_vcpu *vcpu) |
3203a017 | 173 | { |
371dfb2e SC |
174 | struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; |
175 | ||
3203a017 CB |
176 | TEST_ASSERT(sync_regs->crs[2] == 0x10, "cr2 == 10 (sync_regs)"); |
177 | TEST_ASSERT(sync_regs->crs[8] == 1, "cr10 == 1 (sync_regs)"); | |
178 | TEST_ASSERT(sync_regs->crs[10] == 1, "cr10 == 1 (sync_regs)"); | |
179 | TEST_ASSERT(sync_regs->crs[11] == -1, "cr11 == -1 (sync_regs)"); | |
180 | } | |
181 | ||
371dfb2e | 182 | static void assert_normal(struct kvm_vcpu *vcpu) |
b25d4cb4 | 183 | { |
371dfb2e SC |
184 | test_one_reg(vcpu, KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID); |
185 | TEST_ASSERT(vcpu->run->s.regs.pft == KVM_S390_PFAULT_TOKEN_INVALID, | |
b0435a12 | 186 | "pft == 0xff..... (sync_regs)"); |
371dfb2e | 187 | assert_noirq(vcpu); |
b2ff728b PM |
188 | } |
189 | ||
371dfb2e | 190 | static void inject_irq(struct kvm_vcpu *vcpu) |
b2ff728b PM |
191 | { |
192 | struct kvm_s390_irq_state irq_state; | |
193 | struct kvm_s390_irq *irq = &buf[0]; | |
194 | int irqs; | |
195 | ||
196 | /* Inject IRQ */ | |
197 | irq_state.len = sizeof(struct kvm_s390_irq); | |
198 | irq_state.buf = (unsigned long)buf; | |
199 | irq->type = KVM_S390_INT_EMERGENCY; | |
371dfb2e | 200 | irq->u.emerg.code = vcpu->id; |
768e9a61 | 201 | irqs = __vcpu_ioctl(vcpu, KVM_S390_SET_IRQ_STATE, &irq_state); |
a38125f1 | 202 | TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d", errno); |
b25d4cb4 JF |
203 | } |
204 | ||
371dfb2e SC |
205 | static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu) |
206 | { | |
207 | struct kvm_vm *vm; | |
208 | ||
6e1d13bf | 209 | vm = vm_create(1); |
371dfb2e SC |
210 | |
211 | *vcpu = vm_vcpu_add(vm, ARBITRARY_NON_ZERO_VCPU_ID, guest_code_initial); | |
212 | ||
213 | return vm; | |
214 | } | |
215 | ||
b25d4cb4 JF |
216 | static void test_normal(void) |
217 | { | |
371dfb2e SC |
218 | struct kvm_vcpu *vcpu; |
219 | struct kvm_vm *vm; | |
220 | ||
b1edf7f1 | 221 | ksft_print_msg("Testing normal reset\n"); |
371dfb2e | 222 | vm = create_vm(&vcpu); |
b25d4cb4 | 223 | |
768e9a61 | 224 | vcpu_run(vcpu); |
b25d4cb4 | 225 | |
371dfb2e | 226 | inject_irq(vcpu); |
b2ff728b | 227 | |
fcba483e | 228 | vcpu_ioctl(vcpu, KVM_S390_NORMAL_RESET, NULL); |
3203a017 CB |
229 | |
230 | /* must clears */ | |
371dfb2e | 231 | assert_normal(vcpu); |
3203a017 | 232 | /* must not clears */ |
371dfb2e SC |
233 | assert_normal_noclear(vcpu); |
234 | assert_initial_noclear(vcpu); | |
3203a017 | 235 | |
b25d4cb4 JF |
236 | kvm_vm_free(vm); |
237 | } | |
238 | ||
239 | static void test_initial(void) | |
240 | { | |
371dfb2e SC |
241 | struct kvm_vcpu *vcpu; |
242 | struct kvm_vm *vm; | |
243 | ||
b1edf7f1 | 244 | ksft_print_msg("Testing initial reset\n"); |
371dfb2e | 245 | vm = create_vm(&vcpu); |
b25d4cb4 | 246 | |
768e9a61 | 247 | vcpu_run(vcpu); |
b25d4cb4 | 248 | |
371dfb2e | 249 | inject_irq(vcpu); |
b2ff728b | 250 | |
fcba483e | 251 | vcpu_ioctl(vcpu, KVM_S390_INITIAL_RESET, NULL); |
3203a017 CB |
252 | |
253 | /* must clears */ | |
371dfb2e SC |
254 | assert_normal(vcpu); |
255 | assert_initial(vcpu); | |
3203a017 | 256 | /* must not clears */ |
371dfb2e | 257 | assert_initial_noclear(vcpu); |
3203a017 | 258 | |
b25d4cb4 JF |
259 | kvm_vm_free(vm); |
260 | } | |
261 | ||
262 | static void test_clear(void) | |
263 | { | |
371dfb2e SC |
264 | struct kvm_vcpu *vcpu; |
265 | struct kvm_vm *vm; | |
266 | ||
b1edf7f1 | 267 | ksft_print_msg("Testing clear reset\n"); |
371dfb2e | 268 | vm = create_vm(&vcpu); |
b25d4cb4 | 269 | |
768e9a61 | 270 | vcpu_run(vcpu); |
b25d4cb4 | 271 | |
371dfb2e | 272 | inject_irq(vcpu); |
b2ff728b | 273 | |
fcba483e | 274 | vcpu_ioctl(vcpu, KVM_S390_CLEAR_RESET, NULL); |
3203a017 CB |
275 | |
276 | /* must clears */ | |
371dfb2e SC |
277 | assert_normal(vcpu); |
278 | assert_initial(vcpu); | |
279 | assert_clear(vcpu); | |
3203a017 | 280 | |
b25d4cb4 JF |
281 | kvm_vm_free(vm); |
282 | } | |
283 | ||
b1edf7f1 TH |
284 | struct testdef { |
285 | const char *name; | |
286 | void (*test)(void); | |
287 | bool needs_cap; | |
288 | } testlist[] = { | |
289 | { "initial", test_initial, false }, | |
290 | { "normal", test_normal, true }, | |
291 | { "clear", test_clear, true }, | |
292 | }; | |
293 | ||
b25d4cb4 JF |
294 | int main(int argc, char *argv[]) |
295 | { | |
b1edf7f1 TH |
296 | bool has_s390_vcpu_resets = kvm_check_cap(KVM_CAP_S390_VCPU_RESETS); |
297 | int idx; | |
298 | ||
b1edf7f1 TH |
299 | ksft_print_header(); |
300 | ksft_set_plan(ARRAY_SIZE(testlist)); | |
301 | ||
302 | for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { | |
303 | if (!testlist[idx].needs_cap || has_s390_vcpu_resets) { | |
304 | testlist[idx].test(); | |
305 | ksft_test_result_pass("%s\n", testlist[idx].name); | |
306 | } else { | |
307 | ksft_test_result_skip("%s - no VCPU_RESETS capability\n", | |
308 | testlist[idx].name); | |
309 | } | |
b25d4cb4 | 310 | } |
b1edf7f1 TH |
311 | |
312 | ksft_finished(); /* Print results and exit() accordingly */ | |
b25d4cb4 | 313 | } |