xref: /kvm-unit-tests/s390x/emulator.c (revision fdab948bc134fb9989a8265380a55e809879418e)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Emulator tests - for s390x CPU instructions that are usually interpreted
4  *                  by the hardware
5  *
6  * Copyright (c) 2017 Red Hat Inc
7  *
8  * Authors:
9  *  David Hildenbrand <david@redhat.com>
10  */
11 #include <libcflat.h>
12 #include <asm/cpacf.h>
13 #include <asm/interrupt.h>
14 #include <asm/float.h>
15 #include <linux/compiler.h>
16 
17 struct lowcore *lc = NULL;
18 
19 static inline void __test_spm_ipm(uint8_t cc, uint8_t key)
20 {
21 	uint64_t in = (cc << 28) | (key << 24);
22 	uint64_t out = ~0ULL;
23 
24 	report_prefix_pushf("cc=%d,key=%x", cc, key);
25 
26 	asm volatile ("spm %1\n"
27 		      "ipm %0\n"
28 		      : "+r"(out) : "r"(in) : "cc");
29 
30 	report(!(out & 0xc0000000UL), "bit 32 and 33 set to zero");
31 	report((out & ~0xff000000ULL) == ~0xff000000ULL,
32 	       "bit 0-31, 40-63 unchanged");
33 	report(!((in ^ out) & 0x3f000000UL), "cc and key applied");
34 
35 	report_prefix_pop();
36 }
37 
38 /* Test the SET PROGRAM PARAMETER and INSERT PROGRAM PARAMETER instruction */
39 static void test_spm_ipm(void)
40 {
41 	__test_spm_ipm(0, 0xf);
42 	__test_spm_ipm(1, 0x9);
43 	__test_spm_ipm(2, 0x5);
44 	__test_spm_ipm(3, 0x3);
45 	__test_spm_ipm(0, 0);
46 }
47 
48 static __always_inline void __test_cpacf(unsigned int opcode, unsigned long func,
49 				unsigned int r1, unsigned int r2,
50 				unsigned int r3)
51 {
52 	register unsigned long gr0 asm("0") = func;
53 	cpacf_mask_t mask;
54 	register unsigned long gr1 asm("1") = (unsigned long)&mask;
55 
56 	asm volatile(".insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],0\n"
57 		     : : "d" (gr0), "d" (gr1), [opc] "i" (opcode),
58 		         [r1] "i" (r1), [r2] "i" (r2), [r3] "i" (r3));
59 }
60 
61 static __always_inline void __test_cpacf_r1_odd(unsigned int opcode)
62 {
63 	report_prefix_push("r1 odd");
64 	expect_pgm_int();
65 	__test_cpacf(opcode, 0, 1, 4, 6);
66 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
67 	report_prefix_pop();
68 }
69 
70 static __always_inline void __test_cpacf_r1_null(unsigned int opcode)
71 {
72 	report_prefix_push("r1 null");
73 	expect_pgm_int();
74 	__test_cpacf(opcode, 0, 0, 4, 6);
75 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
76 	report_prefix_pop();
77 }
78 
79 static __always_inline void __test_cpacf_r2_odd(unsigned int opcode)
80 {
81 	report_prefix_push("r2 odd");
82 	expect_pgm_int();
83 	__test_cpacf(opcode, 0, 2, 3, 6);
84 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
85 	report_prefix_pop();
86 }
87 
88 static __always_inline void __test_cpacf_r2_null(unsigned int opcode)
89 {
90 	report_prefix_push("r2 null");
91 	expect_pgm_int();
92 	__test_cpacf(opcode, 0, 2, 0, 6);
93 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
94 	report_prefix_pop();
95 }
96 
97 static __always_inline void __test_cpacf_r3_odd(unsigned int opcode)
98 {
99 	report_prefix_push("r3 odd");
100 	expect_pgm_int();
101 	__test_cpacf(opcode, 0, 2, 4, 5);
102 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
103 	report_prefix_pop();
104 }
105 
106 static __always_inline void __test_cpacf_r3_null(unsigned int opcode)
107 {
108 	report_prefix_push("r3 null");
109 	expect_pgm_int();
110 	__test_cpacf(opcode, 0, 2, 4, 0);
111 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
112 	report_prefix_pop();
113 }
114 
115 static __always_inline void __test_cpacf_mod_bit(unsigned int opcode)
116 {
117 	report_prefix_push("mod bit");
118 	expect_pgm_int();
119 	__test_cpacf(opcode, CPACF_DECRYPT, 2, 4, 6);
120 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
121 	report_prefix_pop();
122 }
123 
124 static __always_inline void __test_cpacf_invalid_func(unsigned int opcode)
125 {
126 	report_prefix_push("invalid subfunction");
127 	expect_pgm_int();
128 	/* 127 is unassigned for now. We don't simply use any, as HW
129 	 * might simply mask valid codes in query but they might still work */
130 	if (cpacf_query_func(opcode, 127)) {
131 		report_skip("127 not invalid");
132 	} else {
133 		__test_cpacf(opcode, 127, 2, 4, 6);
134 	}
135 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
136 	report_prefix_pop();
137 }
138 
139 static __always_inline void __test_cpacf_invalid_parm(unsigned int opcode)
140 {
141 	report_prefix_push("invalid parm address");
142 	expect_pgm_int();
143 	__cpacf_query(opcode, (void *) -1);
144 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
145 	report_prefix_pop();
146 }
147 
148 static __always_inline void __test_cpacf_protected_parm(unsigned int opcode)
149 {
150 	report_prefix_push("protected parm address");
151 	expect_pgm_int();
152 	low_prot_enable();
153 	__cpacf_query(opcode, (void *) 8);
154 	low_prot_disable();
155 	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
156 	report_prefix_pop();
157 }
158 
159 static __always_inline void __test_basic_cpacf_opcode(unsigned int opcode)
160 {
161 	bool mod_bit_allowed = false;
162 
163 	if (!__cpacf_check_opcode(opcode)) {
164 		report_skip("not available");
165 		return;
166 	}
167 	report(cpacf_query_func(opcode, 0), "query indicated in query");
168 
169 	switch (opcode) {
170 	case CPACF_KMCTR:
171 		__test_cpacf_r3_odd(opcode);
172 		__test_cpacf_r3_null(opcode);
173 		/* FALL THROUGH */
174 	case CPACF_PRNO:
175 	case CPACF_KMF:
176 	case CPACF_KMC:
177 	case CPACF_KMO:
178 	case CPACF_KM:
179 		__test_cpacf_r1_odd(opcode);
180 		__test_cpacf_r1_null(opcode);
181 		mod_bit_allowed = true;
182 		/* FALL THROUGH */
183 	case CPACF_KMAC:
184 	case CPACF_KIMD:
185 	case CPACF_KLMD:
186 		__test_cpacf_r2_odd(opcode);
187 		__test_cpacf_r2_null(opcode);
188 	        break;
189 	}
190 	if (!mod_bit_allowed)
191 		__test_cpacf_mod_bit(opcode);
192 	__test_cpacf_invalid_func(opcode);
193 	__test_cpacf_invalid_parm(opcode);
194 	__test_cpacf_protected_parm(opcode);
195 }
196 
197 /* COMPUTE MESSAGE AUTHENTICATION CODE */
198 static void test_kmac(void)
199 {
200 	__test_basic_cpacf_opcode(CPACF_KMAC);
201 }
202 
203 /* CIPHER MESSAGE */
204 static void test_km(void)
205 {
206 	__test_basic_cpacf_opcode(CPACF_KM);
207 }
208 /* CIPHER MESSAGE WITH CHAINING */
209 static void test_kmc(void)
210 {
211 	__test_basic_cpacf_opcode(CPACF_KMC);
212 }
213 
214 /* COMPUTE INTERMEDIATE MESSAGE DIGEST */
215 static void test_kimd(void)
216 {
217 	__test_basic_cpacf_opcode(CPACF_KIMD);
218 }
219 
220 /* COMPUTE LAST MESSAGE DIGEST */
221 static void test_klmd(void)
222 {
223 	__test_basic_cpacf_opcode(CPACF_KLMD);
224 }
225 
226 /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */
227 static void test_pckmo(void)
228 {
229 	__test_basic_cpacf_opcode(CPACF_PCKMO);
230 }
231 
232 /* CIPHER MESSAGE WITH CIPHER FEEDBACK */
233 static void test_kmf(void)
234 {
235 	__test_basic_cpacf_opcode(CPACF_KMF);
236 }
237 
238 /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */
239 static void test_kmo(void)
240 {
241 	__test_basic_cpacf_opcode(CPACF_KMO);
242 }
243 
244 /* PERFORM CRYPTOGRAPHIC COMPUTATION */
245 static void test_pcc(void)
246 {
247 	__test_basic_cpacf_opcode(CPACF_PCC);
248 }
249 
250 /* CIPHER MESSAGE WITH COUNTER */
251 static void test_kmctr(void)
252 {
253 	__test_basic_cpacf_opcode(CPACF_KMCTR);
254 }
255 
256 /* PERFORM RANDOM NUMBER OPERATION (formerly PPNO) */
257 static void test_prno(void)
258 {
259 	__test_basic_cpacf_opcode(CPACF_PRNO);
260 }
261 
262 static void test_dxc(void)
263 {
264 	/* DXC (0xff) is to be stored in LC and FPC on a trap (CRT) with AFP */
265 	lc->dxc_vxc = 0x12345678;
266 	set_fpc_dxc(0);
267 
268 	report_prefix_push("afp");
269 	expect_pgm_int();
270 	asm volatile("	.insn	rrf,0xb9600000,%0,%0,8,0\n"
271 		     : : "r"(0) : "memory");
272 	check_pgm_int_code(PGM_INT_CODE_DATA);
273 
274 	report(lc->dxc_vxc == 0xff, "dxc in LC");
275 	report(get_fpc_dxc() == 0xff, "dxc in FPC");
276 	report_prefix_pop();
277 
278 	/* DXC (0xff) is to be stored in LC only on a trap (CRT) without AFP */
279 	lc->dxc_vxc = 0x12345678;
280 	set_fpc_dxc(0);
281 
282 	report_prefix_push("no-afp");
283 	expect_pgm_int();
284 	/* temporarily disable AFP */
285 	afp_disable();
286 	asm volatile("	.insn	rrf,0xb9600000,%0,%0,8,0\n"
287 		     : : "r"(0) : "memory");
288 	afp_enable();
289 	check_pgm_int_code(PGM_INT_CODE_DATA);
290 
291 	report(lc->dxc_vxc == 0xff, "dxc in LC");
292 	report(get_fpc_dxc() == 0, "dxc not in FPC");
293 	report_prefix_pop();
294 }
295 
296 static struct {
297 	const char *name;
298 	void (*func)(void);
299 } tests[] = {
300 	{ "spm/ipm", test_spm_ipm },
301 	{ "kmac", test_kmac },
302 	{ "km", test_km },
303 	{ "kmc", test_kmc },
304 	{ "kimd", test_kimd },
305 	{ "klmd", test_klmd },
306 	{ "pckmo", test_pckmo },
307 	{ "kmf", test_kmf },
308 	{ "kmo", test_kmo },
309 	{ "pcc", test_pcc },
310 	{ "kmctr", test_kmctr },
311 	{ "prno", test_prno },
312 	{ "dxc", test_dxc },
313 	{ NULL, NULL }
314 };
315 
316 int main(int argc, char**argv)
317 {
318 	int i;
319 
320 	report_prefix_push("emulator");
321 	for (i = 0; tests[i].name; i++) {
322 		report_prefix_push(tests[i].name);
323 		tests[i].func();
324 		report_prefix_pop();
325 	}
326 	report_prefix_pop();
327 
328 	return report_summary();
329 }
330