[strace PATCH v2] Introduce s390_sthyi system call decoder

Eugene Syromyatnikov
2018-01-22T13:33:54Z

* 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 db822c5..7355ec9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -269,6 +269,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..0f49369
--- /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