linux/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright(C) 2015-2018 Linaro Limited.
   4 *
   5 * Author: Tor Jeremiassen <tor@ti.com>
   6 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
   7 */
   8
   9#include <linux/err.h>
  10#include <linux/list.h>
  11#include <stdlib.h>
  12#include <opencsd/c_api/opencsd_c_api.h>
  13#include <opencsd/etmv4/trc_pkt_types_etmv4.h>
  14#include <opencsd/ocsd_if_types.h>
  15
  16#include "cs-etm.h"
  17#include "cs-etm-decoder.h"
  18#include "intlist.h"
  19#include "util.h"
  20
  21#define MAX_BUFFER 1024
  22
  23/* use raw logging */
  24#ifdef CS_DEBUG_RAW
  25#define CS_LOG_RAW_FRAMES
  26#ifdef CS_RAW_PACKED
  27#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \
  28                            OCSD_DFRMTR_PACKED_RAW_OUT)
  29#else
  30#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT)
  31#endif
  32#endif
  33
  34struct cs_etm_decoder {
  35        void *data;
  36        void (*packet_printer)(const char *msg);
  37        bool trace_on;
  38        dcd_tree_handle_t dcd_tree;
  39        cs_etm_mem_cb_type mem_access;
  40        ocsd_datapath_resp_t prev_return;
  41        u32 packet_count;
  42        u32 head;
  43        u32 tail;
  44        struct cs_etm_packet packet_buffer[MAX_BUFFER];
  45};
  46
  47static u32
  48cs_etm_decoder__mem_access(const void *context,
  49                           const ocsd_vaddr_t address,
  50                           const ocsd_mem_space_acc_t mem_space __maybe_unused,
  51                           const u32 req_size,
  52                           u8 *buffer)
  53{
  54        struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
  55
  56        return decoder->mem_access(decoder->data,
  57                                   address,
  58                                   req_size,
  59                                   buffer);
  60}
  61
  62int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder,
  63                                      u64 start, u64 end,
  64                                      cs_etm_mem_cb_type cb_func)
  65{
  66        decoder->mem_access = cb_func;
  67
  68        if (ocsd_dt_add_callback_mem_acc(decoder->dcd_tree, start, end,
  69                                         OCSD_MEM_SPACE_ANY,
  70                                         cs_etm_decoder__mem_access, decoder))
  71                return -1;
  72
  73        return 0;
  74}
  75
  76int cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
  77{
  78        ocsd_datapath_resp_t dp_ret;
  79
  80        decoder->prev_return = OCSD_RESP_CONT;
  81
  82        dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
  83                                      0, 0, NULL, NULL);
  84        if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
  85                return -1;
  86
  87        return 0;
  88}
  89
  90int cs_etm_decoder__get_packet(struct cs_etm_decoder *decoder,
  91                               struct cs_etm_packet *packet)
  92{
  93        if (!decoder || !packet)
  94                return -EINVAL;
  95
  96        /* Nothing to do, might as well just return */
  97        if (decoder->packet_count == 0)
  98                return 0;
  99        /*
 100         * The queueing process in function cs_etm_decoder__buffer_packet()
 101         * increments the tail *before* using it.  This is somewhat counter
 102         * intuitive but it has the advantage of centralizing tail management
 103         * at a single location.  Because of that we need to follow the same
 104         * heuristic with the head, i.e we increment it before using its
 105         * value.  Otherwise the first element of the packet queue is not
 106         * used.
 107         */
 108        decoder->head = (decoder->head + 1) & (MAX_BUFFER - 1);
 109
 110        *packet = decoder->packet_buffer[decoder->head];
 111
 112        decoder->packet_count--;
 113
 114        return 1;
 115}
 116
 117static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params,
 118                                             ocsd_etmv4_cfg *config)
 119{
 120        config->reg_configr = params->etmv4.reg_configr;
 121        config->reg_traceidr = params->etmv4.reg_traceidr;
 122        config->reg_idr0 = params->etmv4.reg_idr0;
 123        config->reg_idr1 = params->etmv4.reg_idr1;
 124        config->reg_idr2 = params->etmv4.reg_idr2;
 125        config->reg_idr8 = params->etmv4.reg_idr8;
 126        config->reg_idr9 = 0;
 127        config->reg_idr10 = 0;
 128        config->reg_idr11 = 0;
 129        config->reg_idr12 = 0;
 130        config->reg_idr13 = 0;
 131        config->arch_ver = ARCH_V8;
 132        config->core_prof = profile_CortexA;
 133}
 134
 135static void cs_etm_decoder__print_str_cb(const void *p_context,
 136                                         const char *msg,
 137                                         const int str_len)
 138{
 139        if (p_context && str_len)
 140                ((struct cs_etm_decoder *)p_context)->packet_printer(msg);
 141}
 142
 143static int
 144cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params,
 145                                         struct cs_etm_decoder *decoder)
 146{
 147        int ret = 0;
 148
 149        if (d_params->packet_printer == NULL)
 150                return -1;
 151
 152        decoder->packet_printer = d_params->packet_printer;
 153
 154        /*
 155         * Set up a library default logger to process any printers
 156         * (packet/raw frame) we add later.
 157         */
 158        ret = ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
 159        if (ret != 0)
 160                return -1;
 161
 162        /* no stdout / err / file output */
 163        ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
 164        if (ret != 0)
 165                return -1;
 166
 167        /*
 168         * Set the string CB for the default logger, passes strings to
 169         * perf print logger.
 170         */
 171        ret = ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
 172                                              (void *)decoder,
 173                                              cs_etm_decoder__print_str_cb);
 174        if (ret != 0)
 175                ret = -1;
 176
 177        return 0;
 178}
 179
 180#ifdef CS_LOG_RAW_FRAMES
 181static void
 182cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params,
 183                                       struct cs_etm_decoder *decoder)
 184{
 185        /* Only log these during a --dump operation */
 186        if (d_params->operation == CS_ETM_OPERATION_PRINT) {
 187                /* set up a library default logger to process the
 188                 *  raw frame printer we add later
 189                 */
 190                ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
 191
 192                /* no stdout / err / file output */
 193                ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
 194
 195                /* set the string CB for the default logger,
 196                 * passes strings to perf print logger.
 197                 */
 198                ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
 199                                                (void *)decoder,
 200                                                cs_etm_decoder__print_str_cb);
 201
 202                /* use the built in library printer for the raw frames */
 203                ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
 204                                              CS_RAW_DEBUG_FLAGS);
 205        }
 206}
 207#else
 208static void
 209cs_etm_decoder__init_raw_frame_logging(
 210                struct cs_etm_decoder_params *d_params __maybe_unused,
 211                struct cs_etm_decoder *decoder __maybe_unused)
 212{
 213}
 214#endif
 215
 216static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder,
 217                                                 const char *decoder_name,
 218                                                 void *trace_config)
 219{
 220        u8 csid;
 221
 222        if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name,
 223                                   OCSD_CREATE_FLG_PACKET_PROC,
 224                                   trace_config, &csid))
 225                return -1;
 226
 227        if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
 228                return -1;
 229
 230        return 0;
 231}
 232
 233static int
 234cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params,
 235                                          struct cs_etm_decoder *decoder)
 236{
 237        const char *decoder_name;
 238        ocsd_etmv4_cfg trace_config_etmv4;
 239        void *trace_config;
 240
 241        switch (t_params->protocol) {
 242        case CS_ETM_PROTO_ETMV4i:
 243                cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
 244                decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
 245                trace_config = &trace_config_etmv4;
 246                break;
 247        default:
 248                return -1;
 249        }
 250
 251        return cs_etm_decoder__create_packet_printer(decoder,
 252                                                     decoder_name,
 253                                                     trace_config);
 254}
 255
 256static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 257{
 258        int i;
 259
 260        decoder->head = 0;
 261        decoder->tail = 0;
 262        decoder->packet_count = 0;
 263        for (i = 0; i < MAX_BUFFER; i++) {
 264                decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL;
 265                decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
 266                decoder->packet_buffer[i].last_instr_taken_branch = false;
 267                decoder->packet_buffer[i].exc = false;
 268                decoder->packet_buffer[i].exc_ret = false;
 269                decoder->packet_buffer[i].cpu = INT_MIN;
 270        }
 271}
 272
 273static ocsd_datapath_resp_t
 274cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 275                              const u8 trace_chan_id,
 276                              enum cs_etm_sample_type sample_type)
 277{
 278        u32 et = 0;
 279        struct int_node *inode = NULL;
 280
 281        if (decoder->packet_count >= MAX_BUFFER - 1)
 282                return OCSD_RESP_FATAL_SYS_ERR;
 283
 284        /* Search the RB tree for the cpu associated with this traceID */
 285        inode = intlist__find(traceid_list, trace_chan_id);
 286        if (!inode)
 287                return OCSD_RESP_FATAL_SYS_ERR;
 288
 289        et = decoder->tail;
 290        et = (et + 1) & (MAX_BUFFER - 1);
 291        decoder->tail = et;
 292        decoder->packet_count++;
 293
 294        decoder->packet_buffer[et].sample_type = sample_type;
 295        decoder->packet_buffer[et].exc = false;
 296        decoder->packet_buffer[et].exc_ret = false;
 297        decoder->packet_buffer[et].cpu = *((int *)inode->priv);
 298        decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL;
 299        decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL;
 300
 301        if (decoder->packet_count == MAX_BUFFER - 1)
 302                return OCSD_RESP_WAIT;
 303
 304        return OCSD_RESP_CONT;
 305}
 306
 307static ocsd_datapath_resp_t
 308cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
 309                             const ocsd_generic_trace_elem *elem,
 310                             const uint8_t trace_chan_id)
 311{
 312        int ret = 0;
 313        struct cs_etm_packet *packet;
 314
 315        ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
 316                                            CS_ETM_RANGE);
 317        if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
 318                return ret;
 319
 320        packet = &decoder->packet_buffer[decoder->tail];
 321
 322        packet->start_addr = elem->st_addr;
 323        packet->end_addr = elem->en_addr;
 324        switch (elem->last_i_type) {
 325        case OCSD_INSTR_BR:
 326        case OCSD_INSTR_BR_INDIRECT:
 327                packet->last_instr_taken_branch = elem->last_instr_exec;
 328                break;
 329        case OCSD_INSTR_ISB:
 330        case OCSD_INSTR_DSB_DMB:
 331        case OCSD_INSTR_OTHER:
 332        default:
 333                packet->last_instr_taken_branch = false;
 334                break;
 335        }
 336
 337        return ret;
 338}
 339
 340static ocsd_datapath_resp_t
 341cs_etm_decoder__buffer_trace_on(struct cs_etm_decoder *decoder,
 342                                const uint8_t trace_chan_id)
 343{
 344        return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
 345                                             CS_ETM_TRACE_ON);
 346}
 347
 348static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
 349                                const void *context,
 350                                const ocsd_trc_index_t indx __maybe_unused,
 351                                const u8 trace_chan_id __maybe_unused,
 352                                const ocsd_generic_trace_elem *elem)
 353{
 354        ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
 355        struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
 356
 357        switch (elem->elem_type) {
 358        case OCSD_GEN_TRC_ELEM_UNKNOWN:
 359                break;
 360        case OCSD_GEN_TRC_ELEM_NO_SYNC:
 361                decoder->trace_on = false;
 362                break;
 363        case OCSD_GEN_TRC_ELEM_TRACE_ON:
 364                resp = cs_etm_decoder__buffer_trace_on(decoder,
 365                                                       trace_chan_id);
 366                decoder->trace_on = true;
 367                break;
 368        case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
 369                resp = cs_etm_decoder__buffer_range(decoder, elem,
 370                                                    trace_chan_id);
 371                break;
 372        case OCSD_GEN_TRC_ELEM_EXCEPTION:
 373                decoder->packet_buffer[decoder->tail].exc = true;
 374                break;
 375        case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
 376                decoder->packet_buffer[decoder->tail].exc_ret = true;
 377                break;
 378        case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
 379        case OCSD_GEN_TRC_ELEM_EO_TRACE:
 380        case OCSD_GEN_TRC_ELEM_ADDR_NACC:
 381        case OCSD_GEN_TRC_ELEM_TIMESTAMP:
 382        case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
 383        case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
 384        case OCSD_GEN_TRC_ELEM_EVENT:
 385        case OCSD_GEN_TRC_ELEM_SWTRACE:
 386        case OCSD_GEN_TRC_ELEM_CUSTOM:
 387        default:
 388                break;
 389        }
 390
 391        return resp;
 392}
 393
 394static int cs_etm_decoder__create_etm_packet_decoder(
 395                                        struct cs_etm_trace_params *t_params,
 396                                        struct cs_etm_decoder *decoder)
 397{
 398        const char *decoder_name;
 399        ocsd_etmv4_cfg trace_config_etmv4;
 400        void *trace_config;
 401        u8 csid;
 402
 403        switch (t_params->protocol) {
 404        case CS_ETM_PROTO_ETMV4i:
 405                cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
 406                decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
 407                trace_config = &trace_config_etmv4;
 408                break;
 409        default:
 410                return -1;
 411        }
 412
 413        if (ocsd_dt_create_decoder(decoder->dcd_tree,
 414                                     decoder_name,
 415                                     OCSD_CREATE_FLG_FULL_DECODER,
 416                                     trace_config, &csid))
 417                return -1;
 418
 419        if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
 420                                       cs_etm_decoder__gen_trace_elem_printer,
 421                                       decoder))
 422                return -1;
 423
 424        return 0;
 425}
 426
 427static int
 428cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
 429                                   struct cs_etm_trace_params *t_params,
 430                                   struct cs_etm_decoder *decoder)
 431{
 432        if (d_params->operation == CS_ETM_OPERATION_PRINT)
 433                return cs_etm_decoder__create_etm_packet_printer(t_params,
 434                                                                 decoder);
 435        else if (d_params->operation == CS_ETM_OPERATION_DECODE)
 436                return cs_etm_decoder__create_etm_packet_decoder(t_params,
 437                                                                 decoder);
 438
 439        return -1;
 440}
 441
 442struct cs_etm_decoder *
 443cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
 444                    struct cs_etm_trace_params t_params[])
 445{
 446        struct cs_etm_decoder *decoder;
 447        ocsd_dcd_tree_src_t format;
 448        u32 flags;
 449        int i, ret;
 450
 451        if ((!t_params) || (!d_params))
 452                return NULL;
 453
 454        decoder = zalloc(sizeof(*decoder));
 455
 456        if (!decoder)
 457                return NULL;
 458
 459        decoder->data = d_params->data;
 460        decoder->prev_return = OCSD_RESP_CONT;
 461        cs_etm_decoder__clear_buffer(decoder);
 462        format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED :
 463                                         OCSD_TRC_SRC_SINGLE);
 464        flags = 0;
 465        flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0);
 466        flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0);
 467        flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0);
 468
 469        /*
 470         * Drivers may add barrier frames when used with perf, set up to
 471         * handle this. Barriers const of FSYNC packet repeated 4 times.
 472         */
 473        flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC;
 474
 475        /* Create decode tree for the data source */
 476        decoder->dcd_tree = ocsd_create_dcd_tree(format, flags);
 477
 478        if (decoder->dcd_tree == 0)
 479                goto err_free_decoder;
 480
 481        /* init library print logging support */
 482        ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder);
 483        if (ret != 0)
 484                goto err_free_decoder_tree;
 485
 486        /* init raw frame logging if required */
 487        cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
 488
 489        for (i = 0; i < num_cpu; i++) {
 490                ret = cs_etm_decoder__create_etm_decoder(d_params,
 491                                                         &t_params[i],
 492                                                         decoder);
 493                if (ret != 0)
 494                        goto err_free_decoder_tree;
 495        }
 496
 497        return decoder;
 498
 499err_free_decoder_tree:
 500        ocsd_destroy_dcd_tree(decoder->dcd_tree);
 501err_free_decoder:
 502        free(decoder);
 503        return NULL;
 504}
 505
 506int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder,
 507                                       u64 indx, const u8 *buf,
 508                                       size_t len, size_t *consumed)
 509{
 510        int ret = 0;
 511        ocsd_datapath_resp_t cur = OCSD_RESP_CONT;
 512        ocsd_datapath_resp_t prev_return = decoder->prev_return;
 513        size_t processed = 0;
 514        u32 count;
 515
 516        while (processed < len) {
 517                if (OCSD_DATA_RESP_IS_WAIT(prev_return)) {
 518                        cur = ocsd_dt_process_data(decoder->dcd_tree,
 519                                                   OCSD_OP_FLUSH,
 520                                                   0,
 521                                                   0,
 522                                                   NULL,
 523                                                   NULL);
 524                } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) {
 525                        cur = ocsd_dt_process_data(decoder->dcd_tree,
 526                                                   OCSD_OP_DATA,
 527                                                   indx + processed,
 528                                                   len - processed,
 529                                                   &buf[processed],
 530                                                   &count);
 531                        processed += count;
 532                } else {
 533                        ret = -EINVAL;
 534                        break;
 535                }
 536
 537                /*
 538                 * Return to the input code if the packet buffer is full.
 539                 * Flushing will get done once the packet buffer has been
 540                 * processed.
 541                 */
 542                if (OCSD_DATA_RESP_IS_WAIT(cur))
 543                        break;
 544
 545                prev_return = cur;
 546        }
 547
 548        decoder->prev_return = cur;
 549        *consumed = processed;
 550
 551        return ret;
 552}
 553
 554void cs_etm_decoder__free(struct cs_etm_decoder *decoder)
 555{
 556        if (!decoder)
 557                return;
 558
 559        ocsd_destroy_dcd_tree(decoder->dcd_tree);
 560        decoder->dcd_tree = NULL;
 561        free(decoder);
 562}
 563