88bcf7e5be768be822ad9124fe2f7ca8914541c6
[linux-2.6-microblaze.git] / tools / perf / util / arm-spe-decoder / arm-spe-pkt-decoder.c
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 == __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 = buf[0] & 0x3;
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                 ext_hdr = 1;
214
215                 hdr = buf[1];
216                 if (hdr == SPE_HEADER1_ALIGNMENT)
217                         return arm_spe_get_alignment(buf, len, packet);
218         }
219
220         /*
221          * The short format header's byte 0 or the extended format header's
222          * byte 1 has been assigned to 'hdr', which uses the same encoding for
223          * address packet and counter packet, so don't need to distinguish if
224          * it's short format or extended format and handle in once.
225          */
226         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
227                 return arm_spe_get_addr(buf, len, ext_hdr, packet);
228
229         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
230                 return arm_spe_get_counter(buf, len, ext_hdr, packet);
231
232         return ARM_SPE_BAD_PACKET;
233 }
234
235 int arm_spe_get_packet(const unsigned char *buf, size_t len,
236                        struct arm_spe_pkt *packet)
237 {
238         int ret;
239
240         ret = arm_spe_do_get_packet(buf, len, packet);
241         /* put multiple consecutive PADs on the same line, up to
242          * the fixed-width output format of 16 bytes per line.
243          */
244         if (ret > 0 && packet->type == ARM_SPE_PAD) {
245                 while (ret < 16 && len > (size_t)ret && !buf[ret])
246                         ret += 1;
247         }
248         return ret;
249 }
250
251 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
252                                   const char *fmt, ...)
253 {
254         va_list ap;
255         int ret;
256
257         /* Bail out if any error occurred */
258         if (err && *err)
259                 return *err;
260
261         va_start(ap, fmt);
262         ret = vsnprintf(*buf_p, *blen, fmt, ap);
263         va_end(ap);
264
265         if (ret < 0) {
266                 if (err && !*err)
267                         *err = ret;
268
269         /*
270          * A return value of *blen or more means that the output was
271          * truncated and the buffer is overrun.
272          */
273         } else if ((size_t)ret >= *blen) {
274                 (*buf_p)[*blen - 1] = '\0';
275
276                 /*
277                  * Set *err to 'ret' to avoid overflow if tries to
278                  * fill this buffer sequentially.
279                  */
280                 if (err && !*err)
281                         *err = ret;
282         } else {
283                 *buf_p += ret;
284                 *blen -= ret;
285         }
286
287         return ret;
288 }
289
290 static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
291                                   char *buf, size_t buf_len)
292 {
293         u64 payload = packet->payload;
294         int err = 0;
295
296         arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
297
298         if (payload & BIT(EV_EXCEPTION_GEN))
299                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
300         if (payload & BIT(EV_RETIRED))
301                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
302         if (payload & BIT(EV_L1D_ACCESS))
303                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
304         if (payload & BIT(EV_L1D_REFILL))
305                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
306         if (payload & BIT(EV_TLB_ACCESS))
307                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
308         if (payload & BIT(EV_TLB_WALK))
309                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
310         if (payload & BIT(EV_NOT_TAKEN))
311                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
312         if (payload & BIT(EV_MISPRED))
313                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
314         if (payload & BIT(EV_LLC_ACCESS))
315                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
316         if (payload & BIT(EV_LLC_MISS))
317                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
318         if (payload & BIT(EV_REMOTE_ACCESS))
319                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
320
321         return err;
322 }
323
324 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
325                                  char *buf, size_t buf_len)
326 {
327         int ns, el, idx = packet->index;
328         u64 payload = packet->payload;
329         int err = 0;
330
331         switch (idx) {
332         case SPE_ADDR_PKT_HDR_INDEX_INS:
333         case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
334                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
335                 el = SPE_ADDR_PKT_GET_EL(payload);
336                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
337                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
338                                 "%s 0x%llx el%d ns=%d",
339                                 (idx == 1) ? "TGT" : "PC", payload, el, ns);
340                 break;
341         case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
342                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
343                                        "VA 0x%llx", payload);
344                 break;
345         case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
346                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
347                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
348                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
349                                        "PA 0x%llx ns=%d", payload, ns);
350                 break;
351         default:
352                 /* Unknown index */
353                 err = -1;
354                 break;
355         }
356
357         return err;
358 }
359
360 static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
361                                     char *buf, size_t buf_len)
362 {
363         u64 payload = packet->payload;
364         const char *name = arm_spe_pkt_name(packet->type);
365         int err = 0;
366
367         arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
368                                (unsigned short)payload);
369
370         switch (packet->index) {
371         case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
372                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
373                 break;
374         case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
375                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
376                 break;
377         case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
378                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
379                 break;
380         default:
381                 break;
382         }
383
384         return err;
385 }
386
387 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
388                      size_t buf_len)
389 {
390         int idx = packet->index;
391         unsigned long long payload = packet->payload;
392         const char *name = arm_spe_pkt_name(packet->type);
393         char *buf_orig = buf;
394         size_t blen = buf_len;
395         int err = 0;
396
397         switch (packet->type) {
398         case ARM_SPE_BAD:
399         case ARM_SPE_PAD:
400         case ARM_SPE_END:
401                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
402                 break;
403         case ARM_SPE_EVENTS:
404                 err = arm_spe_pkt_desc_event(packet, buf, buf_len);
405                 break;
406         case ARM_SPE_OP_TYPE:
407                 switch (idx) {
408                 case 0:
409                         arm_spe_pkt_out_string(&err, &buf, &blen,
410                                         payload & 0x1 ? "COND-SELECT" : "INSN-OTHER");
411                         break;
412                 case 1:
413                         arm_spe_pkt_out_string(&err, &buf, &blen,
414                                                payload & 0x1 ? "ST" : "LD");
415
416                         if (payload & 0x2) {
417                                 if (payload & 0x4)
418                                         arm_spe_pkt_out_string(&err, &buf, &blen, " AT");
419                                 if (payload & 0x8)
420                                         arm_spe_pkt_out_string(&err, &buf, &blen, " EXCL");
421                                 if (payload & 0x10)
422                                         arm_spe_pkt_out_string(&err, &buf, &blen, " AR");
423                         } else if (payload & 0x4) {
424                                 arm_spe_pkt_out_string(&err, &buf, &blen, " SIMD-FP");
425                         }
426                         break;
427                 case 2:
428                         arm_spe_pkt_out_string(&err, &buf, &blen, "B");
429
430                         if (payload & 0x1)
431                                 arm_spe_pkt_out_string(&err, &buf, &blen, " COND");
432                         if (payload & 0x2)
433                                 arm_spe_pkt_out_string(&err, &buf, &blen, " IND");
434
435                         break;
436                 default:
437                         /* Unknown index */
438                         err = -1;
439                         break;
440                 }
441                 break;
442         case ARM_SPE_DATA_SOURCE:
443         case ARM_SPE_TIMESTAMP:
444                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
445                 break;
446         case ARM_SPE_ADDRESS:
447                 err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
448                 break;
449         case ARM_SPE_CONTEXT:
450                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
451                                        name, (unsigned long)payload, idx + 1);
452                 break;
453         case ARM_SPE_COUNTER:
454                 err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
455                 break;
456         default:
457                 /* Unknown packet type */
458                 err = -1;
459                 break;
460         }
461
462         /* Output raw data if detect any error */
463         if (err) {
464                 err = 0;
465                 arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
466                                        name, payload, packet->index);
467         }
468
469         return err;
470 }