1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Test for s390x KVM_CAP_SYNC_REGS
4 *
5 * Based on the same test for x86:
6 * Copyright (C) 2018, Google LLC.
7 *
8 * Adaptions for s390x:
9 * Copyright (C) 2019, Red Hat, Inc.
10 *
11 * Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
12 */
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18
19 #include "test_util.h"
20 #include "kvm_util.h"
21 #include "diag318_test_handler.h"
22 #include "kselftest.h"
23
guest_code(void)24 static void guest_code(void)
25 {
26 /*
27 * We embed diag 501 here instead of doing a ucall to avoid that
28 * the compiler has messed with r11 at the time of the ucall.
29 */
30 asm volatile (
31 "0: diag 0,0,0x501\n"
32 " ahi 11,1\n"
33 " j 0b\n"
34 );
35 }
36
37 #define REG_COMPARE(reg) \
38 TEST_ASSERT(left->reg == right->reg, \
39 "Register " #reg \
40 " values did not match: 0x%llx, 0x%llx", \
41 left->reg, right->reg)
42
43 #define REG_COMPARE32(reg) \
44 TEST_ASSERT(left->reg == right->reg, \
45 "Register " #reg \
46 " values did not match: 0x%x, 0x%x", \
47 left->reg, right->reg)
48
49
compare_regs(struct kvm_regs * left,struct kvm_sync_regs * right)50 static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
51 {
52 int i;
53
54 for (i = 0; i < 16; i++)
55 REG_COMPARE(gprs[i]);
56 }
57
compare_sregs(struct kvm_sregs * left,struct kvm_sync_regs * right)58 static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
59 {
60 int i;
61
62 for (i = 0; i < 16; i++)
63 REG_COMPARE32(acrs[i]);
64
65 for (i = 0; i < 16; i++)
66 REG_COMPARE(crs[i]);
67 }
68
69 #undef REG_COMPARE
70
71 #define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318)
72 #define INVALID_SYNC_FIELD 0x80000000
73
test_read_invalid(struct kvm_vcpu * vcpu)74 void test_read_invalid(struct kvm_vcpu *vcpu)
75 {
76 struct kvm_run *run = vcpu->run;
77 int rv;
78
79 /* Request reading invalid register set from VCPU. */
80 run->kvm_valid_regs = INVALID_SYNC_FIELD;
81 rv = _vcpu_run(vcpu);
82 TEST_ASSERT(rv < 0 && errno == EINVAL,
83 "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
84 rv);
85 run->kvm_valid_regs = 0;
86
87 run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
88 rv = _vcpu_run(vcpu);
89 TEST_ASSERT(rv < 0 && errno == EINVAL,
90 "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
91 rv);
92 run->kvm_valid_regs = 0;
93 }
94
test_set_invalid(struct kvm_vcpu * vcpu)95 void test_set_invalid(struct kvm_vcpu *vcpu)
96 {
97 struct kvm_run *run = vcpu->run;
98 int rv;
99
100 /* Request setting invalid register set into VCPU. */
101 run->kvm_dirty_regs = INVALID_SYNC_FIELD;
102 rv = _vcpu_run(vcpu);
103 TEST_ASSERT(rv < 0 && errno == EINVAL,
104 "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
105 rv);
106 run->kvm_dirty_regs = 0;
107
108 run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
109 rv = _vcpu_run(vcpu);
110 TEST_ASSERT(rv < 0 && errno == EINVAL,
111 "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
112 rv);
113 run->kvm_dirty_regs = 0;
114 }
115
test_req_and_verify_all_valid_regs(struct kvm_vcpu * vcpu)116 void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu)
117 {
118 struct kvm_run *run = vcpu->run;
119 struct kvm_sregs sregs;
120 struct kvm_regs regs;
121 int rv;
122
123 /* Request and verify all valid register sets. */
124 run->kvm_valid_regs = TEST_SYNC_FIELDS;
125 rv = _vcpu_run(vcpu);
126 TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
127 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
128 TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
129 (run->s390_sieic.ipa >> 8) == 0x83 &&
130 (run->s390_sieic.ipb >> 16) == 0x501,
131 "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x",
132 run->s390_sieic.icptcode, run->s390_sieic.ipa,
133 run->s390_sieic.ipb);
134
135 vcpu_regs_get(vcpu, ®s);
136 compare_regs(®s, &run->s.regs);
137
138 vcpu_sregs_get(vcpu, &sregs);
139 compare_sregs(&sregs, &run->s.regs);
140 }
141
test_set_and_verify_various_reg_values(struct kvm_vcpu * vcpu)142 void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu)
143 {
144 struct kvm_run *run = vcpu->run;
145 struct kvm_sregs sregs;
146 struct kvm_regs regs;
147 int rv;
148
149 /* Set and verify various register values */
150 run->s.regs.gprs[11] = 0xBAD1DEA;
151 run->s.regs.acrs[0] = 1 << 11;
152
153 run->kvm_valid_regs = TEST_SYNC_FIELDS;
154 run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
155
156 if (get_diag318_info() > 0) {
157 run->s.regs.diag318 = get_diag318_info();
158 run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
159 }
160
161 rv = _vcpu_run(vcpu);
162 TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
163 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
164 TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
165 "r11 sync regs value incorrect 0x%llx.",
166 run->s.regs.gprs[11]);
167 TEST_ASSERT(run->s.regs.acrs[0] == 1 << 11,
168 "acr0 sync regs value incorrect 0x%x.",
169 run->s.regs.acrs[0]);
170 TEST_ASSERT(run->s.regs.diag318 == get_diag318_info(),
171 "diag318 sync regs value incorrect 0x%llx.",
172 run->s.regs.diag318);
173
174 vcpu_regs_get(vcpu, ®s);
175 compare_regs(®s, &run->s.regs);
176
177 vcpu_sregs_get(vcpu, &sregs);
178 compare_sregs(&sregs, &run->s.regs);
179 }
180
test_clear_kvm_dirty_regs_bits(struct kvm_vcpu * vcpu)181 void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu)
182 {
183 struct kvm_run *run = vcpu->run;
184 int rv;
185
186 /* Clear kvm_dirty_regs bits, verify new s.regs values are
187 * overwritten with existing guest values.
188 */
189 run->kvm_valid_regs = TEST_SYNC_FIELDS;
190 run->kvm_dirty_regs = 0;
191 run->s.regs.gprs[11] = 0xDEADBEEF;
192 run->s.regs.diag318 = 0x4B1D;
193 rv = _vcpu_run(vcpu);
194 TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
195 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
196 TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
197 "r11 sync regs value incorrect 0x%llx.",
198 run->s.regs.gprs[11]);
199 TEST_ASSERT(run->s.regs.diag318 != 0x4B1D,
200 "diag318 sync regs value incorrect 0x%llx.",
201 run->s.regs.diag318);
202 }
203
204 struct testdef {
205 const char *name;
206 void (*test)(struct kvm_vcpu *vcpu);
207 } testlist[] = {
208 { "read invalid", test_read_invalid },
209 { "set invalid", test_set_invalid },
210 { "request+verify all valid regs", test_req_and_verify_all_valid_regs },
211 { "set+verify various regs", test_set_and_verify_various_reg_values },
212 { "clear kvm_dirty_regs bits", test_clear_kvm_dirty_regs_bits },
213 };
214
main(int argc,char * argv[])215 int main(int argc, char *argv[])
216 {
217 struct kvm_vcpu *vcpu;
218 struct kvm_vm *vm;
219 int idx;
220
221 TEST_REQUIRE(kvm_has_cap(KVM_CAP_SYNC_REGS));
222
223 ksft_print_header();
224
225 ksft_set_plan(ARRAY_SIZE(testlist));
226
227 /* Create VM */
228 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
229
230 for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
231 testlist[idx].test(vcpu);
232 ksft_test_result_pass("%s\n", testlist[idx].name);
233 }
234
235 kvm_vm_free(vm);
236
237 ksft_finished(); /* Print results and exit() accordingly */
238 }
239