cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

arm-spe-pkt-decoder.c (14650B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Arm Statistical Profiling Extensions (SPE) support
      4 * Copyright (c) 2017-2018, Arm Ltd.
      5 */
      6
      7#include <stdio.h>
      8#include <string.h>
      9#include <endian.h>
     10#include <byteswap.h>
     11#include <linux/bitops.h>
     12#include <stdarg.h>
     13
     14#include "arm-spe-pkt-decoder.h"
     15
     16#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
     17#define le16_to_cpu bswap_16
     18#define le32_to_cpu bswap_32
     19#define le64_to_cpu bswap_64
     20#define memcpy_le64(d, s, n) do { \
     21	memcpy((d), (s), (n));    \
     22	*(d) = le64_to_cpu(*(d)); \
     23} while (0)
     24#else
     25#define le16_to_cpu
     26#define le32_to_cpu
     27#define le64_to_cpu
     28#define memcpy_le64 memcpy
     29#endif
     30
     31static const char * const arm_spe_packet_name[] = {
     32	[ARM_SPE_PAD]		= "PAD",
     33	[ARM_SPE_END]		= "END",
     34	[ARM_SPE_TIMESTAMP]	= "TS",
     35	[ARM_SPE_ADDRESS]	= "ADDR",
     36	[ARM_SPE_COUNTER]	= "LAT",
     37	[ARM_SPE_CONTEXT]	= "CONTEXT",
     38	[ARM_SPE_OP_TYPE]	= "OP-TYPE",
     39	[ARM_SPE_EVENTS]	= "EVENTS",
     40	[ARM_SPE_DATA_SOURCE]	= "DATA-SOURCE",
     41};
     42
     43const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
     44{
     45	return arm_spe_packet_name[type];
     46}
     47
     48/*
     49 * Extracts the field "sz" from header bits and converts to bytes:
     50 *   00 : byte (1)
     51 *   01 : halfword (2)
     52 *   10 : word (4)
     53 *   11 : doubleword (8)
     54 */
     55static unsigned int arm_spe_payload_len(unsigned char hdr)
     56{
     57	return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
     58}
     59
     60static int arm_spe_get_payload(const unsigned char *buf, size_t len,
     61			       unsigned char ext_hdr,
     62			       struct arm_spe_pkt *packet)
     63{
     64	size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
     65
     66	if (len < 1 + ext_hdr + payload_len)
     67		return ARM_SPE_NEED_MORE_BYTES;
     68
     69	buf += 1 + ext_hdr;
     70
     71	switch (payload_len) {
     72	case 1: packet->payload = *(uint8_t *)buf; break;
     73	case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
     74	case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
     75	case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
     76	default: return ARM_SPE_BAD_PACKET;
     77	}
     78
     79	return 1 + ext_hdr + payload_len;
     80}
     81
     82static int arm_spe_get_pad(struct arm_spe_pkt *packet)
     83{
     84	packet->type = ARM_SPE_PAD;
     85	return 1;
     86}
     87
     88static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
     89				 struct arm_spe_pkt *packet)
     90{
     91	unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
     92
     93	if (len < alignment)
     94		return ARM_SPE_NEED_MORE_BYTES;
     95
     96	packet->type = ARM_SPE_PAD;
     97	return alignment - (((uintptr_t)buf) & (alignment - 1));
     98}
     99
    100static int arm_spe_get_end(struct arm_spe_pkt *packet)
    101{
    102	packet->type = ARM_SPE_END;
    103	return 1;
    104}
    105
    106static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
    107				 struct arm_spe_pkt *packet)
    108{
    109	packet->type = ARM_SPE_TIMESTAMP;
    110	return arm_spe_get_payload(buf, len, 0, packet);
    111}
    112
    113static int arm_spe_get_events(const unsigned char *buf, size_t len,
    114			      struct arm_spe_pkt *packet)
    115{
    116	packet->type = ARM_SPE_EVENTS;
    117
    118	/* we use index to identify Events with a less number of
    119	 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
    120	 * LLC-REFILL, and REMOTE-ACCESS events are identified if
    121	 * index > 1.
    122	 */
    123	packet->index = arm_spe_payload_len(buf[0]);
    124
    125	return arm_spe_get_payload(buf, len, 0, packet);
    126}
    127
    128static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
    129				   struct arm_spe_pkt *packet)
    130{
    131	packet->type = ARM_SPE_DATA_SOURCE;
    132	return arm_spe_get_payload(buf, len, 0, packet);
    133}
    134
    135static int arm_spe_get_context(const unsigned char *buf, size_t len,
    136			       struct arm_spe_pkt *packet)
    137{
    138	packet->type = ARM_SPE_CONTEXT;
    139	packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
    140	return arm_spe_get_payload(buf, len, 0, packet);
    141}
    142
    143static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
    144			       struct arm_spe_pkt *packet)
    145{
    146	packet->type = ARM_SPE_OP_TYPE;
    147	packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
    148	return arm_spe_get_payload(buf, len, 0, packet);
    149}
    150
    151static int arm_spe_get_counter(const unsigned char *buf, size_t len,
    152			       const unsigned char ext_hdr, struct arm_spe_pkt *packet)
    153{
    154	packet->type = ARM_SPE_COUNTER;
    155
    156	if (ext_hdr)
    157		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
    158	else
    159		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
    160
    161	return arm_spe_get_payload(buf, len, ext_hdr, packet);
    162}
    163
    164static int arm_spe_get_addr(const unsigned char *buf, size_t len,
    165			    const unsigned char ext_hdr, struct arm_spe_pkt *packet)
    166{
    167	packet->type = ARM_SPE_ADDRESS;
    168
    169	if (ext_hdr)
    170		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
    171	else
    172		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
    173
    174	return arm_spe_get_payload(buf, len, ext_hdr, packet);
    175}
    176
    177static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
    178				 struct arm_spe_pkt *packet)
    179{
    180	unsigned int hdr;
    181	unsigned char ext_hdr = 0;
    182
    183	memset(packet, 0, sizeof(struct arm_spe_pkt));
    184
    185	if (!len)
    186		return ARM_SPE_NEED_MORE_BYTES;
    187
    188	hdr = buf[0];
    189
    190	if (hdr == SPE_HEADER0_PAD)
    191		return arm_spe_get_pad(packet);
    192
    193	if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
    194		return arm_spe_get_end(packet);
    195
    196	if (hdr == SPE_HEADER0_TIMESTAMP)
    197		return arm_spe_get_timestamp(buf, len, packet);
    198
    199	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
    200		return arm_spe_get_events(buf, len, packet);
    201
    202	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
    203		return arm_spe_get_data_source(buf, len, packet);
    204
    205	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
    206		return arm_spe_get_context(buf, len, packet);
    207
    208	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
    209		return arm_spe_get_op_type(buf, len, packet);
    210
    211	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
    212		/* 16-bit extended format header */
    213		if (len == 1)
    214			return ARM_SPE_BAD_PACKET;
    215
    216		ext_hdr = 1;
    217		hdr = buf[1];
    218		if (hdr == SPE_HEADER1_ALIGNMENT)
    219			return arm_spe_get_alignment(buf, len, packet);
    220	}
    221
    222	/*
    223	 * The short format header's byte 0 or the extended format header's
    224	 * byte 1 has been assigned to 'hdr', which uses the same encoding for
    225	 * address packet and counter packet, so don't need to distinguish if
    226	 * it's short format or extended format and handle in once.
    227	 */
    228	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
    229		return arm_spe_get_addr(buf, len, ext_hdr, packet);
    230
    231	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
    232		return arm_spe_get_counter(buf, len, ext_hdr, packet);
    233
    234	return ARM_SPE_BAD_PACKET;
    235}
    236
    237int arm_spe_get_packet(const unsigned char *buf, size_t len,
    238		       struct arm_spe_pkt *packet)
    239{
    240	int ret;
    241
    242	ret = arm_spe_do_get_packet(buf, len, packet);
    243	/* put multiple consecutive PADs on the same line, up to
    244	 * the fixed-width output format of 16 bytes per line.
    245	 */
    246	if (ret > 0 && packet->type == ARM_SPE_PAD) {
    247		while (ret < 16 && len > (size_t)ret && !buf[ret])
    248			ret += 1;
    249	}
    250	return ret;
    251}
    252
    253static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
    254				  const char *fmt, ...)
    255{
    256	va_list ap;
    257	int ret;
    258
    259	/* Bail out if any error occurred */
    260	if (err && *err)
    261		return *err;
    262
    263	va_start(ap, fmt);
    264	ret = vsnprintf(*buf_p, *blen, fmt, ap);
    265	va_end(ap);
    266
    267	if (ret < 0) {
    268		if (err && !*err)
    269			*err = ret;
    270
    271	/*
    272	 * A return value of *blen or more means that the output was
    273	 * truncated and the buffer is overrun.
    274	 */
    275	} else if ((size_t)ret >= *blen) {
    276		(*buf_p)[*blen - 1] = '\0';
    277
    278		/*
    279		 * Set *err to 'ret' to avoid overflow if tries to
    280		 * fill this buffer sequentially.
    281		 */
    282		if (err && !*err)
    283			*err = ret;
    284	} else {
    285		*buf_p += ret;
    286		*blen -= ret;
    287	}
    288
    289	return ret;
    290}
    291
    292static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
    293				  char *buf, size_t buf_len)
    294{
    295	u64 payload = packet->payload;
    296	int err = 0;
    297
    298	arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
    299
    300	if (payload & BIT(EV_EXCEPTION_GEN))
    301		arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
    302	if (payload & BIT(EV_RETIRED))
    303		arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
    304	if (payload & BIT(EV_L1D_ACCESS))
    305		arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
    306	if (payload & BIT(EV_L1D_REFILL))
    307		arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
    308	if (payload & BIT(EV_TLB_ACCESS))
    309		arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
    310	if (payload & BIT(EV_TLB_WALK))
    311		arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
    312	if (payload & BIT(EV_NOT_TAKEN))
    313		arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
    314	if (payload & BIT(EV_MISPRED))
    315		arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
    316	if (payload & BIT(EV_LLC_ACCESS))
    317		arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
    318	if (payload & BIT(EV_LLC_MISS))
    319		arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
    320	if (payload & BIT(EV_REMOTE_ACCESS))
    321		arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
    322	if (payload & BIT(EV_ALIGNMENT))
    323		arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT");
    324	if (payload & BIT(EV_PARTIAL_PREDICATE))
    325		arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED");
    326	if (payload & BIT(EV_EMPTY_PREDICATE))
    327		arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
    328
    329	return err;
    330}
    331
    332static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
    333				    char *buf, size_t buf_len)
    334{
    335	u64 payload = packet->payload;
    336	int err = 0;
    337
    338	switch (packet->index) {
    339	case SPE_OP_PKT_HDR_CLASS_OTHER:
    340		if (SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
    341			arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
    342
    343			/* SVE effective vector length */
    344			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
    345					       SPE_OP_PKG_SVE_EVL(payload));
    346
    347			if (payload & SPE_OP_PKT_SVE_FP)
    348				arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
    349			if (payload & SPE_OP_PKT_SVE_PRED)
    350				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
    351		} else {
    352			arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
    353			arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
    354					       payload & SPE_OP_PKT_COND ?
    355					       "COND-SELECT" : "INSN-OTHER");
    356		}
    357		break;
    358	case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
    359		arm_spe_pkt_out_string(&err, &buf, &buf_len,
    360				       payload & 0x1 ? "ST" : "LD");
    361
    362		if (SPE_OP_PKT_IS_LDST_ATOMIC(payload)) {
    363			if (payload & SPE_OP_PKT_AT)
    364				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
    365			if (payload & SPE_OP_PKT_EXCL)
    366				arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
    367			if (payload & SPE_OP_PKT_AR)
    368				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
    369		}
    370
    371		switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) {
    372		case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP:
    373			arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
    374			break;
    375		case SPE_OP_PKT_LDST_SUBCLASS_GP_REG:
    376			arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
    377			break;
    378		case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG:
    379			arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
    380			break;
    381		case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG:
    382			arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
    383			break;
    384		default:
    385			break;
    386		}
    387
    388		if (SPE_OP_PKT_IS_LDST_SVE(payload)) {
    389			/* SVE effective vector length */
    390			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
    391					       SPE_OP_PKG_SVE_EVL(payload));
    392
    393			if (payload & SPE_OP_PKT_SVE_PRED)
    394				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
    395			if (payload & SPE_OP_PKT_SVE_SG)
    396				arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
    397		}
    398		break;
    399	case SPE_OP_PKT_HDR_CLASS_BR_ERET:
    400		arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
    401
    402		if (payload & SPE_OP_PKT_COND)
    403			arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
    404
    405		if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
    406			arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
    407
    408		break;
    409	default:
    410		/* Unknown index */
    411		err = -1;
    412		break;
    413	}
    414
    415	return err;
    416}
    417
    418static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
    419				 char *buf, size_t buf_len)
    420{
    421	int ns, el, idx = packet->index;
    422	int ch, pat;
    423	u64 payload = packet->payload;
    424	int err = 0;
    425
    426	switch (idx) {
    427	case SPE_ADDR_PKT_HDR_INDEX_INS:
    428	case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
    429		ns = !!SPE_ADDR_PKT_GET_NS(payload);
    430		el = SPE_ADDR_PKT_GET_EL(payload);
    431		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
    432		arm_spe_pkt_out_string(&err, &buf, &buf_len,
    433				"%s 0x%llx el%d ns=%d",
    434				(idx == 1) ? "TGT" : "PC", payload, el, ns);
    435		break;
    436	case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
    437		arm_spe_pkt_out_string(&err, &buf, &buf_len,
    438				       "VA 0x%llx", payload);
    439		break;
    440	case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
    441		ns = !!SPE_ADDR_PKT_GET_NS(payload);
    442		ch = !!SPE_ADDR_PKT_GET_CH(payload);
    443		pat = SPE_ADDR_PKT_GET_PAT(payload);
    444		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
    445		arm_spe_pkt_out_string(&err, &buf, &buf_len,
    446				       "PA 0x%llx ns=%d ch=%d pat=%x",
    447				       payload, ns, ch, pat);
    448		break;
    449	default:
    450		/* Unknown index */
    451		err = -1;
    452		break;
    453	}
    454
    455	return err;
    456}
    457
    458static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
    459				    char *buf, size_t buf_len)
    460{
    461	u64 payload = packet->payload;
    462	const char *name = arm_spe_pkt_name(packet->type);
    463	int err = 0;
    464
    465	arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
    466			       (unsigned short)payload);
    467
    468	switch (packet->index) {
    469	case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
    470		arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
    471		break;
    472	case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
    473		arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
    474		break;
    475	case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
    476		arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
    477		break;
    478	default:
    479		break;
    480	}
    481
    482	return err;
    483}
    484
    485int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
    486		     size_t buf_len)
    487{
    488	int idx = packet->index;
    489	unsigned long long payload = packet->payload;
    490	const char *name = arm_spe_pkt_name(packet->type);
    491	char *buf_orig = buf;
    492	size_t blen = buf_len;
    493	int err = 0;
    494
    495	switch (packet->type) {
    496	case ARM_SPE_BAD:
    497	case ARM_SPE_PAD:
    498	case ARM_SPE_END:
    499		arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
    500		break;
    501	case ARM_SPE_EVENTS:
    502		err = arm_spe_pkt_desc_event(packet, buf, buf_len);
    503		break;
    504	case ARM_SPE_OP_TYPE:
    505		err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
    506		break;
    507	case ARM_SPE_DATA_SOURCE:
    508	case ARM_SPE_TIMESTAMP:
    509		arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
    510		break;
    511	case ARM_SPE_ADDRESS:
    512		err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
    513		break;
    514	case ARM_SPE_CONTEXT:
    515		arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
    516				       name, (unsigned long)payload, idx + 1);
    517		break;
    518	case ARM_SPE_COUNTER:
    519		err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
    520		break;
    521	default:
    522		/* Unknown packet type */
    523		err = -1;
    524		break;
    525	}
    526
    527	/* Output raw data if detect any error */
    528	if (err) {
    529		err = 0;
    530		arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
    531				       name, payload, packet->index);
    532	}
    533
    534	return err;
    535}