* s390.c: New file. * Makefile.am (strace_SOURCES): Add it. * linux/s390/syscallent.h ([380]): Change decoder to s390_sthyi. * linux/s390x/syscallent.h: Likewise. * xlat/s390_sthyi_function_codes.in: New file. --- Makefile.am | 1 + linux/s390/syscallent.h | 1 + linux/s390x/syscallent.h | 1 + s390.c | 1033 +++++++++++++++++++++++++++++++++++++ xlat/s390_sthyi_function_codes.in | 1 + 5 files changed, 1037 insertions(+) create mode 100644 s390.c create mode 100644 xlat/s390_sthyi_function_codes.in diff --git a/Makefile.am b/Makefile.am index 2515876..02e2f3e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -267,6 +267,7 @@ strace_SOURCES = \ rtnl_rule.c \ rtnl_tc.c \ rtnl_tc_action.c \ + s390.c \ sched.c \ sched_attr.h \ scsi.c \ diff --git a/linux/s390/syscallent.h b/linux/s390/syscallent.h index 5482c53..dd1fbb1 100644 --- a/linux/s390/syscallent.h +++ b/linux/s390/syscallent.h @@ -409,6 +409,7 @@ [377] = { 6, TD, SEN(pwritev2), "pwritev2" }, [378] = { 2, 0, SEN(printargs), "s390_guarded_storage" }, [379] = { 5, TD|TF|TSTA, SEN(statx), "statx" }, +[380] = { 4, 0, SEN(s390_sthyi), "s390_sthyi" }, #define SYS_socket_subcall 400 #include "subcall.h" diff --git a/linux/s390x/syscallent.h b/linux/s390x/syscallent.h index 36b1aef..fe5b252 100644 --- a/linux/s390x/syscallent.h +++ b/linux/s390x/syscallent.h @@ -393,6 +393,7 @@ [377] = { 6, TD, SEN(pwritev2), "pwritev2" }, [378] = { 2, 0, SEN(printargs), "s390_guarded_storage" }, [379] = { 5, TD|TF|TSTA, SEN(statx), "statx" }, +[380] = { 4, 0, SEN(s390_sthyi), "s390_sthyi" }, #define SYS_socket_subcall 400 #include "subcall.h" diff --git a/s390.c b/s390.c new file mode 100644 index 0000000..daaf6a0 --- /dev/null +++ b/s390.c @@ -0,0 +1,1033 @@ +/* + * s390-specific syscalls decoders. + * + * 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 "defs.h" + +#if defined S390 || defined S390X + +#include <sys/user.h> + +#include "print_fields.h" + +#include "xlat/s390_sthyi_function_codes.h" + +/* + * Since, for some reason, kernel doesn't expose all these nice constants and + * structures in UAPI, we have to re-declare them ourselves. + */ + +/** + * "The header section is placed at the beginning of the response buffer and + * identifies the location and length of all other sections. Valid sections have + * nonzero offset values in the header. Each section provides information about + * validity of fields within that section." + */ +struct sthyi_hdr { + /** + * Header Flag Byte 1 - These flag settings indicate the environment + * that the instruction was executed in and may influence the value of + * the validity bits. The validity bits, and not these flags, should be + * used to determine if a field is valid. + * - 0x80 - Global Performance Data unavailable + * - 0x40 - One or more hypervisor levels below this level does not + * support the STHYI instruction. When this flag is set the + * value of INFGPDU is not meaningful because the state of the + * Global Performance Data setting cannot be determined. + * - 0x20 - Virtualization stack is incomplete. This bit indicates one + * of two cases: + * - One or more hypervisor levels does not support the STHYI + * instruction. For this case, INFSTHYI will also be set. + * - There were more than three levels of guest/hypervisor information + * to report. + * - 0x10 - Execution environment is not within a logical partition. + */ + uint8_t infhflg1; + uint8_t infhflg2; /**< Header Flag Byte 2 reserved for IBM(R) use */ + uint8_t infhval1; /**< Header Validity Byte 1 reserved for IBM use */ + uint8_t infhval2; /**< Header Validity Byte 2 reserved for IBM use */ + char reserved_1__[3]; /**< Reserved for future IBM use */ + uint8_t infhygct; /**< Count of Hypervisor and Guest Sections */ + uint16_t infhtotl; /**< Total length of response buffer */ + uint16_t infhdln; /**< Length of Header Section mapped by INF0HDR */ + uint16_t infmoff; /**< Offset to Machine Section mapped by INF0MAC */ + uint16_t infmlen; /**< Length of Machine Section */ + uint16_t infpoff; /**< Offset to Partition Section mapped by INF0PAR */ + uint16_t infplen; /**< Length of Partition Section */ + uint16_t infhoff1; /**< Offset to Hypervisor Section1 mapped by INF0HYP */ + uint16_t infhlen1; /**< Length of Hypervisor Section1 */ + uint16_t infgoff1; /**< Offset to Guest Section1 mapped by INF0GST */ + uint16_t infglen1; /**< Length of Guest Section1 */ + uint16_t infhoff2; /**< Offset to Hypervisor Section2 mapped by INF0HYP */ + uint16_t infhlen2; /**< Length of Hypervisor Section2 */ + uint16_t infgoff2; /**< Offset to Guest Section2 mapped by INF0GST */ + uint16_t infglen2; /**< Length of Guest Section2 */ + uint16_t infhoff3; /**< Offset to Hypervisor Section3 mapped by INF0HYP */ + uint16_t infhlen3; /**< Length of Hypervisor Section3 */ + uint16_t infgoff3; /**< Offset to Guest Section3 mapped by INF0GST */ + uint16_t infglen3; /**< Length of Guest Section3 */ + /* 44 bytes in total */ +} ATTRIBUTE_PACKED; + +struct sthyi_machine { + uint8_t infmflg1; /**< Machine Flag Byte 1 reserved for IBM use */ + uint8_t infmflg2; /**< Machine Flag Byte 2 reserved for IBM use */ + /** + * Machine Validity Byte 1 + * - 0x80 - Processor Count Validity. When this bit is on, it indicates + * that INFMSCPS, INFMDCPS, INFMSIFL, and INFMDIFL contain + * valid counts. The validity bit may be off when: + * - STHYI support is not available on a lower level hypervisor, or + * - Global Performance Data is not enabled. + * - 0x40 - Machine ID Validity. This bit being on indicates that a + * SYSIB 1.1.1 was obtained from STSI and information reported + * in the following fields is valid: INFMTYPE, INFMMANU, + * INFMSEQ, and INFMPMAN. + * - 0x20 - Machine Name Validity. This bit being on indicates that the + * INFMNAME field is valid. + */ + uint8_t infmval1; + uint8_t infmval2; /**< Machine Validity Byte 2 reserved for IBM use */ + /** + * Number of shared CPs configured in the machine or in the physical + * partition if the system is physically partitioned. + */ + uint16_t infmscps; + /** + * Number of dedicated CPs configured in this machine or in the physical + * partition if the system is physically partitioned. + */ + uint16_t infmdcps; + /** + * Number of shared IFLs configured in this machine or in the physical + * partition if the system is physically partitioned. + */ + uint16_t infmsifl; + /** + * Number of dedicated IFLs configured in this machine or in the + * physical partition if the system is physically partitioned. + */ + uint16_t infmdifl; + char infmname[8]; /**< EBCDIC Machine Name */ + char infmtype[4]; /**< EBCDIC Type */ + char infmmanu[16]; /**< EBCDIC Manufacturer */ + char infmseq[16]; /**< EBCDIC Sequence Code */ + char infmpman[4]; /**< EBCDIC Plant of Manufacture */ + /* 60 bytes in total*/ +} ATTRIBUTE_PACKED; + +struct sthyi_partition { + /** + * Partition Flag Byte 1 + * - 0x80 - Multithreading (MT) is enabled. + */ + uint8_t infpflg1; + /** Partition Flag Byte 2 reserved for IBM use */ + uint8_t infpflg2; + /** + * Partition Validity Byte 1 + * - 0x80 - Processor count validity. This bit being on indicates that + * INFPSCPS, INFPDCPS, INFPSIFL, and INFPDIFL contain valid + * counts. + * - 0x40 - Partition weight-based capped capacity validity. This bit + * being on indicates that INFPWBCP and INFPWBIF are valid + * - 0x20 - Partition absolute capped capacity validity. This bit being + * on indicates that INFPABCP and INFPABIF are valid. + * - 0x10 - Partition ID validity. This bit being on indicates that a + * SYSIB 2.2.2 was obtained from STSI and information reported + * in the following fields is valid: INFPPNUM and INFPPNAM. + * - 0x08 - LPAR group absolute capacity capping information validity. + * This bit being on indicates that INFPLGNM, INFPLGCP, and + * INFPLGIF are valid. + */ + uint8_t infpval1; + /** Partition Validity Byte 2 reserved for IBM use */ + uint8_t infpval2; + /** Logical partition number */ + uint16_t infppnum; + /** + * Number of shared logical CPs configured for this partition. Count + * of cores when MT is enabled. + */ + uint16_t infpscps; + /** + * Number of dedicated logical CPs configured for this partition. Count + * of cores when MT is enabled. + */ + uint16_t infpdcps; + /** + * Number of shared logical IFLs configured for this partition. Count + * of cores when MT is enabled. + */ + uint16_t infpsifl; + /** + * Number of dedicated logical IFLs configured for this partition. + * Count of cores when MT is enabled. + */ + uint16_t infpdifl; + /** Reserved for future IBM use */ + char reserved_1__[2]; + /** EBCIDIC Logical partition name */ + char infppnam[8]; + /** + * Partition weight-based capped capacity for CPs, a scaled number where + * 0x00010000 represents one core. Zero if not capped. + */ + uint32_t infpwbcp; + /** + * Partition absolute capped capacity for CPs, a scaled number where + * 0x00010000 represents one core. Zero if not capped. + */ + uint32_t infpabcp; + /** + * Partition weight-based capped capacity for IFLs, a scaled number + * where 0x00010000 represents one core. Zero if not capped. + */ + uint32_t infpwbif; + /** + * Partition absolute capped capacity for IFLs, a scaled number where + * 0x00010000 represents one core. Zero if not capped. + */ + uint32_t infpabif; + /** + * EBCIDIC LPAR group name. Binary zeros when the partition is not in + * an LPAR group. EBCDIC and padded with blanks on the right when in a + * group. The group name is reported only when there is a group cap on + * CP or IFL CPU types and the partition has the capped CPU type. + */ + char infplgnm[8]; + /** + * LPAR group absolute capacity value for CP CPU type when nonzero. This + * field will be nonzero only when INFPLGNM is nonzero and a cap is + * defined for the LPAR group for the CP CPU type. When nonzero, + * contains a scaled number where 0x00010000 represents one core. + */ + uint32_t infplgcp; + /** + * LPAR group absolute capacity value for IFL CPU type when nonzero. + * This field will be nonzero only when INFPLGNM is nonzero and a cap + * is defined for the LPAR group for the IFL CPU type. When nonzero, + * contains a scaled number where 0x00010000 represents one core. + */ + uint32_t infplgif; + /* 56 bytes */ +} ATTRIBUTE_PACKED; + +struct sthyi_hypervisor { + /** + * Hypervisor Flag Byte 1 + * - 0x80 - Guest CPU usage hard limiting is using the consumption + * method. + * - 0x40 - If on, LIMITHARD caps use prorated core time for capping. + * If off, raw CPU time is used. + */ + uint8_t infyflg1; + uint8_t infyflg2; /**< Hypervisor Flag Byte 2 reserved for IBM use */ + uint8_t infyval1; /**< Hypervisor Validity Byte 1 reserved for IBM use */ + uint8_t infyval2; /**< Hypervisor Validity Byte 2 reserved for IBM use */ + /** + * Hypervisor Type + * - 1 - z/VM is the hypervisor. + */ + uint8_t infytype; + char reserved_1__[1]; /**< Reserved for future IBM use */ + /** + * Threads in use per CP core. Only valid when MT enabled + * (INFPFLG1 0x80 is ON). + */ + uint8_t infycpt; + /** + * Threads in use per IFL core. Only valid when MT enabled + * (INFPFLG1 0x80 is ON). + */ + uint8_t infyiflt; + /** + * EBCID System Identifier. Left justified and padded with blanks. + * This field will be blanks if non-existent. + */ + char infysyid[8]; + /** + * EBCID Cluster Name. Left justified and padded with blanks. This is + * the name on the SSI statement in the system configuration file. This + * field will be blanks if nonexistent. + */ + char infyclnm[8]; + /** + * Total number of CPs shared among guests of this hypervisor. + * Number of cores when MT enabled. + */ + uint16_t infyscps; + /** + * Total number of CPs dedicated to guests of this hypervisor. + * Number of cores when MT enabled. + */ + uint16_t infydcps; + /** + * Total number of IFLs shared among guests of this hypervisor. + * Number of cores when MT enabled. + */ + uint16_t infysifl; + /** + * Total number of IFLs dedicated to guests of this hypervisor. + * Number of cores when MT enabled. + */ + uint16_t infydifl; + /* 32 bytes */ +} ATTRIBUTE_PACKED; + +struct sthyi_guest { + /** + * Guest Flag Byte 1 + * - 0x80 - Guest is mobility enabled + * - 0x40 - Guest has multiple virtual CPU types + * - 0x20 - Guest CP dispatch type has LIMITHARD cap + * - 0x10 - Guest IFL dispatch type has LIMITHARD cap + * - 0x08 - Virtual CPs are thread dispatched + * - 0x04 - Virtual IFLs are thread dispatched + */ + uint8_t infgflg1; + uint8_t infgflg2; /**< Guest Flag Byte 2 reserved for IBM use */ + uint8_t infgval1; /**< Guest Validity Byte 1 reserved for IBM use */ + uint8_t infgval2; /**< Guest Validity Byte 2 reserved for IBM use */ + char infgusid[8]; /**< EBCDIC Userid */ + uint16_t infgscps; /**< Number of guest shared CPs */ + uint16_t infgdcps; /**< Number of guest dedicated CPs */ + /** + * Dispatch type for guest CPs. This field is valid if INFGSCPS or + * INFGDCPS is greater than zero. + * - 0 - General Purpose (CP) + */ + uint8_t infgcpdt; + char reserved_1__[3]; /**< Reserved for future IBM use */ + /** + * Guest current capped capacity for shared virtual CPs, a scaled number + * where 0x00010000 represents one core. This field is zero to + * indicate not capped when: + * - There is no CP individual limit (that is, the "Guest CP dispatch + * type has LIMITHARD cap" bit in field INFGFLG1 is OFF). + * - There are no shared CPs on the system (that is, INFYSCPS = 0). + * If there is a CP limit but there are no shared CPs or virtual CPs, + * the limit is meaningless and does not apply to anything. + */ + uint32_t infgcpcc; + uint16_t infgsifl; /**< Number of guest shared IFLs */ + uint16_t infgdifl; /**< Number of guest dedicated IFLs */ + /** + * Dispatch type for guest IFLs. This field is valid if INFGSIFL or + * INFGDIFL is greater than zero. + * - 0 - General Purpose (CP) + * - 3 - Integrated Facility for Linux (IFL) + */ + uint8_t infgifdt; + char reserved_2__[3]; /**< Reserved for future IBM use */ + /** + * Guest current capped capacity for shared virtual IFLs, a scaled + * number where 0x00010000 represents one core. This field is zero + * to indicate not capped with an IFL limit when: + * - There is no IFL individual limit (that is, the "Guest IFL dispatch + * type has LIMITHARD cap" bit in field INFGFLG1 is OFF). + * - The guest's IFLs are dispatched on CPs (that is, INFGIFDT = 00). + * When the guest's IFLs are dispatched on CPs, the CP individual + * limit (in INFGCPCC) is applied to the guest's virtual IFLs and + * virtual CPs. + */ + uint32_t infgifcc; + /** + * CPU Pool Capping Flags + * - 0x80 - CPU Pool's CP virtual type has LIMITHARD cap + * - 0x40 - CPU Pool's CP virtual type has CAPACITY cap + * - 0x20 - CPU Pool's IFL virtual type has LIMITHARD cap + * - 0x10 - CPU Pool's IFL virtual type has CAPACITY cap + * - 0x08 - CPU Pool uses prorated core time. + */ + uint8_t infgpflg; + char reserved_3__[3]; /**< Reserved for future IBM use */ + /** + * EBCDIC CPU Pool Name. This field will be blanks if the guest is not + * in a CPU Pool. + */ + char infgpnam[8]; + /** + * CPU Pool capped capacity for shared virtual CPs, a scaled number + * where 0x00010000 represents one core. This field will be zero if + * not capped. + */ + uint32_t infgpccc; + /** + * CPU Pool capped capacity for shared virtual IFLs, a scaled number + * where 0x00010000 represents one core. This field will be zero if + * not capped. + */ + uint32_t infgpicc; + /* 56 bytes */ +} ATTRIBUTE_PACKED; + + +static void +decode_ebcdic(const char *ebcdic, char *ascii, size_t size) +{ + /* + * This is mostly Linux's EBCDIC-ASCII conversion table, except for + * various non-representable characters that are converted to spaces for + * readability purposes, as it is intended to be a hint for the string + * contents and not precise conversion. + */ + static char conv_table[] = + "\0\1\2\3 \11 \177 \13\14\15\16\17" + "\20\21\22\23 \n\10 \30\31 \34\35\36\37" + " \34 \n\27\33 \5\6\7" + " \26 \4 \24\25 \32" + " " " .<(+|" + "& " "!$*);~" + "-/ " "|,%_>?" + " `" ":#@'=\"" + " abcdefghi" " " + " jklmnopqr" " " + " ~stuvwxyz" " " + "^ " "[] " + "{ABCDEFGHI" " " + "}JKLMNOPQR" " " + "\\ STUVWXYZ" " " + "0123456789" " "; + + while (size--) + *ascii++ = conv_table[(unsigned char) *ebcdic++]; +} + +#define DECODE_EBCDIC(ebcdic_, ascii_) \ + decode_ebcdic((ebcdic_), (ascii_), \ + sizeof(ebcdic_) + MUST_BE_ARRAY(ebcdic_)) +#define PRINT_EBCDIC(ebcdic_) \ + do { \ + char ascii_str[sizeof(ebcdic_) + MUST_BE_ARRAY(ebcdic_)]; \ + \ + DECODE_EBCDIC(ebcdic_, ascii_str); \ + print_quoted_string(ascii_str, sizeof(ascii_str), \ + QUOTE_EMIT_COMMENT); \ + } while (0) + +#define PRINT_FIELD_EBCDIC(prefix_, where_, field_) \ + do { \ + PRINT_FIELD_HEX_ARRAY(prefix_, where_, field_); \ + PRINT_EBCDIC((where_).field_); \ + } while (0) + +#define PRINT_FIELD_WEIGHT(prefix_, where_, field_) \ + do { \ + PRINT_FIELD_X(prefix_, where_, field_); \ + if ((where_).field_) \ + tprintf_comment("%u %u/65536 cores", \ + (where_).field_ >> 16, \ + (where_).field_ & 0xFFFF); \ + else \ + tprints_comment("unlimited"); \ + } while (0) + + +static bool +is_filled(char *ptr, char fill, size_t size) +{ + while (size--) + if (*ptr++ != fill) + return false; + + return true; +} + +#define IS_ZERO(arr_) \ + is_filled(arr_, '\0', sizeof(arr_) + MUST_BE_ARRAY(arr_)) +#define IS_BLANK(arr_) /* 0x40 is space in EBCDIC */ \ + is_filled(arr_, '\x40', sizeof(arr_) + MUST_BE_ARRAY(arr_)) + +#define CHECK_SIZE(hdr_, size_, name_, ...) \ + do { \ + if ((size_) < sizeof(*(hdr_))) { \ + tprintf_comment("Invalid " name_ " with size " \ + "%hu < %zu expected", \ + ##__VA_ARGS__, \ + (size_), sizeof(*(hdr_))); \ + print_quoted_string((char *) (hdr_), (size_), \ + QUOTE_FORCE_HEX); \ + \ + return; \ + } \ + } while (0) + +#define PRINT_UNKNOWN_TAIL(hdr_, size_) \ + do { \ + if ((size_) > sizeof(*(hdr_)) && \ + !is_filled((char *) ((hdr_) + 1), '\0', \ + (size_) - sizeof(*(hdr_)))) \ + print_quoted_string((char *) ((hdr_) + 1), \ + (size_) - sizeof(*(hdr_)), \ + QUOTE_FORCE_HEX); \ + } while (0) + +static void +print_sthyi_machine(struct tcb *tcp, struct sthyi_machine *hdr, uint16_t size, + bool *dummy) +{ + int cnt_val, name_val, id_val; + + CHECK_SIZE(hdr, size, "machine structure"); + + tprints("/* machine */ {"); + if (!abbrev(tcp)) { + if (hdr->infmflg1) { /* Reserved */ + PRINT_FIELD_0X("", *hdr, infmflg1); + tprints(", "); + } + if (hdr->infmflg2) { /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infmflg2); + tprints(", "); + } + } + + PRINT_FIELD_0X("", *hdr, infmval1); + cnt_val = !!(hdr->infmval1 & 0x80); + id_val = !!(hdr->infmval1 & 0x40); + name_val = !!(hdr->infmval1 & 0x20); + + if (!abbrev(tcp)) { + if (hdr->infmval1) + tprintf_comment("processor count validity: %d, " + "machine ID validity: %d, " + "machine name validity: %d%s%#.0x%s", + cnt_val, id_val, name_val, + hdr->infmval1 & 0x1F ? ", " : "", + hdr->infmval1 & 0x1F, + hdr->infmval1 & 0x1F ? " - ???" : ""); + if (hdr->infmval2) + PRINT_FIELD_0X(", ", *hdr, infmval2); + } + + if (cnt_val || hdr->infmscps) + PRINT_FIELD_U(", ", *hdr, infmscps); + if (cnt_val || hdr->infmdcps) + PRINT_FIELD_U(", ", *hdr, infmdcps); + if (cnt_val || hdr->infmsifl) + PRINT_FIELD_U(", ", *hdr, infmsifl); + if (cnt_val || hdr->infmdifl) + PRINT_FIELD_U(", ", *hdr, infmdifl); + + if (!abbrev(tcp)) { + if (name_val || hdr->infmname) + PRINT_FIELD_EBCDIC(", ", *hdr, infmname); + + if (id_val || !IS_ZERO(hdr->infmtype)) + PRINT_FIELD_EBCDIC(", ", *hdr, infmtype); + if (id_val || !IS_ZERO(hdr->infmmanu)) + PRINT_FIELD_EBCDIC(", ", *hdr, infmmanu); + if (id_val || !IS_ZERO(hdr->infmseq)) + PRINT_FIELD_EBCDIC(", ", *hdr, infmseq); + if (id_val || !IS_ZERO(hdr->infmpman)) + PRINT_FIELD_EBCDIC(", ", *hdr, infmpman); + + PRINT_UNKNOWN_TAIL(hdr, size); + } else { + tprints(", ..."); + } + + tprints("}"); +} + +static void +print_sthyi_partition(struct tcb *tcp, struct sthyi_partition *hdr, + uint16_t size, bool *mt) +{ + int cnt_val, wcap_val, acap_val, id_val, lpar_val; + + *mt = false; + + CHECK_SIZE(hdr, size, "partition structure"); + + *mt = !!(hdr->infpflg1 & 0x80); + + PRINT_FIELD_0X("/* partition */ {", *hdr, infpflg1); + if (!abbrev(tcp) && hdr->infpflg1) + tprintf_comment("%s%s%#.0x%s", + hdr->infpflg1 & 0x80 ? + "0x80 - multithreading is enabled" : "", + (hdr->infpflg1 & 0x80) && (hdr->infpflg1 & 0x7F) ? + ", " : "", + hdr->infpflg1 & 0x7F, + hdr->infpflg1 & 0x7F ? " - ???" : ""); + if (!abbrev(tcp) && hdr->infpflg2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infpflg2); + + PRINT_FIELD_0X(", ", *hdr, infpval1); + cnt_val = !!(hdr->infpval1 & 0x80); + wcap_val = !!(hdr->infpval1 & 0x40); + acap_val = !!(hdr->infpval1 & 0x20); + id_val = !!(hdr->infpval1 & 0x10); + lpar_val = !!(hdr->infpval1 & 0x08); + + if (!abbrev(tcp) && hdr->infpval1) + tprintf_comment("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%s%#.0x%s", + cnt_val, wcap_val, acap_val, id_val, lpar_val, + hdr->infpval1 & 0x07 ? ", " : "", + hdr->infpval1 & 0x07, + hdr->infpval1 & 0x07 ? " - ???" : ""); + if (!abbrev(tcp) && hdr->infpval2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infpval2); + + if (id_val || hdr->infppnum) + PRINT_FIELD_U(", ", *hdr, infppnum); + + if (cnt_val || hdr->infpscps) + PRINT_FIELD_U(", ", *hdr, infpscps); + if (cnt_val || hdr->infpdcps) + PRINT_FIELD_U(", ", *hdr, infpdcps); + if (cnt_val || hdr->infpsifl) + PRINT_FIELD_U(", ", *hdr, infpsifl); + if (cnt_val || hdr->infpdifl) + PRINT_FIELD_U(", ", *hdr, infpdifl); + + if (!abbrev(tcp) && !IS_ZERO(hdr->reserved_1__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_1__); + + if (id_val || !IS_ZERO(hdr->infppnam)) + PRINT_FIELD_EBCDIC(", ", *hdr, infppnam); + + if (!abbrev(tcp)) { + if (wcap_val || hdr->infpwbcp) + PRINT_FIELD_WEIGHT(", ", *hdr, infpwbcp); + if (acap_val || hdr->infpabcp) + PRINT_FIELD_WEIGHT(", ", *hdr, infpabcp); + if (wcap_val || hdr->infpwbif) + PRINT_FIELD_WEIGHT(", ", *hdr, infpwbif); + if (acap_val || hdr->infpabif) + PRINT_FIELD_WEIGHT(", ", *hdr, infpabif); + + if (!IS_ZERO(hdr->infplgnm)) { + PRINT_FIELD_EBCDIC(", ", *hdr, infplgnm); + + PRINT_FIELD_WEIGHT(", ", *hdr, infplgcp); + PRINT_FIELD_WEIGHT(", ", *hdr, infplgif); + } else { + if (lpar_val) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, infplgnm); + if (hdr->infplgcp) + PRINT_FIELD_X(", ", *hdr, infplgcp); + if (hdr->infplgif) + PRINT_FIELD_X(", ", *hdr, infplgif); + } + + PRINT_UNKNOWN_TAIL(hdr, size); + } else { + tprints(", ..."); + } + + tprints("}"); +} + +static void +print_sthyi_hypervisor(struct tcb *tcp, struct sthyi_hypervisor *hdr, + uint16_t size, int num, bool mt) +{ + CHECK_SIZE(hdr, size, "hypervisor %d structure", num); + + tprintf("/* hypervisor %d */ ", num); + PRINT_FIELD_0X("{", *hdr, infyflg1); + if (!abbrev(tcp) && hdr->infyflg1) + tprintf_comment("%s%s%s%s%#.0x%s", + hdr->infyflg1 & 0x80 ? + "0x80 - guest CPU usage had limiting is using " + "the consumption method" : "", + (hdr->infyflg1 & 0x80) && (hdr->infyflg1 & 0x40) ? + ", " : "", + hdr->infyflg1 & 0x40 ? + "0x40 - LIMITHARD caps use prorated core time " + "for capping" : "", + (hdr->infyflg1 & 0xC0) && (hdr->infyflg1 & 0x3F) ? + ", " : "", + hdr->infyflg1 & 0x3F, + hdr->infyflg1 & 0x3F ? " - ???" : ""); + + if (!abbrev(tcp)) { + if (hdr->infyflg2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infyflg2); + if (hdr->infyval1) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infyval1); + if (hdr->infyval2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infyval2); + + PRINT_FIELD_U(", ", *hdr, infytype); + switch (hdr->infytype) { + case 1: + tprints_comment("z/VM is the hypervisor"); + break; + default: + tprints_comment("unknown hypervisor type"); + } + + if (!IS_ZERO(hdr->reserved_1__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_1__); + + if (mt || hdr->infycpt) + PRINT_FIELD_U(", ", *hdr, infycpt); + if (mt || hdr->infyiflt) + PRINT_FIELD_U(", ", *hdr, infyiflt); + } + + if (!abbrev(tcp) || !IS_BLANK(hdr->infysyid)) + PRINT_FIELD_EBCDIC(", ", *hdr, infysyid); + if (!abbrev(tcp) || !IS_BLANK(hdr->infyclnm)) + PRINT_FIELD_EBCDIC(", ", *hdr, infyclnm); + + if (!abbrev(tcp) || hdr->infyscps) + PRINT_FIELD_U(", ", *hdr, infyscps); + if (!abbrev(tcp) || hdr->infydcps) + PRINT_FIELD_U(", ", *hdr, infydcps); + if (!abbrev(tcp) || hdr->infysifl) + PRINT_FIELD_U(", ", *hdr, infysifl); + if (!abbrev(tcp) || hdr->infydifl) + PRINT_FIELD_U(", ", *hdr, infydifl); + + if (!abbrev(tcp)) { + PRINT_UNKNOWN_TAIL(hdr, size); + } else { + tprints(", ..."); + } + + tprints("}"); +} + +static void +print_sthyi_guest(struct tcb *tcp, struct sthyi_guest *hdr, uint16_t size, + int num, bool mt) +{ + CHECK_SIZE(hdr, size, "guest %d structure", num); + + tprintf("/* guest %d */ ", num); + PRINT_FIELD_0X("{", *hdr, infgflg1); + if (!abbrev(tcp) && hdr->infgflg1) + tprintf_comment("%s%s%s%s%s%s%s%s%s%s%s%s%#.0x%s", + hdr->infgflg1 & 0x80 ? + "0x80 - guest is mobility enabled" : "", + (hdr->infgflg1 & 0x80) && (hdr->infgflg1 & 0x40) ? + ", " : "", + hdr->infgflg1 & 0x40 ? + "0x40 - guest has multiple virtual CPU types" : + "", + (hdr->infgflg1 & 0xC0) && (hdr->infgflg1 & 0x20) ? + ", " : "", + hdr->infgflg1 & 0x20 ? + "0x20 - guest CP dispatch type has LIMITHARD " + "cap" : "", + (hdr->infgflg1 & 0xE0) && (hdr->infgflg1 & 0x10) ? + ", " : "", + hdr->infgflg1 & 0x10 ? + "0x10 - guest IFL dispatch type has LIMITHARD " + "cap" : "", + (hdr->infgflg1 & 0xF0) && (hdr->infgflg1 & 0x08) ? + ", " : "", + hdr->infgflg1 & 0x08 ? + "0x08 - virtual CPs are thread dispatched" : + "", + (hdr->infgflg1 & 0xF8) && (hdr->infgflg1 & 0x04) ? + ", " : "", + hdr->infgflg1 & 0x04 ? + "0x04 - virtual IFLs are thread dispatched" : + "", + (hdr->infgflg1 & 0xFC) && (hdr->infgflg1 & 0x03) ? + ", " : "", + hdr->infgflg1 & 0x03, + hdr->infgflg1 & 0x03 ? " - ???" : ""); + if (!abbrev(tcp)) { + if (hdr->infgflg2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infgflg2); + if (hdr->infgval1) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infgval1); + if (hdr->infgval2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infgval2); + } + + PRINT_FIELD_EBCDIC(", ", *hdr, infgusid); + + if (!abbrev(tcp) || hdr->infgscps) + PRINT_FIELD_U(", ", *hdr, infgscps); + if (!abbrev(tcp) || hdr->infgdcps) + PRINT_FIELD_U(", ", *hdr, infgdcps); + + if (!abbrev(tcp)) { + PRINT_FIELD_U(", ", *hdr, infgcpdt); + switch (hdr->infgcpdt) { + case 0: + tprints_comment("General Purpose (CP)"); + break; + default: + tprints_comment("unknown"); + } + + if (!IS_ZERO(hdr->reserved_1__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_1__); + } + + if (!abbrev(tcp) || hdr->infgcpcc) + PRINT_FIELD_WEIGHT(", ", *hdr, infgcpcc); + + if (!abbrev(tcp) || hdr->infgsifl) + PRINT_FIELD_U(", ", *hdr, infgsifl); + if (!abbrev(tcp) || hdr->infgdifl) + PRINT_FIELD_U(", ", *hdr, infgdifl); + + if (!abbrev(tcp)) { + PRINT_FIELD_U(", ", *hdr, infgifdt); + switch (hdr->infgifdt) { + case 0: + tprints_comment("General Purpose (CP)"); + break; + case 3: + tprints_comment("Integrated Facility for Linux (IFL)"); + break; + default: + tprints_comment("unknown"); + } + + if (!IS_ZERO(hdr->reserved_2__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_2__); + } + + if (!abbrev(tcp) || hdr->infgifcc) + PRINT_FIELD_WEIGHT(", ", *hdr, infgifcc); + + PRINT_FIELD_0X(", ", *hdr, infgpflg); + if (!abbrev(tcp) && hdr->infgpflg) + tprintf_comment("%s%s%s%s%s%s%s%s%s%s%#.0x%s", + hdr->infgpflg & 0x80 ? + "0x80 - CPU pool's CP virtual type has " + "LIMITHARD cap" : "", + (hdr->infgpflg & 0x80) && (hdr->infgpflg & 0x40) ? + ", " : "", + hdr->infgpflg & 0x40 ? + "0x40 - CPU pool's CP virtual type has " + "CAPACITY cap" : "", + (hdr->infgpflg & 0xC0) && (hdr->infgpflg & 0x20) ? + ", " : "", + hdr->infgpflg & 0x20 ? + "0x20 - CPU pool's IFL virtual type has " + "LIMITHARD cap" : "", + (hdr->infgpflg & 0xE0) && (hdr->infgpflg & 0x10) ? + ", " : "", + hdr->infgpflg & 0x10 ? + "0x10 - CPU pool's IFL virtual type has " + "CAPACITY cap" : "", + (hdr->infgpflg & 0xF0) && (hdr->infgpflg & 0x08) ? + ", " : "", + hdr->infgpflg & 0x08 ? + "0x08 - CPU pool uses prorated core time" : "", + (hdr->infgpflg & 0xF8) && (hdr->infgpflg & 0x07) ? + ", " : "", + hdr->infgpflg & 0x07, + hdr->infgpflg & 0x07 ? " - ???" : ""); + + if (!abbrev(tcp)) { + if (!IS_ZERO(hdr->reserved_3__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_3__); + + if (!IS_BLANK(hdr->infgpnam)) + PRINT_FIELD_EBCDIC(", ", *hdr, infgpnam); + + PRINT_FIELD_WEIGHT(", ", *hdr, infgpccc); + PRINT_FIELD_WEIGHT(", ", *hdr, infgpicc); + + PRINT_UNKNOWN_TAIL(hdr, size); + } else { + tprints(", ..."); + } + + tprints("}"); +} + +#define STHYI_PRINT_STRUCT(l_, name_) \ + do { \ + if (hdr->inf ##l_## off && hdr->inf ##l_## off + \ + hdr->inf ##l_## len <= sizeof(data)) { \ + tprints(", "); \ + print_sthyi_ ##name_(tcp, (struct sthyi_ ##name_ *) \ + (data + hdr->inf ##l_## off), \ + hdr->inf ##l_## len, &mt); \ + } \ + } while (0) + +#define STHYI_PRINT_HV_STRUCT(l_, n_, name_) \ + do { \ + if (hdr->inf ##l_## off ##n_ && hdr->inf ##l_## off ##n_ + \ + hdr->inf ##l_## len ##n_ <= sizeof(data)) { \ + tprints(", "); \ + print_sthyi_ ##name_(tcp, (struct sthyi_ ##name_ *) \ + (data + hdr->inf ##l_## off ##n_), \ + hdr->inf ##l_## len ##n_, n_, mt); \ + } \ + } while (0) + +static void +print_sthyi_buf(struct tcb *tcp, kernel_ulong_t ptr) +{ + char data[PAGE_SIZE]; + struct sthyi_hdr *hdr = (struct sthyi_hdr *) data; + bool mt = false; + + if (umove_or_printaddr(tcp, ptr, &data)) + return; + + tprints("{"); + + /* Header */ + PRINT_FIELD_0X("/* header */ {", *hdr, infhflg1); + + if (abbrev(tcp)) { + tprints(", ..."); + goto sthyi_sections; + } + + if (hdr->infhflg1) + tprintf_comment("%s%s%s%s%s%s%s%s%#.0x%s", + hdr->infhflg1 & 0x80 ? + "0x80 - Global Performance Data unavailable" : + "", + (hdr->infhflg1 & 0x80) && (hdr->infhflg1 & 0x40) ? + ", " : "", + hdr->infhflg1 & 0x40 ? + "0x40 - One or more hypervisor levels below " + "this level does not support the STHYI " + "instruction" : "", + (hdr->infhflg1 & 0xC0) && (hdr->infhflg1 & 0x20) ? + ", " : "", + hdr->infhflg1 & 0x20 ? + "0x20 - Virtualization stack is incomplete" : + "", + (hdr->infhflg1 & 0xE0) && (hdr->infhflg1 & 0x10) ? + ", " : "", + hdr->infhflg1 & 0x10 ? + "0x10 - Execution environment is not within " + "a logical partition" : "", + (hdr->infhflg1 & 0xF0) && (hdr->infhflg1 & 0x0F) ? + ", " : "", + hdr->infhflg1 & 0x0F, + hdr->infhflg1 & 0x0F ? " - ???" : ""); + if (hdr->infhflg2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infhflg2); + if (hdr->infhval1) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infhval1); + if (hdr->infhval2) /* Reserved */ + PRINT_FIELD_0X(", ", *hdr, infhval2); + + if (!IS_ZERO(hdr->reserved_1__)) + PRINT_FIELD_HEX_ARRAY(", ", *hdr, reserved_1__); + + PRINT_FIELD_U(", ", *hdr, infhygct); + PRINT_FIELD_U(", ", *hdr, infhtotl); + + PRINT_FIELD_U(", ", *hdr, infhdln); + PRINT_FIELD_U(", ", *hdr, infmoff); + PRINT_FIELD_U(", ", *hdr, infmlen); + PRINT_FIELD_U(", ", *hdr, infpoff); + PRINT_FIELD_U(", ", *hdr, infplen); + + PRINT_FIELD_U(", ", *hdr, infhoff1); + PRINT_FIELD_U(", ", *hdr, infhlen1); + PRINT_FIELD_U(", ", *hdr, infgoff1); + PRINT_FIELD_U(", ", *hdr, infglen1); + PRINT_FIELD_U(", ", *hdr, infhoff2); + PRINT_FIELD_U(", ", *hdr, infhlen2); + PRINT_FIELD_U(", ", *hdr, infgoff2); + PRINT_FIELD_U(", ", *hdr, infglen2); + PRINT_FIELD_U(", ", *hdr, infhoff3); + PRINT_FIELD_U(", ", *hdr, infhlen3); + PRINT_FIELD_U(", ", *hdr, infgoff3); + PRINT_FIELD_U(", ", *hdr, infglen3); + + PRINT_UNKNOWN_TAIL(hdr, hdr->infhdln); + +sthyi_sections: + tprints("}"); + + STHYI_PRINT_STRUCT(m, machine); + STHYI_PRINT_STRUCT(p, partition); + + STHYI_PRINT_HV_STRUCT(h, 1, hypervisor); + STHYI_PRINT_HV_STRUCT(g, 1, guest); + STHYI_PRINT_HV_STRUCT(h, 2, hypervisor); + STHYI_PRINT_HV_STRUCT(g, 2, guest); + STHYI_PRINT_HV_STRUCT(h, 3, hypervisor); + STHYI_PRINT_HV_STRUCT(g, 3, guest); + + tprints("}"); +} + +/** + * Wrapper for the s390 STHYI instruction that provides hypervisor information. + * + * See https://www.ibm.com/support/knowledgecenter/SSB27U_6.3.0/com.ibm.zvm.v630.hcpb4/hcpb4sth.htm + * for the instruction documentation. + * + * The difference in the kernel wrapper is that it doesn't require the 4K + * alignment for the resp_buffer page (as it just copies from the internal + * cache). + */ +SYS_FUNC(s390_sthyi) +{ + /* in, function ID from s390_sthyi_function_codes */ + kernel_ulong_t function_code = tcp->u_arg[0]; + /* out, pointer to page-sized buffer */ + kernel_ulong_t resp_buffer_ptr = tcp->u_arg[1]; + /* out, pointer to u64 containing function result */ + kernel_ulong_t return_code_ptr = tcp->u_arg[2]; + /* in, should be 0, at the moment */ + kernel_ulong_t flags = tcp->u_arg[3]; + + if (entering(tcp)) { + printxval64(s390_sthyi_function_codes, function_code, + "STHYI_FC_???"); + tprints(", "); + } else { + switch (function_code) { + case STHYI_FC_CP_IFL_CAP: + print_sthyi_buf(tcp, resp_buffer_ptr); + break; + + default: + printaddr(resp_buffer_ptr); + } + + tprints(", "); + printnum_int64(tcp, return_code_ptr, "%" PRIu64); + tprintf(", %#" PRI_klx, flags); + } + + return 0; +} + +#endif /* defined S390 || defined S390X */ diff --git a/xlat/s390_sthyi_function_codes.in b/xlat/s390_sthyi_function_codes.in new file mode 100644 index 0000000..380cd7f --- /dev/null +++ b/xlat/s390_sthyi_function_codes.in @@ -0,0 +1 @@ +STHYI_FC_CP_IFL_CAP 0 -- 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