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