2018-01-18 08:21:45 +03:00
/*
* s390 - specific syscalls decoders .
*
* Copyright ( c ) 2018 The strace developers .
* All rights reserved .
*
2018-12-10 03:00:00 +03:00
* SPDX - License - Identifier : LGPL - 2.1 - or - later
2018-01-18 08:21:45 +03:00
*/
# include "defs.h"
# if defined S390 || defined S390X
2018-12-30 18:35:21 +03:00
# include <sys / user.h>
2018-01-18 08:21:45 +03:00
2018-12-30 18:35:21 +03:00
# include "print_fields.h"
2018-01-18 08:21:45 +03:00
2018-12-30 18:35:21 +03:00
# include "xlat / s390_guarded_storage_commands.h"
# include "xlat / s390_runtime_instr_commands.h"
# include "xlat / s390_sthyi_function_codes.h"
2018-01-18 08:21:45 +03:00
/*
* 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 + + ] ;
}
2018-12-30 18:35:21 +03:00
# define DECODE_EBCDIC(ebcdic_, ascii_) \
2018-01-18 08:21:45 +03:00
decode_ebcdic ( ( ebcdic_ ) , ( ascii_ ) , \
sizeof ( ebcdic_ ) + MUST_BE_ARRAY ( ebcdic_ ) )
2018-12-30 18:35:21 +03:00
# define PRINT_EBCDIC(ebcdic_) \
2018-01-18 08:21:45 +03:00
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 )
2018-12-30 18:35:21 +03:00
# define PRINT_FIELD_EBCDIC(prefix_, where_, field_) \
2018-01-18 08:21:45 +03:00
do { \
PRINT_FIELD_HEX_ARRAY ( prefix_ , where_ , field_ ) ; \
PRINT_EBCDIC ( ( where_ ) . field_ ) ; \
} while ( 0 )
2018-12-30 18:35:21 +03:00
# define PRINT_FIELD_WEIGHT(prefix_, where_, field_) \
2018-01-18 08:21:45 +03:00
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 )
2018-12-30 18:35:21 +03:00
# define IS_BLANK(arr_) /* 0x40 is space in EBCDIC */ \
2018-01-18 08:21:45 +03:00
is_filled ( arr_ , ' \x40 ' , sizeof ( arr_ ) + MUST_BE_ARRAY ( arr_ ) )
2018-12-30 18:35:21 +03:00
# define CHECK_SIZE(hdr_, size_, name_, ...) \
2018-01-18 08:21:45 +03:00
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 )
2018-12-30 18:35:21 +03:00
# define PRINT_UNKNOWN_TAIL(hdr_, size_) \
2018-01-18 08:21:45 +03:00
do { \
if ( ( size_ ) > sizeof ( * ( hdr_ ) ) & & \
! is_filled ( ( char * ) ( ( hdr_ ) + 1 ) , ' \0 ' , \
2018-11-30 18:41:39 +03:00
( size_ ) - sizeof ( * ( hdr_ ) ) ) ) { \
tprints ( " , " ) ; \
2018-01-18 08:21:45 +03:00
print_quoted_string ( ( char * ) ( ( hdr_ ) + 1 ) , \
( size_ ) - sizeof ( * ( hdr_ ) ) , \
QUOTE_FORCE_HEX ) ; \
2018-11-30 18:41:39 +03:00
} \
2018-01-18 08:21:45 +03:00
} 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 ) ;
2018-02-22 02:21:35 +03:00
if ( id_val | | ! IS_ARRAY_ZERO ( hdr - > infmtype ) )
2018-01-18 08:21:45 +03:00
PRINT_FIELD_EBCDIC ( " , " , * hdr , infmtype ) ;
2018-02-22 02:21:35 +03:00
if ( id_val | | ! IS_ARRAY_ZERO ( hdr - > infmmanu ) )
2018-01-18 08:21:45 +03:00
PRINT_FIELD_EBCDIC ( " , " , * hdr , infmmanu ) ;
2018-02-22 02:21:35 +03:00
if ( id_val | | ! IS_ARRAY_ZERO ( hdr - > infmseq ) )
2018-01-18 08:21:45 +03:00
PRINT_FIELD_EBCDIC ( " , " , * hdr , infmseq ) ;
2018-02-22 02:21:35 +03:00
if ( id_val | | ! IS_ARRAY_ZERO ( hdr - > infmpman ) )
2018-01-18 08:21:45 +03:00
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 ) ;
2018-02-22 02:21:35 +03:00
if ( ! abbrev ( tcp ) & & ! IS_ARRAY_ZERO ( hdr - > reserved_1__ ) )
2018-01-18 08:21:45 +03:00
PRINT_FIELD_HEX_ARRAY ( " , " , * hdr , reserved_1__ ) ;
2018-02-22 02:21:35 +03:00
if ( id_val | | ! IS_ARRAY_ZERO ( hdr - > infppnam ) )
2018-01-18 08:21:45 +03:00
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 ) ;
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > infplgnm ) ) {
2018-01-18 08:21:45 +03:00
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 " ) ;
}
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > reserved_1__ ) )
2018-01-18 08:21:45 +03:00
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 " ) ;
}
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > reserved_1__ ) )
2018-01-18 08:21:45 +03:00
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 " ) ;
}
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > reserved_2__ ) )
2018-01-18 08:21:45 +03:00
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 ) ) {
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > reserved_3__ ) )
2018-01-18 08:21:45 +03:00
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 ( " } " ) ;
}
2018-12-30 18:35:21 +03:00
# define STHYI_PRINT_STRUCT(l_, name_) \
2018-01-18 08:21:45 +03:00
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 )
2018-12-30 18:35:21 +03:00
# define STHYI_PRINT_HV_STRUCT(l_, n_, name_) \
2018-01-18 08:21:45 +03:00
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 ) ;
2018-02-22 02:21:35 +03:00
if ( ! IS_ARRAY_ZERO ( hdr - > reserved_1__ ) )
2018-01-18 08:21:45 +03:00
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 4 K
* 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 ;
}
2018-01-12 19:25:38 +03:00
/*
* Structures are written based on
* https : //www-304.ibm.com/support/docview.wss?uid=isg29c69415c1e82603c852576700058075a&aid=1#page=85
*/
struct guard_storage_control_block {
uint64_t reserved ;
/**
* Guard Storage Designation
* - Bits 0. . J , J = = 64 - GSC - Guard Storage Origin ( GSO )
* - Bits 53. .55 - Guard Load Shift ( GLS )
* - Bits 58. .63 - Guard Storage Characteristic ( GSC ) , this is J from
* the first item , valud values are 25. .56 .
*/
uint64_t gsd ;
uint64_t gssm ; /**< Guard Storage Section Mask */
uint64_t gs_epl_a ; /**< Guard Storage Event Parameter List Address */
} ;
struct guard_storage_event_parameter_list {
uint8_t pad1 ;
/**
* Guard Storage Event Addressing Mode
* - 0x40 - Extended addressing mode ( E )
* - 0x80 - Basic addressing mode ( B )
*/
uint8_t gs_eam ;
/**
* Guard Storage Event Cause indication
* - 0x01 - CPU was in transaction execution mode ( TX )
* - 0x02 - CPU was in constrained transaction execution mode ( CX )
* - 0x80 - Instruction causing the event : 0 - LGG , 1 - LLGFGS
*/
uint8_t gs_eci ;
/**
* Guard Storage Event Access Information
* - 0x01 - DAT mode
* - Bits 1. .2 - Address space indication
* - Bits 4. .7 - AR number
*/
uint8_t gs_eai ;
uint32_t pad2 ;
uint64_t gs_eha ; /**< Guard Storage Event Handler Address */
uint64_t gs_eia ; /**< Guard Storage Event Instruction Address */
uint64_t gs_eoa ; /**< Guard Storage Event Operation Address */
uint64_t gs_eir ; /**< Guard Storage Event Intermediate Result */
uint64_t gs_era ; /**< Guard Storage Event Return Address */
} ;
static void
guard_storage_print_gsepl ( struct tcb * tcp , uint64_t addr )
{
struct guard_storage_event_parameter_list gsepl ;
/* Since it is 64-bit even on 31-bit s390... */
if ( sizeof ( addr ) > current_klongsize & &
addr > = ( 1ULL < < ( current_klongsize * 8 ) ) ) {
tprintf ( " %# " PRIx64 , addr ) ;
return ;
}
if ( umove_or_printaddr ( tcp , addr , & gsepl ) )
return ;
tprints ( " [{ " ) ;
if ( ! abbrev ( tcp ) ) {
if ( gsepl . pad1 ) {
PRINT_FIELD_0X ( " " , gsepl , pad1 ) ;
tprints ( " , " ) ;
}
PRINT_FIELD_0X ( " " , gsepl , gs_eam ) ;
tprintf_comment ( " extended addressing mode: %u, "
" basic addressing mode: %u " ,
! ! ( gsepl . gs_eam & 0x2 ) , ! ! ( gsepl . gs_eam & 0x1 ) ) ;
PRINT_FIELD_0X ( " , " , gsepl , gs_eci ) ;
tprintf_comment ( " CPU in TX: %u, CPU in CX: %u, instruction: %s " ,
! ! ( gsepl . gs_eci & 0x80 ) ,
! ! ( gsepl . gs_eci & 0x40 ) ,
gsepl . gs_eci & 0x01 ? " LLGFGS " : " LGG " ) ;
PRINT_FIELD_0X ( " , " , gsepl , gs_eai ) ;
tprintf_comment ( " DAT: %u, address space indication: %u, "
" AR number: %u " ,
! ! ( gsepl . gs_eai & 0x40 ) ,
( gsepl . gs_eai > > 4 ) & 0x3 ,
gsepl . gs_eai & 0xF ) ;
if ( gsepl . pad2 )
PRINT_FIELD_0X ( " , " , gsepl , pad2 ) ;
tprints ( " , " ) ;
}
PRINT_FIELD_X ( " " , gsepl , gs_eha ) ;
if ( ! abbrev ( tcp ) ) {
PRINT_FIELD_X ( " , " , gsepl , gs_eia ) ;
PRINT_FIELD_X ( " , " , gsepl , gs_eoa ) ;
PRINT_FIELD_X ( " , " , gsepl , gs_eir ) ;
PRINT_FIELD_X ( " , " , gsepl , gs_era ) ;
} else {
tprints ( " , ... " ) ;
}
tprints ( " }] " ) ;
}
# define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
static void
guard_storage_print_gscb ( struct tcb * tcp , kernel_ulong_t addr )
{
struct guard_storage_control_block gscb ;
if ( umove_or_printaddr ( tcp , addr , & gscb ) )
return ;
tprints ( " { " ) ;
if ( gscb . reserved ) {
PRINT_FIELD_0X ( " " , gscb , reserved ) ;
tprints ( " , " ) ;
}
PRINT_FIELD_0X ( " " , gscb , gsd ) ;
if ( ! abbrev ( tcp ) ) {
unsigned int gsc = gscb . gsd & 0x3F ;
bool gsc_valid = gsc > = 25 & & gsc < = 56 ;
tprintf_comment ( " GS origin: %#*.* " PRIx64 " %s, "
" guard load shift: % " PRIu64 " , "
" GS characteristic: %u " ,
gsc_valid ? 2 + DIV_ROUND_UP ( 64 - gsc , 4 ) : 0 ,
gsc_valid ? DIV_ROUND_UP ( 64 - gsc , 4 ) : 0 ,
gsc_valid ? gscb . gsd > > gsc : 0 ,
gsc_valid ? " " : " [invalid] " ,
( gscb . gsd > > 8 ) & 0x7 , gsc ) ;
}
PRINT_FIELD_0X ( " , " , gscb , gssm ) ;
tprints ( " , gs_epl_a= " ) ;
guard_storage_print_gsepl ( tcp , gscb . gs_epl_a ) ;
tprints ( " } " ) ;
}
SYS_FUNC ( s390_guarded_storage )
{
int command = ( int ) tcp - > u_arg [ 0 ] ;
kernel_ulong_t gs_cb = tcp - > u_arg [ 1 ] ;
printxval ( s390_guarded_storage_commands , command , " GS_??? " ) ;
switch ( command ) {
case GS_ENABLE :
case GS_DISABLE :
case GS_CLEAR_BC_CB :
case GS_BROADCAST :
break ;
case GS_SET_BC_CB :
tprints ( " , " ) ;
guard_storage_print_gscb ( tcp , gs_cb ) ;
break ;
default :
tprints ( " , " ) ;
printaddr ( gs_cb ) ;
}
return RVAL_DECODED ;
}
2018-01-14 11:37:43 +03:00
SYS_FUNC ( s390_runtime_instr )
{
int command = ( int ) tcp - > u_arg [ 0 ] ;
int signum = ( int ) tcp - > u_arg [ 1 ] ;
2018-04-16 02:14:02 +03:00
printxval_d ( s390_runtime_instr_commands , command ,
" S390_RUNTIME_INSTR_??? " ) ;
2018-01-14 11:37:43 +03:00
/*
* signum is ignored since Linux 4.4 , but let ' s print it for start
* command anyway .
*/
switch ( command ) {
case S390_RUNTIME_INSTR_START :
tprints ( " , " ) ;
2018-10-07 06:12:42 +03:00
printsignal ( signum ) ;
2018-01-14 11:37:43 +03:00
break ;
case S390_RUNTIME_INSTR_STOP :
default :
break ;
}
return RVAL_DECODED ;
}
2018-01-14 12:40:21 +03:00
SYS_FUNC ( s390_pci_mmio_write )
{
kernel_ulong_t mmio_addr = tcp - > u_arg [ 0 ] ;
kernel_ulong_t user_buf = tcp - > u_arg [ 1 ] ;
kernel_ulong_t length = tcp - > u_arg [ 2 ] ;
tprintf ( " %# " PRI_klx " , " , mmio_addr ) ;
printstr_ex ( tcp , user_buf , length , QUOTE_FORCE_HEX ) ;
tprintf ( " , % " PRI_klu , length ) ;
return RVAL_DECODED ;
}
SYS_FUNC ( s390_pci_mmio_read )
{
kernel_ulong_t mmio_addr = tcp - > u_arg [ 0 ] ;
kernel_ulong_t user_buf = tcp - > u_arg [ 1 ] ;
kernel_ulong_t length = tcp - > u_arg [ 2 ] ;
if ( entering ( tcp ) ) {
tprintf ( " %# " PRI_klx " , " , mmio_addr ) ;
} else {
if ( ! syserror ( tcp ) )
printstr_ex ( tcp , user_buf , length , QUOTE_FORCE_HEX ) ;
else
printaddr ( user_buf ) ;
tprintf ( " , % " PRI_klu , length ) ;
}
return 0 ;
}
2018-01-18 08:21:45 +03:00
# endif /* defined S390 || defined S390X */