xref: /linux/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c (revision da1d9caf95def6f0320819cf941c9fd1069ba9e1)
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 
31 static 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 
43 const 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  */
55 static unsigned int arm_spe_payload_len(unsigned char hdr)
56 {
57 	return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
58 }
59 
60 static 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 
82 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
83 {
84 	packet->type = ARM_SPE_PAD;
85 	return 1;
86 }
87 
88 static 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 
100 static int arm_spe_get_end(struct arm_spe_pkt *packet)
101 {
102 	packet->type = ARM_SPE_END;
103 	return 1;
104 }
105 
106 static 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 
113 static 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 
128 static 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 
135 static 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 
143 static 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 
151 static 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 
164 static 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 
177 static 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 
237 int 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 
253 static 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 
292 static 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 
332 static 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 
418 static 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 
458 static 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 
485 int 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 }
536