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