Command line help - demangling isn't just for C++
[valgrind.git] / coregrind / m_extension / extension-s390x.c
blob34e2e0409d8090a2a6d3af0ff603e17f2d78dd5c
2 /*--------------------------------------------------------------------*/
3 /*--- Handle s390x-specific extensions. extension-s390x.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) IBM Corp. 2024
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, see <http://www.gnu.org/licenses/>.
25 The GNU General Public License is contained in the file COPYING.
28 /* Contributed by Andreas Arnez */
30 #if defined(VGP_s390x_linux)
32 #include "libvex_s390x_common.h"
33 #include "priv_extension.h"
34 #include "priv_types_n_macros.h"
35 #include "pub_core_libcassert.h"
36 #include "pub_core_threadstate.h"
38 #undef SYSNO
40 #define READ_FUNCTION_CODE(tst, extname) \
41 ({ \
42 PRE_REG_READ(tst, extname "(func_code)", r0, 7, sizeof(UChar)); \
43 tst->arch.vex.guest_r0 & 0xff; \
46 #define READ_GPR(tst, name, regno) \
47 ({ \
48 PRE_REG_READ(tst, name, r0, sizeof(ULong) * (regno), sizeof(ULong)); \
49 *((&tst->arch.vex.guest_r0) + (regno)); \
52 #define WRITE_GPR(tst, regno, value) \
53 ({ \
54 *((&tst->arch.vex.guest_r0) + (regno)) = value; \
55 POST_REG_WRITE(tst, r0, sizeof(ULong) * (regno), sizeof(ULong)); \
58 #define S390_CC_OP_SET 35
60 #define WRITE_CC(tst, value) \
61 ({ \
62 tst->arch.vex.guest_CC_OP = S390_CC_OP_SET; \
63 tst->arch.vex.guest_CC_DEP1 = value; \
64 tst->arch.vex.guest_CC_DEP2 = 0; \
65 tst->arch.vex.guest_CC_NDEP = 0; \
66 POST_REG_WRITE(tst, CC_OP, 0, sizeof(ULong) * 4); \
69 #define INSN_ERR(msg) \
70 ({ \
71 VG_(umsg)("Illegal operation: %s", msg); \
72 ExtErr_Illop; \
75 union reg_pair {
76 struct {
77 ULong a, b;
79 unsigned __int128 pair;
82 /* To avoid code duplication, provide macros for generating inline assembly
83 functions where applicable. */
85 #define S390_DEFINE_DO_RRR_INSN(fname, opc) \
86 static Int fname(ULong func, ULong parms, ULong* addr1, ULong* addr2, \
87 ULong* len2, ULong* addr3, ULong* len3) \
88 { \
89 union reg_pair op1 = {{*addr1, 0}}; \
90 union reg_pair op2 = {{*addr2, *len2}}; \
91 union reg_pair op3 = {{*addr3, *len3}}; \
92 register ULong reg0 asm("0") = func; \
93 register void* reg1 asm("1") = (void*)parms; \
94 UInt cc; \
96 asm volatile(".insn rrf, " #opc "0000, %[op1], %[op2], %[op3], 0\n" \
97 "ipm %[cc]\n" \
98 : [cc] "=d"(cc), [op1] "+a"(op1.pair), \
99 [op2] "+a"(op2.pair), [op3] "+a"(op3.pair) \
100 : "d"(reg0), "d"(reg1) \
101 : "cc", "memory"); \
102 *addr1 = op1.a; \
103 *addr2 = op2.a; \
104 *len2 = op2.b; \
105 *addr3 = op3.a; \
106 *len3 = op3.b; \
107 return cc >> 28; \
110 #define S390_DEFINE_DO_RR_INSN(fname, opc) \
111 static Int fname(ULong func, ULong parms, ULong* addr1, ULong* len1, \
112 ULong* addr2, ULong* len2) \
114 union reg_pair op1 = {{*addr1, *len1}}; \
115 union reg_pair op2 = {{*addr2, *len2}}; \
116 register ULong reg0 asm("0") = func; \
117 register void* reg1 asm("1") = (void*)parms; \
118 UInt cc; \
120 asm volatile(".insn rre, " #opc "0000, %[op1], %[op2]\n" \
121 "ipm %[cc]\n" \
122 : [cc] "=d"(cc), [op1] "+a"(op1.pair), [op2] "+a"(op2.pair) \
123 : "d"(reg0), "d"(reg1) \
124 : "cc", "memory"); \
125 *addr1 = op1.a; \
126 *len1 = op1.b; \
127 *addr2 = op2.a; \
128 *len2 = op2.b; \
129 return cc >> 28; \
132 #define S390_DEFINE_DO_0R_INSN(fname, opc) \
133 static Int fname(ULong func, ULong parms, ULong* addr2, ULong* len2) \
135 union reg_pair op2 = {{*addr2, *len2}}; \
136 register ULong reg0 asm("0") = func; \
137 register void* reg1 asm("1") = (void*)parms; \
138 UInt cc; \
140 asm volatile(".insn rre, " #opc "0000, 0, %[op2]\n" \
141 "ipm %[cc]\n" \
142 : [cc] "=d"(cc), [op2] "+a"(op2.pair) \
143 : "d"(reg0), "d"(reg1) \
144 : "cc", "memory"); \
145 *addr2 = op2.a; \
146 *len2 = op2.b; \
147 return cc >> 28; \
150 #define S390_DEFINE_DO_00_INSN(fname, opc) \
151 static Int fname(ULong func, ULong parms) \
153 register ULong reg0 asm("0") = func; \
154 register void* reg1 asm("1") = (void*)parms; \
155 UInt cc; \
157 asm volatile(".insn rre, " #opc "0000, 0, 0\n" \
158 "ipm %[cc]\n" \
159 : [cc] "=d"(cc) \
160 : "d"(reg0), "d"(reg1) \
161 : "cc", "memory"); \
162 return cc >> 28; \
165 #define S390_SETBIT(x) (1UL << (63 - (x % 64)))
166 #define S390_SETBITS(lo, hi) (((1UL << (hi + 1 - lo)) - 1) << (63 - (hi % 64)))
168 /* Helper routine for query functions: Filter the bit vector `fc' using a given
169 `filter' vector */
170 static void s390_filter_functions(ULong* fc,
171 ULong fc_len,
172 const ULong* filter,
173 ULong filter_len)
175 ULong n_fc = fc_len / sizeof(ULong);
176 ULong n_filter = filter_len / sizeof(ULong);
178 for (ULong i = 0; i < n_fc; i++) {
179 if (i < n_filter)
180 fc[i] &= filter[i];
181 else
182 fc[i] = 0;
186 /*---------------------------------------------------------------*/
187 /*--- PRNO (perform random number operation) ---*/
188 /*---------------------------------------------------------------*/
190 S390_DEFINE_DO_RR_INSN(do_PRNO_insn, 0xb93c)
192 /* PRNO functions that we support if the hardware does. */
193 static const ULong PRNO_functions[] = {
194 (S390_SETBIT(0) // Query
195 | S390_SETBIT(3)), // SHA-512-DRNG
196 (S390_SETBIT(112) // TRNG-Query-Raw-to-Conditioned-Ratio
197 | S390_SETBIT(114)), // TRNG
200 static enum ExtensionError do_extension_PRNO(ThreadState* tst, ULong variant)
202 UChar r1 = variant & 0xf;
203 UChar r2 = (variant >> 4) & 0xf;
204 UChar func = READ_FUNCTION_CODE(tst, "PRNO");
205 UChar fc = func & 0x7f;
206 UChar mflag = func & 128;
207 ULong parms = READ_GPR(tst, "PRNO(r1)", 1);
208 ULong parms_len;
209 Int cc = 0;
210 ULong orig_addr1 = 0, orig_len1 = 0, orig_addr2 = 0, orig_len2 = 0;
211 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
213 switch (fc) {
214 case 0: // Query
215 parms_len = 16;
216 PRE_MEM_WRITE(tst, "PRNO(parms)", parms, parms_len);
217 cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
218 s390_filter_functions((ULong*)parms, parms_len, PRNO_functions,
219 sizeof(PRNO_functions));
220 POST_MEM_WRITE(tst, parms, parms_len);
221 break;
222 case 112: // TRNG-Query-Raw-to-Conditioned-Ratio
223 parms_len = 8;
224 PRE_MEM_WRITE(tst, "PRNO(parms)", parms, parms_len);
225 cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
226 POST_MEM_WRITE(tst, parms, parms_len);
227 break;
228 case 3: // SHA-512-DRNG
229 parms_len = 240;
230 PRE_MEM_READ(tst, "PRNO(parms)", parms, parms_len);
231 if (mflag == 0) {
232 // Generate operation
233 addr1 = orig_addr1 = READ_GPR(tst, "PRNO(op1_addr)", r1);
234 len1 = orig_len1 = READ_GPR(tst, "PRNO(op1_len)", r1 + 1);
235 PRE_MEM_WRITE(tst, "PRNO(op1)", addr1, len1);
236 } else {
237 // Seed operation
238 addr2 = READ_GPR(tst, "PRNO(op2_addr)", r2);
239 len2 = READ_GPR(tst, "PRNO(op2_len)", r2 + 1);
240 PRE_MEM_READ(tst, "PRNO(op2)", addr2, len2);
242 PRE_MEM_WRITE(tst, "PRNO(parms)", parms, parms_len);
243 cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
244 POST_MEM_WRITE(tst, parms, parms_len);
245 if (mflag == 0) {
246 WRITE_GPR(tst, r1 + 1, len1);
247 // The operand is filled from right to left
248 POST_MEM_WRITE(tst, orig_addr1 + len1, orig_len1 - len1);
250 break;
251 case 114: // TRNG
252 addr1 = orig_addr1 = READ_GPR(tst, "PRNO(op1_addr)", r1);
253 len1 = orig_len1 = READ_GPR(tst, "PRNO(op1_len)", r1 + 1);
254 PRE_MEM_WRITE(tst, "PRNO(op1)", addr1, len1);
255 addr2 = orig_addr2 = READ_GPR(tst, "PRNO(op2_addr)", r2);
256 len2 = orig_len2 = READ_GPR(tst, "PRNO(op2_len)", r2 + 1);
257 PRE_MEM_WRITE(tst, "PRNO(op2)", addr2, len2);
258 cc = do_PRNO_insn(func, parms, &addr1, &len1, &addr2, &len2);
259 WRITE_GPR(tst, r1, addr1);
260 WRITE_GPR(tst, r1 + 1, len1);
261 WRITE_GPR(tst, r2, addr2);
262 WRITE_GPR(tst, r2 + 1, len2);
263 POST_MEM_WRITE(tst, orig_addr1, orig_len1 - len1);
264 POST_MEM_WRITE(tst, orig_addr2, orig_len2 - len2);
265 break;
266 default:
267 return INSN_ERR("PRNO: unknown function code\n");
269 WRITE_CC(tst, cc);
270 return ExtErr_OK;
273 /*---------------------------------------------------------------*/
274 /*--- NNPA (neural network processing assist) ---*/
275 /*---------------------------------------------------------------*/
277 static Int do_NNPA_insn(ULong* gpr0, ULong parms)
279 register ULong reg0 asm("0") = *gpr0;
280 register void* reg1 asm("1") = (void*)parms;
281 Int cc;
283 asm volatile(".insn rre, 0xb93b0000, 0, 0\n"
284 "ipm %[cc]\n"
285 "srl %[cc], 28\n"
286 : [cc] "=d"(cc), "+d"(reg0)
287 : "d"(reg1)
288 : "cc", "memory");
289 *gpr0 = reg0;
290 return cc;
293 /* NNPA function codes */
294 typedef enum {
295 S390_NNPA_QAF = 0x00,
296 S390_NNPA_ADD = 0x10,
297 S390_NNPA_SUB = 0x11,
298 S390_NNPA_MUL = 0x12,
299 S390_NNPA_DIV = 0x13,
300 S390_NNPA_MIN = 0x14,
301 S390_NNPA_MAX = 0x15,
302 S390_NNPA_LOG = 0x20,
303 S390_NNPA_EXP = 0x21,
304 S390_NNPA_RELU = 0x31,
305 S390_NNPA_TANH = 0x32,
306 S390_NNPA_SIGMOID = 0x33,
307 S390_NNPA_SOFTMAX = 0x34,
308 S390_NNPA_BATCHNORM = 0x40,
309 S390_NNPA_MAXPOOL2D = 0x50,
310 S390_NNPA_AVGPOOL2D = 0x51,
311 S390_NNPA_LSTMACT = 0x60,
312 S390_NNPA_GRUACT = 0x61,
313 S390_NNPA_CONVOLUTION = 0x70,
314 S390_NNPA_MATMUL_OP = 0x71,
315 S390_NNPA_MATMUL_OP_BCAST23 = 0x72,
316 } s390_nnpa_function_t;
318 /* Suported NNPA functions */
319 static const ULong NNPA_functions[] = {
320 (S390_SETBIT(S390_NNPA_QAF) | S390_SETBIT(S390_NNPA_ADD) |
321 S390_SETBIT(S390_NNPA_SUB) | S390_SETBIT(S390_NNPA_MUL) |
322 S390_SETBIT(S390_NNPA_DIV) | S390_SETBIT(S390_NNPA_MIN) |
323 S390_SETBIT(S390_NNPA_MAX) | S390_SETBIT(S390_NNPA_LOG) |
324 S390_SETBIT(S390_NNPA_EXP) | S390_SETBIT(S390_NNPA_RELU) |
325 S390_SETBIT(S390_NNPA_TANH) | S390_SETBIT(S390_NNPA_SIGMOID) |
326 S390_SETBIT(S390_NNPA_SOFTMAX)),
327 (S390_SETBIT(S390_NNPA_BATCHNORM) | S390_SETBIT(S390_NNPA_MAXPOOL2D) |
328 S390_SETBIT(S390_NNPA_AVGPOOL2D) | S390_SETBIT(S390_NNPA_LSTMACT) |
329 S390_SETBIT(S390_NNPA_GRUACT) | S390_SETBIT(S390_NNPA_CONVOLUTION) |
330 S390_SETBIT(S390_NNPA_MATMUL_OP) |
331 S390_SETBIT(S390_NNPA_MATMUL_OP_BCAST23)),
334 /* Supported parameter block formats */
335 static const ULong NNPA_ipbf[] = {
336 (S390_SETBIT(0)),
339 /* Supported data types and data layout formats */
340 static const ULong NNPA_dtypes_layouts[] = {
341 /* Data types */
342 (S390_SETBIT(0) | // data type 1 (16 bit)
344 /* Data layout formats */
345 S390_SETBIT(32 + 0) | // 4D-feature tensor
346 S390_SETBIT(32 + 1) // 4D-kernel tensor
350 static const ULong NNPA_conversions[] = {
351 (S390_SETBIT(1) | // BFP tiny format
352 S390_SETBIT(2)), // BFP short format
355 struct s390_NNPA_parms_qaf {
356 ULong funcs[4];
357 ULong ipbf[2];
358 ULong dtypes_layouts;
359 UInt reserved1;
360 UInt mdis;
361 ULong mts;
362 ULong conversions;
363 ULong reserved2[22];
366 struct s390_NNPA_tensor0 {
367 UChar layout;
368 UChar dtype;
369 UShort reserved1;
370 UInt reserved2;
371 UInt dim4, dim3, dim2, dim1;
372 ULong address;
375 struct s390_NNPA_parms0 {
376 ULong pbvn : 16;
377 ULong mvn : 8;
378 ULong ribm : 24;
379 ULong reserved0 : 15;
380 ULong cf : 1;
381 ULong reserved1[6];
382 ULong save_area_address;
383 struct s390_NNPA_tensor0 out[2];
384 struct s390_NNPA_tensor0 reserved2[2];
385 struct s390_NNPA_tensor0 in[3];
386 ULong reserved3[12];
387 UInt param[5];
388 UInt reserved4;
389 ULong reserved5[13];
392 enum {
393 s390_NNPA_message_in = 0,
394 s390_NNPA_message_out = 3,
395 s390_NNPA_message_n = 5,
398 static const char* const s390_NNPA_errmsg_dtype[s390_NNPA_message_n] = {
399 "NNPA: unknown data type in input tensor 1",
400 "NNPA: unknown data type in input tensor 2",
401 "NNPA: unknown data type in input tensor 3",
402 "NNPA: unknown data type in output tensor 1",
403 "NNPA: unknown data type in output tensor 2",
406 static const char* const s390_NNPA_errmsg_layout[s390_NNPA_message_n] = {
407 "NNPA: unknown layout in input tensor 1",
408 "NNPA: unknown layout in input tensor 2",
409 "NNPA: unknown layout in input tensor 3",
410 "NNPA: unknown layout in output tensor 1",
411 "NNPA: unknown layout in output tensor 2",
414 static const char* const s390_NNPA_errmsg_access[s390_NNPA_message_n] = {
415 "NNPA(in_tensor_1)", "NNPA(in_tensor_2)", "NNPA(in_tensor_3)",
416 "NNPA(out_tensor_1)", "NNPA(out_tensor_2)",
419 struct s390_NNPA_mem_dimensions {
420 ULong dim[5]; // total dimensions
421 ULong used[5]; // used dimensions, without padding
422 ULong step[5];
425 /* Determine the 5 dimensions used to represent the tensor data in memory */
426 static enum ExtensionError
427 NNPA_tensor0_size(const struct s390_NNPA_tensor0* t,
428 UInt msg_idx,
429 struct s390_NNPA_mem_dimensions* out_md)
431 struct s390_NNPA_mem_dimensions md;
432 ULong elem_size;
434 if (t->dtype == 0)
435 elem_size = 2;
436 else
437 return INSN_ERR(s390_NNPA_errmsg_dtype[msg_idx]);
439 switch (t->layout) {
440 case 0: // 4D-feature tensor
441 md.dim[0] = md.used[0] = t->dim4;
442 md.dim[1] = md.used[1] = (t->dim1 + 63) / 64;
443 md.dim[2] = md.used[2] = t->dim3;
444 md.dim[3] = (t->dim2 + 31) / 32 * 32;
445 md.used[3] = t->dim2;
446 md.dim[4] = 64;
447 md.used[4] = t->dim1;
448 break;
449 case 1: // 4D-kernel tensor
450 md.dim[0] = md.used[0] = (t->dim1 + 63) / 64;
451 md.dim[1] = md.used[1] = t->dim4;
452 md.dim[2] = md.used[2] = t->dim3;
453 md.dim[3] = (t->dim2 + 31) / 32 * 32;
454 md.used[3] = t->dim2;
455 md.dim[4] = 64;
456 md.used[4] = t->dim1;
457 break;
458 default:
459 return INSN_ERR(s390_NNPA_errmsg_layout[msg_idx]);
461 md.step[4] = elem_size * md.dim[4];
462 md.step[3] = md.step[4] * md.dim[3];
463 md.step[2] = md.step[3] * md.dim[2];
464 md.step[1] = md.step[2] * md.dim[1];
465 md.step[0] = md.step[1] * md.dim[0]; // total size
466 *out_md = md;
467 return ExtErr_OK;
470 static enum ExtensionError NNPA_pre_read_tensor0(
471 ThreadState* tst, UInt msg_idx, const struct s390_NNPA_tensor0* t)
473 struct s390_NNPA_mem_dimensions md;
474 enum ExtensionError ret;
476 ret = NNPA_tensor0_size(t, msg_idx, &md);
477 if (ret != ExtErr_OK)
478 return ret;
480 for (ULong d0 = 0; d0 < md.used[0]; d0++) {
481 for (ULong d1 = 0; d1 < md.used[1]; d1++) {
482 for (ULong d2 = 0; d2 < md.used[2]; d2++) {
483 for (ULong d3 = 0; d3 < md.used[3]; d3++) {
484 ULong addr = t->address + d0 * md.step[1] + d1 * md.step[2] +
485 d2 * md.step[3] + d3 * md.step[4];
486 PRE_MEM_READ(tst, s390_NNPA_errmsg_access[msg_idx], addr,
487 md.dim[4]);
492 return ExtErr_OK;
495 static UWord NNPA_pre_write_tensor0(ThreadState* tst,
496 UInt msg_idx,
497 const struct s390_NNPA_tensor0* t)
499 struct s390_NNPA_mem_dimensions md;
500 enum ExtensionError ret;
502 ret = NNPA_tensor0_size(t, msg_idx, &md);
503 if (ret != ExtErr_OK)
504 return ret;
506 PRE_MEM_WRITE(tst, "NNPA(out_tensor)", t->address, md.step[0]);
507 return ExtErr_OK;
510 static void NNPA_post_write_tensor0(ThreadState* tst,
511 UInt msg_idx,
512 const struct s390_NNPA_tensor0* t)
514 struct s390_NNPA_mem_dimensions md;
515 enum ExtensionError ret;
517 ret = NNPA_tensor0_size(t, msg_idx, &md);
518 if (ret != ExtErr_OK)
519 return;
521 for (ULong d0 = 0; d0 < md.used[0]; d0++) {
522 for (ULong d1 = 0; d1 < md.used[1]; d1++) {
523 for (ULong d2 = 0; d2 < md.used[2]; d2++) {
524 for (ULong d3 = 0; d3 < md.used[3]; d3++) {
525 ULong addr = t->address + d0 * md.step[1] + d1 * md.step[2] +
526 d2 * md.step[3] + d3 * md.step[4];
527 POST_MEM_WRITE(tst, addr, md.dim[4]);
534 static enum ExtensionError do_extension_NNPA(ThreadState* tst, ULong variant)
536 ULong gpr0 = READ_GPR(tst, "NNPA(r0)", 0);
537 UChar fc = gpr0 & 0x7f;
538 ULong parms_addr = READ_GPR(tst, "NNPA(r1)", 1);
539 Int cc = 0;
540 ULong parms_len;
542 if (fc == S390_NNPA_QAF) { // Query
543 struct s390_NNPA_parms_qaf* parms = (void*)parms_addr;
545 parms_len = sizeof(struct s390_NNPA_parms_qaf);
546 PRE_MEM_WRITE(tst, "NNPA(parms)", parms_addr, parms_len);
547 cc = do_NNPA_insn(&gpr0, parms_addr);
548 s390_filter_functions(parms->funcs, sizeof(parms->funcs), NNPA_functions,
549 sizeof(NNPA_functions));
550 s390_filter_functions(parms->ipbf, sizeof(parms->ipbf), NNPA_ipbf,
551 sizeof(NNPA_ipbf));
552 s390_filter_functions(&parms->dtypes_layouts, sizeof(ULong),
553 NNPA_dtypes_layouts, sizeof(NNPA_dtypes_layouts));
554 s390_filter_functions(&parms->conversions, sizeof(ULong),
555 NNPA_conversions, sizeof(NNPA_conversions));
556 } else {
557 struct s390_NNPA_parms0* parms = (void*)parms_addr;
558 const struct s390_NNPA_parms0 orig_parms = *parms;
559 ULong save_area_size = 0;
560 UInt in_tensors;
561 UInt out_tensors;
563 parms_len = 4096;
564 PRE_MEM_READ(tst, "NNPA(parms)", parms_addr,
565 sizeof(struct s390_NNPA_parms0));
566 if (parms->cf) {
567 PRE_MEM_READ(tst, "NNPA(parms.csb)", parms_addr + 512,
568 parms_len - 512);
570 PRE_MEM_WRITE(tst, "NNPA(parms)", parms_addr, parms_len);
572 switch (fc) {
573 case S390_NNPA_ADD:
574 case S390_NNPA_SUB:
575 case S390_NNPA_MUL:
576 case S390_NNPA_DIV:
577 case S390_NNPA_MIN:
578 case S390_NNPA_MAX:
579 in_tensors = 2;
580 out_tensors = 1;
581 break;
582 case S390_NNPA_LOG:
583 case S390_NNPA_EXP:
584 case S390_NNPA_RELU:
585 case S390_NNPA_TANH:
586 case S390_NNPA_SIGMOID:
587 in_tensors = 1;
588 out_tensors = 1;
589 break;
590 case S390_NNPA_SOFTMAX:
591 in_tensors = 1;
592 out_tensors = 1;
593 save_area_size = 8192;
594 break;
595 case S390_NNPA_BATCHNORM:
596 in_tensors = 3;
597 out_tensors = 1;
598 break;
599 case S390_NNPA_MAXPOOL2D:
600 case S390_NNPA_AVGPOOL2D:
601 in_tensors = 1;
602 out_tensors = 1;
603 break;
604 case S390_NNPA_LSTMACT:
605 in_tensors = 3;
606 out_tensors = 2;
607 break;
608 case S390_NNPA_GRUACT:
609 case S390_NNPA_CONVOLUTION:
610 case S390_NNPA_MATMUL_OP:
611 case S390_NNPA_MATMUL_OP_BCAST23:
612 in_tensors = 3;
613 out_tensors = 1;
614 break;
615 default:
616 return INSN_ERR("NNPA: unknown function code\n");
619 for (UInt i = 0; i < in_tensors; i++) {
620 enum ExtensionError retval =
621 NNPA_pre_read_tensor0(tst, s390_NNPA_message_in + i, &parms->in[i]);
622 if (retval != ExtErr_OK)
623 return retval;
625 for (UInt i = 0; i < out_tensors; i++) {
626 enum ExtensionError retval = NNPA_pre_write_tensor0(
627 tst, s390_NNPA_message_out + i, &parms->out[i]);
628 if (retval != ExtErr_OK)
629 return retval;
631 if (save_area_size != 0) {
632 PRE_MEM_WRITE(tst, "NNPA(save_area)", parms->save_area_address,
633 save_area_size);
635 cc = do_NNPA_insn(&gpr0, parms_addr);
636 if (cc == 0) {
637 for (UInt i = 0; i < out_tensors; i++) {
638 NNPA_post_write_tensor0(tst, s390_NNPA_message_out + i,
639 &orig_parms.out[i]);
643 POST_MEM_WRITE(tst, parms_addr, parms_len);
644 WRITE_GPR(tst, 0, gpr0);
645 WRITE_CC(tst, cc);
646 return ExtErr_OK;
649 /*---------------------------------------------------------------*/
650 /*--- DFLTCC (deflate conversion call) ---*/
651 /*---------------------------------------------------------------*/
653 static Int do_DFLTCC_insn(UChar func,
654 ULong parms,
655 ULong* addr1,
656 ULong* len1,
657 ULong* addr2,
658 ULong* len2,
659 ULong addr3)
661 register UChar reg0 asm("0") = func;
662 register void* reg1 asm("1") = (void*)parms;
663 union reg_pair op1 = {{*addr1, *len1}};
664 union reg_pair op2 = {{*addr2, *len2}};
665 Int cc;
667 asm volatile(".insn rrf, 0xb9390000, %[op1], %[op2], %[op3], 0\n"
668 "ipm %[cc]\n"
669 "srl %[cc], 28\n"
670 : [cc] "=d"(cc), [op1] "+a"(op1.pair), [op2] "+a"(op2.pair)
671 : "d"(reg0), "d"(reg1), [op3] "d"(addr3)
672 : "cc", "memory");
673 *addr1 = op1.a;
674 *len1 = op1.b;
675 *addr2 = op2.a;
676 *len2 = op2.b;
677 return cc;
680 struct s390_DFLTCC_parms0 {
681 UShort pbvn;
682 UChar mvn;
683 UChar ribm[3];
684 UShort reserved0 : 15;
685 UShort cf : 1;
686 ULong reserved1;
687 UShort nt : 1;
688 UShort reserved2 : 1;
689 UShort cvt : 1;
690 UShort reserved3 : 1;
691 UShort htt : 1;
692 UShort bcf : 1;
693 UShort bcc : 1;
694 UShort bhf : 1;
695 UShort reserved4 : 1;
696 UShort reserved5 : 1;
697 UShort dhtgc : 1;
698 UShort reserved6 : 5;
699 UChar reserved7 : 5;
700 UChar sbb : 3;
701 UChar oesc : 8;
702 UShort reserved8 : 12;
703 UShort ifs : 4;
704 UShort ifl;
705 UChar reserved9[20];
706 UShort hl;
707 UShort reserved10 : 1;
708 UShort ho : 15;
709 UChar data[1488];
712 /* DFLTCC functions that we support if the hardware does. */
713 static const ULong DFLTCC_functions[] = {
714 (S390_SETBIT(0) // Query
715 | S390_SETBIT(1) // GDHT
716 | S390_SETBIT(2) // CMPR
717 | S390_SETBIT(4)), // XPND
720 static UWord do_extension_DFLTCC(ThreadState* tst, ULong variant)
722 enum { circ_hist_len = 32768 };
723 UChar r1 = variant & 0xf;
724 UChar r2 = (variant >> 4) & 0xf;
725 UChar r3 = (variant >> 8) & 0xf;
726 UChar func = READ_FUNCTION_CODE(tst, "DFLTCC");
727 UChar fc = func & 0x7f;
728 Bool hbt = (func & 128) != 0;
729 ULong parms = READ_GPR(tst, "DFLTCC(r1)", 1);
730 ULong parms_len;
731 Int cc = 0;
732 ULong orig_addr1 = 0, orig_len1 = 0;
733 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0, addr3 = 0;
734 Bool do_compress = 0;
736 switch (fc) {
737 case 0: // Query
738 parms_len = 32;
739 PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
740 cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
741 s390_filter_functions((ULong*)parms, 16, DFLTCC_functions,
742 sizeof(DFLTCC_functions));
743 POST_MEM_WRITE(tst, parms, parms_len);
744 break;
745 case 1: // GDHT
746 parms_len = 384;
747 PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
748 PRE_MEM_WRITE(tst, "DFLTCC(parms)", parms, parms_len);
749 addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
750 len2 = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
751 if (len2 > 32768)
752 len2 = 32768;
753 PRE_MEM_READ(tst, "DFLTCC(parms)", addr2, len2);
754 cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
755 POST_MEM_WRITE(tst, parms, parms_len);
756 break;
757 case 2: // CMPR
758 do_compress = 1;
759 /* fallthrough */
760 case 4: // XPND
762 struct s390_DFLTCC_parms0* p;
763 parms_len = 1536;
764 PRE_MEM_READ(tst, "DFLTCC(parms)", parms, parms_len);
765 p = (void*)parms;
766 addr1 = orig_addr1 = READ_GPR(tst, "DFLTCC(op1_addr)", r1);
767 len1 = orig_len1 = READ_GPR(tst, "DFLTCC(op1_len)", r1 + 1);
768 PRE_MEM_WRITE(tst, "DFLTCC(op1)", addr1, len1);
769 addr2 = READ_GPR(tst, "DFLTCC(op2_addr)", r2);
770 len2 = READ_GPR(tst, "DFLTCC(op2_len)", r2 + 1);
771 PRE_MEM_READ(tst, "DFLTCC(op2)", addr2, len2);
772 addr3 = READ_GPR(tst, "DFLTCC(op3)", r3);
773 if (hbt) {
774 PRE_MEM_WRITE(tst, "DFLTCC(op3)", addr3, circ_hist_len);
776 if (!p->nt) {
777 if (hbt) {
778 ULong hl1 = circ_hist_len - p->ho;
779 if (hl1 >= p->hl) {
780 hl1 = p->hl;
781 } else {
782 PRE_MEM_READ(tst, "DFLTCC(op3)", addr3, p->hl - hl1);
784 PRE_MEM_READ(tst, "DFLTCC(op3)", addr3 + p->ho, hl1);
785 } else {
786 PRE_MEM_READ(tst, "DFLTCC(op2.hist)", addr2 - p->hl, p->hl);
789 cc = do_DFLTCC_insn(func, parms, &addr1, &len1, &addr2, &len2, addr3);
790 POST_MEM_WRITE(tst, parms, parms_len);
791 POST_MEM_WRITE(tst, orig_addr1,
792 orig_len1 - len1 + (do_compress && p->sbb ? 1 : 0));
793 if (hbt) {
794 ULong hl1 = circ_hist_len - p->ho;
795 if (hl1 >= p->hl) {
796 hl1 = p->hl;
797 } else {
798 POST_MEM_WRITE(tst, addr3, p->hl - hl1);
800 POST_MEM_WRITE(tst, addr3 + p->ho, hl1);
802 WRITE_GPR(tst, r1, addr1);
803 WRITE_GPR(tst, r1 + 1, len1);
804 WRITE_GPR(tst, r2, addr2);
805 WRITE_GPR(tst, r2 + 1, len2);
806 break;
808 default:
809 return INSN_ERR("DFLTCC: unknown function code\n");
811 WRITE_CC(tst, cc);
812 return ExtErr_OK;
815 /*---------------------------------------------------------------*/
816 /*--- STFLE (store facility list extended) ---*/
817 /*---------------------------------------------------------------*/
819 static enum ExtensionError do_extension_STFLE(ThreadState* tst, ULong variant)
821 Int cc = 0;
822 UChar b2 = variant & 0xf;
823 UShort d2 = (variant >> 8) & 0xfff;
824 ULong gpr0 = READ_GPR(tst, "STFLE(r0)", 0);
825 ULong last_dw = gpr0 & 0xff;
826 ULong addr = READ_GPR(tst, "STFLE(b2)", b2) + d2;
828 PRE_MEM_WRITE(tst, "STFLE(bits)", addr, (last_dw + 1) * sizeof(ULong));
829 static const ULong accepted_facility[] = {
830 /* === 0 .. 63 === */
831 (S390_SETBITS(0, 19)
832 /* 20: HFP-multiply-and-add/subtract, not supported */
833 | S390_SETBITS(21, 22)
834 /* 23: HFP-unnormalized-extension, not supported */
835 | S390_SETBITS(24, 25)
836 /* 26: parsing-enhancement, not supported */
837 | S390_SETBITS(27, 28)
838 /* 29: unassigned */
839 | S390_SETBITS(30, 30)
840 /* 31: extract-CPU-time, not supported */
841 | S390_SETBITS(32, 41)
842 /* 42-43: DFP, not fully supported */
843 /* 44: PFPO, not fully supported */
844 | S390_SETBITS(45, 47)
845 /* 48: DFP zoned-conversion, not supported */
846 /* 49: includes PPA, not supported */
847 /* 50: constrained transactional-execution, not supported */
848 | S390_SETBITS(51, 55)
849 /* 56: unassigned */
850 | S390_SETBITS(57, 63)),
852 /* === 64 .. 127 === */
853 (S390_SETBITS(64, 72)
854 /* 73: transactional-execution, not supported */
855 | S390_SETBITS(74, 78)
856 /* 80: DFP packed-conversion, not supported */
857 /* 81: PPA-in-order, not supported */
858 | S390_SETBITS(82, 82)
859 /* 83-127: unassigned */),
861 /* === 128 .. 191 === */
862 (S390_SETBITS(128, 131)
863 /* 132: unassigned */
864 /* 133: guarded-storage, not supported */
865 /* 134: vector packed decimal, not supported */
866 | S390_SETBITS(135, 135)
867 /* 136: unassigned */
868 /* 137: unassigned */
869 | S390_SETBITS(138, 142)
870 /* 143: unassigned */
871 | S390_SETBITS(144, 149)
872 /* 150: unassigned */
873 | S390_SETBITS(151, 151)
874 /* 152: vector packed decimal enhancement, not supported */
875 /* 153: unassigned */
876 /* 154: unassigned */
877 | S390_SETBITS(155, 156)
878 /* 157-164: unassigned */
879 | S390_SETBITS(165, 165)
880 /* 166-167: unassigned */
881 | S390_SETBITS(168, 168)
882 /* 168-191: unassigned */),
884 /* === 192 .. 255 === */
885 /* 192: vector-packed-decimal, not supported */
886 (S390_SETBITS(193, 194)
887 /* 195: unassigned */
888 | S390_SETBITS(196, 197)),
890 asm("lgr 0,%[r0]\n"
891 ".insn s,0xb2b00000,%[out]\n" /* stfle */
892 "lgr %[r0],0\n"
893 "ipm %[cc]\n"
894 "srl %[cc],28\n"
895 : [out] "=Q"(*(ULong(*)[last_dw + 1])(void*)addr), [r0] "+d"(gpr0),
896 [cc] "=d"(cc)
898 : "cc");
900 WRITE_GPR(tst, 0, gpr0);
901 if (last_dw > (gpr0 & 0xff))
902 last_dw = gpr0 & 0xff;
903 s390_filter_functions((ULong*)addr, (last_dw + 1) * sizeof(ULong),
904 accepted_facility, sizeof(accepted_facility));
905 POST_MEM_WRITE(tst, addr, (last_dw + 1) * sizeof(ULong));
907 WRITE_CC(tst, cc);
908 return ExtErr_OK;
911 /*---------------------------------------------------------------*/
912 /*--- KM (cypher message) ---*/
913 /*---------------------------------------------------------------*/
915 S390_DEFINE_DO_RR_INSN(do_KM_insn, 0xb92e)
917 /* List all the functions supported. This list provides the parameter block
918 sizes and will also be used for filtering the supported functions. The
919 function names are included for documentation purposes only. */
921 #define S390_DO_FUNCTIONS \
922 S390_DO_FUNC(0, S390_KM_Query, 16) \
923 S390_DO_FUNC(1, S390_KM_DEA, 8) \
924 S390_DO_FUNC(2, S390_KM_TDEA_128, 16) \
925 S390_DO_FUNC(3, S390_KM_TDEA_192, 24) \
926 S390_DO_FUNC(9, S390_KM_Encrypted_DEA, 32) \
927 S390_DO_FUNC(10, S390_KM_Encrypted_TDEA_128, 40) \
928 S390_DO_FUNC(11, S390_KM_Encrypted_TDEA_192, 48) \
929 S390_DO_FUNC(18, S390_KM_AES_128, 16) \
930 S390_DO_FUNC(19, S390_KM_AES_192, 24) \
931 S390_DO_FUNC(20, S390_KM_AES_256, 32) \
932 S390_DO_FUNC(26, S390_KM_Encrypted_AES_128, 48) \
933 S390_DO_FUNC(27, S390_KM_Encrypted_AES_192, 56) \
934 S390_DO_FUNC(28, S390_KM_Encrypted_AES_256, 64) \
935 S390_DO_FUNC(50, S390_KM_XTS_AES_128, 32) \
936 S390_DO_FUNC(52, S390_KM_XTS_AES_256, 48) \
937 S390_DO_FUNC(58, S390_KM_XTS_Encrypted_AES_128, 64) \
938 S390_DO_FUNC(60, S390_KM_XTS_Encrypted_AES_256, 80)
940 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
941 static const UChar S390_KM_parms_len[] = {S390_DO_FUNCTIONS};
942 #undef S390_DO_FUNC
944 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
945 static const ULong S390_KM_supported_fc[] = {0 S390_DO_FUNCTIONS};
946 #undef S390_DO_FUNC
948 #undef S390_DO_FUNCTIONS
950 static enum ExtensionError do_extension_KM(ThreadState* tst, ULong variant)
952 UChar r1 = variant & 0xf;
953 UChar r2 = (variant >> 4) & 0xf;
954 UChar func = READ_FUNCTION_CODE(tst, "KM");
955 UChar fc = func & 0x7f;
956 ULong parms = READ_GPR(tst, "KM(r1)", 1);
957 ULong parms_len = 0;
958 Int cc = 0;
959 ULong orig_addr1, orig_len2 = 0;
960 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
962 if (fc < sizeof(S390_KM_parms_len) / sizeof(S390_KM_parms_len[0]))
963 parms_len = S390_KM_parms_len[fc];
964 if (parms_len == 0)
965 return INSN_ERR("KM: unknown function code\n");
967 if (fc == 0) { // Query
968 PRE_MEM_WRITE(tst, "KM(parms)", parms, parms_len);
969 cc = do_KM_insn(func, parms, &addr1, &len1, &addr2, &len2);
970 s390_filter_functions((ULong*)parms, parms_len, S390_KM_supported_fc,
971 sizeof(S390_KM_supported_fc));
972 POST_MEM_WRITE(tst, parms, parms_len);
973 } else {
974 addr1 = orig_addr1 = READ_GPR(tst, "KM(op1_addr)", r1);
975 addr2 = READ_GPR(tst, "KM(op2_addr)", r2);
976 len2 = orig_len2 = READ_GPR(tst, "KM(op2_len)", r2 + 1);
977 PRE_MEM_READ(tst, "KM(parms)", parms, parms_len);
978 PRE_MEM_WRITE(tst, "KM(op1)", addr1, len2);
979 PRE_MEM_READ(tst, "KM(op2)", addr2, len2);
980 cc = do_KM_insn(func, parms, &addr1, &len1, &addr2, &len2);
981 WRITE_GPR(tst, r1, addr1);
982 WRITE_GPR(tst, r2, addr2);
983 WRITE_GPR(tst, r2 + 1, len2);
984 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
986 WRITE_CC(tst, cc);
987 return ExtErr_OK;
990 /*---------------------------------------------------------------*/
991 /*--- KMC (cypher message with chaining) ---*/
992 /*---------------------------------------------------------------*/
994 S390_DEFINE_DO_RR_INSN(do_KMC_insn, 0xb92f)
996 #define S390_DO_FUNCTIONS \
997 S390_DO_FUNC(0, S390_KMC_Query, 16) \
998 S390_DO_FUNC(1, S390_KMC_DEA, 16) \
999 S390_DO_FUNC(2, S390_KMC_TDEA_128, 24) \
1000 S390_DO_FUNC(3, S390_KMC_TDEA_192, 32) \
1001 S390_DO_FUNC(9, S390_KMC_Encrypted_DEA, 40) \
1002 S390_DO_FUNC(10, S390_KMC_Encrypted_TDEA_128, 48) \
1003 S390_DO_FUNC(11, S390_KMC_Encrypted_TDEA_192, 56) \
1004 S390_DO_FUNC(18, S390_KMC_AES_128, 32) \
1005 S390_DO_FUNC(19, S390_KMC_AES_192, 40) \
1006 S390_DO_FUNC(20, S390_KMC_AES_256, 48) \
1007 S390_DO_FUNC(26, S390_KMC_Encrypted_AES_128, 64) \
1008 S390_DO_FUNC(27, S390_KMC_Encrypted_AES_192, 72) \
1009 S390_DO_FUNC(28, S390_KMC_Encrypted_AES_256, 80)
1011 #define S390_DO_FUNCTIONS1 S390_DO_FUNC(67, S390_KMC_PRNG, 32)
1013 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1014 static const UChar S390_KMC_parms_len[] = {
1015 S390_DO_FUNCTIONS S390_DO_FUNCTIONS1};
1016 #undef S390_DO_FUNC
1018 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1019 static const ULong S390_KMC_supported_fc[] = {0 S390_DO_FUNCTIONS,
1020 0 S390_DO_FUNCTIONS1};
1021 #undef S390_DO_FUNC
1023 #undef S390_DO_FUNCTIONS
1024 #undef S390_DO_FUNCTIONS1
1026 static enum ExtensionError do_extension_KMC(ThreadState* tst, ULong variant)
1028 UChar r1 = variant & 0xf;
1029 UChar r2 = (variant >> 4) & 0xf;
1030 UChar func = READ_FUNCTION_CODE(tst, "KMC");
1031 UChar fc = func & 0x7f;
1032 ULong parms = READ_GPR(tst, "KMC(r1)", 1);
1033 ULong parms_len = 0;
1034 Int cc = 0;
1035 ULong orig_addr1, orig_len2 = 0;
1036 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
1038 if (fc < sizeof(S390_KMC_parms_len) / sizeof(S390_KMC_parms_len[0]))
1039 parms_len = S390_KMC_parms_len[fc];
1040 if (parms_len == 0)
1041 return INSN_ERR("KMC: unknown function code\n");
1043 PRE_MEM_WRITE(tst, "KMC(parms)", parms, parms_len);
1044 if (fc == 0) { // Query
1045 cc = do_KMC_insn(func, parms, &addr1, &len1, &addr2, &len2);
1046 s390_filter_functions((ULong*)parms, parms_len, S390_KMC_supported_fc,
1047 sizeof(S390_KMC_supported_fc));
1048 } else {
1049 addr1 = orig_addr1 = READ_GPR(tst, "KMC(op1_addr)", r1);
1050 addr2 = READ_GPR(tst, "KMC(op2_addr)", r2);
1051 len2 = orig_len2 = READ_GPR(tst, "KMC(op2_len)", r2 + 1);
1052 PRE_MEM_READ(tst, "KMC(parms)", parms, parms_len);
1053 PRE_MEM_WRITE(tst, "KMC(op1)", addr1, len2);
1054 PRE_MEM_READ(tst, "KMC(op2)", addr2, len2);
1055 cc = do_KMC_insn(func, parms, &addr1, &len1, &addr2, &len2);
1056 WRITE_GPR(tst, r1, addr1);
1057 WRITE_GPR(tst, r2, addr2);
1058 WRITE_GPR(tst, r2 + 1, len2);
1059 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
1061 POST_MEM_WRITE(tst, parms, parms_len);
1062 WRITE_CC(tst, cc);
1063 return ExtErr_OK;
1066 /*---------------------------------------------------------------*/
1067 /*--- KIMD (compute intermediate message digest) ---*/
1068 /*---------------------------------------------------------------*/
1070 S390_DEFINE_DO_0R_INSN(do_KIMD_insn, 0xb93e)
1072 #define S390_DO_FUNCTIONS \
1073 S390_DO_FUNC(0, S390_KIMD_Query, 16) \
1074 S390_DO_FUNC(1, S390_KIMD_SHA_1, 20) \
1075 S390_DO_FUNC(2, S390_KIMD_SHA_256, 32) \
1076 S390_DO_FUNC(3, S390_KIMD_SHA_512, 64) \
1077 S390_DO_FUNC(32, S390_KIMD_SHA3_224, 200) \
1078 S390_DO_FUNC(33, S390_KIMD_SHA3_256, 200) \
1079 S390_DO_FUNC(34, S390_KIMD_SHA3_384, 200) \
1080 S390_DO_FUNC(35, S390_KIMD_SHA3_512, 200) \
1081 S390_DO_FUNC(36, S390_KIMD_SHAKE_128, 200) \
1082 S390_DO_FUNC(37, S390_KIMD_SHAKE_256, 200) \
1083 S390_DO_FUNC(65, S390_KIMD_GHASH, 32)
1085 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1086 static const UChar S390_KIMD_parms_len[] = {S390_DO_FUNCTIONS};
1087 #undef S390_DO_FUNC
1089 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1090 static const ULong S390_KIMD_supported_fc[] = {0 S390_DO_FUNCTIONS};
1091 #undef S390_DO_FUNC
1093 #undef S390_DO_FUNCTIONS
1095 static enum ExtensionError do_extension_KIMD(ThreadState* tst, ULong variant)
1097 UChar r2 = (variant >> 4) & 0xf;
1098 UChar func = READ_FUNCTION_CODE(tst, "KIMD");
1099 UChar fc = func & 0x7f;
1100 ULong parms = READ_GPR(tst, "KIMD(r1)", 1);
1101 ULong parms_len = 0;
1102 Int cc = 0;
1103 ULong addr2 = 0, len2 = 0;
1105 if (fc < sizeof(S390_KIMD_parms_len) / sizeof(S390_KIMD_parms_len[0]))
1106 parms_len = S390_KIMD_parms_len[fc];
1107 if (parms_len == 0)
1108 return INSN_ERR("KIMD: unknown function code\n");
1110 if (fc == 0) { // Query
1111 PRE_MEM_WRITE(tst, "KIMD(parms)", parms, parms_len);
1112 cc = do_KIMD_insn(func, parms, &addr2, &len2);
1113 s390_filter_functions((ULong*)parms, parms_len, S390_KIMD_supported_fc,
1114 sizeof(S390_KIMD_supported_fc));
1115 POST_MEM_WRITE(tst, parms, parms_len);
1116 } else {
1117 addr2 = READ_GPR(tst, "KIMD(op2_addr)", r2);
1118 len2 = READ_GPR(tst, "KIMD(op2_len)", r2 + 1);
1119 PRE_MEM_READ(tst, "KIMD(parms)", parms, parms_len);
1120 PRE_MEM_WRITE(tst, "KIMD(parms)", parms, parms_len);
1121 PRE_MEM_READ(tst, "KIMD(op2)", addr2, len2);
1122 cc = do_KIMD_insn(func, parms, &addr2, &len2);
1123 WRITE_GPR(tst, r2, addr2);
1124 WRITE_GPR(tst, r2 + 1, len2);
1125 POST_MEM_WRITE(tst, parms, parms_len);
1127 WRITE_CC(tst, cc);
1128 return ExtErr_OK;
1131 /*---------------------------------------------------------------*/
1132 /*--- KLMD (compute last message digest) ---*/
1133 /*---------------------------------------------------------------*/
1135 S390_DEFINE_DO_RR_INSN(do_KLMD_insn, 0xb93f)
1137 #define S390_DO_FUNCTIONS \
1138 S390_DO_FUNC(0, S390_KLMD_Query, 16) \
1139 S390_DO_FUNC(1, S390_KLMD_SHA_1, 28) \
1140 S390_DO_FUNC(2, S390_KLMD_SHA_256, 40) \
1141 S390_DO_FUNC(3, S390_KLMD_SHA_512, 80) \
1142 S390_DO_FUNC(32, S390_KLMD_SHA3_224, 200) \
1143 S390_DO_FUNC(33, S390_KLMD_SHA3_256, 200) \
1144 S390_DO_FUNC(34, S390_KLMD_SHA3_384, 200) \
1145 S390_DO_FUNC(35, S390_KLMD_SHA3_512, 200) \
1146 S390_DO_FUNC(36, S390_KLMD_SHAKE_128, 200) \
1147 S390_DO_FUNC(37, S390_KLMD_SHAKE_256, 200)
1149 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1150 static const UChar S390_KLMD_parms_len[] = {S390_DO_FUNCTIONS};
1151 #undef S390_DO_FUNC
1153 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1154 static const ULong S390_KLMD_supported_fc[] = {0 S390_DO_FUNCTIONS};
1155 #undef S390_DO_FUNC
1157 #undef S390_DO_FUNCTIONS
1159 static enum ExtensionError do_extension_KLMD(ThreadState* tst, ULong variant)
1161 UChar r1 = variant & 0xf;
1162 UChar r2 = (variant >> 4) & 0xf;
1163 ULong func = READ_GPR(tst, "KLMD(r0)", 0);
1164 UChar fc = func & 0x7f;
1165 ULong parms = READ_GPR(tst, "KLMD(r1)", 1);
1166 ULong parms_len = 0;
1167 Int cc = 0;
1168 ULong orig_addr1 = 0, orig_len1 = 0;
1169 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
1171 if (fc < sizeof(S390_KLMD_parms_len) / sizeof(S390_KLMD_parms_len[0]))
1172 parms_len = S390_KLMD_parms_len[fc];
1173 if (parms_len == 0)
1174 return INSN_ERR("KLMD: unknown function code\n");
1175 PRE_MEM_WRITE(tst, "KLMD(parms)", parms, parms_len);
1177 if (fc == 0) { // Query
1178 cc = do_KLMD_insn(func, parms, &addr1, &len1, &addr2, &len2);
1179 s390_filter_functions((ULong*)parms, parms_len, S390_KLMD_supported_fc,
1180 sizeof(S390_KLMD_supported_fc));
1181 } else {
1182 /* The "shake" functions use the first operand */
1183 Bool have_op1 = fc >= 36 && fc <= 37;
1185 PRE_MEM_READ(tst, "KLMD(parms)", parms, parms_len);
1186 if (have_op1) {
1187 if (r1 == 0 || r1 % 2 != 0)
1188 return INSN_ERR("KLMD: bad r1 field");
1189 addr1 = orig_addr1 = READ_GPR(tst, "KLMD(op1_addr)", r1);
1190 len1 = orig_len1 = READ_GPR(tst, "KLMD(op1_len)", r1 + 1);
1191 PRE_MEM_WRITE(tst, "KLMD(op1)", addr1, len1);
1193 addr2 = READ_GPR(tst, "KLMD(op2_addr)", r2);
1194 len2 = READ_GPR(tst, "KLMD(op2_len)", r2 + 1);
1195 PRE_MEM_READ(tst, "KLMD(op2)", addr2, len2);
1196 cc = do_KLMD_insn(func, parms, &addr1, &len1, &addr2, &len2);
1197 if (have_op1) {
1198 WRITE_GPR(tst, r1, addr1);
1199 WRITE_GPR(tst, r1 + 1, len1);
1200 POST_MEM_WRITE(tst, orig_addr1, orig_len1 - len1);
1202 WRITE_GPR(tst, r2, addr2);
1203 WRITE_GPR(tst, r2 + 1, len2);
1205 POST_MEM_WRITE(tst, parms, parms_len);
1206 WRITE_CC(tst, cc);
1207 return ExtErr_OK;
1210 /*---------------------------------------------------------------*/
1211 /*--- KMAC (compute message authentication code) ---*/
1212 /*---------------------------------------------------------------*/
1214 S390_DEFINE_DO_0R_INSN(do_KMAC_insn, 0xb91e)
1216 #define S390_DO_FUNCTIONS \
1217 S390_DO_FUNC(0, S390_KMAC_Query, 16) \
1218 S390_DO_FUNC(1, S390_KMAC_DEA, 16) \
1219 S390_DO_FUNC(2, S390_KMAC_TDEA_128, 24) \
1220 S390_DO_FUNC(3, S390_KMAC_TDEA_192, 32) \
1221 S390_DO_FUNC(9, S390_KMAC_Encrypted_DEA, 40) \
1222 S390_DO_FUNC(10, S390_KMAC_Encrypted_TDEA_128, 48) \
1223 S390_DO_FUNC(11, S390_KMAC_Encrypted_TDEA_192, 56) \
1224 S390_DO_FUNC(18, S390_KMAC_AES_128, 32) \
1225 S390_DO_FUNC(19, S390_KMAC_AES_192, 40) \
1226 S390_DO_FUNC(20, S390_KMAC_AES_256, 48) \
1227 S390_DO_FUNC(26, S390_KMAC_Encrypted_AES_128, 64) \
1228 S390_DO_FUNC(27, S390_KMAC_Encrypted_AES_192, 72) \
1229 S390_DO_FUNC(28, S390_KMAC_Encrypted_AES_256, 80)
1231 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1232 static const UChar S390_KMAC_parms_len[] = {S390_DO_FUNCTIONS};
1233 #undef S390_DO_FUNC
1235 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1236 static const ULong S390_KMAC_supported_fc[] = {0 S390_DO_FUNCTIONS};
1237 #undef S390_DO_FUNC
1239 #undef S390_DO_FUNCTIONS
1241 static enum ExtensionError do_extension_KMAC(ThreadState* tst, ULong variant)
1243 UChar r2 = (variant >> 4) & 0xf;
1244 UChar func = READ_FUNCTION_CODE(tst, "KMAC");
1245 UChar fc = func & 0x7f;
1246 ULong parms = READ_GPR(tst, "KMAC(r1)", 1);
1247 ULong parms_len = 0;
1248 Int cc = 0;
1249 ULong addr2 = 0, len2 = 0;
1251 if (fc < sizeof(S390_KMAC_parms_len) / sizeof(S390_KMAC_parms_len[0]))
1252 parms_len = S390_KMAC_parms_len[fc];
1253 if (parms_len == 0)
1254 return INSN_ERR("KMAC: unknown function code\n");
1256 if (fc == 0) { // Query
1257 PRE_MEM_WRITE(tst, "KMAC(parms)", parms, parms_len);
1258 cc = do_KMAC_insn(func, parms, &addr2, &len2);
1259 s390_filter_functions((ULong*)parms, parms_len, S390_KMAC_supported_fc,
1260 sizeof(S390_KMAC_supported_fc));
1261 POST_MEM_WRITE(tst, parms, parms_len);
1262 } else {
1263 addr2 = READ_GPR(tst, "KMAC(op2_addr)", r2);
1264 len2 = READ_GPR(tst, "KMAC(op2_len)", r2 + 1);
1265 PRE_MEM_READ(tst, "KMAC(parms)", parms, parms_len);
1266 PRE_MEM_WRITE(tst, "KMAC(parms)", parms, parms_len);
1267 PRE_MEM_READ(tst, "KMAC(op2)", addr2, len2);
1268 cc = do_KMAC_insn(func, parms, &addr2, &len2);
1269 WRITE_GPR(tst, r2, addr2);
1270 WRITE_GPR(tst, r2 + 1, len2);
1271 if (cc != 1)
1272 POST_MEM_WRITE(tst, parms, parms_len);
1274 WRITE_CC(tst, cc);
1275 return ExtErr_OK;
1278 /*---------------------------------------------------------------*/
1279 /*--- PCC (perform cryptographic computation) ---*/
1280 /*---------------------------------------------------------------*/
1282 S390_DEFINE_DO_00_INSN(do_PCC_insn, 0xb92c)
1284 enum PCC_function_class {
1285 PCC_Unassigned = 0,
1286 PCC_Query,
1287 PCC_Compute_Last_Block_CMAC,
1288 PCC_Compute_XTS_Parameter,
1289 PCC_Scalar_Multiply,
1292 #define S390_DO_FUNCTIONS \
1293 S390_DO_FUNC(0, PCC_Query, Query, 16, 16) \
1294 S390_DO_FUNC(1, PCC_Compute_Last_Block_CMAC, Using_DEA, 8, 32) \
1295 S390_DO_FUNC(2, PCC_Compute_Last_Block_CMAC, Using_TDEA_128, 8, 40) \
1296 S390_DO_FUNC(3, PCC_Compute_Last_Block_CMAC, Using_TDEA_192, 8, 48) \
1297 S390_DO_FUNC(9, PCC_Compute_Last_Block_CMAC, Using_Encrypted_DEA, 8, 56) \
1298 S390_DO_FUNC(10, PCC_Compute_Last_Block_CMAC, Using_Encrypted_TDEA_128, 8, \
1299 64) \
1300 S390_DO_FUNC(11, PCC_Compute_Last_Block_CMAC, Using_Encrypted_TDEA_192, 8, \
1301 72) \
1302 S390_DO_FUNC(18, PCC_Compute_Last_Block_CMAC, Using_AES_128, 16, 56) \
1303 S390_DO_FUNC(19, PCC_Compute_Last_Block_CMAC, Using_AES_192, 16, 64) \
1304 S390_DO_FUNC(20, PCC_Compute_Last_Block_CMAC, Using_AES_256, 16, 72) \
1305 S390_DO_FUNC(26, PCC_Compute_Last_Block_CMAC, Using_Encrypted_AES_128, 16, \
1306 88) \
1307 S390_DO_FUNC(27, PCC_Compute_Last_Block_CMAC, Using_Encrypted_AES_192, 16, \
1308 96) \
1309 S390_DO_FUNC(28, PCC_Compute_Last_Block_CMAC, Using_Encrypted_AES_256, 16, \
1310 104) \
1311 S390_DO_FUNC(50, PCC_Compute_XTS_Parameter, Using_AES_128, 16, 80) \
1312 S390_DO_FUNC(52, PCC_Compute_XTS_Parameter, Using_AES_256, 16, 96) \
1313 S390_DO_FUNC(58, PCC_Compute_XTS_Parameter, Using_Encrypted_AES_128, 16, \
1314 112) \
1315 S390_DO_FUNC(60, PCC_Compute_XTS_Parameter, Using_Encrypted_AES_256, 16, 128)
1317 #define S390_DO_FUNCTIONS1 \
1318 S390_DO_FUNC(64, PCC_Scalar_Multiply, P256, 64, 168) \
1319 S390_DO_FUNC(65, PCC_Scalar_Multiply, P384, 96, 248) \
1320 S390_DO_FUNC(66, PCC_Scalar_Multiply, P521, 160, 408) \
1321 S390_DO_FUNC(72, PCC_Scalar_Multiply, Ed25519, 64, 168) \
1322 S390_DO_FUNC(73, PCC_Scalar_Multiply, Ed448, 128, 328) \
1323 S390_DO_FUNC(80, PCC_Scalar_Multiply, X25519, 32, 104) \
1324 S390_DO_FUNC(81, PCC_Scalar_Multiply, X448, 64, 200)
1326 #define S390_DO_FUNC(fc, class, name, rlen, plen) \
1327 [fc] = {class, rlen / 8, plen / 8},
1328 static const struct {
1329 UChar fc_class : 3;
1330 UChar result_len : 5;
1331 UChar parms_len;
1332 } S390_PCC_fc_info[] = {S390_DO_FUNCTIONS S390_DO_FUNCTIONS1};
1333 #undef S390_DO_FUNC
1335 #define S390_DO_FUNC(fc, class, name, rlen, plen) | S390_SETBIT(fc)
1336 static const ULong S390_PCC_supported_fc[] = {0 S390_DO_FUNCTIONS,
1337 0 S390_DO_FUNCTIONS1};
1338 #undef S390_DO_FUNC
1340 #undef S390_DO_FUNCTIONS
1341 #undef S390_DO_FUNCTIONS1
1343 static enum ExtensionError do_extension_PCC(ThreadState* tst, ULong variant)
1345 UChar func = READ_FUNCTION_CODE(tst, "PCC");
1346 UChar fc = func & 0x7f;
1347 ULong parms = READ_GPR(tst, "PCC(r1)", 1);
1348 ULong parms_len = 0;
1349 Int cc = 0;
1350 UChar fc_class = PCC_Unassigned;
1351 ULong result_offs, result_len, msg_len;
1353 if (fc < sizeof(S390_PCC_fc_info) / sizeof(S390_PCC_fc_info[0])) {
1354 fc_class = S390_PCC_fc_info[fc].fc_class;
1355 result_len = S390_PCC_fc_info[fc].result_len * 8;
1356 parms_len = S390_PCC_fc_info[fc].parms_len * 8;
1359 switch (fc_class) {
1360 case PCC_Query:
1361 PRE_MEM_WRITE(tst, "PCC(parms)", parms, parms_len);
1362 cc = do_PCC_insn(func, parms);
1363 s390_filter_functions((ULong*)parms, parms_len, S390_PCC_supported_fc,
1364 sizeof(S390_PCC_supported_fc));
1365 result_offs = 0;
1366 break;
1367 case PCC_Compute_Last_Block_CMAC:
1368 /* result_len == sizeof(ICV) == sizeof(message) */
1369 PRE_MEM_READ(tst, "PCC(parms)", parms, 8);
1370 msg_len = (*(UChar*)parms + 7) / 8;
1371 if (msg_len > result_len)
1372 msg_len = result_len;
1373 if (msg_len != 0) {
1374 PRE_MEM_READ(tst, "PCC(parms)", parms + 8, msg_len);
1376 result_offs = 8 + result_len;
1377 PRE_MEM_READ(tst, "PCC(parms)", parms + result_offs,
1378 parms_len - result_offs);
1379 PRE_MEM_WRITE(tst, "PCC(parms.CMAC)", parms + result_offs, result_len);
1380 cc = do_PCC_insn(func, parms);
1381 break;
1382 case PCC_Compute_XTS_Parameter:
1383 /* result_len == sizeof(XTS parameter) */
1384 result_offs = parms_len - result_len;
1385 PRE_MEM_READ(tst, "PCC(parms)", parms, result_offs - 16);
1386 if (*(ULong*)(parms + result_offs - 32) != 0) {
1387 /* block sequential number non-zero -> read intermediate bit index t */
1388 result_offs -= 16;
1389 result_len += 16;
1390 PRE_MEM_READ(tst, "PCC(parms.t)", parms + result_offs, 16);
1391 if (*(ULong*)(parms + result_offs) != 0) {
1392 /* t != 0: read partial XTS parameter */
1393 PRE_MEM_READ(tst, "PCC(parms.XTS)", parms + result_offs + 16,
1394 result_len);
1397 PRE_MEM_WRITE(tst, "PCC(parms)", parms + result_offs, result_len);
1398 cc = do_PCC_insn(func, parms);
1399 break;
1400 case PCC_Scalar_Multiply:
1401 /* result_len == sizeof(result) == sizeof(source) */
1402 result_offs = 0;
1403 PRE_MEM_READ(tst, "PCC(parms)", parms + result_len,
1404 parms_len - result_len);
1405 PRE_MEM_WRITE(tst, "PCC(parms)", parms, 4096);
1406 if (*(ULong*)(parms + parms_len - 8) != 0) {
1407 /* continuation -> read the continuation state buffer as well */
1408 PRE_MEM_READ(tst, "PCC(parms.CSB)", parms + parms_len,
1409 4096 - parms_len);
1411 cc = do_PCC_insn(func, parms);
1412 break;
1413 default:
1414 return INSN_ERR("PCC: unknown function code\n");
1417 if (cc == 0 || cc == 3) // normal or partial completion
1418 POST_MEM_WRITE(tst, parms + result_offs, result_len);
1419 WRITE_CC(tst, cc);
1420 return ExtErr_OK;
1423 /*---------------------------------------------------------------*/
1424 /*--- KMCTR (cypher message with counter) ---*/
1425 /*---------------------------------------------------------------*/
1427 S390_DEFINE_DO_RRR_INSN(do_KMCTR_insn, 0xb92d)
1429 #define S390_DO_FUNCTIONS \
1430 S390_DO_FUNC(0, S390_KMCTR_Query, 16) \
1431 S390_DO_FUNC(1, S390_KMCTR_DEA, 8) \
1432 S390_DO_FUNC(2, S390_KMCTR_TDEA_128, 16) \
1433 S390_DO_FUNC(3, S390_KMCTR_TDEA_192, 24) \
1434 S390_DO_FUNC(9, S390_KMCTR_Encrypted_DEA, 32) \
1435 S390_DO_FUNC(10, S390_KMCTR_Encrypted_TDEA_128, 40) \
1436 S390_DO_FUNC(11, S390_KMCTR_Encrypted_TDEA_192, 48) \
1437 S390_DO_FUNC(18, S390_KMCTR_AES_128, 16) \
1438 S390_DO_FUNC(19, S390_KMCTR_AES_192, 24) \
1439 S390_DO_FUNC(20, S390_KMCTR_AES_256, 32) \
1440 S390_DO_FUNC(26, S390_KMCTR_Encrypted_AES_128, 48) \
1441 S390_DO_FUNC(27, S390_KMCTR_Encrypted_AES_192, 56) \
1442 S390_DO_FUNC(28, S390_KMCTR_Encrypted_AES_256, 64)
1444 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1445 static const UChar S390_KMCTR_parms_len[] = {S390_DO_FUNCTIONS};
1446 #undef S390_DO_FUNC
1448 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1449 static const ULong S390_KMCTR_supported_fc[] = {0 S390_DO_FUNCTIONS};
1450 #undef S390_DO_FUNC
1452 #undef S390_DO_FUNCTIONS
1454 enum {
1455 S390_KMCTR_parms_len_n =
1456 sizeof(S390_KMCTR_parms_len) / sizeof(S390_KMCTR_parms_len[0])
1459 static enum ExtensionError do_extension_KMCTR(ThreadState* tst, ULong variant)
1461 UChar r1 = variant & 0xf;
1462 UChar r2 = (variant >> 4) & 0xf;
1463 UChar r3 = (variant >> 8) & 0xf;
1464 UChar func = READ_FUNCTION_CODE(tst, "KMCTR");
1465 UChar fc = func & 0x7f;
1466 ULong parms = READ_GPR(tst, "KMCTR(r1)", 1);
1467 ULong parms_len = 0;
1468 Int cc = 0;
1469 ULong orig_addr1, orig_len2 = 0;
1470 ULong addr1 = 0, addr2 = 0, addr3 = 0, len2 = 0, len3 = 0;
1472 if (fc < S390_KMCTR_parms_len_n)
1473 parms_len = S390_KMCTR_parms_len[fc];
1474 if (parms_len == 0)
1475 return INSN_ERR("KMCTR: unknown function code\n");
1477 if (fc == 0) { // Query
1478 PRE_MEM_WRITE(tst, "KMCTR(parms)", parms, parms_len);
1479 cc = do_KMCTR_insn(func, parms, &addr1, &addr2, &len2, &addr3, &len3);
1480 s390_filter_functions((ULong*)parms, parms_len, S390_KMCTR_supported_fc,
1481 sizeof(S390_KMCTR_supported_fc));
1482 POST_MEM_WRITE(tst, parms, parms_len);
1483 } else {
1484 addr1 = orig_addr1 = READ_GPR(tst, "KMCTR(op1_addr)", r1);
1485 addr2 = READ_GPR(tst, "KMCTR(op2_addr)", r2);
1486 addr3 = READ_GPR(tst, "KMCTR(op3_addr)", r3);
1487 len2 = orig_len2 = READ_GPR(tst, "KMCTR(op2_len)", r2 + 1);
1488 PRE_MEM_READ(tst, "KMCTR(parms)", parms, parms_len);
1489 PRE_MEM_WRITE(tst, "KMCTR(op1)", addr1, len2);
1490 PRE_MEM_READ(tst, "KMCTR(op2)", addr2, len2);
1491 PRE_MEM_READ(tst, "KMCTR(op3)", addr3, len2);
1492 cc = do_KMCTR_insn(func, parms, &addr1, &addr2, &len2, &addr3, &len3);
1493 WRITE_GPR(tst, r1, addr1);
1494 WRITE_GPR(tst, r2, addr2);
1495 WRITE_GPR(tst, r2 + 1, len2);
1496 WRITE_GPR(tst, r3, addr3);
1497 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
1499 WRITE_CC(tst, cc);
1500 return ExtErr_OK;
1503 /*---------------------------------------------------------------*/
1504 /*--- KMO (cypher message with output feedback) ---*/
1505 /*---------------------------------------------------------------*/
1507 S390_DEFINE_DO_RR_INSN(do_KMO_insn, 0xb92b)
1509 /* Same functions and parameter block sizes as for KMCTR */
1510 static const UChar* const S390_KMO_parms_len = S390_KMCTR_parms_len;
1511 static const ULong* const S390_KMO_supported_fc = S390_KMCTR_supported_fc;
1512 enum { S390_KMO_parms_len_n = S390_KMCTR_parms_len_n };
1514 static enum ExtensionError do_extension_KMO(ThreadState* tst, ULong variant)
1516 UChar r1 = variant & 0xf;
1517 UChar r2 = (variant >> 4) & 0xf;
1518 UChar func = READ_FUNCTION_CODE(tst, "KMO");
1519 UChar fc = func & 0x7f;
1520 ULong parms = READ_GPR(tst, "KMO(r1)", 1);
1521 ULong parms_len = 0;
1522 Int cc = 0;
1523 ULong orig_addr1, orig_len2 = 0;
1524 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
1526 if (fc < S390_KMO_parms_len_n)
1527 parms_len = S390_KMO_parms_len[fc];
1528 if (parms_len == 0)
1529 return INSN_ERR("KMO: unknown function code\n");
1531 PRE_MEM_WRITE(tst, "KMO(parms)", parms, parms_len);
1532 if (fc == 0) { // Query
1533 cc = do_KMO_insn(func, parms, &addr1, &len1, &addr2, &len2);
1534 s390_filter_functions((ULong*)parms, parms_len, S390_KMO_supported_fc,
1535 sizeof(S390_KMO_supported_fc));
1536 } else {
1537 addr1 = orig_addr1 = READ_GPR(tst, "KMO(op1_addr)", r1);
1538 addr2 = READ_GPR(tst, "KMO(op2_addr)", r2);
1539 len2 = orig_len2 = READ_GPR(tst, "KMO(op2_len)", r2 + 1);
1540 PRE_MEM_READ(tst, "KMO(parms)", parms, parms_len);
1541 PRE_MEM_WRITE(tst, "KMO(op1)", addr1, len2);
1542 PRE_MEM_READ(tst, "KMO(op2)", addr2, len2);
1543 cc = do_KMO_insn(func, parms, &addr1, &len1, &addr2, &len2);
1544 WRITE_GPR(tst, r1, addr1);
1545 WRITE_GPR(tst, r2, addr2);
1546 WRITE_GPR(tst, r2 + 1, len2);
1547 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
1549 POST_MEM_WRITE(tst, parms, parms_len);
1550 WRITE_CC(tst, cc);
1551 return ExtErr_OK;
1554 /*---------------------------------------------------------------*/
1555 /*--- KMF (cypher message with output feedback) ---*/
1556 /*---------------------------------------------------------------*/
1558 S390_DEFINE_DO_RR_INSN(do_KMF_insn, 0xb92a)
1560 /* Same functions and parameter block sizes as for KMCTR */
1561 static const UChar* const S390_KMF_parms_len = S390_KMCTR_parms_len;
1562 static const ULong* const S390_KMF_supported_fc = S390_KMCTR_supported_fc;
1563 enum { S390_KMF_parms_len_n = S390_KMCTR_parms_len_n };
1565 static enum ExtensionError do_extension_KMF(ThreadState* tst, ULong variant)
1567 UChar r1 = variant & 0xf;
1568 UChar r2 = (variant >> 4) & 0xf;
1569 ULong func = READ_GPR(tst, "KLMD(r0)", 0);
1570 UChar fc = func & 0x7f;
1571 ULong parms = READ_GPR(tst, "KMF(r1)", 1);
1572 ULong parms_len = 0;
1573 Int cc = 0;
1574 ULong orig_addr1, orig_len2 = 0;
1575 ULong addr1 = 0, len1 = 0, addr2 = 0, len2 = 0;
1577 if (fc < S390_KMF_parms_len_n)
1578 parms_len = S390_KMF_parms_len[fc];
1579 if (parms_len == 0)
1580 return INSN_ERR("KMF: unknown function code\n");
1582 PRE_MEM_WRITE(tst, "KMF(parms)", parms, parms_len);
1583 if (fc == 0) { // Query
1584 cc = do_KMF_insn(func, parms, &addr1, &len1, &addr2, &len2);
1585 s390_filter_functions((ULong*)parms, parms_len, S390_KMF_supported_fc,
1586 sizeof(S390_KMF_supported_fc));
1587 } else {
1588 addr1 = orig_addr1 = READ_GPR(tst, "KMF(op1_addr)", r1);
1589 addr2 = READ_GPR(tst, "KMF(op2_addr)", r2);
1590 len2 = orig_len2 = READ_GPR(tst, "KMF(op2_len)", r2 + 1);
1591 PRE_MEM_READ(tst, "KMF(parms)", parms, parms_len);
1592 PRE_MEM_WRITE(tst, "KMF(op1)", addr1, len2);
1593 PRE_MEM_READ(tst, "KMF(op2)", addr2, len2);
1594 cc = do_KMF_insn(func, parms, &addr1, &len1, &addr2, &len2);
1595 WRITE_GPR(tst, r1, addr1);
1596 WRITE_GPR(tst, r2, addr2);
1597 WRITE_GPR(tst, r2 + 1, len2);
1598 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
1600 POST_MEM_WRITE(tst, parms, parms_len);
1601 WRITE_CC(tst, cc);
1602 return ExtErr_OK;
1605 /*---------------------------------------------------------------*/
1606 /*--- KMA (cypher message with authentication) ---*/
1607 /*---------------------------------------------------------------*/
1609 S390_DEFINE_DO_RRR_INSN(do_KMA_insn, 0xb929)
1611 #define S390_DO_FUNCTIONS \
1612 S390_DO_FUNC(0, S390_KMA_Query, 16) \
1613 S390_DO_FUNC(18, S390_KMA_GCM_AES_128, 96) \
1614 S390_DO_FUNC(19, S390_KMA_GCM_AES_192, 104) \
1615 S390_DO_FUNC(20, S390_KMA_GCM_AES_256, 112) \
1616 S390_DO_FUNC(26, S390_KMA_GCM_Encrypted_AES_128, 128) \
1617 S390_DO_FUNC(27, S390_KMA_GCM_Encrypted_AES_192, 136) \
1618 S390_DO_FUNC(28, S390_KMA_GCM_Encrypted_AES_256, 144)
1620 #define S390_DO_FUNC(fc, name, plen) [fc] = plen,
1621 static const UChar S390_KMA_parms_len[] = {S390_DO_FUNCTIONS};
1622 #undef S390_DO_FUNC
1624 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1625 static const ULong S390_KMA_supported_fc[] = {0 S390_DO_FUNCTIONS};
1626 #undef S390_DO_FUNC
1628 #undef S390_DO_FUNCTIONS
1630 static enum ExtensionError do_extension_KMA(ThreadState* tst, ULong variant)
1632 UChar r1 = variant & 0xf;
1633 UChar r2 = (variant >> 4) & 0xf;
1634 UChar r3 = (variant >> 8) & 0xf;
1635 ULong func = READ_GPR(tst, "KMA(gpr0)", 0);
1636 UChar fc = func & 0x7f;
1637 ULong parms = READ_GPR(tst, "KMA(r1)", 1);
1638 ULong parms_len = 0;
1639 Int cc = 0;
1640 ULong orig_addr1, orig_len2;
1641 ULong addr1 = 0, addr2 = 0, addr3 = 0, len2 = 0, len3 = 0;
1643 if (fc < sizeof(S390_KMA_parms_len) / sizeof(S390_KMA_parms_len[0]))
1644 parms_len = S390_KMA_parms_len[fc];
1645 if (parms_len == 0)
1646 return INSN_ERR("KMA: unknown function code\n");
1648 if (fc == 0) { // Query
1649 PRE_MEM_WRITE(tst, "KMA(parms)", parms, parms_len);
1650 cc = do_KMA_insn(func, parms, &addr1, &addr2, &len2, &addr3, &len3);
1651 s390_filter_functions((ULong*)parms, parms_len, S390_KMA_supported_fc,
1652 sizeof(S390_KMA_supported_fc));
1653 POST_MEM_WRITE(tst, parms, parms_len);
1654 } else {
1655 addr1 = orig_addr1 = READ_GPR(tst, "KMA(op1_addr)", r1);
1656 addr2 = READ_GPR(tst, "KMA(op2_addr)", r2);
1657 addr3 = READ_GPR(tst, "KMA(op3_addr)", r3);
1658 len2 = orig_len2 = READ_GPR(tst, "KMA(op2_len)", r2 + 1);
1659 len3 = READ_GPR(tst, "KMA(op3_len)", r3 + 1);
1660 PRE_MEM_READ(tst, "KMA(parms)", parms, parms_len);
1661 PRE_MEM_WRITE(tst, "KMA(op1)", addr1, len2);
1662 PRE_MEM_READ(tst, "KMA(op2)", addr2, len2);
1663 PRE_MEM_READ(tst, "KMA(op3)", addr3, len3);
1664 cc = do_KMA_insn(func, parms, &addr1, &addr2, &len2, &addr3, &len3);
1665 WRITE_GPR(tst, r1, addr1);
1666 WRITE_GPR(tst, r2, addr2);
1667 WRITE_GPR(tst, r2 + 1, len2);
1668 WRITE_GPR(tst, r3, addr3);
1669 WRITE_GPR(tst, r3 + 1, len3);
1670 POST_MEM_WRITE(tst, orig_addr1, orig_len2 - len2);
1672 WRITE_CC(tst, cc);
1673 return ExtErr_OK;
1676 /*---------------------------------------------------------------*/
1677 /*--- KDSA (compute intermediate message digest) ---*/
1678 /*---------------------------------------------------------------*/
1680 S390_DEFINE_DO_0R_INSN(do_KDSA_insn, 0xb93a)
1682 /* We specify the parameter block size without the CSB here. Also note that
1683 this approach only supports sizes that are a multiple of 8. */
1684 #define S390_DO_FUNCTIONS \
1685 S390_DO_FUNC(0, S390_KDSA_Query, 16) \
1686 S390_DO_FUNC(1, S390_KDSA_ECDSA_Verify_P256, 168) \
1687 S390_DO_FUNC(2, S390_KDSA_ECDSA_Verify_P384, 248) \
1688 S390_DO_FUNC(3, S390_KDSA_ECDSA_Verify_P521, 408) \
1689 S390_DO_FUNC(9, S390_KDSA_ECDSA_Sign_P256, 168) \
1690 S390_DO_FUNC(10, S390_KDSA_ECDSA_Sign_P384, 248) \
1691 S390_DO_FUNC(11, S390_KDSA_ECDSA_Sign_P521, 408) \
1692 S390_DO_FUNC(17, S390_KDSA_Encrypted_ECDSA_Sign_P256, 200) \
1693 S390_DO_FUNC(18, S390_KDSA_Encrypted_ECDSA_Sign_P384, 280) \
1694 S390_DO_FUNC(19, S390_KDSA_Encrypted_ECDSA_Sign_P521, 440) \
1695 S390_DO_FUNC(32, S390_KDSA_EdDSA_Verify_Ed25519, 104) \
1696 S390_DO_FUNC(36, S390_KDSA_EdDSA_Verify_Ed448, 200) \
1697 S390_DO_FUNC(40, S390_KDSA_EdDSA_Sign_Ed25519, 120) \
1698 S390_DO_FUNC(44, S390_KDSA_EdDSA_Sign_Ed448, 216) \
1699 S390_DO_FUNC(48, S390_KDSA_Encrypted_EdDSA_Sign_Ed25519, 152) \
1700 S390_DO_FUNC(52, S390_KDSA_Encrypted_EdDSA_Sign_Ed448, 248)
1702 #define S390_DO_FUNC(fc, name, plen) [fc] = plen / 8,
1703 static const UChar S390_KDSA_parms_len[] = {S390_DO_FUNCTIONS};
1704 #undef S390_DO_FUNC
1706 #define S390_DO_FUNC(fc, name, plen) | S390_SETBIT(fc)
1707 static const ULong S390_KDSA_supported_fc[] = {0 S390_DO_FUNCTIONS};
1708 #undef S390_DO_FUNC
1710 #undef S390_DO_FUNCTIONS
1712 static enum ExtensionError do_extension_KDSA(ThreadState* tst, ULong variant)
1714 UChar r2 = (variant >> 4) & 0xf;
1715 UChar func = READ_FUNCTION_CODE(tst, "KDSA");
1716 UChar fc = func & 0x7f;
1717 ULong parms = READ_GPR(tst, "KDSA(r1)", 1);
1718 ULong parms_len = 0;
1719 Int cc = 0;
1720 ULong addr2 = 0, len2 = 0;
1722 if (fc < sizeof(S390_KDSA_parms_len) / sizeof(S390_KDSA_parms_len[0]))
1723 parms_len = S390_KDSA_parms_len[fc] * 8;
1724 if (parms_len == 0)
1725 return INSN_ERR("KDSA: unknown function code\n");
1727 if (fc == 0) { // Query
1728 PRE_MEM_WRITE(tst, "KDSA(parms)", parms, parms_len);
1729 cc = do_KDSA_insn(func, parms, &addr2, &len2);
1730 s390_filter_functions((ULong*)parms, parms_len, S390_KDSA_supported_fc,
1731 sizeof(S390_KDSA_supported_fc));
1732 POST_MEM_WRITE(tst, parms, parms_len);
1733 } else {
1734 addr2 = READ_GPR(tst, "KDSA(op2_addr)", r2);
1735 len2 = READ_GPR(tst, "KDSA(op2_len)", r2 + 1);
1736 PRE_MEM_READ(tst, "KDSA(parms)", parms, parms_len);
1737 /* the CSB must also be writable */
1738 PRE_MEM_WRITE(tst, "KDSA(parms)", parms, 4096);
1739 PRE_MEM_READ(tst, "KDSA(op2)", addr2, len2);
1740 cc = do_KDSA_insn(func, parms, &addr2, &len2);
1741 WRITE_GPR(tst, r2, addr2);
1742 WRITE_GPR(tst, r2 + 1, len2);
1743 POST_MEM_WRITE(tst, parms, parms_len);
1745 WRITE_CC(tst, cc);
1746 return ExtErr_OK;
1749 /*---------------------------------------------------------------*/
1750 /*--- Main function: select and call appropriate extension ---*/
1751 /*---------------------------------------------------------------*/
1753 enum ExtensionError ML_(do_client_extension)(ThreadState* tst)
1755 ULong code = REG_READ(tst, SYSNO);
1756 ULong id = code & ((1ULL << S390_EXT_ID_NBITS) - 1);
1757 ULong variant = code >> S390_EXT_ID_NBITS;
1759 switch (id) {
1760 case S390_EXT_PRNO:
1761 return do_extension_PRNO(tst, variant);
1762 case S390_EXT_NNPA:
1763 return do_extension_NNPA(tst, variant);
1764 case S390_EXT_DFLT:
1765 return do_extension_DFLTCC(tst, variant);
1766 case S390_EXT_STFLE:
1767 return do_extension_STFLE(tst, variant);
1768 case S390_EXT_KM:
1769 return do_extension_KM(tst, variant);
1770 case S390_EXT_KMC:
1771 return do_extension_KMC(tst, variant);
1772 case S390_EXT_KIMD:
1773 return do_extension_KIMD(tst, variant);
1774 case S390_EXT_KLMD:
1775 return do_extension_KLMD(tst, variant);
1776 case S390_EXT_KMAC:
1777 return do_extension_KMAC(tst, variant);
1778 case S390_EXT_PCC:
1779 return do_extension_PCC(tst, variant);
1780 case S390_EXT_KMCTR:
1781 return do_extension_KMCTR(tst, variant);
1782 case S390_EXT_KMO:
1783 return do_extension_KMO(tst, variant);
1784 case S390_EXT_KMF:
1785 return do_extension_KMF(tst, variant);
1786 case S390_EXT_KMA:
1787 return do_extension_KMA(tst, variant);
1788 case S390_EXT_KDSA:
1789 return do_extension_KDSA(tst, variant);
1790 default:
1791 VG_(core_panic)("unknown extension ID");
1795 #endif