2019-05-29 07:18:02 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2015-07-17 19:33:37 +03:00
/*
* intel_pt_pkt_decoder . c : Intel Processor Trace support
* Copyright ( c ) 2013 - 2014 , Intel Corporation .
*/
# include <stdio.h>
# include <string.h>
# include <endian.h>
# include <byteswap.h>
2017-02-09 15:22:22 -03:00
# include <linux/compiler.h>
2015-07-17 19:33:37 +03:00
# include "intel-pt-pkt-decoder.h"
# define BIT(n) (1 << (n))
# define BIT63 ((uint64_t)1 << 63)
2021-11-04 14:23:11 +01:00
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
2015-07-17 19:33:37 +03:00
# define le16_to_cpu bswap_16
# define le32_to_cpu bswap_32
# define le64_to_cpu bswap_64
# define memcpy_le64(d, s, n) do { \
memcpy ( ( d ) , ( s ) , ( n ) ) ; \
* ( d ) = le64_to_cpu ( * ( d ) ) ; \
} while ( 0 )
# else
# define le16_to_cpu
# define le32_to_cpu
# define le64_to_cpu
# define memcpy_le64 memcpy
# endif
static const char * const packet_name [ ] = {
[ INTEL_PT_BAD ] = " Bad Packet! " ,
[ INTEL_PT_PAD ] = " PAD " ,
[ INTEL_PT_TNT ] = " TNT " ,
[ INTEL_PT_TIP_PGD ] = " TIP.PGD " ,
[ INTEL_PT_TIP_PGE ] = " TIP.PGE " ,
[ INTEL_PT_TSC ] = " TSC " ,
2015-07-17 19:33:53 +03:00
[ INTEL_PT_TMA ] = " TMA " ,
2015-07-17 19:33:37 +03:00
[ INTEL_PT_MODE_EXEC ] = " MODE.Exec " ,
[ INTEL_PT_MODE_TSX ] = " MODE.TSX " ,
2015-07-17 19:33:53 +03:00
[ INTEL_PT_MTC ] = " MTC " ,
2015-07-17 19:33:37 +03:00
[ INTEL_PT_TIP ] = " TIP " ,
[ INTEL_PT_FUP ] = " FUP " ,
2015-07-17 19:33:53 +03:00
[ INTEL_PT_CYC ] = " CYC " ,
[ INTEL_PT_VMCS ] = " VMCS " ,
2015-07-17 19:33:37 +03:00
[ INTEL_PT_PSB ] = " PSB " ,
[ INTEL_PT_PSBEND ] = " PSBEND " ,
[ INTEL_PT_CBR ] = " CBR " ,
2015-07-17 19:33:53 +03:00
[ INTEL_PT_TRACESTOP ] = " TraceSTOP " ,
2015-07-17 19:33:37 +03:00
[ INTEL_PT_PIP ] = " PIP " ,
[ INTEL_PT_OVF ] = " OVF " ,
2015-07-17 19:33:53 +03:00
[ INTEL_PT_MNT ] = " MNT " ,
2017-05-26 11:17:14 +03:00
[ INTEL_PT_PTWRITE ] = " PTWRITE " ,
[ INTEL_PT_PTWRITE_IP ] = " PTWRITE " ,
[ INTEL_PT_EXSTOP ] = " EXSTOP " ,
[ INTEL_PT_EXSTOP_IP ] = " EXSTOP " ,
[ INTEL_PT_MWAIT ] = " MWAIT " ,
[ INTEL_PT_PWRE ] = " PWRE " ,
[ INTEL_PT_PWRX ] = " PWRX " ,
2019-06-10 10:27:53 +03:00
[ INTEL_PT_BBP ] = " BBP " ,
[ INTEL_PT_BIP ] = " BIP " ,
[ INTEL_PT_BEP ] = " BEP " ,
[ INTEL_PT_BEP_IP ] = " BEP " ,
perf intel-pt: pkt-decoder: Add CFE and EVD packets
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new
Intel PT feature called Event Trace which requires 2 new packets CFE and
EVD. Add them to the packet decoder and packet decoder test.
Committer notes:
I got the "Intel® 64 and IA-32 architectures software developer’s manual
combined volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:
https://cdrdv2.intel.com/v1/dl/getContent/671200
And these new packets are described in page 3951:
<quote>
32.2.4
Event Trace is a capability that exposes details about the asynchronous
events, when they are generated, and when their corresponding software
event handler completes execution. These include:
o Interrupts, including NMI and SMI, including the interrupt vector when
defined.
o Faults, exceptions including the fault vector.
— Page faults additionally include the page fault address, when in context.
o Event handler returns, including IRET and RSM.
o VM exits and VM entries.¹
— VM exits include the values written to the “exit reason” and “exit qualification” VMCS fields.
INIT and SIPI events.
o TSX aborts, including the abort status returned for the RTM instructions.
o Shutdown.
Additionally, it provides indication of the status of the Interrupt Flag
(IF), to indicate when interrupts are masked.
</quote>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20220124084201.2699795-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-01-24 10:41:39 +02:00
[ INTEL_PT_CFE ] = " CFE " ,
[ INTEL_PT_CFE_IP ] = " CFE " ,
[ INTEL_PT_EVD ] = " EVD " ,
2015-07-17 19:33:37 +03:00
} ;
const char * intel_pt_pkt_name ( enum intel_pt_pkt_type type )
{
return packet_name [ type ] ;
}
static int intel_pt_get_long_tnt ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
uint64_t payload ;
int count ;
if ( len < 8 )
return INTEL_PT_NEED_MORE_BYTES ;
payload = le64_to_cpu ( * ( uint64_t * ) buf ) ;
for ( count = 47 ; count ; count - - ) {
if ( payload & BIT63 )
break ;
payload < < = 1 ;
}
packet - > type = INTEL_PT_TNT ;
packet - > count = count ;
packet - > payload = payload < < 1 ;
return 8 ;
}
static int intel_pt_get_pip ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
uint64_t payload = 0 ;
if ( len < 8 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_PIP ;
memcpy_le64 ( & payload , buf + 2 , 6 ) ;
2021-02-18 11:57:53 +02:00
packet - > payload = payload ;
2015-07-17 19:33:37 +03:00
return 8 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_tracestop ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_TRACESTOP ;
return 2 ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_get_cbr ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 4 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_CBR ;
2017-05-26 11:17:15 +03:00
packet - > payload = le16_to_cpu ( * ( uint16_t * ) ( buf + 2 ) ) ;
2015-07-17 19:33:37 +03:00
return 4 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_vmcs ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
unsigned int count = ( 52 - 5 ) > > 3 ;
if ( count < 1 | | count > 7 )
return INTEL_PT_BAD_PACKET ;
if ( len < count + 2 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_VMCS ;
packet - > count = count ;
memcpy_le64 ( & packet - > payload , buf + 2 , count ) ;
return count + 2 ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_get_ovf ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_OVF ;
return 2 ;
}
static int intel_pt_get_psb ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
int i ;
if ( len < 16 )
return INTEL_PT_NEED_MORE_BYTES ;
for ( i = 2 ; i < 16 ; i + = 2 ) {
if ( buf [ i ] ! = 2 | | buf [ i + 1 ] ! = 0x82 )
return INTEL_PT_BAD_PACKET ;
}
packet - > type = INTEL_PT_PSB ;
return 16 ;
}
static int intel_pt_get_psbend ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_PSBEND ;
return 2 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_tma ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 7 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_TMA ;
packet - > payload = buf [ 2 ] | ( buf [ 3 ] < < 8 ) ;
packet - > count = buf [ 5 ] | ( ( buf [ 6 ] & BIT ( 0 ) ) < < 8 ) ;
return 7 ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_get_pad ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_PAD ;
return 1 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_mnt ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 11 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_MNT ;
memcpy_le64 ( & packet - > payload , buf + 3 , 8 ) ;
2022-01-24 10:41:38 +02:00
return 11 ;
2015-07-17 19:33:53 +03:00
}
static int intel_pt_get_3byte ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 3 )
return INTEL_PT_NEED_MORE_BYTES ;
switch ( buf [ 2 ] ) {
case 0x88 : /* MNT */
return intel_pt_get_mnt ( buf , len , packet ) ;
default :
return INTEL_PT_BAD_PACKET ;
}
}
2017-05-26 11:17:14 +03:00
static int intel_pt_get_ptwrite ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
packet - > count = ( buf [ 1 ] > > 5 ) & 0x3 ;
packet - > type = buf [ 1 ] & BIT ( 7 ) ? INTEL_PT_PTWRITE_IP :
INTEL_PT_PTWRITE ;
switch ( packet - > count ) {
case 0 :
if ( len < 6 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > payload = le32_to_cpu ( * ( uint32_t * ) ( buf + 2 ) ) ;
return 6 ;
case 1 :
if ( len < 10 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > payload = le64_to_cpu ( * ( uint64_t * ) ( buf + 2 ) ) ;
return 10 ;
default :
return INTEL_PT_BAD_PACKET ;
}
}
static int intel_pt_get_exstop ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_EXSTOP ;
return 2 ;
}
static int intel_pt_get_exstop_ip ( struct intel_pt_pkt * packet )
{
packet - > type = INTEL_PT_EXSTOP_IP ;
return 2 ;
}
static int intel_pt_get_mwait ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 10 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_MWAIT ;
packet - > payload = le64_to_cpu ( * ( uint64_t * ) ( buf + 2 ) ) ;
return 10 ;
}
static int intel_pt_get_pwre ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 4 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_PWRE ;
memcpy_le64 ( & packet - > payload , buf + 2 , 2 ) ;
return 4 ;
}
static int intel_pt_get_pwrx ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 7 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_PWRX ;
memcpy_le64 ( & packet - > payload , buf + 2 , 5 ) ;
return 7 ;
}
2019-06-10 10:27:53 +03:00
static int intel_pt_get_bbp ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 3 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_BBP ;
packet - > count = buf [ 2 ] > > 7 ;
packet - > payload = buf [ 2 ] & 0x1f ;
return 3 ;
}
static int intel_pt_get_bip_4 ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 5 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_BIP ;
packet - > count = buf [ 0 ] > > 3 ;
memcpy_le64 ( & packet - > payload , buf + 1 , 4 ) ;
return 5 ;
}
static int intel_pt_get_bip_8 ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 9 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_BIP ;
packet - > count = buf [ 0 ] > > 3 ;
memcpy_le64 ( & packet - > payload , buf + 1 , 8 ) ;
return 9 ;
}
static int intel_pt_get_bep ( size_t len , struct intel_pt_pkt * packet )
{
if ( len < 2 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_BEP ;
return 2 ;
}
static int intel_pt_get_bep_ip ( size_t len , struct intel_pt_pkt * packet )
{
if ( len < 2 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_BEP_IP ;
return 2 ;
}
perf intel-pt: pkt-decoder: Add CFE and EVD packets
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new
Intel PT feature called Event Trace which requires 2 new packets CFE and
EVD. Add them to the packet decoder and packet decoder test.
Committer notes:
I got the "Intel® 64 and IA-32 architectures software developer’s manual
combined volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:
https://cdrdv2.intel.com/v1/dl/getContent/671200
And these new packets are described in page 3951:
<quote>
32.2.4
Event Trace is a capability that exposes details about the asynchronous
events, when they are generated, and when their corresponding software
event handler completes execution. These include:
o Interrupts, including NMI and SMI, including the interrupt vector when
defined.
o Faults, exceptions including the fault vector.
— Page faults additionally include the page fault address, when in context.
o Event handler returns, including IRET and RSM.
o VM exits and VM entries.¹
— VM exits include the values written to the “exit reason” and “exit qualification” VMCS fields.
INIT and SIPI events.
o TSX aborts, including the abort status returned for the RTM instructions.
o Shutdown.
Additionally, it provides indication of the status of the Interrupt Flag
(IF), to indicate when interrupts are masked.
</quote>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20220124084201.2699795-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-01-24 10:41:39 +02:00
static int intel_pt_get_cfe ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 4 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = buf [ 2 ] & 0x80 ? INTEL_PT_CFE_IP : INTEL_PT_CFE ;
packet - > count = buf [ 2 ] & 0x1f ;
packet - > payload = buf [ 3 ] ;
return 4 ;
}
static int intel_pt_get_evd ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 11 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_EVD ;
packet - > count = buf [ 2 ] & 0x3f ;
packet - > payload = buf [ 3 ] ;
memcpy_le64 ( & packet - > payload , buf + 3 , 8 ) ;
return 11 ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_get_ext ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 2 )
return INTEL_PT_NEED_MORE_BYTES ;
2017-05-26 11:17:14 +03:00
if ( ( buf [ 1 ] & 0x1f ) = = 0x12 )
return intel_pt_get_ptwrite ( buf , len , packet ) ;
2015-07-17 19:33:37 +03:00
switch ( buf [ 1 ] ) {
case 0xa3 : /* Long TNT */
return intel_pt_get_long_tnt ( buf , len , packet ) ;
case 0x43 : /* PIP */
return intel_pt_get_pip ( buf , len , packet ) ;
2015-07-17 19:33:53 +03:00
case 0x83 : /* TraceStop */
return intel_pt_get_tracestop ( packet ) ;
2015-07-17 19:33:37 +03:00
case 0x03 : /* CBR */
return intel_pt_get_cbr ( buf , len , packet ) ;
2015-07-17 19:33:53 +03:00
case 0xc8 : /* VMCS */
return intel_pt_get_vmcs ( buf , len , packet ) ;
2015-07-17 19:33:37 +03:00
case 0xf3 : /* OVF */
return intel_pt_get_ovf ( packet ) ;
case 0x82 : /* PSB */
return intel_pt_get_psb ( buf , len , packet ) ;
case 0x23 : /* PSBEND */
return intel_pt_get_psbend ( packet ) ;
2015-07-17 19:33:53 +03:00
case 0x73 : /* TMA */
return intel_pt_get_tma ( buf , len , packet ) ;
case 0xC3 : /* 3-byte header */
return intel_pt_get_3byte ( buf , len , packet ) ;
2017-05-26 11:17:14 +03:00
case 0x62 : /* EXSTOP no IP */
return intel_pt_get_exstop ( packet ) ;
case 0xE2 : /* EXSTOP with IP */
return intel_pt_get_exstop_ip ( packet ) ;
case 0xC2 : /* MWAIT */
return intel_pt_get_mwait ( buf , len , packet ) ;
case 0x22 : /* PWRE */
return intel_pt_get_pwre ( buf , len , packet ) ;
case 0xA2 : /* PWRX */
return intel_pt_get_pwrx ( buf , len , packet ) ;
2019-06-10 10:27:53 +03:00
case 0x63 : /* BBP */
return intel_pt_get_bbp ( buf , len , packet ) ;
case 0x33 : /* BEP no IP */
return intel_pt_get_bep ( len , packet ) ;
case 0xb3 : /* BEP with IP */
return intel_pt_get_bep_ip ( len , packet ) ;
perf intel-pt: pkt-decoder: Add CFE and EVD packets
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new
Intel PT feature called Event Trace which requires 2 new packets CFE and
EVD. Add them to the packet decoder and packet decoder test.
Committer notes:
I got the "Intel® 64 and IA-32 architectures software developer’s manual
combined volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:
https://cdrdv2.intel.com/v1/dl/getContent/671200
And these new packets are described in page 3951:
<quote>
32.2.4
Event Trace is a capability that exposes details about the asynchronous
events, when they are generated, and when their corresponding software
event handler completes execution. These include:
o Interrupts, including NMI and SMI, including the interrupt vector when
defined.
o Faults, exceptions including the fault vector.
— Page faults additionally include the page fault address, when in context.
o Event handler returns, including IRET and RSM.
o VM exits and VM entries.¹
— VM exits include the values written to the “exit reason” and “exit qualification” VMCS fields.
INIT and SIPI events.
o TSX aborts, including the abort status returned for the RTM instructions.
o Shutdown.
Additionally, it provides indication of the status of the Interrupt Flag
(IF), to indicate when interrupts are masked.
</quote>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20220124084201.2699795-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-01-24 10:41:39 +02:00
case 0x13 : /* CFE */
return intel_pt_get_cfe ( buf , len , packet ) ;
case 0x53 : /* EVD */
return intel_pt_get_evd ( buf , len , packet ) ;
2015-07-17 19:33:37 +03:00
default :
return INTEL_PT_BAD_PACKET ;
}
}
static int intel_pt_get_short_tnt ( unsigned int byte ,
struct intel_pt_pkt * packet )
{
int count ;
for ( count = 6 ; count ; count - - ) {
if ( byte & BIT ( 7 ) )
break ;
byte < < = 1 ;
}
packet - > type = INTEL_PT_TNT ;
packet - > count = count ;
packet - > payload = ( uint64_t ) byte < < 57 ;
return 1 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_cyc ( unsigned int byte , const unsigned char * buf ,
size_t len , struct intel_pt_pkt * packet )
{
unsigned int offs = 1 , shift ;
uint64_t payload = byte > > 3 ;
byte > > = 2 ;
len - = 1 ;
for ( shift = 5 ; byte & 1 ; shift + = 7 ) {
if ( offs > 9 )
return INTEL_PT_BAD_PACKET ;
if ( len < offs )
return INTEL_PT_NEED_MORE_BYTES ;
byte = buf [ offs + + ] ;
2018-06-07 14:30:02 +03:00
payload | = ( ( uint64_t ) byte > > 1 ) < < shift ;
2015-07-17 19:33:53 +03:00
}
packet - > type = INTEL_PT_CYC ;
packet - > payload = payload ;
return offs ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_get_ip ( enum intel_pt_pkt_type type , unsigned int byte ,
const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
2016-07-20 12:00:06 +03:00
int ip_len ;
packet - > count = byte > > 5 ;
switch ( packet - > count ) {
2015-07-17 19:33:37 +03:00
case 0 :
2016-07-20 12:00:06 +03:00
ip_len = 0 ;
2015-07-17 19:33:37 +03:00
break ;
case 1 :
if ( len < 3 )
return INTEL_PT_NEED_MORE_BYTES ;
2016-07-20 12:00:06 +03:00
ip_len = 2 ;
2015-07-17 19:33:37 +03:00
packet - > payload = le16_to_cpu ( * ( uint16_t * ) ( buf + 1 ) ) ;
break ;
case 2 :
if ( len < 5 )
return INTEL_PT_NEED_MORE_BYTES ;
2016-07-20 12:00:06 +03:00
ip_len = 4 ;
2015-07-17 19:33:37 +03:00
packet - > payload = le32_to_cpu ( * ( uint32_t * ) ( buf + 1 ) ) ;
break ;
case 3 :
2016-07-20 12:00:06 +03:00
case 4 :
2015-07-17 19:33:37 +03:00
if ( len < 7 )
return INTEL_PT_NEED_MORE_BYTES ;
2016-07-20 12:00:06 +03:00
ip_len = 6 ;
2015-07-17 19:33:37 +03:00
memcpy_le64 ( & packet - > payload , buf + 1 , 6 ) ;
break ;
2016-07-20 12:00:06 +03:00
case 6 :
if ( len < 9 )
return INTEL_PT_NEED_MORE_BYTES ;
ip_len = 8 ;
packet - > payload = le64_to_cpu ( * ( uint64_t * ) ( buf + 1 ) ) ;
break ;
2015-07-17 19:33:37 +03:00
default :
return INTEL_PT_BAD_PACKET ;
}
packet - > type = type ;
2016-07-20 12:00:06 +03:00
return ip_len + 1 ;
2015-07-17 19:33:37 +03:00
}
static int intel_pt_get_mode ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 2 )
return INTEL_PT_NEED_MORE_BYTES ;
switch ( buf [ 1 ] > > 5 ) {
case 0 :
packet - > type = INTEL_PT_MODE_EXEC ;
2022-01-24 10:41:40 +02:00
packet - > count = buf [ 1 ] ;
2015-07-17 19:33:37 +03:00
switch ( buf [ 1 ] & 3 ) {
case 0 :
packet - > payload = 16 ;
break ;
case 1 :
packet - > payload = 64 ;
break ;
case 2 :
packet - > payload = 32 ;
break ;
default :
return INTEL_PT_BAD_PACKET ;
}
break ;
case 1 :
packet - > type = INTEL_PT_MODE_TSX ;
if ( ( buf [ 1 ] & 3 ) = = 3 )
return INTEL_PT_BAD_PACKET ;
packet - > payload = buf [ 1 ] & 3 ;
break ;
default :
return INTEL_PT_BAD_PACKET ;
}
return 2 ;
}
static int intel_pt_get_tsc ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 8 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_TSC ;
memcpy_le64 ( & packet - > payload , buf + 1 , 7 ) ;
return 8 ;
}
2015-07-17 19:33:53 +03:00
static int intel_pt_get_mtc ( const unsigned char * buf , size_t len ,
struct intel_pt_pkt * packet )
{
if ( len < 2 )
return INTEL_PT_NEED_MORE_BYTES ;
packet - > type = INTEL_PT_MTC ;
packet - > payload = buf [ 1 ] ;
return 2 ;
}
2015-07-17 19:33:37 +03:00
static int intel_pt_do_get_packet ( const unsigned char * buf , size_t len ,
2019-06-10 10:27:53 +03:00
struct intel_pt_pkt * packet ,
enum intel_pt_pkt_ctx ctx )
2015-07-17 19:33:37 +03:00
{
unsigned int byte ;
memset ( packet , 0 , sizeof ( struct intel_pt_pkt ) ) ;
if ( ! len )
return INTEL_PT_NEED_MORE_BYTES ;
byte = buf [ 0 ] ;
2019-06-10 10:27:53 +03:00
switch ( ctx ) {
case INTEL_PT_NO_CTX :
break ;
case INTEL_PT_BLK_4_CTX :
if ( ( byte & 0x7 ) = = 4 )
return intel_pt_get_bip_4 ( buf , len , packet ) ;
break ;
case INTEL_PT_BLK_8_CTX :
if ( ( byte & 0x7 ) = = 4 )
return intel_pt_get_bip_8 ( buf , len , packet ) ;
break ;
default :
break ;
2020-04-28 17:18:43 +08:00
}
2019-06-10 10:27:53 +03:00
2015-07-17 19:33:37 +03:00
if ( ! ( byte & BIT ( 0 ) ) ) {
if ( byte = = 0 )
return intel_pt_get_pad ( packet ) ;
if ( byte = = 2 )
return intel_pt_get_ext ( buf , len , packet ) ;
return intel_pt_get_short_tnt ( byte , packet ) ;
}
2015-07-17 19:33:53 +03:00
if ( ( byte & 2 ) )
return intel_pt_get_cyc ( byte , buf , len , packet ) ;
2015-07-17 19:33:37 +03:00
switch ( byte & 0x1f ) {
case 0x0D :
return intel_pt_get_ip ( INTEL_PT_TIP , byte , buf , len , packet ) ;
case 0x11 :
return intel_pt_get_ip ( INTEL_PT_TIP_PGE , byte , buf , len ,
packet ) ;
case 0x01 :
return intel_pt_get_ip ( INTEL_PT_TIP_PGD , byte , buf , len ,
packet ) ;
case 0x1D :
return intel_pt_get_ip ( INTEL_PT_FUP , byte , buf , len , packet ) ;
case 0x19 :
switch ( byte ) {
case 0x99 :
return intel_pt_get_mode ( buf , len , packet ) ;
case 0x19 :
return intel_pt_get_tsc ( buf , len , packet ) ;
2015-07-17 19:33:53 +03:00
case 0x59 :
return intel_pt_get_mtc ( buf , len , packet ) ;
2015-07-17 19:33:37 +03:00
default :
return INTEL_PT_BAD_PACKET ;
}
default :
return INTEL_PT_BAD_PACKET ;
}
}
2019-06-10 10:27:53 +03:00
void intel_pt_upd_pkt_ctx ( const struct intel_pt_pkt * packet ,
enum intel_pt_pkt_ctx * ctx )
{
switch ( packet - > type ) {
case INTEL_PT_BAD :
case INTEL_PT_PAD :
case INTEL_PT_TSC :
case INTEL_PT_TMA :
case INTEL_PT_MTC :
case INTEL_PT_FUP :
case INTEL_PT_CYC :
case INTEL_PT_CBR :
case INTEL_PT_MNT :
case INTEL_PT_EXSTOP :
case INTEL_PT_EXSTOP_IP :
case INTEL_PT_PWRE :
case INTEL_PT_PWRX :
case INTEL_PT_BIP :
break ;
case INTEL_PT_TNT :
case INTEL_PT_TIP :
case INTEL_PT_TIP_PGD :
case INTEL_PT_TIP_PGE :
case INTEL_PT_MODE_EXEC :
case INTEL_PT_MODE_TSX :
case INTEL_PT_PIP :
case INTEL_PT_OVF :
case INTEL_PT_VMCS :
case INTEL_PT_TRACESTOP :
case INTEL_PT_PSB :
case INTEL_PT_PSBEND :
case INTEL_PT_PTWRITE :
case INTEL_PT_PTWRITE_IP :
case INTEL_PT_MWAIT :
case INTEL_PT_BEP :
case INTEL_PT_BEP_IP :
perf intel-pt: pkt-decoder: Add CFE and EVD packets
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new
Intel PT feature called Event Trace which requires 2 new packets CFE and
EVD. Add them to the packet decoder and packet decoder test.
Committer notes:
I got the "Intel® 64 and IA-32 architectures software developer’s manual
combined volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:
https://cdrdv2.intel.com/v1/dl/getContent/671200
And these new packets are described in page 3951:
<quote>
32.2.4
Event Trace is a capability that exposes details about the asynchronous
events, when they are generated, and when their corresponding software
event handler completes execution. These include:
o Interrupts, including NMI and SMI, including the interrupt vector when
defined.
o Faults, exceptions including the fault vector.
— Page faults additionally include the page fault address, when in context.
o Event handler returns, including IRET and RSM.
o VM exits and VM entries.¹
— VM exits include the values written to the “exit reason” and “exit qualification” VMCS fields.
INIT and SIPI events.
o TSX aborts, including the abort status returned for the RTM instructions.
o Shutdown.
Additionally, it provides indication of the status of the Interrupt Flag
(IF), to indicate when interrupts are masked.
</quote>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20220124084201.2699795-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-01-24 10:41:39 +02:00
case INTEL_PT_CFE :
case INTEL_PT_CFE_IP :
case INTEL_PT_EVD :
2019-06-10 10:27:53 +03:00
* ctx = INTEL_PT_NO_CTX ;
break ;
case INTEL_PT_BBP :
if ( packet - > count )
* ctx = INTEL_PT_BLK_4_CTX ;
else
* ctx = INTEL_PT_BLK_8_CTX ;
break ;
default :
break ;
}
}
2015-07-17 19:33:37 +03:00
int intel_pt_get_packet ( const unsigned char * buf , size_t len ,
2019-06-10 10:27:53 +03:00
struct intel_pt_pkt * packet , enum intel_pt_pkt_ctx * ctx )
2015-07-17 19:33:37 +03:00
{
int ret ;
2019-06-10 10:27:53 +03:00
ret = intel_pt_do_get_packet ( buf , len , packet , * ctx ) ;
2015-07-17 19:33:37 +03:00
if ( ret > 0 ) {
while ( ret < 8 & & len > ( size_t ) ret & & ! buf [ ret ] )
ret + = 1 ;
2019-06-10 10:27:53 +03:00
intel_pt_upd_pkt_ctx ( packet , ctx ) ;
2015-07-17 19:33:37 +03:00
}
return ret ;
}
int intel_pt_pkt_desc ( const struct intel_pt_pkt * packet , char * buf ,
size_t buf_len )
{
2015-07-17 19:33:53 +03:00
int ret , i , nr ;
2015-07-17 19:33:37 +03:00
unsigned long long payload = packet - > payload ;
const char * name = intel_pt_pkt_name ( packet - > type ) ;
switch ( packet - > type ) {
case INTEL_PT_BAD :
case INTEL_PT_PAD :
case INTEL_PT_PSB :
case INTEL_PT_PSBEND :
2015-07-17 19:33:53 +03:00
case INTEL_PT_TRACESTOP :
2015-07-17 19:33:37 +03:00
case INTEL_PT_OVF :
return snprintf ( buf , buf_len , " %s " , name ) ;
case INTEL_PT_TNT : {
size_t blen = buf_len ;
ret = snprintf ( buf , blen , " %s " , name ) ;
if ( ret < 0 )
return ret ;
buf + = ret ;
blen - = ret ;
for ( i = 0 ; i < packet - > count ; i + + ) {
if ( payload & BIT63 )
ret = snprintf ( buf , blen , " T " ) ;
else
ret = snprintf ( buf , blen , " N " ) ;
if ( ret < 0 )
return ret ;
buf + = ret ;
blen - = ret ;
payload < < = 1 ;
}
ret = snprintf ( buf , blen , " (%d) " , packet - > count ) ;
if ( ret < 0 )
return ret ;
blen - = ret ;
return buf_len - blen ;
}
case INTEL_PT_TIP_PGD :
case INTEL_PT_TIP_PGE :
case INTEL_PT_TIP :
case INTEL_PT_FUP :
if ( ! ( packet - > count ) )
return snprintf ( buf , buf_len , " %s no ip " , name ) ;
2017-02-09 15:22:22 -03:00
__fallthrough ;
2015-07-17 19:33:53 +03:00
case INTEL_PT_CYC :
case INTEL_PT_VMCS :
case INTEL_PT_MTC :
case INTEL_PT_MNT :
2015-07-17 19:33:37 +03:00
case INTEL_PT_CBR :
case INTEL_PT_TSC :
2015-07-17 19:33:53 +03:00
return snprintf ( buf , buf_len , " %s 0x%llx " , name , payload ) ;
case INTEL_PT_TMA :
return snprintf ( buf , buf_len , " %s CTC 0x%x FC 0x%x " , name ,
( unsigned ) payload , packet - > count ) ;
2015-07-17 19:33:37 +03:00
case INTEL_PT_MODE_EXEC :
2022-01-24 10:41:40 +02:00
return snprintf ( buf , buf_len , " %s IF:%d %lld " ,
name , ! ! ( packet - > count & 4 ) , payload ) ;
2015-07-17 19:33:37 +03:00
case INTEL_PT_MODE_TSX :
return snprintf ( buf , buf_len , " %s TXAbort:%u InTX:%u " ,
name , ( unsigned ) ( payload > > 1 ) & 1 ,
( unsigned ) payload & 1 ) ;
case INTEL_PT_PIP :
2021-02-18 11:57:53 +02:00
nr = packet - > payload & INTEL_PT_VMX_NR_FLAG ? 1 : 0 ;
payload & = ~ INTEL_PT_VMX_NR_FLAG ;
2015-07-17 19:33:53 +03:00
ret = snprintf ( buf , buf_len , " %s 0x%llx (NR=%d) " ,
2021-02-18 11:57:53 +02:00
name , payload > > 1 , nr ) ;
2015-07-17 19:33:37 +03:00
return ret ;
2017-05-26 11:17:14 +03:00
case INTEL_PT_PTWRITE :
return snprintf ( buf , buf_len , " %s 0x%llx IP:0 " , name , payload ) ;
case INTEL_PT_PTWRITE_IP :
return snprintf ( buf , buf_len , " %s 0x%llx IP:1 " , name , payload ) ;
2019-06-10 10:27:53 +03:00
case INTEL_PT_BEP :
2017-05-26 11:17:14 +03:00
case INTEL_PT_EXSTOP :
return snprintf ( buf , buf_len , " %s IP:0 " , name ) ;
2019-06-10 10:27:53 +03:00
case INTEL_PT_BEP_IP :
2017-05-26 11:17:14 +03:00
case INTEL_PT_EXSTOP_IP :
return snprintf ( buf , buf_len , " %s IP:1 " , name ) ;
case INTEL_PT_MWAIT :
return snprintf ( buf , buf_len , " %s 0x%llx Hints 0x%x Extensions 0x%x " ,
name , payload , ( unsigned int ) ( payload & 0xff ) ,
( unsigned int ) ( ( payload > > 32 ) & 0x3 ) ) ;
case INTEL_PT_PWRE :
return snprintf ( buf , buf_len , " %s 0x%llx HW:%u CState:%u Sub-CState:%u " ,
name , payload , ! ! ( payload & 0x80 ) ,
( unsigned int ) ( ( payload > > 12 ) & 0xf ) ,
( unsigned int ) ( ( payload > > 8 ) & 0xf ) ) ;
case INTEL_PT_PWRX :
return snprintf ( buf , buf_len , " %s 0x%llx Last CState:%u Deepest CState:%u Wake Reason 0x%x " ,
name , payload ,
( unsigned int ) ( ( payload > > 4 ) & 0xf ) ,
( unsigned int ) ( payload & 0xf ) ,
( unsigned int ) ( ( payload > > 8 ) & 0xf ) ) ;
2019-06-10 10:27:53 +03:00
case INTEL_PT_BBP :
return snprintf ( buf , buf_len , " %s SZ %s-byte Type 0x%llx " ,
name , packet - > count ? " 4 " : " 8 " , payload ) ;
case INTEL_PT_BIP :
return snprintf ( buf , buf_len , " %s ID 0x%02x Value 0x%llx " ,
name , packet - > count , payload ) ;
perf intel-pt: pkt-decoder: Add CFE and EVD packets
As of Intel SDM (https://www.intel.com/sdm) version 076, there is a new
Intel PT feature called Event Trace which requires 2 new packets CFE and
EVD. Add them to the packet decoder and packet decoder test.
Committer notes:
I got the "Intel® 64 and IA-32 architectures software developer’s manual
combined volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4" PDF at:
https://cdrdv2.intel.com/v1/dl/getContent/671200
And these new packets are described in page 3951:
<quote>
32.2.4
Event Trace is a capability that exposes details about the asynchronous
events, when they are generated, and when their corresponding software
event handler completes execution. These include:
o Interrupts, including NMI and SMI, including the interrupt vector when
defined.
o Faults, exceptions including the fault vector.
— Page faults additionally include the page fault address, when in context.
o Event handler returns, including IRET and RSM.
o VM exits and VM entries.¹
— VM exits include the values written to the “exit reason” and “exit qualification” VMCS fields.
INIT and SIPI events.
o TSX aborts, including the abort status returned for the RTM instructions.
o Shutdown.
Additionally, it provides indication of the status of the Interrupt Flag
(IF), to indicate when interrupts are masked.
</quote>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20220124084201.2699795-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-01-24 10:41:39 +02:00
case INTEL_PT_CFE :
case INTEL_PT_CFE_IP :
return snprintf ( buf , buf_len , " %s IP:%d Type 0x%02x Vector 0x%llx " ,
name , packet - > type = = INTEL_PT_CFE_IP , packet - > count , payload ) ;
case INTEL_PT_EVD :
return snprintf ( buf , buf_len , " %s Type 0x%02x Payload 0x%llx " ,
name , packet - > count , payload ) ;
2015-07-17 19:33:37 +03:00
default :
break ;
}
return snprintf ( buf , buf_len , " %s 0x%llx (%d) " ,
name , payload , packet - > count ) ;
}