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 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 427 static 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 469 static 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 496 int 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