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"
15 
16 #define VCPU_ID 3
17 #define LOCAL_IRQS 32
18 
19 struct kvm_s390_irq buf[VCPU_ID + LOCAL_IRQS];
20 
21 struct kvm_vm *vm;
22 struct kvm_run *run;
23 struct kvm_sync_regs *regs;
24 static uint64_t regs_null[16];
25 
26 static uint64_t crs[16] = { 0x40000ULL,
27 			    0x42000ULL,
28 			    0, 0, 0, 0, 0,
29 			    0x43000ULL,
30 			    0, 0, 0, 0, 0,
31 			    0x44000ULL,
32 			    0, 0
33 };
34 
35 static void guest_code_initial(void)
36 {
37 	/* Round toward 0 */
38 	uint32_t fpc = 0x11;
39 
40 	/* Dirty registers */
41 	asm volatile (
42 		"	lctlg	0,15,%0\n"
43 		"	sfpc	%1\n"
44 		: : "Q" (crs), "d" (fpc));
45 	GUEST_SYNC(0);
46 }
47 
48 static void test_one_reg(uint64_t id, uint64_t value)
49 {
50 	struct kvm_one_reg reg;
51 	uint64_t eval_reg;
52 
53 	reg.addr = (uintptr_t)&eval_reg;
54 	reg.id = id;
55 	vcpu_get_reg(vm, VCPU_ID, &reg);
56 	TEST_ASSERT(eval_reg == value, "value == %s", value);
57 }
58 
59 static void assert_noirq(void)
60 {
61 	struct kvm_s390_irq_state irq_state;
62 	int irqs;
63 
64 	irq_state.len = sizeof(buf);
65 	irq_state.buf = (unsigned long)buf;
66 	irqs = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state);
67 	/*
68 	 * irqs contains the number of retrieved interrupts. Any interrupt
69 	 * (notably, the emergency call interrupt we have injected) should
70 	 * be cleared by the resets, so this should be 0.
71 	 */
72 	TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d\n", errno);
73 	TEST_ASSERT(!irqs, "IRQ pending");
74 }
75 
76 static void assert_clear(void)
77 {
78 	struct kvm_sregs sregs;
79 	struct kvm_regs regs;
80 	struct kvm_fpu fpu;
81 
82 	vcpu_regs_get(vm, VCPU_ID, &regs);
83 	TEST_ASSERT(!memcmp(&regs.gprs, regs_null, sizeof(regs.gprs)), "grs == 0");
84 
85 	vcpu_sregs_get(vm, VCPU_ID, &sregs);
86 	TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0");
87 
88 	vcpu_fpu_get(vm, VCPU_ID, &fpu);
89 	TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0");
90 }
91 
92 static void assert_initial(void)
93 {
94 	struct kvm_sregs sregs;
95 	struct kvm_fpu fpu;
96 
97 	vcpu_sregs_get(vm, VCPU_ID, &sregs);
98 	TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0");
99 	TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, "cr14 == 0xC2000000");
100 	TEST_ASSERT(!memcmp(&sregs.crs[1], regs_null, sizeof(sregs.crs[1]) * 12),
101 		    "cr1-13 == 0");
102 	TEST_ASSERT(sregs.crs[15] == 0, "cr15 == 0");
103 
104 	vcpu_fpu_get(vm, VCPU_ID, &fpu);
105 	TEST_ASSERT(!fpu.fpc, "fpc == 0");
106 
107 	test_one_reg(KVM_REG_S390_GBEA, 1);
108 	test_one_reg(KVM_REG_S390_PP, 0);
109 	test_one_reg(KVM_REG_S390_TODPR, 0);
110 	test_one_reg(KVM_REG_S390_CPU_TIMER, 0);
111 	test_one_reg(KVM_REG_S390_CLOCK_COMP, 0);
112 }
113 
114 static void assert_normal(void)
115 {
116 	test_one_reg(KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID);
117 	assert_noirq();
118 }
119 
120 static void inject_irq(int cpu_id)
121 {
122 	struct kvm_s390_irq_state irq_state;
123 	struct kvm_s390_irq *irq = &buf[0];
124 	int irqs;
125 
126 	/* Inject IRQ */
127 	irq_state.len = sizeof(struct kvm_s390_irq);
128 	irq_state.buf = (unsigned long)buf;
129 	irq->type = KVM_S390_INT_EMERGENCY;
130 	irq->u.emerg.code = cpu_id;
131 	irqs = _vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state);
132 	TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno);
133 }
134 
135 static void test_normal(void)
136 {
137 	printf("Testing normal reset\n");
138 	/* Create VM */
139 	vm = vm_create_default(VCPU_ID, 0, guest_code_initial);
140 	run = vcpu_state(vm, VCPU_ID);
141 	regs = &run->s.regs;
142 
143 	vcpu_run(vm, VCPU_ID);
144 
145 	inject_irq(VCPU_ID);
146 
147 	vcpu_ioctl(vm, VCPU_ID, KVM_S390_NORMAL_RESET, 0);
148 	assert_normal();
149 	kvm_vm_free(vm);
150 }
151 
152 static void test_initial(void)
153 {
154 	printf("Testing initial reset\n");
155 	vm = vm_create_default(VCPU_ID, 0, guest_code_initial);
156 	run = vcpu_state(vm, VCPU_ID);
157 	regs = &run->s.regs;
158 
159 	vcpu_run(vm, VCPU_ID);
160 
161 	inject_irq(VCPU_ID);
162 
163 	vcpu_ioctl(vm, VCPU_ID, KVM_S390_INITIAL_RESET, 0);
164 	assert_normal();
165 	assert_initial();
166 	kvm_vm_free(vm);
167 }
168 
169 static void test_clear(void)
170 {
171 	printf("Testing clear reset\n");
172 	vm = vm_create_default(VCPU_ID, 0, guest_code_initial);
173 	run = vcpu_state(vm, VCPU_ID);
174 	regs = &run->s.regs;
175 
176 	vcpu_run(vm, VCPU_ID);
177 
178 	inject_irq(VCPU_ID);
179 
180 	vcpu_ioctl(vm, VCPU_ID, KVM_S390_CLEAR_RESET, 0);
181 	assert_normal();
182 	assert_initial();
183 	assert_clear();
184 	kvm_vm_free(vm);
185 }
186 
187 int main(int argc, char *argv[])
188 {
189 	setbuf(stdout, NULL);	/* Tell stdout not to buffer its content */
190 
191 	test_initial();
192 	if (kvm_check_cap(KVM_CAP_S390_VCPU_RESETS)) {
193 		test_normal();
194 		test_clear();
195 	}
196 	return 0;
197 }
198