* configure.ac (AC_CHECK_FUNCS): Add iconv_open. (AC_CHECK_HEADERS): Add iconv.h. * tests/s390_sthyi-v.c: New file. * tests/s390_sthyi.c: Likewise. * tests/.gitignore: Add s390_sthyi, s390_sthyi-v. * tests/pure_executables.list: Likewise. * tests/gen_tests.in (s390_sthyi, s390_sthyi): New tests. --- configure.ac | 2 + tests/.gitignore | 2 + tests/gen_tests.in | 2 + tests/pure_executables.list | 2 + tests/s390_sthyi-v.c | 2 + tests/s390_sthyi.c | 786 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 796 insertions(+) create mode 100644 tests/s390_sthyi-v.c create mode 100644 tests/s390_sthyi.c diff --git a/configure.ac b/configure.ac index d962f19..001dfa8 100644 --- a/configure.ac +++ b/configure.ac @@ -287,6 +287,7 @@ AC_CHECK_FUNCS(m4_normalize([ fstatat ftruncate futimens + iconv_open if_indextoname open64 prctl @@ -394,6 +395,7 @@ AC_CHECK_HEADERS(m4_normalize([ asm/sysmips.h bluetooth/bluetooth.h elf.h + iconv.h inttypes.h linux/bsg.h linux/cryptouser.h diff --git a/tests/.gitignore b/tests/.gitignore index 4c54589..19aa493 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -357,6 +357,8 @@ rt_sigsuspend rt_sigtimedwait rt_tgsigqueueinfo run_expect_termsig +s390_sthyi +s390_sthyi-v sched_get_priority_mxx sched_rr_get_interval sched_xetaffinity diff --git a/tests/gen_tests.in b/tests/gen_tests.in index 93b1687..968f6e4 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -303,6 +303,8 @@ rt_sigreturn -esignal='!USR1' rt_sigsuspend -a20 -esignal=none rt_sigtimedwait -a38 rt_tgsigqueueinfo -esignal=none +s390_sthyi -a47 +s390_sthyi-v -e trace=s390_sthyi -a47 sched test_trace_expr times -e/sched sched_get_priority_mxx -a33 -e trace=sched_get_priority_min,sched_get_priority_max sched_rr_get_interval -a31 diff --git a/tests/pure_executables.list b/tests/pure_executables.list index 8f5ff31..d8b997d 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -296,6 +296,8 @@ rt_sigreturn rt_sigsuspend rt_sigtimedwait rt_tgsigqueueinfo +s390_sthyi +s390_sthyi-v sched_get_priority_mxx sched_rr_get_interval sched_xetaffinity diff --git a/tests/s390_sthyi-v.c b/tests/s390_sthyi-v.c new file mode 100644 index 0000000..8605520 --- /dev/null +++ b/tests/s390_sthyi-v.c @@ -0,0 +1,2 @@ +#define VERBOSE 1 +#include "s390_sthyi.c" diff --git a/tests/s390_sthyi.c b/tests/s390_sthyi.c new file mode 100644 index 0000000..8b241dd --- /dev/null +++ b/tests/s390_sthyi.c @@ -0,0 +1,786 @@ +/* + * Check decoding of s390_sthyi syscall. + * + * Copyright (c) 2018 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" +#include <asm/unistd.h> + +#if defined HAVE_ICONV_H && defined HAVE_ICONV_OPEN && defined __NR_s390_sthyi + +# include <errno.h> +# include <iconv.h> +# include <inttypes.h> +# include <stdbool.h> +# include <stdint.h> +# include <stdio.h> +# include <unistd.h> + +# include <sys/user.h> + +# define EBCDIC_MAX_LEN 16 + +# ifndef VERBOSE +# define VERBOSE 0 +# endif + +static bool +print_0x8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero) +{ + if (!zero && !buf[offs]) + return false; + + printf("%s=%#02hhx", prefix, buf[offs]); + + return true; +} + +static bool +print_u8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero) +{ + if (!zero && !buf[offs]) + return false; + + printf("%s=%hhu", prefix, buf[offs]); + + return true; +} + +static bool +print_u16(const char *prefix, unsigned char *buf, unsigned int offs, bool zero) +{ + uint16_t val = *(uint16_t *) (buf + offs); + + if (!zero && !val) + return false; + + printf("%s=%" PRIu16, prefix, val); + + return true; +} + +static bool +print_x32(const char *prefix, unsigned char *buf, unsigned int offs, bool zero) +{ + uint32_t val = *(uint32_t *) (buf + offs); + + if (!zero && !val) + return false; + + printf("%s=%#" PRIx32, prefix, val); + + return true; +} + +static bool +print_weight(const char *prefix, unsigned char *buf, unsigned int offs, + bool zero) +{ + uint32_t val = *(uint32_t *) (buf + offs); + + if (print_x32(prefix, buf, offs, zero)) { + if (val) + printf(" /* %u %u/65536 cores */", + val >> 16, val & 0xFFFF); + else + printf(" /* unlimited */"); + + return true; + } + + return false; +} + +static char * +ebcdic2ascii(unsigned char *ebcdic, size_t size) +{ + static char ascii_buf[EBCDIC_MAX_LEN]; + + char *ebcdic_pos = (char *) ebcdic; + char *ascii_pos = ascii_buf; + size_t ebcdic_left = size; + size_t ascii_left = size; + size_t ret; + + iconv_t cd = iconv_open("ASCII", "EBCDICUS"); + + if (size > sizeof(ascii_buf)) + error_msg_and_fail("ebcdic2ascii: EBCDIC string is too big: " + "%zu (maximum is %zu)", + size, sizeof(ascii_buf)); + if (cd == (iconv_t) -1) + perror_msg_and_fail("ebcdic2ascii: unable to allocate a " + "conversion descriptior for converting " + "EBCDIC to ASCII"); + + while ((ret = iconv(cd, &ebcdic_pos, &ebcdic_left, + &ascii_pos, &ascii_left)) == (size_t) -1) { + switch (errno) { + case EILSEQ: + case EINVAL: /* That one is quite unexpected, actually */ + if (!ebcdic_left || !ascii_left) + goto ebcdic2ascii_end; + + *ascii_pos++ = ' '; + ebcdic_pos++; + ebcdic_left--; + + break; + + case E2BIG: + perror_msg_and_fail("ebcdic2ascii: ran out of " + "ASCII buffer unexpectedly"); + default: + perror_msg_and_fail("ebcdic2ascii: unexpected error"); + } + } + +ebcdic2ascii_end: + iconv_close(cd); + + if (ebcdic_left != ascii_left) + error_msg_and_fail("ebcdic2ascii: ASCII string differs in size " + "from EBCDIC"); + + return ascii_buf; +} + +# if VERBOSE +static bool +is_empty(unsigned char *ptr, size_t size) +{ + size_t i; + + for (i = 0; !*ptr && i < size; ptr++, i++) + ; + + return i == size; +} +# endif /* !VERBOSE */ + +static bool +print_ebcdic(const char *prefix, unsigned char *addr, unsigned int offs, + size_t size, bool zero, bool blank) +{ + const char *ascii = ebcdic2ascii(addr + offs, size); + + if (!zero) { + size_t i; + + for (i = 0; (addr[offs + i] == (blank ? 64 : 0)) && (i < size); + i++) + ; + + if (i == size) + return false; + } + + printf("%s=", prefix); + print_quoted_hex((char *) (addr + offs), size); + printf(" /* "); + print_quoted_memory(ascii, size); + printf(" */"); + + return true; +} + +static void +print_hypervisor_header(unsigned char *buf, int level, unsigned int offs_pos, + unsigned int len_pos, bool mt) +{ + uint16_t offs = *(uint16_t *) (buf + offs_pos); + uint16_t hdr_size = *(uint16_t *) (buf + len_pos); + unsigned char *cur; + + if (!offs) + return; + if (hdr_size < 32) + error_msg_and_fail("sthyi: hypervisor %d section is too small " + "(got %hu, 32 expected)", level, hdr_size); + + cur = buf + offs; + + printf(", /* hypervisor %d */ {infyflg1", level); + print_0x8("", cur, 0, true); +# if VERBOSE + if (cur[0]) { + bool printed = false; + + printf(" /* "); + if (cur[0] & 0x80) { + printf("0x80 - guest CPU usage had limiting is using " + "the consumption method"); + printed = true; + } + if (cur[0] & 0x40) { + if (printed) + printf(", "); + printf("0x40 - LIMITHARD caps use prorated core time " + "for capping"); + printed = true; + } + if (cur[0] & 0x3F) { + if (printed) + printf(", "); + printf("%#hhx - ???", cur[0] & 0x3F); + } + printf(" */"); + } + + print_0x8(", infyflg2", cur, 1, false); + print_0x8(", infyval1", cur, 2, false); + print_0x8(", infyval2", cur, 3, false); + + print_u8(", infytype", cur, 4, true); + if (cur[4] == 1) + printf(" /* z/VM is the hypervisor */"); + else + printf(" /* unknown hypervisor type */"); + + if (cur[5]) + printf(", reserved_1__=\"\\x%#02hhx\"", cur[5]); + + print_u8(", infycpt", cur, 6, mt); + print_u8(", infyiflt", cur, 7, mt); +# endif /* !VERBOSE */ + + print_ebcdic(", infysyid", cur, 8, 8, VERBOSE, true); + print_ebcdic(", infyclnm", cur, 16, 8, VERBOSE, true); + + print_u16(", infyscps", cur, 24, VERBOSE); + print_u16(", infydcps", cur, 26, VERBOSE); + print_u16(", infysifl", cur, 28, VERBOSE); + print_u16(", infydifl", cur, 30, VERBOSE); + +# if VERBOSE + if (hdr_size > 32 && !is_empty(cur + 32, hdr_size - 32)) { + printf(", "); + print_quoted_hex((char *) (cur + 32), hdr_size - 32); + } +# else /* !VERBOSE */ + printf(", ..."); +# endif /* !VERBOSE */ + + printf("}"); +} + +static void +print_guest_header(unsigned char *buf, int level, unsigned int offs_pos, + unsigned int len_pos) +{ + uint16_t offs = *(uint16_t *) (buf + offs_pos); + uint16_t hdr_size = *(uint16_t *) (buf + len_pos); + unsigned char *cur; + + if (!offs) + return; + if (hdr_size < 56) + error_msg_and_fail("sthyi: guest %d section is too small " + "(got %hu, 56 expected)", level, hdr_size); + + cur = buf + offs; + + printf(", /* guest %d */ {infgflg1", level); + print_0x8("", cur, 0, true); +# if VERBOSE + if (cur[0]) { + bool printed = false; + + printf(" /* "); + if (cur[0] & 0x80) { + printf("0x80 - guest is mobility enabled"); + printed = true; + } + if (cur[0] & 0x40) { + if (printed) + printf(", "); + printf("0x40 - guest has multiple virtual CPU types"); + printed = true; + } + if (cur[0] & 0x20) { + if (printed) + printf(", "); + printf("0x20 - guest CP dispatch type has LIMITHARD " + "cap"); + printed = true; + } + if (cur[0] & 0x10) { + if (printed) + printf(", "); + printf("0x10 - guest IFL dispatch type has LIMITHARD " + "cap"); + printed = true; + } + if (cur[0] & 0x08) { + if (printed) + printf(", "); + printf("0x08 - virtual CPs are thread dispatched"); + printed = true; + } + if (cur[0] & 0x04) { + if (printed) + printf(", "); + printf("0x04 - virtual IFLs are thread dispatched"); + printed = true; + } + if (cur[0] & 0x3) { + if (printed) + printf(", "); + printf("%#hhx - ???", cur[0] & 0x3); + } + printf(" */"); + } + + print_0x8(", infgflg2", cur, 1, false); + print_0x8(", infgval1", cur, 2, false); + print_0x8(", infgval2", cur, 3, false); +# endif /* !VERBOSE */ + + print_ebcdic(", infgusid", cur, 4, 8, true, false); + + print_u16(", infgscps", cur, 12, VERBOSE); + print_u16(", infgdcps", cur, 14, VERBOSE); + +# if VERBOSE + print_u8(", infgcpdt", cur, 16, true); + if (cur[16] == 0) + printf(" /* General Purpose (CP) */"); + else + printf(" /* unknown */"); + + if (cur[17] || cur[18] || cur[19]) + printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"", + cur[17], cur[18], cur[19]); +# endif /* !VERBOSE */ + + print_weight(", infgcpcc", cur, 20, VERBOSE); + + print_u16(", infgsifl", cur, 24, VERBOSE); + print_u16(", infgdifl", cur, 26, VERBOSE); + +# if VERBOSE + print_u8(", infgifdt", cur, 28, true); + if (cur[28] == 0) + printf(" /* General Purpose (CP) */"); + else if (cur[28] == 3) + printf(" /* Integrated Facility for Linux (IFL) */"); + else + printf(" /* unknown */"); + + if (cur[29] || cur[30] || cur[31]) + printf(", reserved_2__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"", + cur[29], cur[30], cur[31]); +# endif /* !VERBOSE */ + + print_weight(", infgifcc", cur, 32, VERBOSE); + + print_0x8(", infgpflg", cur, 36, true); +# if VERBOSE + if (cur[36]) { + bool printed = false; + + printf(" /* "); + if (cur[36] & 0x80) { + printf("0x80 - CPU pool's CP virtual type has " + "LIMITHARD cap"); + printed = true; + } + if (cur[36] & 0x40) { + if (printed) + printf(", "); + printf("0x40 - CPU pool's CP virtual type has " + "CAPACITY cap"); + printed = true; + } + if (cur[36] & 0x20) { + if (printed) + printf(", "); + printf("0x20 - CPU pool's IFL virtual type has " + "LIMITHARD cap"); + printed = true; + } + if (cur[36] & 0x10) { + if (printed) + printf(", "); + printf("0x10 - CPU pool's IFL virtual type has " + "CAPACITY cap"); + printed = true; + } + if (cur[36] & 0x08) { + if (printed) + printf(", "); + printf("0x08 - CPU pool uses prorated core time"); + printed = true; + } + if (cur[36] & 0x7) { + if (printed) + printf(", "); + printf("%#hhx - ???", cur[36] & 0x7); + } + printf(" */"); + } + + if (cur[37] || cur[38] || cur[39]) + printf(", reserved_3__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"", + cur[37], cur[38], cur[39]); + + print_ebcdic(", infgpnam", cur, 40, 8, false, true); + + print_weight(", infgpccc", cur, 48, true); + print_weight(", infgpicc", cur, 52, true); + + if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) { + printf(", "); + print_quoted_hex((char *) (cur + 56), hdr_size - 56); + } +# else /* !VERBOSE */ + printf(", ..."); +# endif /* !VERBOSE */ + + printf("}"); +} + +static void +print_sthyi(unsigned char *buf) +{ + unsigned char *cur; + uint16_t hdr_size; + uint16_t offs; + bool mt = false; + + hdr_size = *(uint16_t *) (buf + 10); + if (hdr_size < 44) + error_msg_and_fail("sthyi: header section is too small " + "(got %hu, 44 expected)", hdr_size); + + /* INFHFLG1 */ + print_0x8("{/* header */ {infhflg1", buf, 0, true); +# if VERBOSE + if (buf[0]) { + bool printed = false; + + printf(" /* "); + if (buf[0] & 0x80) { + printf("0x80 - Global Performance Data unavailable"); + printed = true; + } + if (buf[0] & 0x40) { + if (printed) + printf(", "); + printf("0x40 - One or more hypervisor levels below " + "this level does not support the STHYI " + "instruction"); + printed = true; + } + if (buf[0] & 0x20) { + if (printed) + printf(", "); + printf("0x20 - Virtualization stack is incomplete"); + printed = true; + } + if (buf[0] & 0x10) { + if (printed) + printf(", "); + printf("0x10 - Execution environment is not within a " + "logical partition"); + printed = true; + } + if (buf[0] & 0xF) { + if (printed) + printf(", "); + printf("%#hhx - ???", buf[0] & 0xF); + } + printf(" */"); + } + + print_0x8(", infhflg2", buf, 1, false); + print_0x8(", infhval1", buf, 2, false); + print_0x8(", infhval2", buf, 3, false); + + /* Reserved */ + if (buf[4] || buf[5] || buf[6]) + printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"", + buf[4], buf[5], buf[6]); + + print_u8(", infhygct", buf, 7, true); + print_u16(", infhtotl", buf, 8, true); + print_u16(", infhdln", buf, 10, true); + print_u16(", infmoff", buf, 12, true); + print_u16(", infmlen", buf, 14, true); + print_u16(", infpoff", buf, 16, true); + print_u16(", infplen", buf, 18, true); + print_u16(", infhoff1", buf, 20, true); + print_u16(", infhlen1", buf, 22, true); + print_u16(", infgoff1", buf, 24, true); + print_u16(", infglen1", buf, 26, true); + print_u16(", infhoff2", buf, 28, true); + print_u16(", infhlen2", buf, 30, true); + print_u16(", infgoff2", buf, 32, true); + print_u16(", infglen2", buf, 34, true); + print_u16(", infhoff3", buf, 36, true); + print_u16(", infhlen3", buf, 38, true); + print_u16(", infgoff3", buf, 40, true); + print_u16(", infglen3", buf, 42, true); + + if (hdr_size > 44 && !is_empty(buf + 44, hdr_size - 44)) { + printf(", "); + print_quoted_hex((char *) (buf + 44), hdr_size - 44); + } +# else /* !VERBOSE */ + printf(", ..."); +# endif /* !VERBOSE */ + + printf("}"); + + /* Machine header */ + offs = *(uint16_t *) (buf + 12); + if (!offs) + goto partition_hdr; + + hdr_size = *(uint16_t *) (buf + 14); + if (hdr_size < 60) + error_msg_and_fail("sthyi: machine section is too small " + "(got %hu, 60 expected)", hdr_size); + + cur = buf + offs; + + printf(", /* machine */ {"); + +# if VERBOSE + print_0x8("infmflg1", cur, 0, false); + if (cur[0]) + printf(", "); + print_0x8("infmflg2", cur, 1, false); + if (cur[1]) + printf(", "); +# endif /* !VERBOSE */ + print_0x8("infmval1", cur, 2, true); + + bool cnt_valid = cur[2] & 0x80; +# if VERBOSE + bool id_valid = cur[2] & 0x40; + bool name_valid = cur[2] & 0x20; + + printf(" /* processor count validity: %d, machine ID validity: %d, " + "machine name validity: %d", + !!cnt_valid, !!id_valid, !!name_valid); + if (cur[2] & 0x1F) + printf(", %#hhx - ???", cur[2] & 0x1F); + printf(" */"); + print_0x8(", infmval2", cur, 3, false); +# endif /* !VERBOSE */ + + print_u16(", infmscps", cur, 4, cnt_valid); + print_u16(", infmdcps", cur, 6, cnt_valid); + print_u16(", infmsifl", cur, 8, cnt_valid); + print_u16(", infmdifl", cur, 10, cnt_valid); + +# if VERBOSE + print_ebcdic(", infmname", cur, 12, 8, name_valid, false); + + print_ebcdic(", infmtype", cur, 20, 4, id_valid, false); + print_ebcdic(", infmmanu", cur, 24, 16, id_valid, false); + print_ebcdic(", infmseq", cur, 40, 16, id_valid, false); + print_ebcdic(", infmpman", cur, 56, 4, id_valid, false); + + if (hdr_size > 60 && !is_empty(cur + 60, hdr_size - 60)) { + printf(", "); + print_quoted_hex((char *) (cur + 60), hdr_size - 60); + } +# else /* !VERBOSE */ + printf(", ..."); +# endif /* !VERBOSE */ + + printf("}"); + +partition_hdr: + /* Partition header */ + offs = *(uint16_t *) (buf + 16); + if (!offs) + goto hv_hdr; + + hdr_size = *(uint16_t *) (buf + 18); + if (hdr_size < 56) + error_msg_and_fail("sthyi: partition section is too small " + "(got %hu, 56 expected)", hdr_size); + + cur = buf + offs; + + print_0x8(", /* partition */ {infpflg1", cur, 0, true); + mt = !!(cur[0] & 0x80); +# if VERBOSE + if (cur[0]) { + bool printed = false; + + printf(" /* "); + if (cur[0] & 0x80) { + printf("0x80 - multithreading is enabled"); + printed = true; + } + if (cur[0] & 0x7F) { + if (printed) + printf(", "); + printf("%#hhx - ???", cur[0] & 0x7F); + } + printf(" */"); + } + print_0x8(", infpflg2", cur, 1, false); +# endif /* !VERBOSE */ + print_0x8(", infpval1", cur, 2, true); + + bool pcnt_valid = cur[2] & 0x80; + bool pid_valid = cur[2] & 0x10; +# if VERBOSE + bool pwcap_valid = cur[2] & 0x40; + bool pacap_valid = cur[2] & 0x20; + bool lpar_valid = cur[2] & 0x08; +# endif /* !VERBOSE */ + +# if VERBOSE + printf(" /* processor count validity: %d, partition weight-based " + "capacity validity: %d, partition absolute capacity validity: " + "%d, partition ID validity: %d, LPAR group absolute capacity " + "capping information validity: %d", + !!pcnt_valid, !!pwcap_valid, !!pacap_valid, !!pid_valid, + !!lpar_valid); + if (cur[2] & 0x7) + printf(", %#hhx - ???", cur[2] & 0x7); + printf(" */"); + + print_0x8(", infpval2", cur, 3, false); +# endif /* !VERBOSE */ + + print_u16(", infppnum", cur, 4, pid_valid); + + print_u16(", infpscps", cur, 6, pcnt_valid); + print_u16(", infpdcps", cur, 8, pcnt_valid); + print_u16(", infpsifl", cur, 10, pcnt_valid); + print_u16(", infpdifl", cur, 12, pcnt_valid); + +# if VERBOSE + if (cur[14] || cur[15]) + printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\"", + cur[14], cur[15]); +# endif /* !VERBOSE */ + + print_ebcdic(", infppnam", cur, 16, 8, pid_valid, false); + +# if VERBOSE + print_weight(", infpwbcp", cur, 24, pwcap_valid); + print_weight(", infpabcp", cur, 28, pacap_valid); + print_weight(", infpwbif", cur, 32, pwcap_valid); + print_weight(", infpabif", cur, 36, pacap_valid); + + if (print_ebcdic(", infplgnm", cur, 40, 8, false, false)) { + + print_weight(", infplgcp", cur, 48, false); + print_weight(", infplgif", cur, 52, false); + } else { + if (lpar_valid) { + printf(", infplgnm="); + print_quoted_hex((char *) (cur + 40), 8); + } + + print_x32(", infplgcp", cur, 48, false); + print_x32(", infplgif", cur, 52, false); + } + + if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) { + printf(", "); + print_quoted_hex((char *) (cur + 56), hdr_size - 56); + } +# else /* !VERBOSE */ + printf(", ..."); +# endif /* !VERBOSE */ + + printf("}"); + +hv_hdr: + /* Hypervisor/guest headers */ + print_hypervisor_header(buf, 1, 20, 22, mt); + print_guest_header(buf, 1, 24, 26); + print_hypervisor_header(buf, 2, 28, 30, mt); + print_guest_header(buf, 2, 32, 34); + print_hypervisor_header(buf, 3, 36, 38, mt); + print_guest_header(buf, 3, 40, 42); + + printf("}"); +} + +int +main(void) +{ + static const kernel_ulong_t bogus_func = + (kernel_ulong_t) 0xdeafbeefdeadc0deULL; + static const kernel_ulong_t bogus_resp_buf = + (kernel_ulong_t) 0xfacefeedac0ffeedULL; + static const kernel_ulong_t bogus_ret_code = + (kernel_ulong_t) 0xf00dfa57decaffedULL; + static const kernel_ulong_t bogus_flags = + (kernel_ulong_t) 0xfee1deadfa57beefULL; + + unsigned char *buf = tail_alloc(PAGE_SIZE); + uint64_t *ret = tail_alloc(sizeof(*ret)); + + long rc; + + rc = syscall(__NR_s390_sthyi, 0, 0, 0, 0); + printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, NULL, NULL, 0) = %s\n", + sprintrc(rc)); + + rc = syscall(__NR_s390_sthyi, bogus_func, bogus_resp_buf, + bogus_ret_code, bogus_flags); + printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %#llx, %#llx, %#llx) = " + "%s\n", + (unsigned long long) bogus_func, + (unsigned long long) bogus_resp_buf, + (unsigned long long) bogus_ret_code, + (unsigned long long) bogus_flags, + sprintrc(rc)); + + rc = syscall(__NR_s390_sthyi, bogus_func, buf, ret, 0); + printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %p, %p, 0) = %s\n", + (unsigned long long) bogus_func, buf, ret, sprintrc(rc)); + + rc = syscall(__NR_s390_sthyi, 0, buf, ret, 0); + if (rc) + error_msg_and_fail("syscall(__NR_s390_sthyi, 0, buf, ret, 0) " + "returned unexpected value of %ld", rc); + + printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, "); + print_sthyi(buf); + printf(", [0], 0) = 0\n"); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("HAVE_ICONV_H && HAVE_ICONV_OPEN && __NR_s390_sthyi") + +#endif -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-s390" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html