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 12 #include "arm-spe-pkt-decoder.h" 13 14 #define BIT(n) (1ULL << (n)) 15 16 #define NS_FLAG BIT(63) 17 #define EL_FLAG (BIT(62) | BIT(61)) 18 19 #define SPE_HEADER0_PAD 0x0 20 #define SPE_HEADER0_END 0x1 21 #define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */ 22 #define SPE_HEADER0_ADDRESS_MASK 0x38 23 #define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */ 24 #define SPE_HEADER0_COUNTER_MASK 0x38 25 #define SPE_HEADER0_TIMESTAMP 0x71 26 #define SPE_HEADER0_TIMESTAMP 0x71 27 #define SPE_HEADER0_EVENTS 0x2 28 #define SPE_HEADER0_EVENTS_MASK 0xf 29 #define SPE_HEADER0_SOURCE 0x3 30 #define SPE_HEADER0_SOURCE_MASK 0xf 31 #define SPE_HEADER0_CONTEXT 0x24 32 #define SPE_HEADER0_CONTEXT_MASK 0x3c 33 #define SPE_HEADER0_OP_TYPE 0x8 34 #define SPE_HEADER0_OP_TYPE_MASK 0x3c 35 #define SPE_HEADER1_ALIGNMENT 0x0 36 #define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */ 37 #define SPE_HEADER1_ADDRESS_MASK 0xf8 38 #define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */ 39 #define SPE_HEADER1_COUNTER_MASK 0xf8 40 41 #if __BYTE_ORDER == __BIG_ENDIAN 42 #define le16_to_cpu bswap_16 43 #define le32_to_cpu bswap_32 44 #define le64_to_cpu bswap_64 45 #define memcpy_le64(d, s, n) do { \ 46 memcpy((d), (s), (n)); \ 47 *(d) = le64_to_cpu(*(d)); \ 48 } while (0) 49 #else 50 #define le16_to_cpu 51 #define le32_to_cpu 52 #define le64_to_cpu 53 #define memcpy_le64 memcpy 54 #endif 55 56 static const char * const arm_spe_packet_name[] = { 57 [ARM_SPE_PAD] = "PAD", 58 [ARM_SPE_END] = "END", 59 [ARM_SPE_TIMESTAMP] = "TS", 60 [ARM_SPE_ADDRESS] = "ADDR", 61 [ARM_SPE_COUNTER] = "LAT", 62 [ARM_SPE_CONTEXT] = "CONTEXT", 63 [ARM_SPE_OP_TYPE] = "OP-TYPE", 64 [ARM_SPE_EVENTS] = "EVENTS", 65 [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE", 66 }; 67 68 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type) 69 { 70 return arm_spe_packet_name[type]; 71 } 72 73 /* return ARM SPE payload size from its encoding, 74 * which is in bits 5:4 of the byte. 75 * 00 : byte 76 * 01 : halfword (2) 77 * 10 : word (4) 78 * 11 : doubleword (8) 79 */ 80 static int payloadlen(unsigned char byte) 81 { 82 return 1 << ((byte & 0x30) >> 4); 83 } 84 85 static int arm_spe_get_payload(const unsigned char *buf, size_t len, 86 struct arm_spe_pkt *packet) 87 { 88 size_t payload_len = payloadlen(buf[0]); 89 90 if (len < 1 + payload_len) 91 return ARM_SPE_NEED_MORE_BYTES; 92 93 buf++; 94 95 switch (payload_len) { 96 case 1: packet->payload = *(uint8_t *)buf; break; 97 case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break; 98 case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break; 99 case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break; 100 default: return ARM_SPE_BAD_PACKET; 101 } 102 103 return 1 + payload_len; 104 } 105 106 static int arm_spe_get_pad(struct arm_spe_pkt *packet) 107 { 108 packet->type = ARM_SPE_PAD; 109 return 1; 110 } 111 112 static int arm_spe_get_alignment(const unsigned char *buf, size_t len, 113 struct arm_spe_pkt *packet) 114 { 115 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1); 116 117 if (len < alignment) 118 return ARM_SPE_NEED_MORE_BYTES; 119 120 packet->type = ARM_SPE_PAD; 121 return alignment - (((uintptr_t)buf) & (alignment - 1)); 122 } 123 124 static int arm_spe_get_end(struct arm_spe_pkt *packet) 125 { 126 packet->type = ARM_SPE_END; 127 return 1; 128 } 129 130 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len, 131 struct arm_spe_pkt *packet) 132 { 133 packet->type = ARM_SPE_TIMESTAMP; 134 return arm_spe_get_payload(buf, len, packet); 135 } 136 137 static int arm_spe_get_events(const unsigned char *buf, size_t len, 138 struct arm_spe_pkt *packet) 139 { 140 int ret = arm_spe_get_payload(buf, len, packet); 141 142 packet->type = ARM_SPE_EVENTS; 143 144 /* we use index to identify Events with a less number of 145 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS, 146 * LLC-REFILL, and REMOTE-ACCESS events are identified iff 147 * index > 1. 148 */ 149 packet->index = ret - 1; 150 151 return ret; 152 } 153 154 static int arm_spe_get_data_source(const unsigned char *buf, size_t len, 155 struct arm_spe_pkt *packet) 156 { 157 packet->type = ARM_SPE_DATA_SOURCE; 158 return arm_spe_get_payload(buf, len, packet); 159 } 160 161 static int arm_spe_get_context(const unsigned char *buf, size_t len, 162 struct arm_spe_pkt *packet) 163 { 164 packet->type = ARM_SPE_CONTEXT; 165 packet->index = buf[0] & 0x3; 166 167 return arm_spe_get_payload(buf, len, packet); 168 } 169 170 static int arm_spe_get_op_type(const unsigned char *buf, size_t len, 171 struct arm_spe_pkt *packet) 172 { 173 packet->type = ARM_SPE_OP_TYPE; 174 packet->index = buf[0] & 0x3; 175 return arm_spe_get_payload(buf, len, packet); 176 } 177 178 static int arm_spe_get_counter(const unsigned char *buf, size_t len, 179 const unsigned char ext_hdr, struct arm_spe_pkt *packet) 180 { 181 if (len < 2) 182 return ARM_SPE_NEED_MORE_BYTES; 183 184 packet->type = ARM_SPE_COUNTER; 185 if (ext_hdr) 186 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); 187 else 188 packet->index = buf[0] & 0x7; 189 190 packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1)); 191 192 return 1 + ext_hdr + 2; 193 } 194 195 static int arm_spe_get_addr(const unsigned char *buf, size_t len, 196 const unsigned char ext_hdr, struct arm_spe_pkt *packet) 197 { 198 if (len < 8) 199 return ARM_SPE_NEED_MORE_BYTES; 200 201 packet->type = ARM_SPE_ADDRESS; 202 if (ext_hdr) 203 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); 204 else 205 packet->index = buf[0] & 0x7; 206 207 memcpy_le64(&packet->payload, buf + 1, 8); 208 209 return 1 + ext_hdr + 8; 210 } 211 212 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len, 213 struct arm_spe_pkt *packet) 214 { 215 unsigned int byte; 216 217 memset(packet, 0, sizeof(struct arm_spe_pkt)); 218 219 if (!len) 220 return ARM_SPE_NEED_MORE_BYTES; 221 222 byte = buf[0]; 223 if (byte == SPE_HEADER0_PAD) 224 return arm_spe_get_pad(packet); 225 else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */ 226 return arm_spe_get_end(packet); 227 else if (byte & 0xc0 /* 0y11xxxxxx */) { 228 if (byte & 0x80) { 229 if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS) 230 return arm_spe_get_addr(buf, len, 0, packet); 231 if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER) 232 return arm_spe_get_counter(buf, len, 0, packet); 233 } else 234 if (byte == SPE_HEADER0_TIMESTAMP) 235 return arm_spe_get_timestamp(buf, len, packet); 236 else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS) 237 return arm_spe_get_events(buf, len, packet); 238 else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE) 239 return arm_spe_get_data_source(buf, len, packet); 240 else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT) 241 return arm_spe_get_context(buf, len, packet); 242 else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE) 243 return arm_spe_get_op_type(buf, len, packet); 244 } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) { 245 /* 16-bit header */ 246 byte = buf[1]; 247 if (byte == SPE_HEADER1_ALIGNMENT) 248 return arm_spe_get_alignment(buf, len, packet); 249 else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS) 250 return arm_spe_get_addr(buf, len, 1, packet); 251 else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER) 252 return arm_spe_get_counter(buf, len, 1, packet); 253 } 254 255 return ARM_SPE_BAD_PACKET; 256 } 257 258 int arm_spe_get_packet(const unsigned char *buf, size_t len, 259 struct arm_spe_pkt *packet) 260 { 261 int ret; 262 263 ret = arm_spe_do_get_packet(buf, len, packet); 264 /* put multiple consecutive PADs on the same line, up to 265 * the fixed-width output format of 16 bytes per line. 266 */ 267 if (ret > 0 && packet->type == ARM_SPE_PAD) { 268 while (ret < 16 && len > (size_t)ret && !buf[ret]) 269 ret += 1; 270 } 271 return ret; 272 } 273 274 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, 275 size_t buf_len) 276 { 277 int ret, ns, el, idx = packet->index; 278 unsigned long long payload = packet->payload; 279 const char *name = arm_spe_pkt_name(packet->type); 280 281 switch (packet->type) { 282 case ARM_SPE_BAD: 283 case ARM_SPE_PAD: 284 case ARM_SPE_END: 285 return snprintf(buf, buf_len, "%s", name); 286 case ARM_SPE_EVENTS: { 287 size_t blen = buf_len; 288 289 ret = 0; 290 ret = snprintf(buf, buf_len, "EV"); 291 buf += ret; 292 blen -= ret; 293 if (payload & 0x1) { 294 ret = snprintf(buf, buf_len, " EXCEPTION-GEN"); 295 buf += ret; 296 blen -= ret; 297 } 298 if (payload & 0x2) { 299 ret = snprintf(buf, buf_len, " RETIRED"); 300 buf += ret; 301 blen -= ret; 302 } 303 if (payload & 0x4) { 304 ret = snprintf(buf, buf_len, " L1D-ACCESS"); 305 buf += ret; 306 blen -= ret; 307 } 308 if (payload & 0x8) { 309 ret = snprintf(buf, buf_len, " L1D-REFILL"); 310 buf += ret; 311 blen -= ret; 312 } 313 if (payload & 0x10) { 314 ret = snprintf(buf, buf_len, " TLB-ACCESS"); 315 buf += ret; 316 blen -= ret; 317 } 318 if (payload & 0x20) { 319 ret = snprintf(buf, buf_len, " TLB-REFILL"); 320 buf += ret; 321 blen -= ret; 322 } 323 if (payload & 0x40) { 324 ret = snprintf(buf, buf_len, " NOT-TAKEN"); 325 buf += ret; 326 blen -= ret; 327 } 328 if (payload & 0x80) { 329 ret = snprintf(buf, buf_len, " MISPRED"); 330 buf += ret; 331 blen -= ret; 332 } 333 if (idx > 1) { 334 if (payload & 0x100) { 335 ret = snprintf(buf, buf_len, " LLC-ACCESS"); 336 buf += ret; 337 blen -= ret; 338 } 339 if (payload & 0x200) { 340 ret = snprintf(buf, buf_len, " LLC-REFILL"); 341 buf += ret; 342 blen -= ret; 343 } 344 if (payload & 0x400) { 345 ret = snprintf(buf, buf_len, " REMOTE-ACCESS"); 346 buf += ret; 347 blen -= ret; 348 } 349 } 350 if (ret < 0) 351 return ret; 352 blen -= ret; 353 return buf_len - blen; 354 } 355 case ARM_SPE_OP_TYPE: 356 switch (idx) { 357 case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ? 358 "COND-SELECT" : "INSN-OTHER"); 359 case 1: { 360 size_t blen = buf_len; 361 362 if (payload & 0x1) 363 ret = snprintf(buf, buf_len, "ST"); 364 else 365 ret = snprintf(buf, buf_len, "LD"); 366 buf += ret; 367 blen -= ret; 368 if (payload & 0x2) { 369 if (payload & 0x4) { 370 ret = snprintf(buf, buf_len, " AT"); 371 buf += ret; 372 blen -= ret; 373 } 374 if (payload & 0x8) { 375 ret = snprintf(buf, buf_len, " EXCL"); 376 buf += ret; 377 blen -= ret; 378 } 379 if (payload & 0x10) { 380 ret = snprintf(buf, buf_len, " AR"); 381 buf += ret; 382 blen -= ret; 383 } 384 } else if (payload & 0x4) { 385 ret = snprintf(buf, buf_len, " SIMD-FP"); 386 buf += ret; 387 blen -= ret; 388 } 389 if (ret < 0) 390 return ret; 391 blen -= ret; 392 return buf_len - blen; 393 } 394 case 2: { 395 size_t blen = buf_len; 396 397 ret = snprintf(buf, buf_len, "B"); 398 buf += ret; 399 blen -= ret; 400 if (payload & 0x1) { 401 ret = snprintf(buf, buf_len, " COND"); 402 buf += ret; 403 blen -= ret; 404 } 405 if (payload & 0x2) { 406 ret = snprintf(buf, buf_len, " IND"); 407 buf += ret; 408 blen -= ret; 409 } 410 if (ret < 0) 411 return ret; 412 blen -= ret; 413 return buf_len - blen; 414 } 415 default: return 0; 416 } 417 case ARM_SPE_DATA_SOURCE: 418 case ARM_SPE_TIMESTAMP: 419 return snprintf(buf, buf_len, "%s %lld", name, payload); 420 case ARM_SPE_ADDRESS: 421 switch (idx) { 422 case 0: 423 case 1: ns = !!(packet->payload & NS_FLAG); 424 el = (packet->payload & EL_FLAG) >> 61; 425 payload &= ~(0xffULL << 56); 426 return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d", 427 (idx == 1) ? "TGT" : "PC", payload, el, ns); 428 case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload); 429 case 3: ns = !!(packet->payload & NS_FLAG); 430 payload &= ~(0xffULL << 56); 431 return snprintf(buf, buf_len, "PA 0x%llx ns=%d", 432 payload, ns); 433 default: return 0; 434 } 435 case ARM_SPE_CONTEXT: 436 return snprintf(buf, buf_len, "%s 0x%lx el%d", name, 437 (unsigned long)payload, idx + 1); 438 case ARM_SPE_COUNTER: { 439 size_t blen = buf_len; 440 441 ret = snprintf(buf, buf_len, "%s %d ", name, 442 (unsigned short)payload); 443 buf += ret; 444 blen -= ret; 445 switch (idx) { 446 case 0: ret = snprintf(buf, buf_len, "TOT"); break; 447 case 1: ret = snprintf(buf, buf_len, "ISSUE"); break; 448 case 2: ret = snprintf(buf, buf_len, "XLAT"); break; 449 default: ret = 0; 450 } 451 if (ret < 0) 452 return ret; 453 blen -= ret; 454 return buf_len - blen; 455 } 456 default: 457 break; 458 } 459 460 return snprintf(buf, buf_len, "%s 0x%llx (%d)", 461 name, payload, packet->index); 462 } 463