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		case SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG:
385			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MTE-TAG");
386			break;
387		case SPE_OP_PKT_LDST_SUBCLASS_MEMCPY:
388			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMCPY");
389			break;
390		case SPE_OP_PKT_LDST_SUBCLASS_MEMSET:
391			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMSET");
392			break;
393		default:
394			break;
395		}
396
397		if (SPE_OP_PKT_IS_LDST_SVE(payload)) {
398			/* SVE effective vector length */
399			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
400					       SPE_OP_PKG_SVE_EVL(payload));
401
402			if (payload & SPE_OP_PKT_SVE_PRED)
403				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
404			if (payload & SPE_OP_PKT_SVE_SG)
405				arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
406		}
407		break;
408	case SPE_OP_PKT_HDR_CLASS_BR_ERET:
409		arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
410
411		if (payload & SPE_OP_PKT_COND)
412			arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
413
414		if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
415			arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
416
417		break;
418	default:
419		/* Unknown index */
420		err = -1;
421		break;
422	}
423
424	return err;
425}
426
427static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
428				 char *buf, size_t buf_len)
429{
430	int ns, el, idx = packet->index;
431	int ch, pat;
432	u64 payload = packet->payload;
433	int err = 0;
434	static const char *idx_name[] = {"PC", "TGT", "VA", "PA", "PBT"};
435
436	switch (idx) {
437	case SPE_ADDR_PKT_HDR_INDEX_INS:
438	case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
439	case SPE_ADDR_PKT_HDR_INDEX_PREV_BRANCH:
440		ns = !!SPE_ADDR_PKT_GET_NS(payload);
441		el = SPE_ADDR_PKT_GET_EL(payload);
442		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
443		arm_spe_pkt_out_string(&err, &buf, &buf_len,
444				"%s 0x%llx el%d ns=%d",
445				idx_name[idx], payload, el, ns);
446		break;
447	case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
448		arm_spe_pkt_out_string(&err, &buf, &buf_len,
449				       "VA 0x%llx", payload);
450		break;
451	case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
452		ns = !!SPE_ADDR_PKT_GET_NS(payload);
453		ch = !!SPE_ADDR_PKT_GET_CH(payload);
454		pat = SPE_ADDR_PKT_GET_PAT(payload);
455		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
456		arm_spe_pkt_out_string(&err, &buf, &buf_len,
457				       "PA 0x%llx ns=%d ch=%d pat=%x",
458				       payload, ns, ch, pat);
459		break;
460	default:
461		/* Unknown index */
462		err = -1;
463		break;
464	}
465
466	return err;
467}
468
469static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
470				    char *buf, size_t buf_len)
471{
472	u64 payload = packet->payload;
473	const char *name = arm_spe_pkt_name(packet->type);
474	int err = 0;
475
476	arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
477			       (unsigned short)payload);
478
479	switch (packet->index) {
480	case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
481		arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
482		break;
483	case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
484		arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
485		break;
486	case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
487		arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
488		break;
489	default:
490		break;
491	}
492
493	return err;
494}
495
496int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
497		     size_t buf_len)
498{
499	int idx = packet->index;
500	unsigned long long payload = packet->payload;
501	const char *name = arm_spe_pkt_name(packet->type);
502	char *buf_orig = buf;
503	size_t blen = buf_len;
504	int err = 0;
505
506	switch (packet->type) {
507	case ARM_SPE_BAD:
508	case ARM_SPE_PAD:
509	case ARM_SPE_END:
510		arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
511		break;
512	case ARM_SPE_EVENTS:
513		err = arm_spe_pkt_desc_event(packet, buf, buf_len);
514		break;
515	case ARM_SPE_OP_TYPE:
516		err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
517		break;
518	case ARM_SPE_DATA_SOURCE:
519	case ARM_SPE_TIMESTAMP:
520		arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
521		break;
522	case ARM_SPE_ADDRESS:
523		err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
524		break;
525	case ARM_SPE_CONTEXT:
526		arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
527				       name, (unsigned long)payload, idx + 1);
528		break;
529	case ARM_SPE_COUNTER:
530		err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
531		break;
532	default:
533		/* Unknown packet type */
534		err = -1;
535		break;
536	}
537
538	/* Output raw data if detect any error */
539	if (err) {
540		err = 0;
541		arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
542				       name, payload, packet->index);
543	}
544
545	return err;
546}
547