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