File Index
Files and directories
Sign in
FILE

sync_regs_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/s390/sync_regs_test.c C
  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
 24static 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
 50static 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
 58static 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
 74void 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
 95void 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
116void 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, &regs);
136	compare_regs(&regs, &run->s.regs);
137
138	vcpu_sregs_get(vcpu, &sregs);
139	compare_sregs(&sregs, &run->s.regs);
140}
141
142void 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, &regs);
175	compare_regs(&regs, &run->s.regs);
176
177	vcpu_sregs_get(vcpu, &sregs);
178	compare_sregs(&sregs, &run->s.regs);
179}
180
181void 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
204struct 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
215int 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}
~/ Read-only file preview.