perf arm-spe: Refactor context packet handling
[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         if (ext_hdr)
156                 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
157         else
158                 packet->index = buf[0] & 0x7;
159
160         return arm_spe_get_payload(buf, len, ext_hdr, packet);
161 }
162
163 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
164                             const unsigned char ext_hdr, struct arm_spe_pkt *packet)
165 {
166         packet->type = ARM_SPE_ADDRESS;
167
168         if (ext_hdr)
169                 packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
170         else
171                 packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
172
173         return arm_spe_get_payload(buf, len, ext_hdr, packet);
174 }
175
176 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
177                                  struct arm_spe_pkt *packet)
178 {
179         unsigned int hdr;
180         unsigned char ext_hdr = 0;
181
182         memset(packet, 0, sizeof(struct arm_spe_pkt));
183
184         if (!len)
185                 return ARM_SPE_NEED_MORE_BYTES;
186
187         hdr = buf[0];
188
189         if (hdr == SPE_HEADER0_PAD)
190                 return arm_spe_get_pad(packet);
191
192         if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
193                 return arm_spe_get_end(packet);
194
195         if (hdr == SPE_HEADER0_TIMESTAMP)
196                 return arm_spe_get_timestamp(buf, len, packet);
197
198         if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
199                 return arm_spe_get_events(buf, len, packet);
200
201         if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
202                 return arm_spe_get_data_source(buf, len, packet);
203
204         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
205                 return arm_spe_get_context(buf, len, packet);
206
207         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
208                 return arm_spe_get_op_type(buf, len, packet);
209
210         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
211                 /* 16-bit extended format header */
212                 ext_hdr = 1;
213
214                 hdr = buf[1];
215                 if (hdr == SPE_HEADER1_ALIGNMENT)
216                         return arm_spe_get_alignment(buf, len, packet);
217         }
218
219         /*
220          * The short format header's byte 0 or the extended format header's
221          * byte 1 has been assigned to 'hdr', which uses the same encoding for
222          * address packet and counter packet, so don't need to distinguish if
223          * it's short format or extended format and handle in once.
224          */
225         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
226                 return arm_spe_get_addr(buf, len, ext_hdr, packet);
227
228         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
229                 return arm_spe_get_counter(buf, len, ext_hdr, packet);
230
231         return ARM_SPE_BAD_PACKET;
232 }
233
234 int arm_spe_get_packet(const unsigned char *buf, size_t len,
235                        struct arm_spe_pkt *packet)
236 {
237         int ret;
238
239         ret = arm_spe_do_get_packet(buf, len, packet);
240         /* put multiple consecutive PADs on the same line, up to
241          * the fixed-width output format of 16 bytes per line.
242          */
243         if (ret > 0 && packet->type == ARM_SPE_PAD) {
244                 while (ret < 16 && len > (size_t)ret && !buf[ret])
245                         ret += 1;
246         }
247         return ret;
248 }
249
250 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
251                                   const char *fmt, ...)
252 {
253         va_list ap;
254         int ret;
255
256         /* Bail out if any error occurred */
257         if (err && *err)
258                 return *err;
259
260         va_start(ap, fmt);
261         ret = vsnprintf(*buf_p, *blen, fmt, ap);
262         va_end(ap);
263
264         if (ret < 0) {
265                 if (err && !*err)
266                         *err = ret;
267
268         /*
269          * A return value of *blen or more means that the output was
270          * truncated and the buffer is overrun.
271          */
272         } else if ((size_t)ret >= *blen) {
273                 (*buf_p)[*blen - 1] = '\0';
274
275                 /*
276                  * Set *err to 'ret' to avoid overflow if tries to
277                  * fill this buffer sequentially.
278                  */
279                 if (err && !*err)
280                         *err = ret;
281         } else {
282                 *buf_p += ret;
283                 *blen -= ret;
284         }
285
286         return ret;
287 }
288
289 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
290                                  char *buf, size_t buf_len)
291 {
292         int ns, el, idx = packet->index;
293         u64 payload = packet->payload;
294         int err = 0;
295
296         switch (idx) {
297         case SPE_ADDR_PKT_HDR_INDEX_INS:
298         case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
299                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
300                 el = SPE_ADDR_PKT_GET_EL(payload);
301                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
302                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
303                                 "%s 0x%llx el%d ns=%d",
304                                 (idx == 1) ? "TGT" : "PC", payload, el, ns);
305                 break;
306         case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
307                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
308                                        "VA 0x%llx", payload);
309                 break;
310         case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
311                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
312                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
313                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
314                                        "PA 0x%llx ns=%d", payload, ns);
315                 break;
316         default:
317                 /* Unknown index */
318                 err = -1;
319                 break;
320         }
321
322         return err;
323 }
324
325 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
326                      size_t buf_len)
327 {
328         int idx = packet->index;
329         unsigned long long payload = packet->payload;
330         const char *name = arm_spe_pkt_name(packet->type);
331         char *buf_orig = buf;
332         size_t blen = buf_len;
333         int err = 0;
334
335         switch (packet->type) {
336         case ARM_SPE_BAD:
337         case ARM_SPE_PAD:
338         case ARM_SPE_END:
339                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
340                 break;
341         case ARM_SPE_EVENTS:
342                 arm_spe_pkt_out_string(&err, &buf, &blen, "EV");
343
344                 if (payload & 0x1)
345                         arm_spe_pkt_out_string(&err, &buf, &blen, " EXCEPTION-GEN");
346                 if (payload & 0x2)
347                         arm_spe_pkt_out_string(&err, &buf, &blen, " RETIRED");
348                 if (payload & 0x4)
349                         arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-ACCESS");
350                 if (payload & 0x8)
351                         arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-REFILL");
352                 if (payload & 0x10)
353                         arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-ACCESS");
354                 if (payload & 0x20)
355                         arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-REFILL");
356                 if (payload & 0x40)
357                         arm_spe_pkt_out_string(&err, &buf, &blen, " NOT-TAKEN");
358                 if (payload & 0x80)
359                         arm_spe_pkt_out_string(&err, &buf, &blen, " MISPRED");
360                 if (idx > 1) {
361                         if (payload & 0x100)
362                                 arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-ACCESS");
363                         if (payload & 0x200)
364                                 arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-REFILL");
365                         if (payload & 0x400)
366                                 arm_spe_pkt_out_string(&err, &buf, &blen, " REMOTE-ACCESS");
367                 }
368                 break;
369         case ARM_SPE_OP_TYPE:
370                 switch (idx) {
371                 case 0:
372                         arm_spe_pkt_out_string(&err, &buf, &blen,
373                                         payload & 0x1 ? "COND-SELECT" : "INSN-OTHER");
374                         break;
375                 case 1:
376                         arm_spe_pkt_out_string(&err, &buf, &blen,
377                                                payload & 0x1 ? "ST" : "LD");
378
379                         if (payload & 0x2) {
380                                 if (payload & 0x4)
381                                         arm_spe_pkt_out_string(&err, &buf, &blen, " AT");
382                                 if (payload & 0x8)
383                                         arm_spe_pkt_out_string(&err, &buf, &blen, " EXCL");
384                                 if (payload & 0x10)
385                                         arm_spe_pkt_out_string(&err, &buf, &blen, " AR");
386                         } else if (payload & 0x4) {
387                                 arm_spe_pkt_out_string(&err, &buf, &blen, " SIMD-FP");
388                         }
389                         break;
390                 case 2:
391                         arm_spe_pkt_out_string(&err, &buf, &blen, "B");
392
393                         if (payload & 0x1)
394                                 arm_spe_pkt_out_string(&err, &buf, &blen, " COND");
395                         if (payload & 0x2)
396                                 arm_spe_pkt_out_string(&err, &buf, &blen, " IND");
397
398                         break;
399                 default:
400                         /* Unknown index */
401                         err = -1;
402                         break;
403                 }
404                 break;
405         case ARM_SPE_DATA_SOURCE:
406         case ARM_SPE_TIMESTAMP:
407                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
408                 break;
409         case ARM_SPE_ADDRESS:
410                 err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
411                 break;
412         case ARM_SPE_CONTEXT:
413                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
414                                        name, (unsigned long)payload, idx + 1);
415                 break;
416         case ARM_SPE_COUNTER:
417                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %d ", name,
418                                        (unsigned short)payload);
419                 switch (idx) {
420                 case 0:
421                         arm_spe_pkt_out_string(&err, &buf, &blen, "TOT");
422                         break;
423                 case 1:
424                         arm_spe_pkt_out_string(&err, &buf, &blen, "ISSUE");
425                         break;
426                 case 2:
427                         arm_spe_pkt_out_string(&err, &buf, &blen, "XLAT");
428                         break;
429                 default:
430                         break;
431                 }
432                 break;
433         default:
434                 /* Unknown packet type */
435                 err = -1;
436                 break;
437         }
438
439         /* Output raw data if detect any error */
440         if (err) {
441                 err = 0;
442                 arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
443                                        name, payload, packet->index);
444         }
445
446         return err;
447 }