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