1 /*
2  * Check decoding of s390_sthyi syscall.
3  *
4  * Copyright (c) 2018 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "tests.h"
31 #include <asm/unistd.h>
32 
33 #if defined HAVE_ICONV_H && defined HAVE_ICONV_OPEN && defined __NR_s390_sthyi
34 
35 # include <errno.h>
36 # include <iconv.h>
37 # include <inttypes.h>
38 # include <stdbool.h>
39 # include <stdint.h>
40 # include <stdio.h>
41 # include <unistd.h>
42 
43 # include <sys/user.h>
44 
45 # define EBCDIC_MAX_LEN 16
46 
47 # ifndef VERBOSE
48 #  define VERBOSE 0
49 # endif
50 
51 static bool
print_0x8(const char * prefix,unsigned char * buf,unsigned int offs,bool zero)52 print_0x8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
53 {
54 	if (!zero && !buf[offs])
55 		return false;
56 
57 	printf("%s=%#02hhx", prefix, buf[offs]);
58 
59 	return true;
60 }
61 
62 static bool
print_u8(const char * prefix,unsigned char * buf,unsigned int offs,bool zero)63 print_u8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
64 {
65 	if (!zero && !buf[offs])
66 		return false;
67 
68 	printf("%s=%hhu", prefix, buf[offs]);
69 
70 	return true;
71 }
72 
73 static bool
print_u16(const char * prefix,unsigned char * buf,unsigned int offs,bool zero)74 print_u16(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
75 {
76 	uint16_t val = *(uint16_t *) (buf + offs);
77 
78 	if (!zero && !val)
79 		return false;
80 
81 	printf("%s=%" PRIu16, prefix, val);
82 
83 	return true;
84 }
85 
86 static bool
print_x32(const char * prefix,unsigned char * buf,unsigned int offs,bool zero)87 print_x32(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
88 {
89 	uint32_t val = *(uint32_t *) (buf + offs);
90 
91 	if (!zero && !val)
92 		return false;
93 
94 	printf("%s=%#" PRIx32, prefix, val);
95 
96 	return true;
97 }
98 
99 static bool
print_weight(const char * prefix,unsigned char * buf,unsigned int offs,bool zero)100 print_weight(const char *prefix, unsigned char *buf, unsigned int offs,
101 	     bool zero)
102 {
103 	uint32_t val = *(uint32_t *) (buf + offs);
104 
105 	if (print_x32(prefix, buf, offs, zero)) {
106 		if (val)
107 			printf(" /* %u %u/65536 cores */",
108 			       val >> 16, val & 0xFFFF);
109 		else
110 			printf(" /* unlimited */");
111 
112 		return true;
113 	}
114 
115 	return false;
116 }
117 
118 static char *
ebcdic2ascii(unsigned char * ebcdic,size_t size)119 ebcdic2ascii(unsigned char *ebcdic, size_t size)
120 {
121 	static char ascii_buf[EBCDIC_MAX_LEN];
122 
123 	char *ebcdic_pos = (char *) ebcdic;
124 	char *ascii_pos = ascii_buf;
125 	size_t ebcdic_left = size;
126 	size_t ascii_left = size;
127 	size_t ret;
128 
129 	iconv_t cd = iconv_open("ASCII", "EBCDICUS");
130 
131 	if (size > sizeof(ascii_buf))
132 		error_msg_and_fail("ebcdic2ascii: EBCDIC string is too big: "
133 				   "%zu (maximum is %zu)",
134 				   size, sizeof(ascii_buf));
135 	if (cd == (iconv_t) -1)
136 		perror_msg_and_fail("ebcdic2ascii: unable to allocate a "
137 				    "conversion descriptior for converting "
138 				    "EBCDIC to ASCII");
139 
140 	while ((ret = iconv(cd, &ebcdic_pos, &ebcdic_left,
141 	    &ascii_pos, &ascii_left)) == (size_t) -1) {
142 		switch (errno) {
143 		case EILSEQ:
144 		case EINVAL: /* That one is quite unexpected, actually */
145 			if (!ebcdic_left || !ascii_left)
146 				goto ebcdic2ascii_end;
147 
148 			*ascii_pos++ = ' ';
149 			ebcdic_pos++;
150 			ebcdic_left--;
151 
152 			break;
153 
154 		case E2BIG:
155 			perror_msg_and_fail("ebcdic2ascii: ran out of "
156 					    "ASCII buffer unexpectedly");
157 		default:
158 			perror_msg_and_fail("ebcdic2ascii: unexpected error");
159 		}
160 	}
161 
162 ebcdic2ascii_end:
163 	iconv_close(cd);
164 
165 	if (ebcdic_left != ascii_left)
166 		error_msg_and_fail("ebcdic2ascii: ASCII string differs in size "
167 				   "from EBCDIC");
168 
169 	return ascii_buf;
170 }
171 
172 # if VERBOSE
173 static bool
is_empty(unsigned char * ptr,size_t size)174 is_empty(unsigned char *ptr, size_t size)
175 {
176 	size_t i;
177 
178 	for (i = 0; !*ptr && i < size; ptr++, i++)
179 		;
180 
181 	return i == size;
182 }
183 # endif /* !VERBOSE */
184 
185 static bool
print_ebcdic(const char * prefix,unsigned char * addr,unsigned int offs,size_t size,bool zero,bool blank)186 print_ebcdic(const char *prefix, unsigned char *addr, unsigned int offs,
187 	     size_t size, bool zero, bool blank)
188 {
189 	const char *ascii = ebcdic2ascii(addr + offs, size);
190 
191 	if (!zero) {
192 		size_t i;
193 
194 		for (i = 0; (addr[offs + i] == (blank ? 64 : 0)) && (i < size);
195 		    i++)
196 			;
197 
198 		if (i == size)
199 			return false;
200 	}
201 
202 	printf("%s=", prefix);
203 	print_quoted_hex((char *) (addr + offs), size);
204 	printf(" /* ");
205 	print_quoted_memory(ascii, size);
206 	printf(" */");
207 
208 	return true;
209 }
210 
211 static void
print_hypervisor_header(unsigned char * buf,int level,unsigned int offs_pos,unsigned int len_pos,bool mt)212 print_hypervisor_header(unsigned char *buf, int level, unsigned int offs_pos,
213 			unsigned int len_pos, bool mt)
214 {
215 	uint16_t offs = *(uint16_t *) (buf + offs_pos);
216 	uint16_t hdr_size = *(uint16_t *) (buf + len_pos);
217 	unsigned char *cur;
218 
219 	if (!offs)
220 		return;
221 	if (hdr_size < 32)
222 		error_msg_and_fail("sthyi: hypervisor %d section is too small "
223 			           "(got %hu, 32 expected)", level, hdr_size);
224 
225 	cur = buf + offs;
226 
227 	printf(", /* hypervisor %d */ {infyflg1", level);
228 	print_0x8("", cur, 0, true);
229 # if VERBOSE
230 	if (cur[0]) {
231 		bool printed = false;
232 
233 		printf(" /* ");
234 		if (cur[0] & 0x80) {
235 			printf("0x80 - guest CPU usage had limiting is using "
236 			       "the consumption method");
237 			printed = true;
238 		}
239 		if (cur[0] & 0x40) {
240 			if (printed)
241 				printf(", ");
242 			printf("0x40 - LIMITHARD caps use prorated core time "
243 			       "for capping");
244 			printed = true;
245 		}
246 		if (cur[0] & 0x3F) {
247 			if (printed)
248 				printf(", ");
249 			printf("%#hhx - ???", cur[0] & 0x3F);
250 		}
251 		printf(" */");
252 	}
253 
254 	print_0x8(", infyflg2", cur, 1, false);
255 	print_0x8(", infyval1", cur, 2, false);
256 	print_0x8(", infyval2", cur, 3, false);
257 
258 	print_u8(", infytype", cur, 4, true);
259 	if (cur[4] == 1)
260 		printf(" /* z/VM is the hypervisor */");
261 	else
262 		printf(" /* unknown hypervisor type */");
263 
264 	if (cur[5])
265 		printf(", reserved_1__=\"\\x%#02hhx\"", cur[5]);
266 
267 	print_u8(", infycpt",  cur, 6, mt);
268 	print_u8(", infyiflt", cur, 7, mt);
269 # endif /* !VERBOSE */
270 
271 	print_ebcdic(", infysyid", cur, 8,  8, VERBOSE, true);
272 	print_ebcdic(", infyclnm", cur, 16, 8, VERBOSE, true);
273 
274 	print_u16(", infyscps", cur, 24, VERBOSE);
275 	print_u16(", infydcps", cur, 26, VERBOSE);
276 	print_u16(", infysifl", cur, 28, VERBOSE);
277 	print_u16(", infydifl", cur, 30, VERBOSE);
278 
279 # if VERBOSE
280 	if (hdr_size > 32 && !is_empty(cur + 32, hdr_size - 32)) {
281 		printf(", ");
282 		print_quoted_hex((char *) (cur + 32), hdr_size - 32);
283 	}
284 # else /* !VERBOSE */
285 	printf(", ...");
286 # endif /* !VERBOSE */
287 
288 	printf("}");
289 }
290 
291 static void
print_guest_header(unsigned char * buf,int level,unsigned int offs_pos,unsigned int len_pos)292 print_guest_header(unsigned char *buf, int level, unsigned int offs_pos,
293 		   unsigned int len_pos)
294 {
295 	uint16_t offs = *(uint16_t *) (buf + offs_pos);
296 	uint16_t hdr_size = *(uint16_t *) (buf + len_pos);
297 	unsigned char *cur;
298 
299 	if (!offs)
300 		return;
301 	if (hdr_size < 56)
302 		error_msg_and_fail("sthyi: guest %d section is too small "
303 			           "(got %hu, 56 expected)", level, hdr_size);
304 
305 	cur = buf + offs;
306 
307 	printf(", /* guest %d */ {infgflg1", level);
308 	print_0x8("", cur, 0, true);
309 # if VERBOSE
310 	if (cur[0]) {
311 		bool printed = false;
312 
313 		printf(" /* ");
314 		if (cur[0] & 0x80) {
315 			printf("0x80 - guest is mobility enabled");
316 			printed = true;
317 		}
318 		if (cur[0] & 0x40) {
319 			if (printed)
320 				printf(", ");
321 			printf("0x40 - guest has multiple virtual CPU types");
322 			printed = true;
323 		}
324 		if (cur[0] & 0x20) {
325 			if (printed)
326 				printf(", ");
327 			printf("0x20 - guest CP dispatch type has LIMITHARD "
328 			       "cap");
329 			printed = true;
330 		}
331 		if (cur[0] & 0x10) {
332 			if (printed)
333 				printf(", ");
334 			printf("0x10 - guest IFL dispatch type has LIMITHARD "
335 			       "cap");
336 			printed = true;
337 		}
338 		if (cur[0] & 0x08) {
339 			if (printed)
340 				printf(", ");
341 			printf("0x08 - virtual CPs are thread dispatched");
342 			printed = true;
343 		}
344 		if (cur[0] & 0x04) {
345 			if (printed)
346 				printf(", ");
347 			printf("0x04 - virtual IFLs are thread dispatched");
348 			printed = true;
349 		}
350 		if (cur[0] & 0x3) {
351 			if (printed)
352 				printf(", ");
353 			printf("%#hhx - ???", cur[0] & 0x3);
354 		}
355 		printf(" */");
356 	}
357 
358 	print_0x8(", infgflg2", cur, 1, false);
359 	print_0x8(", infgval1", cur, 2, false);
360 	print_0x8(", infgval2", cur, 3, false);
361 # endif /* !VERBOSE */
362 
363 	print_ebcdic(", infgusid", cur, 4, 8, true, false);
364 
365 	print_u16(", infgscps", cur, 12, VERBOSE);
366 	print_u16(", infgdcps", cur, 14, VERBOSE);
367 
368 # if VERBOSE
369 	print_u8(", infgcpdt", cur, 16, true);
370 	if (cur[16] == 0)
371 		printf(" /* General Purpose (CP) */");
372 	else
373 		printf(" /* unknown */");
374 
375 	if (cur[17] || cur[18] || cur[19])
376 		printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
377 		       cur[17], cur[18], cur[19]);
378 # endif /* !VERBOSE */
379 
380 	print_weight(", infgcpcc", cur, 20, VERBOSE);
381 
382 	print_u16(", infgsifl", cur, 24, VERBOSE);
383 	print_u16(", infgdifl", cur, 26, VERBOSE);
384 
385 # if VERBOSE
386 	print_u8(", infgifdt", cur, 28, true);
387 	if (cur[28] == 0)
388 		printf(" /* General Purpose (CP) */");
389 	else if (cur[28] == 3)
390 		printf(" /* Integrated Facility for Linux (IFL) */");
391 	else
392 		printf(" /* unknown */");
393 
394 	if (cur[29] || cur[30] || cur[31])
395 		printf(", reserved_2__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
396 		       cur[29], cur[30], cur[31]);
397 # endif /* !VERBOSE */
398 
399 	print_weight(", infgifcc", cur, 32, VERBOSE);
400 
401 	print_0x8(", infgpflg", cur, 36, true);
402 # if VERBOSE
403 	if (cur[36]) {
404 		bool printed = false;
405 
406 		printf(" /* ");
407 		if (cur[36] & 0x80) {
408 			printf("0x80 - CPU pool's CP virtual type has "
409 			       "LIMITHARD cap");
410 			printed = true;
411 		}
412 		if (cur[36] & 0x40) {
413 			if (printed)
414 				printf(", ");
415 			printf("0x40 - CPU pool's CP virtual type has "
416 			       "CAPACITY cap");
417 			printed = true;
418 		}
419 		if (cur[36] & 0x20) {
420 			if (printed)
421 				printf(", ");
422 			printf("0x20 - CPU pool's IFL virtual type has "
423 			       "LIMITHARD cap");
424 			printed = true;
425 		}
426 		if (cur[36] & 0x10) {
427 			if (printed)
428 				printf(", ");
429 			printf("0x10 - CPU pool's IFL virtual type has "
430 			       "CAPACITY cap");
431 			printed = true;
432 		}
433 		if (cur[36] & 0x08) {
434 			if (printed)
435 				printf(", ");
436 			printf("0x08 - CPU pool uses prorated core time");
437 			printed = true;
438 		}
439 		if (cur[36] & 0x7) {
440 			if (printed)
441 				printf(", ");
442 			printf("%#hhx - ???", cur[36] & 0x7);
443 		}
444 		printf(" */");
445 	}
446 
447 	if (cur[37] || cur[38] || cur[39])
448 		printf(", reserved_3__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
449 		       cur[37], cur[38], cur[39]);
450 
451 	print_ebcdic(", infgpnam", cur, 40, 8, false, true);
452 
453 	print_weight(", infgpccc", cur, 48, true);
454 	print_weight(", infgpicc", cur, 52, true);
455 
456 	if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) {
457 		printf(", ");
458 		print_quoted_hex((char *) (cur + 56), hdr_size - 56);
459 	}
460 # else /* !VERBOSE */
461 	printf(", ...");
462 # endif /* !VERBOSE */
463 
464 	printf("}");
465 }
466 
467 static void
print_sthyi(unsigned char * buf)468 print_sthyi(unsigned char *buf)
469 {
470 	unsigned char *cur;
471 	uint16_t hdr_size;
472 	uint16_t offs;
473 	bool mt = false;
474 
475 	hdr_size = *(uint16_t *) (buf + 10);
476 	if (hdr_size < 44)
477 		error_msg_and_fail("sthyi: header section is too small "
478 			           "(got %hu, 44 expected)", hdr_size);
479 
480 	/* INFHFLG1 */
481 	print_0x8("{/* header */ {infhflg1", buf, 0, true);
482 # if VERBOSE
483 	if (buf[0]) {
484 		bool printed = false;
485 
486 		printf(" /* ");
487 		if (buf[0] & 0x80) {
488 			printf("0x80 - Global Performance Data unavailable");
489 			printed = true;
490 		}
491 		if (buf[0] & 0x40) {
492 			if (printed)
493 				printf(", ");
494 			printf("0x40 - One or more hypervisor levels below "
495 			       "this level does not support the STHYI "
496 			       "instruction");
497 			printed = true;
498 		}
499 		if (buf[0] & 0x20) {
500 			if (printed)
501 				printf(", ");
502 			printf("0x20 - Virtualization stack is incomplete");
503 			printed = true;
504 		}
505 		if (buf[0] & 0x10) {
506 			if (printed)
507 				printf(", ");
508 			printf("0x10 - Execution environment is not within a "
509 			       "logical partition");
510 			printed = true;
511 		}
512 		if (buf[0] & 0xF) {
513 			if (printed)
514 				printf(", ");
515 			printf("%#hhx - ???", buf[0] & 0xF);
516 		}
517 		printf(" */");
518 	}
519 
520 	print_0x8(", infhflg2", buf, 1, false);
521 	print_0x8(", infhval1", buf, 2, false);
522 	print_0x8(", infhval2", buf, 3, false);
523 
524 	/* Reserved */
525 	if (buf[4] || buf[5] || buf[6])
526 		printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
527 		       buf[4], buf[5], buf[6]);
528 
529 	print_u8(", infhygct", buf, 7, true);
530 	print_u16(", infhtotl", buf, 8, true);
531 	print_u16(", infhdln", buf, 10, true);
532 	print_u16(", infmoff", buf, 12, true);
533 	print_u16(", infmlen", buf, 14, true);
534 	print_u16(", infpoff", buf, 16, true);
535 	print_u16(", infplen", buf, 18, true);
536 	print_u16(", infhoff1", buf, 20, true);
537 	print_u16(", infhlen1", buf, 22, true);
538 	print_u16(", infgoff1", buf, 24, true);
539 	print_u16(", infglen1", buf, 26, true);
540 	print_u16(", infhoff2", buf, 28, true);
541 	print_u16(", infhlen2", buf, 30, true);
542 	print_u16(", infgoff2", buf, 32, true);
543 	print_u16(", infglen2", buf, 34, true);
544 	print_u16(", infhoff3", buf, 36, true);
545 	print_u16(", infhlen3", buf, 38, true);
546 	print_u16(", infgoff3", buf, 40, true);
547 	print_u16(", infglen3", buf, 42, true);
548 
549 	if (hdr_size > 44 && !is_empty(buf + 44, hdr_size - 44)) {
550 		printf(", ");
551 		print_quoted_hex((char *) (buf + 44), hdr_size - 44);
552 	}
553 # else /* !VERBOSE */
554 	printf(", ...");
555 # endif /* !VERBOSE */
556 
557 	printf("}");
558 
559 	/* Machine header */
560 	offs = *(uint16_t *) (buf + 12);
561 	if (!offs)
562 		goto partition_hdr;
563 
564 	hdr_size = *(uint16_t *) (buf + 14);
565 	if (hdr_size < 60)
566 		error_msg_and_fail("sthyi: machine section is too small "
567 			           "(got %hu, 60 expected)", hdr_size);
568 
569 	cur = buf + offs;
570 
571 	printf(", /* machine */ {");
572 
573 # if VERBOSE
574 	print_0x8("infmflg1", cur, 0, false);
575 	if (cur[0])
576 		printf(", ");
577 	print_0x8("infmflg2", cur, 1, false);
578 	if (cur[1])
579 		printf(", ");
580 # endif /* !VERBOSE */
581 	print_0x8("infmval1", cur, 2, true);
582 
583 	bool cnt_valid = cur[2] & 0x80;
584 # if VERBOSE
585 	bool id_valid = cur[2] & 0x40;
586 	bool name_valid = cur[2] & 0x20;
587 
588 	printf(" /* processor count validity: %d, machine ID validity: %d, "
589 	       "machine name validity: %d",
590 	       !!cnt_valid, !!id_valid, !!name_valid);
591 	if (cur[2] & 0x1F)
592 		printf(", %#hhx - ???", cur[2] & 0x1F);
593 	printf(" */");
594 	print_0x8(", infmval2", cur, 3, false);
595 # endif /* !VERBOSE */
596 
597 	print_u16(", infmscps", cur, 4,  cnt_valid);
598 	print_u16(", infmdcps", cur, 6,  cnt_valid);
599 	print_u16(", infmsifl", cur, 8,  cnt_valid);
600 	print_u16(", infmdifl", cur, 10, cnt_valid);
601 
602 # if VERBOSE
603 	print_ebcdic(", infmname", cur, 12, 8, name_valid, false);
604 
605 	print_ebcdic(", infmtype", cur, 20, 4,  id_valid, false);
606 	print_ebcdic(", infmmanu", cur, 24, 16, id_valid, false);
607 	print_ebcdic(", infmseq",  cur, 40, 16, id_valid, false);
608 	print_ebcdic(", infmpman", cur, 56, 4,  id_valid, false);
609 
610 	if (hdr_size > 60 && !is_empty(cur + 60, hdr_size - 60)) {
611 		printf(", ");
612 		print_quoted_hex((char *) (cur + 60), hdr_size - 60);
613 	}
614 # else /* !VERBOSE */
615 	printf(", ...");
616 # endif /* !VERBOSE */
617 
618 	printf("}");
619 
620 partition_hdr:
621 	/* Partition header */
622 	offs = *(uint16_t *) (buf + 16);
623 	if (!offs)
624 		goto hv_hdr;
625 
626 	hdr_size = *(uint16_t *) (buf + 18);
627 	if (hdr_size < 56)
628 		error_msg_and_fail("sthyi: partition section is too small "
629 			           "(got %hu, 56 expected)", hdr_size);
630 
631 	cur = buf + offs;
632 
633 	print_0x8(", /* partition */ {infpflg1", cur, 0, true);
634 	mt = !!(cur[0] & 0x80);
635 # if VERBOSE
636 	if (cur[0]) {
637 		bool printed = false;
638 
639 		printf(" /* ");
640 		if (cur[0] & 0x80) {
641 			printf("0x80 - multithreading is enabled");
642 			printed = true;
643 		}
644 		if (cur[0] & 0x7F) {
645 			if (printed)
646 				printf(", ");
647 			printf("%#hhx - ???", cur[0] & 0x7F);
648 		}
649 		printf(" */");
650 	}
651 	print_0x8(", infpflg2", cur, 1, false);
652 # endif /* !VERBOSE */
653 	print_0x8(", infpval1", cur, 2, true);
654 
655 	bool pcnt_valid  = cur[2] & 0x80;
656 	bool pid_valid   = cur[2] & 0x10;
657 # if VERBOSE
658 	bool pwcap_valid = cur[2] & 0x40;
659 	bool pacap_valid = cur[2] & 0x20;
660 	bool lpar_valid  = cur[2] & 0x08;
661 # endif /* !VERBOSE */
662 
663 # if VERBOSE
664 	printf(" /* processor count validity: %d, partition weight-based "
665 	       "capacity validity: %d, partition absolute capacity validity: "
666 	       "%d, partition ID validity: %d, LPAR group absolute capacity "
667 	       "capping information validity: %d",
668 	       !!pcnt_valid, !!pwcap_valid, !!pacap_valid, !!pid_valid,
669 	       !!lpar_valid);
670 	if (cur[2] & 0x7)
671 		printf(", %#hhx - ???", cur[2] & 0x7);
672 	printf(" */");
673 
674 	print_0x8(", infpval2", cur, 3, false);
675 # endif /* !VERBOSE */
676 
677 	print_u16(", infppnum", cur, 4, pid_valid);
678 
679 	print_u16(", infpscps", cur, 6,  pcnt_valid);
680 	print_u16(", infpdcps", cur, 8,  pcnt_valid);
681 	print_u16(", infpsifl", cur, 10, pcnt_valid);
682 	print_u16(", infpdifl", cur, 12, pcnt_valid);
683 
684 # if VERBOSE
685 	if (cur[14] || cur[15])
686 		printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\"",
687 		       cur[14], cur[15]);
688 # endif /* !VERBOSE */
689 
690 	print_ebcdic(", infppnam", cur, 16, 8, pid_valid, false);
691 
692 # if VERBOSE
693 	print_weight(", infpwbcp", cur, 24, pwcap_valid);
694 	print_weight(", infpabcp", cur, 28, pacap_valid);
695 	print_weight(", infpwbif", cur, 32, pwcap_valid);
696 	print_weight(", infpabif", cur, 36, pacap_valid);
697 
698 	if (print_ebcdic(", infplgnm", cur, 40, 8, false, false)) {
699 
700 		print_weight(", infplgcp", cur, 48, false);
701 		print_weight(", infplgif", cur, 52, false);
702 	} else {
703 		if (lpar_valid) {
704 			printf(", infplgnm=");
705 			print_quoted_hex((char *) (cur + 40), 8);
706 		}
707 
708 		print_x32(", infplgcp", cur, 48, false);
709 		print_x32(", infplgif", cur, 52, false);
710 	}
711 
712 	if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) {
713 		printf(", ");
714 		print_quoted_hex((char *) (cur + 56), hdr_size - 56);
715 	}
716 # else /* !VERBOSE */
717 	printf(", ...");
718 # endif /* !VERBOSE */
719 
720 	printf("}");
721 
722 hv_hdr:
723 	/* Hypervisor/guest headers */
724 	print_hypervisor_header(buf, 1, 20, 22, mt);
725 	print_guest_header(buf, 1, 24, 26);
726 	print_hypervisor_header(buf, 2, 28, 30, mt);
727 	print_guest_header(buf, 2, 32, 34);
728 	print_hypervisor_header(buf, 3, 36, 38, mt);
729 	print_guest_header(buf, 3, 40, 42);
730 
731 	printf("}");
732 }
733 
734 int
main(void)735 main(void)
736 {
737 	static const kernel_ulong_t bogus_func =
738 		(kernel_ulong_t) 0xdeafbeefdeadc0deULL;
739 	static const kernel_ulong_t bogus_resp_buf =
740 		(kernel_ulong_t) 0xfacefeedac0ffeedULL;
741 	static const kernel_ulong_t bogus_ret_code =
742 		(kernel_ulong_t) 0xf00dfa57decaffedULL;
743 	static const kernel_ulong_t bogus_flags =
744 		(kernel_ulong_t) 0xfee1deadfa57beefULL;
745 
746 	unsigned char *buf = tail_alloc(PAGE_SIZE);
747 	uint64_t *ret = tail_alloc(sizeof(*ret));
748 
749 	long rc;
750 
751 	rc = syscall(__NR_s390_sthyi, 0, 0, 0, 0);
752 	printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, NULL, NULL, 0) = %s\n",
753 	       sprintrc(rc));
754 
755 	rc = syscall(__NR_s390_sthyi, bogus_func, bogus_resp_buf,
756 		     bogus_ret_code, bogus_flags);
757 	printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %#llx, %#llx, %#llx) = "
758 	       "%s\n",
759 	       (unsigned long long) bogus_func,
760 	       (unsigned long long) bogus_resp_buf,
761 	       (unsigned long long) bogus_ret_code,
762 	       (unsigned long long) bogus_flags,
763 	       sprintrc(rc));
764 
765 	rc = syscall(__NR_s390_sthyi, bogus_func, buf, ret, 0);
766 	printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %p, %p, 0) = %s\n",
767 	       (unsigned long long) bogus_func, buf, ret, sprintrc(rc));
768 
769 	rc = syscall(__NR_s390_sthyi, 0, buf, ret, 0);
770 	if (rc)
771 		error_msg_and_fail("syscall(__NR_s390_sthyi, 0, buf, ret, 0) "
772 				   "returned unexpected value of %ld", rc);
773 
774 	printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, ");
775 	print_sthyi(buf);
776 	printf(", [0], 0) = 0\n");
777 
778 	puts("+++ exited with 0 +++");
779 	return 0;
780 }
781 
782 #else
783 
784 SKIP_MAIN_UNDEFINED("HAVE_ICONV_H && HAVE_ICONV_OPEN && __NR_s390_sthyi")
785 
786 #endif
787