Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Arm Statistical Profiling Extensions (SPE) support
0004  * Copyright (c) 2017-2018, Arm Ltd.
0005  */
0006 
0007 #include <stdio.h>
0008 #include <string.h>
0009 #include <endian.h>
0010 #include <byteswap.h>
0011 #include <linux/bitops.h>
0012 #include <stdarg.h>
0013 
0014 #include "arm-spe-pkt-decoder.h"
0015 
0016 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
0017 #define le16_to_cpu bswap_16
0018 #define le32_to_cpu bswap_32
0019 #define le64_to_cpu bswap_64
0020 #define memcpy_le64(d, s, n) do { \
0021     memcpy((d), (s), (n));    \
0022     *(d) = le64_to_cpu(*(d)); \
0023 } while (0)
0024 #else
0025 #define le16_to_cpu
0026 #define le32_to_cpu
0027 #define le64_to_cpu
0028 #define memcpy_le64 memcpy
0029 #endif
0030 
0031 static const char * const arm_spe_packet_name[] = {
0032     [ARM_SPE_PAD]       = "PAD",
0033     [ARM_SPE_END]       = "END",
0034     [ARM_SPE_TIMESTAMP] = "TS",
0035     [ARM_SPE_ADDRESS]   = "ADDR",
0036     [ARM_SPE_COUNTER]   = "LAT",
0037     [ARM_SPE_CONTEXT]   = "CONTEXT",
0038     [ARM_SPE_OP_TYPE]   = "OP-TYPE",
0039     [ARM_SPE_EVENTS]    = "EVENTS",
0040     [ARM_SPE_DATA_SOURCE]   = "DATA-SOURCE",
0041 };
0042 
0043 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
0044 {
0045     return arm_spe_packet_name[type];
0046 }
0047 
0048 /*
0049  * Extracts the field "sz" from header bits and converts to bytes:
0050  *   00 : byte (1)
0051  *   01 : halfword (2)
0052  *   10 : word (4)
0053  *   11 : doubleword (8)
0054  */
0055 static unsigned int arm_spe_payload_len(unsigned char hdr)
0056 {
0057     return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
0058 }
0059 
0060 static int arm_spe_get_payload(const unsigned char *buf, size_t len,
0061                    unsigned char ext_hdr,
0062                    struct arm_spe_pkt *packet)
0063 {
0064     size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
0065 
0066     if (len < 1 + ext_hdr + payload_len)
0067         return ARM_SPE_NEED_MORE_BYTES;
0068 
0069     buf += 1 + ext_hdr;
0070 
0071     switch (payload_len) {
0072     case 1: packet->payload = *(uint8_t *)buf; break;
0073     case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
0074     case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
0075     case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
0076     default: return ARM_SPE_BAD_PACKET;
0077     }
0078 
0079     return 1 + ext_hdr + payload_len;
0080 }
0081 
0082 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
0083 {
0084     packet->type = ARM_SPE_PAD;
0085     return 1;
0086 }
0087 
0088 static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
0089                  struct arm_spe_pkt *packet)
0090 {
0091     unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
0092 
0093     if (len < alignment)
0094         return ARM_SPE_NEED_MORE_BYTES;
0095 
0096     packet->type = ARM_SPE_PAD;
0097     return alignment - (((uintptr_t)buf) & (alignment - 1));
0098 }
0099 
0100 static int arm_spe_get_end(struct arm_spe_pkt *packet)
0101 {
0102     packet->type = ARM_SPE_END;
0103     return 1;
0104 }
0105 
0106 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
0107                  struct arm_spe_pkt *packet)
0108 {
0109     packet->type = ARM_SPE_TIMESTAMP;
0110     return arm_spe_get_payload(buf, len, 0, packet);
0111 }
0112 
0113 static int arm_spe_get_events(const unsigned char *buf, size_t len,
0114                   struct arm_spe_pkt *packet)
0115 {
0116     packet->type = ARM_SPE_EVENTS;
0117 
0118     /* we use index to identify Events with a less number of
0119      * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
0120      * LLC-REFILL, and REMOTE-ACCESS events are identified if
0121      * index > 1.
0122      */
0123     packet->index = arm_spe_payload_len(buf[0]);
0124 
0125     return arm_spe_get_payload(buf, len, 0, packet);
0126 }
0127 
0128 static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
0129                    struct arm_spe_pkt *packet)
0130 {
0131     packet->type = ARM_SPE_DATA_SOURCE;
0132     return arm_spe_get_payload(buf, len, 0, packet);
0133 }
0134 
0135 static int arm_spe_get_context(const unsigned char *buf, size_t len,
0136                    struct arm_spe_pkt *packet)
0137 {
0138     packet->type = ARM_SPE_CONTEXT;
0139     packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
0140     return arm_spe_get_payload(buf, len, 0, packet);
0141 }
0142 
0143 static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
0144                    struct arm_spe_pkt *packet)
0145 {
0146     packet->type = ARM_SPE_OP_TYPE;
0147     packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
0148     return arm_spe_get_payload(buf, len, 0, packet);
0149 }
0150 
0151 static int arm_spe_get_counter(const unsigned char *buf, size_t len,
0152                    const unsigned char ext_hdr, struct arm_spe_pkt *packet)
0153 {
0154     packet->type = ARM_SPE_COUNTER;
0155 
0156     if (ext_hdr)
0157         packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
0158     else
0159         packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
0160 
0161     return arm_spe_get_payload(buf, len, ext_hdr, packet);
0162 }
0163 
0164 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
0165                 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
0166 {
0167     packet->type = ARM_SPE_ADDRESS;
0168 
0169     if (ext_hdr)
0170         packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
0171     else
0172         packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
0173 
0174     return arm_spe_get_payload(buf, len, ext_hdr, packet);
0175 }
0176 
0177 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
0178                  struct arm_spe_pkt *packet)
0179 {
0180     unsigned int hdr;
0181     unsigned char ext_hdr = 0;
0182 
0183     memset(packet, 0, sizeof(struct arm_spe_pkt));
0184 
0185     if (!len)
0186         return ARM_SPE_NEED_MORE_BYTES;
0187 
0188     hdr = buf[0];
0189 
0190     if (hdr == SPE_HEADER0_PAD)
0191         return arm_spe_get_pad(packet);
0192 
0193     if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
0194         return arm_spe_get_end(packet);
0195 
0196     if (hdr == SPE_HEADER0_TIMESTAMP)
0197         return arm_spe_get_timestamp(buf, len, packet);
0198 
0199     if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
0200         return arm_spe_get_events(buf, len, packet);
0201 
0202     if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
0203         return arm_spe_get_data_source(buf, len, packet);
0204 
0205     if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
0206         return arm_spe_get_context(buf, len, packet);
0207 
0208     if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
0209         return arm_spe_get_op_type(buf, len, packet);
0210 
0211     if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
0212         /* 16-bit extended format header */
0213         if (len == 1)
0214             return ARM_SPE_BAD_PACKET;
0215 
0216         ext_hdr = 1;
0217         hdr = buf[1];
0218         if (hdr == SPE_HEADER1_ALIGNMENT)
0219             return arm_spe_get_alignment(buf, len, packet);
0220     }
0221 
0222     /*
0223      * The short format header's byte 0 or the extended format header's
0224      * byte 1 has been assigned to 'hdr', which uses the same encoding for
0225      * address packet and counter packet, so don't need to distinguish if
0226      * it's short format or extended format and handle in once.
0227      */
0228     if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
0229         return arm_spe_get_addr(buf, len, ext_hdr, packet);
0230 
0231     if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
0232         return arm_spe_get_counter(buf, len, ext_hdr, packet);
0233 
0234     return ARM_SPE_BAD_PACKET;
0235 }
0236 
0237 int arm_spe_get_packet(const unsigned char *buf, size_t len,
0238                struct arm_spe_pkt *packet)
0239 {
0240     int ret;
0241 
0242     ret = arm_spe_do_get_packet(buf, len, packet);
0243     /* put multiple consecutive PADs on the same line, up to
0244      * the fixed-width output format of 16 bytes per line.
0245      */
0246     if (ret > 0 && packet->type == ARM_SPE_PAD) {
0247         while (ret < 16 && len > (size_t)ret && !buf[ret])
0248             ret += 1;
0249     }
0250     return ret;
0251 }
0252 
0253 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
0254                   const char *fmt, ...)
0255 {
0256     va_list ap;
0257     int ret;
0258 
0259     /* Bail out if any error occurred */
0260     if (err && *err)
0261         return *err;
0262 
0263     va_start(ap, fmt);
0264     ret = vsnprintf(*buf_p, *blen, fmt, ap);
0265     va_end(ap);
0266 
0267     if (ret < 0) {
0268         if (err && !*err)
0269             *err = ret;
0270 
0271     /*
0272      * A return value of *blen or more means that the output was
0273      * truncated and the buffer is overrun.
0274      */
0275     } else if ((size_t)ret >= *blen) {
0276         (*buf_p)[*blen - 1] = '\0';
0277 
0278         /*
0279          * Set *err to 'ret' to avoid overflow if tries to
0280          * fill this buffer sequentially.
0281          */
0282         if (err && !*err)
0283             *err = ret;
0284     } else {
0285         *buf_p += ret;
0286         *blen -= ret;
0287     }
0288 
0289     return ret;
0290 }
0291 
0292 static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
0293                   char *buf, size_t buf_len)
0294 {
0295     u64 payload = packet->payload;
0296     int err = 0;
0297 
0298     arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
0299 
0300     if (payload & BIT(EV_EXCEPTION_GEN))
0301         arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
0302     if (payload & BIT(EV_RETIRED))
0303         arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
0304     if (payload & BIT(EV_L1D_ACCESS))
0305         arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
0306     if (payload & BIT(EV_L1D_REFILL))
0307         arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
0308     if (payload & BIT(EV_TLB_ACCESS))
0309         arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
0310     if (payload & BIT(EV_TLB_WALK))
0311         arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
0312     if (payload & BIT(EV_NOT_TAKEN))
0313         arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
0314     if (payload & BIT(EV_MISPRED))
0315         arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
0316     if (payload & BIT(EV_LLC_ACCESS))
0317         arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
0318     if (payload & BIT(EV_LLC_MISS))
0319         arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
0320     if (payload & BIT(EV_REMOTE_ACCESS))
0321         arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
0322     if (payload & BIT(EV_ALIGNMENT))
0323         arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT");
0324     if (payload & BIT(EV_PARTIAL_PREDICATE))
0325         arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED");
0326     if (payload & BIT(EV_EMPTY_PREDICATE))
0327         arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
0328 
0329     return err;
0330 }
0331 
0332 static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
0333                     char *buf, size_t buf_len)
0334 {
0335     u64 payload = packet->payload;
0336     int err = 0;
0337 
0338     switch (packet->index) {
0339     case SPE_OP_PKT_HDR_CLASS_OTHER:
0340         if (SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
0341             arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
0342 
0343             /* SVE effective vector length */
0344             arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
0345                            SPE_OP_PKG_SVE_EVL(payload));
0346 
0347             if (payload & SPE_OP_PKT_SVE_FP)
0348                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
0349             if (payload & SPE_OP_PKT_SVE_PRED)
0350                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
0351         } else {
0352             arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
0353             arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
0354                            payload & SPE_OP_PKT_COND ?
0355                            "COND-SELECT" : "INSN-OTHER");
0356         }
0357         break;
0358     case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
0359         arm_spe_pkt_out_string(&err, &buf, &buf_len,
0360                        payload & 0x1 ? "ST" : "LD");
0361 
0362         if (SPE_OP_PKT_IS_LDST_ATOMIC(payload)) {
0363             if (payload & SPE_OP_PKT_AT)
0364                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
0365             if (payload & SPE_OP_PKT_EXCL)
0366                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
0367             if (payload & SPE_OP_PKT_AR)
0368                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
0369         }
0370 
0371         switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) {
0372         case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP:
0373             arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
0374             break;
0375         case SPE_OP_PKT_LDST_SUBCLASS_GP_REG:
0376             arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
0377             break;
0378         case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG:
0379             arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
0380             break;
0381         case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG:
0382             arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
0383             break;
0384         default:
0385             break;
0386         }
0387 
0388         if (SPE_OP_PKT_IS_LDST_SVE(payload)) {
0389             /* SVE effective vector length */
0390             arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
0391                            SPE_OP_PKG_SVE_EVL(payload));
0392 
0393             if (payload & SPE_OP_PKT_SVE_PRED)
0394                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
0395             if (payload & SPE_OP_PKT_SVE_SG)
0396                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
0397         }
0398         break;
0399     case SPE_OP_PKT_HDR_CLASS_BR_ERET:
0400         arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
0401 
0402         if (payload & SPE_OP_PKT_COND)
0403             arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
0404 
0405         if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
0406             arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
0407 
0408         break;
0409     default:
0410         /* Unknown index */
0411         err = -1;
0412         break;
0413     }
0414 
0415     return err;
0416 }
0417 
0418 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
0419                  char *buf, size_t buf_len)
0420 {
0421     int ns, el, idx = packet->index;
0422     int ch, pat;
0423     u64 payload = packet->payload;
0424     int err = 0;
0425 
0426     switch (idx) {
0427     case SPE_ADDR_PKT_HDR_INDEX_INS:
0428     case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
0429         ns = !!SPE_ADDR_PKT_GET_NS(payload);
0430         el = SPE_ADDR_PKT_GET_EL(payload);
0431         payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
0432         arm_spe_pkt_out_string(&err, &buf, &buf_len,
0433                 "%s 0x%llx el%d ns=%d",
0434                 (idx == 1) ? "TGT" : "PC", payload, el, ns);
0435         break;
0436     case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
0437         arm_spe_pkt_out_string(&err, &buf, &buf_len,
0438                        "VA 0x%llx", payload);
0439         break;
0440     case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
0441         ns = !!SPE_ADDR_PKT_GET_NS(payload);
0442         ch = !!SPE_ADDR_PKT_GET_CH(payload);
0443         pat = SPE_ADDR_PKT_GET_PAT(payload);
0444         payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
0445         arm_spe_pkt_out_string(&err, &buf, &buf_len,
0446                        "PA 0x%llx ns=%d ch=%d pat=%x",
0447                        payload, ns, ch, pat);
0448         break;
0449     default:
0450         /* Unknown index */
0451         err = -1;
0452         break;
0453     }
0454 
0455     return err;
0456 }
0457 
0458 static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
0459                     char *buf, size_t buf_len)
0460 {
0461     u64 payload = packet->payload;
0462     const char *name = arm_spe_pkt_name(packet->type);
0463     int err = 0;
0464 
0465     arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
0466                    (unsigned short)payload);
0467 
0468     switch (packet->index) {
0469     case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
0470         arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
0471         break;
0472     case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
0473         arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
0474         break;
0475     case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
0476         arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
0477         break;
0478     default:
0479         break;
0480     }
0481 
0482     return err;
0483 }
0484 
0485 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
0486              size_t buf_len)
0487 {
0488     int idx = packet->index;
0489     unsigned long long payload = packet->payload;
0490     const char *name = arm_spe_pkt_name(packet->type);
0491     char *buf_orig = buf;
0492     size_t blen = buf_len;
0493     int err = 0;
0494 
0495     switch (packet->type) {
0496     case ARM_SPE_BAD:
0497     case ARM_SPE_PAD:
0498     case ARM_SPE_END:
0499         arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
0500         break;
0501     case ARM_SPE_EVENTS:
0502         err = arm_spe_pkt_desc_event(packet, buf, buf_len);
0503         break;
0504     case ARM_SPE_OP_TYPE:
0505         err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
0506         break;
0507     case ARM_SPE_DATA_SOURCE:
0508     case ARM_SPE_TIMESTAMP:
0509         arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
0510         break;
0511     case ARM_SPE_ADDRESS:
0512         err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
0513         break;
0514     case ARM_SPE_CONTEXT:
0515         arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
0516                        name, (unsigned long)payload, idx + 1);
0517         break;
0518     case ARM_SPE_COUNTER:
0519         err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
0520         break;
0521     default:
0522         /* Unknown packet type */
0523         err = -1;
0524         break;
0525     }
0526 
0527     /* Output raw data if detect any error */
0528     if (err) {
0529         err = 0;
0530         arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
0531                        name, payload, packet->index);
0532     }
0533 
0534     return err;
0535 }