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