18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * intel_pt_decoder.c: Intel Processor Trace support 48c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#ifndef _GNU_SOURCE 88c2ecf20Sopenharmony_ci#define _GNU_SOURCE 98c2ecf20Sopenharmony_ci#endif 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <stdbool.h> 128c2ecf20Sopenharmony_ci#include <string.h> 138c2ecf20Sopenharmony_ci#include <errno.h> 148c2ecf20Sopenharmony_ci#include <stdint.h> 158c2ecf20Sopenharmony_ci#include <inttypes.h> 168c2ecf20Sopenharmony_ci#include <linux/compiler.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "../auxtrace.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "intel-pt-insn-decoder.h" 238c2ecf20Sopenharmony_ci#include "intel-pt-pkt-decoder.h" 248c2ecf20Sopenharmony_ci#include "intel-pt-decoder.h" 258c2ecf20Sopenharmony_ci#include "intel-pt-log.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define BITULL(x) (1ULL << (x)) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* IA32_RTIT_CTL MSR bits */ 308c2ecf20Sopenharmony_ci#define INTEL_PT_CYC_ENABLE BITULL(1) 318c2ecf20Sopenharmony_ci#define INTEL_PT_CYC_THRESHOLD (BITULL(22) | BITULL(21) | BITULL(20) | BITULL(19)) 328c2ecf20Sopenharmony_ci#define INTEL_PT_CYC_THRESHOLD_SHIFT 19 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define INTEL_PT_BLK_SIZE 1024 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BIT63 (((uint64_t)1 << 63)) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define INTEL_PT_RETURN 1 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Maximum number of loops with no packets consumed i.e. stuck in a loop */ 418c2ecf20Sopenharmony_ci#define INTEL_PT_MAX_LOOPS 10000 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct intel_pt_blk { 448c2ecf20Sopenharmony_ci struct intel_pt_blk *prev; 458c2ecf20Sopenharmony_ci uint64_t ip[INTEL_PT_BLK_SIZE]; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct intel_pt_stack { 498c2ecf20Sopenharmony_ci struct intel_pt_blk *blk; 508c2ecf20Sopenharmony_ci struct intel_pt_blk *spare; 518c2ecf20Sopenharmony_ci int pos; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cienum intel_pt_pkt_state { 558c2ecf20Sopenharmony_ci INTEL_PT_STATE_NO_PSB, 568c2ecf20Sopenharmony_ci INTEL_PT_STATE_NO_IP, 578c2ecf20Sopenharmony_ci INTEL_PT_STATE_ERR_RESYNC, 588c2ecf20Sopenharmony_ci INTEL_PT_STATE_IN_SYNC, 598c2ecf20Sopenharmony_ci INTEL_PT_STATE_TNT_CONT, 608c2ecf20Sopenharmony_ci INTEL_PT_STATE_TNT, 618c2ecf20Sopenharmony_ci INTEL_PT_STATE_TIP, 628c2ecf20Sopenharmony_ci INTEL_PT_STATE_TIP_PGD, 638c2ecf20Sopenharmony_ci INTEL_PT_STATE_FUP, 648c2ecf20Sopenharmony_ci INTEL_PT_STATE_FUP_NO_TIP, 658c2ecf20Sopenharmony_ci INTEL_PT_STATE_RESAMPLE, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci switch (pkt_state) { 718c2ecf20Sopenharmony_ci case INTEL_PT_STATE_NO_PSB: 728c2ecf20Sopenharmony_ci case INTEL_PT_STATE_NO_IP: 738c2ecf20Sopenharmony_ci case INTEL_PT_STATE_ERR_RESYNC: 748c2ecf20Sopenharmony_ci case INTEL_PT_STATE_IN_SYNC: 758c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TNT_CONT: 768c2ecf20Sopenharmony_ci case INTEL_PT_STATE_RESAMPLE: 778c2ecf20Sopenharmony_ci return true; 788c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TNT: 798c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TIP: 808c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TIP_PGD: 818c2ecf20Sopenharmony_ci case INTEL_PT_STATE_FUP: 828c2ecf20Sopenharmony_ci case INTEL_PT_STATE_FUP_NO_TIP: 838c2ecf20Sopenharmony_ci return false; 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci return true; 868c2ecf20Sopenharmony_ci }; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#ifdef INTEL_PT_STRICT 908c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB 918c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB 928c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR3 INTEL_PT_STATE_NO_PSB 938c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR4 INTEL_PT_STATE_NO_PSB 948c2ecf20Sopenharmony_ci#else 958c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR1 (decoder->pkt_state) 968c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_IP 978c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR3 INTEL_PT_STATE_ERR_RESYNC 988c2ecf20Sopenharmony_ci#define INTEL_PT_STATE_ERR4 INTEL_PT_STATE_IN_SYNC 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct intel_pt_decoder { 1028c2ecf20Sopenharmony_ci int (*get_trace)(struct intel_pt_buffer *buffer, void *data); 1038c2ecf20Sopenharmony_ci int (*walk_insn)(struct intel_pt_insn *intel_pt_insn, 1048c2ecf20Sopenharmony_ci uint64_t *insn_cnt_ptr, uint64_t *ip, uint64_t to_ip, 1058c2ecf20Sopenharmony_ci uint64_t max_insn_cnt, void *data); 1068c2ecf20Sopenharmony_ci bool (*pgd_ip)(uint64_t ip, void *data); 1078c2ecf20Sopenharmony_ci int (*lookahead)(void *data, intel_pt_lookahead_cb_t cb, void *cb_data); 1088c2ecf20Sopenharmony_ci void *data; 1098c2ecf20Sopenharmony_ci struct intel_pt_state state; 1108c2ecf20Sopenharmony_ci const unsigned char *buf; 1118c2ecf20Sopenharmony_ci size_t len; 1128c2ecf20Sopenharmony_ci bool return_compression; 1138c2ecf20Sopenharmony_ci bool branch_enable; 1148c2ecf20Sopenharmony_ci bool mtc_insn; 1158c2ecf20Sopenharmony_ci bool pge; 1168c2ecf20Sopenharmony_ci bool have_tma; 1178c2ecf20Sopenharmony_ci bool have_cyc; 1188c2ecf20Sopenharmony_ci bool fixup_last_mtc; 1198c2ecf20Sopenharmony_ci bool have_last_ip; 1208c2ecf20Sopenharmony_ci bool in_psb; 1218c2ecf20Sopenharmony_ci bool hop; 1228c2ecf20Sopenharmony_ci bool hop_psb_fup; 1238c2ecf20Sopenharmony_ci bool leap; 1248c2ecf20Sopenharmony_ci enum intel_pt_param_flags flags; 1258c2ecf20Sopenharmony_ci uint64_t pos; 1268c2ecf20Sopenharmony_ci uint64_t last_ip; 1278c2ecf20Sopenharmony_ci uint64_t ip; 1288c2ecf20Sopenharmony_ci uint64_t cr3; 1298c2ecf20Sopenharmony_ci uint64_t timestamp; 1308c2ecf20Sopenharmony_ci uint64_t tsc_timestamp; 1318c2ecf20Sopenharmony_ci uint64_t ref_timestamp; 1328c2ecf20Sopenharmony_ci uint64_t buf_timestamp; 1338c2ecf20Sopenharmony_ci uint64_t sample_timestamp; 1348c2ecf20Sopenharmony_ci uint64_t ret_addr; 1358c2ecf20Sopenharmony_ci uint64_t ctc_timestamp; 1368c2ecf20Sopenharmony_ci uint64_t ctc_delta; 1378c2ecf20Sopenharmony_ci uint64_t cycle_cnt; 1388c2ecf20Sopenharmony_ci uint64_t cyc_ref_timestamp; 1398c2ecf20Sopenharmony_ci uint32_t last_mtc; 1408c2ecf20Sopenharmony_ci uint32_t tsc_ctc_ratio_n; 1418c2ecf20Sopenharmony_ci uint32_t tsc_ctc_ratio_d; 1428c2ecf20Sopenharmony_ci uint32_t tsc_ctc_mult; 1438c2ecf20Sopenharmony_ci uint32_t tsc_slip; 1448c2ecf20Sopenharmony_ci uint32_t ctc_rem_mask; 1458c2ecf20Sopenharmony_ci int mtc_shift; 1468c2ecf20Sopenharmony_ci struct intel_pt_stack stack; 1478c2ecf20Sopenharmony_ci enum intel_pt_pkt_state pkt_state; 1488c2ecf20Sopenharmony_ci enum intel_pt_pkt_ctx pkt_ctx; 1498c2ecf20Sopenharmony_ci enum intel_pt_pkt_ctx prev_pkt_ctx; 1508c2ecf20Sopenharmony_ci enum intel_pt_blk_type blk_type; 1518c2ecf20Sopenharmony_ci int blk_type_pos; 1528c2ecf20Sopenharmony_ci struct intel_pt_pkt packet; 1538c2ecf20Sopenharmony_ci struct intel_pt_pkt tnt; 1548c2ecf20Sopenharmony_ci int pkt_step; 1558c2ecf20Sopenharmony_ci int pkt_len; 1568c2ecf20Sopenharmony_ci int last_packet_type; 1578c2ecf20Sopenharmony_ci unsigned int cbr; 1588c2ecf20Sopenharmony_ci unsigned int cbr_seen; 1598c2ecf20Sopenharmony_ci unsigned int max_non_turbo_ratio; 1608c2ecf20Sopenharmony_ci double max_non_turbo_ratio_fp; 1618c2ecf20Sopenharmony_ci double cbr_cyc_to_tsc; 1628c2ecf20Sopenharmony_ci double calc_cyc_to_tsc; 1638c2ecf20Sopenharmony_ci bool have_calc_cyc_to_tsc; 1648c2ecf20Sopenharmony_ci int exec_mode; 1658c2ecf20Sopenharmony_ci unsigned int insn_bytes; 1668c2ecf20Sopenharmony_ci uint64_t period; 1678c2ecf20Sopenharmony_ci enum intel_pt_period_type period_type; 1688c2ecf20Sopenharmony_ci uint64_t tot_insn_cnt; 1698c2ecf20Sopenharmony_ci uint64_t period_insn_cnt; 1708c2ecf20Sopenharmony_ci uint64_t period_mask; 1718c2ecf20Sopenharmony_ci uint64_t period_ticks; 1728c2ecf20Sopenharmony_ci uint64_t last_masked_timestamp; 1738c2ecf20Sopenharmony_ci uint64_t tot_cyc_cnt; 1748c2ecf20Sopenharmony_ci uint64_t sample_tot_cyc_cnt; 1758c2ecf20Sopenharmony_ci uint64_t base_cyc_cnt; 1768c2ecf20Sopenharmony_ci uint64_t cyc_cnt_timestamp; 1778c2ecf20Sopenharmony_ci uint64_t ctl; 1788c2ecf20Sopenharmony_ci uint64_t cyc_threshold; 1798c2ecf20Sopenharmony_ci double tsc_to_cyc; 1808c2ecf20Sopenharmony_ci bool continuous_period; 1818c2ecf20Sopenharmony_ci bool overflow; 1828c2ecf20Sopenharmony_ci bool set_fup_tx_flags; 1838c2ecf20Sopenharmony_ci bool set_fup_ptw; 1848c2ecf20Sopenharmony_ci bool set_fup_mwait; 1858c2ecf20Sopenharmony_ci bool set_fup_pwre; 1868c2ecf20Sopenharmony_ci bool set_fup_exstop; 1878c2ecf20Sopenharmony_ci bool set_fup_bep; 1888c2ecf20Sopenharmony_ci bool sample_cyc; 1898c2ecf20Sopenharmony_ci unsigned int fup_tx_flags; 1908c2ecf20Sopenharmony_ci unsigned int tx_flags; 1918c2ecf20Sopenharmony_ci uint64_t fup_ptw_payload; 1928c2ecf20Sopenharmony_ci uint64_t fup_mwait_payload; 1938c2ecf20Sopenharmony_ci uint64_t fup_pwre_payload; 1948c2ecf20Sopenharmony_ci uint64_t cbr_payload; 1958c2ecf20Sopenharmony_ci uint64_t timestamp_insn_cnt; 1968c2ecf20Sopenharmony_ci uint64_t sample_insn_cnt; 1978c2ecf20Sopenharmony_ci uint64_t stuck_ip; 1988c2ecf20Sopenharmony_ci int no_progress; 1998c2ecf20Sopenharmony_ci int stuck_ip_prd; 2008c2ecf20Sopenharmony_ci int stuck_ip_cnt; 2018c2ecf20Sopenharmony_ci const unsigned char *next_buf; 2028c2ecf20Sopenharmony_ci size_t next_len; 2038c2ecf20Sopenharmony_ci unsigned char temp_buf[INTEL_PT_PKT_MAX_SZ]; 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic uint64_t intel_pt_lower_power_of_2(uint64_t x) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int i; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci for (i = 0; x != 1; i++) 2118c2ecf20Sopenharmony_ci x >>= 1; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return x << i; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic uint64_t intel_pt_cyc_threshold(uint64_t ctl) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci if (!(ctl & INTEL_PT_CYC_ENABLE)) 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return (ctl & INTEL_PT_CYC_THRESHOLD) >> INTEL_PT_CYC_THRESHOLD_SHIFT; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void intel_pt_setup_period(struct intel_pt_decoder *decoder) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if (decoder->period_type == INTEL_PT_PERIOD_TICKS) { 2278c2ecf20Sopenharmony_ci uint64_t period; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci period = intel_pt_lower_power_of_2(decoder->period); 2308c2ecf20Sopenharmony_ci decoder->period_mask = ~(period - 1); 2318c2ecf20Sopenharmony_ci decoder->period_ticks = period; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic uint64_t multdiv(uint64_t t, uint32_t n, uint32_t d) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci if (!d) 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci return (t / d) * n + ((t % d) * n) / d; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistruct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct intel_pt_decoder *decoder; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!params->get_trace || !params->walk_insn) 2478c2ecf20Sopenharmony_ci return NULL; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci decoder = zalloc(sizeof(struct intel_pt_decoder)); 2508c2ecf20Sopenharmony_ci if (!decoder) 2518c2ecf20Sopenharmony_ci return NULL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci decoder->get_trace = params->get_trace; 2548c2ecf20Sopenharmony_ci decoder->walk_insn = params->walk_insn; 2558c2ecf20Sopenharmony_ci decoder->pgd_ip = params->pgd_ip; 2568c2ecf20Sopenharmony_ci decoder->lookahead = params->lookahead; 2578c2ecf20Sopenharmony_ci decoder->data = params->data; 2588c2ecf20Sopenharmony_ci decoder->return_compression = params->return_compression; 2598c2ecf20Sopenharmony_ci decoder->branch_enable = params->branch_enable; 2608c2ecf20Sopenharmony_ci decoder->hop = params->quick >= 1; 2618c2ecf20Sopenharmony_ci decoder->leap = params->quick >= 2; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci decoder->flags = params->flags; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci decoder->ctl = params->ctl; 2668c2ecf20Sopenharmony_ci decoder->period = params->period; 2678c2ecf20Sopenharmony_ci decoder->period_type = params->period_type; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci decoder->max_non_turbo_ratio = params->max_non_turbo_ratio; 2708c2ecf20Sopenharmony_ci decoder->max_non_turbo_ratio_fp = params->max_non_turbo_ratio; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci decoder->cyc_threshold = intel_pt_cyc_threshold(decoder->ctl); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci intel_pt_setup_period(decoder); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci decoder->mtc_shift = params->mtc_period; 2778c2ecf20Sopenharmony_ci decoder->ctc_rem_mask = (1 << decoder->mtc_shift) - 1; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_n = params->tsc_ctc_ratio_n; 2808c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d = params->tsc_ctc_ratio_d; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (!decoder->tsc_ctc_ratio_n) 2838c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d = 0; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (decoder->tsc_ctc_ratio_d) { 2868c2ecf20Sopenharmony_ci if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d)) 2878c2ecf20Sopenharmony_ci decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n / 2888c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * A TSC packet can slip past MTC packets so that the timestamp appears 2938c2ecf20Sopenharmony_ci * to go backwards. One estimate is that can be up to about 40 CPU 2948c2ecf20Sopenharmony_ci * cycles, which is certainly less than 0x1000 TSC ticks, but accept 2958c2ecf20Sopenharmony_ci * slippage an order of magnitude more to be on the safe side. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci decoder->tsc_slip = 0x10000; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift); 3008c2ecf20Sopenharmony_ci intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n); 3018c2ecf20Sopenharmony_ci intel_pt_log("timestamp: tsc_ctc_ratio_d %u\n", decoder->tsc_ctc_ratio_d); 3028c2ecf20Sopenharmony_ci intel_pt_log("timestamp: tsc_ctc_mult %u\n", decoder->tsc_ctc_mult); 3038c2ecf20Sopenharmony_ci intel_pt_log("timestamp: tsc_slip %#x\n", decoder->tsc_slip); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (decoder->hop) 3068c2ecf20Sopenharmony_ci intel_pt_log("Hop mode: decoding FUP and TIPs, but not TNT\n"); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return decoder; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void intel_pt_pop_blk(struct intel_pt_stack *stack) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct intel_pt_blk *blk = stack->blk; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci stack->blk = blk->prev; 3168c2ecf20Sopenharmony_ci if (!stack->spare) 3178c2ecf20Sopenharmony_ci stack->spare = blk; 3188c2ecf20Sopenharmony_ci else 3198c2ecf20Sopenharmony_ci free(blk); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic uint64_t intel_pt_pop(struct intel_pt_stack *stack) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci if (!stack->pos) { 3258c2ecf20Sopenharmony_ci if (!stack->blk) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci intel_pt_pop_blk(stack); 3288c2ecf20Sopenharmony_ci if (!stack->blk) 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci stack->pos = INTEL_PT_BLK_SIZE; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci return stack->blk->ip[--stack->pos]; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int intel_pt_alloc_blk(struct intel_pt_stack *stack) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct intel_pt_blk *blk; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (stack->spare) { 3408c2ecf20Sopenharmony_ci blk = stack->spare; 3418c2ecf20Sopenharmony_ci stack->spare = NULL; 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci blk = malloc(sizeof(struct intel_pt_blk)); 3448c2ecf20Sopenharmony_ci if (!blk) 3458c2ecf20Sopenharmony_ci return -ENOMEM; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci blk->prev = stack->blk; 3498c2ecf20Sopenharmony_ci stack->blk = blk; 3508c2ecf20Sopenharmony_ci stack->pos = 0; 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int intel_pt_push(struct intel_pt_stack *stack, uint64_t ip) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci int err; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!stack->blk || stack->pos == INTEL_PT_BLK_SIZE) { 3598c2ecf20Sopenharmony_ci err = intel_pt_alloc_blk(stack); 3608c2ecf20Sopenharmony_ci if (err) 3618c2ecf20Sopenharmony_ci return err; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci stack->blk->ip[stack->pos++] = ip; 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void intel_pt_clear_stack(struct intel_pt_stack *stack) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci while (stack->blk) 3718c2ecf20Sopenharmony_ci intel_pt_pop_blk(stack); 3728c2ecf20Sopenharmony_ci stack->pos = 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void intel_pt_free_stack(struct intel_pt_stack *stack) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci intel_pt_clear_stack(stack); 3788c2ecf20Sopenharmony_ci zfree(&stack->blk); 3798c2ecf20Sopenharmony_ci zfree(&stack->spare); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_civoid intel_pt_decoder_free(struct intel_pt_decoder *decoder) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci intel_pt_free_stack(&decoder->stack); 3858c2ecf20Sopenharmony_ci free(decoder); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int intel_pt_ext_err(int code) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci switch (code) { 3918c2ecf20Sopenharmony_ci case -ENOMEM: 3928c2ecf20Sopenharmony_ci return INTEL_PT_ERR_NOMEM; 3938c2ecf20Sopenharmony_ci case -ENOSYS: 3948c2ecf20Sopenharmony_ci return INTEL_PT_ERR_INTERN; 3958c2ecf20Sopenharmony_ci case -EBADMSG: 3968c2ecf20Sopenharmony_ci return INTEL_PT_ERR_BADPKT; 3978c2ecf20Sopenharmony_ci case -ENODATA: 3988c2ecf20Sopenharmony_ci return INTEL_PT_ERR_NODATA; 3998c2ecf20Sopenharmony_ci case -EILSEQ: 4008c2ecf20Sopenharmony_ci return INTEL_PT_ERR_NOINSN; 4018c2ecf20Sopenharmony_ci case -ENOENT: 4028c2ecf20Sopenharmony_ci return INTEL_PT_ERR_MISMAT; 4038c2ecf20Sopenharmony_ci case -EOVERFLOW: 4048c2ecf20Sopenharmony_ci return INTEL_PT_ERR_OVR; 4058c2ecf20Sopenharmony_ci case -ENOSPC: 4068c2ecf20Sopenharmony_ci return INTEL_PT_ERR_LOST; 4078c2ecf20Sopenharmony_ci case -ELOOP: 4088c2ecf20Sopenharmony_ci return INTEL_PT_ERR_NELOOP; 4098c2ecf20Sopenharmony_ci default: 4108c2ecf20Sopenharmony_ci return INTEL_PT_ERR_UNK; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic const char *intel_pt_err_msgs[] = { 4158c2ecf20Sopenharmony_ci [INTEL_PT_ERR_NOMEM] = "Memory allocation failed", 4168c2ecf20Sopenharmony_ci [INTEL_PT_ERR_INTERN] = "Internal error", 4178c2ecf20Sopenharmony_ci [INTEL_PT_ERR_BADPKT] = "Bad packet", 4188c2ecf20Sopenharmony_ci [INTEL_PT_ERR_NODATA] = "No more data", 4198c2ecf20Sopenharmony_ci [INTEL_PT_ERR_NOINSN] = "Failed to get instruction", 4208c2ecf20Sopenharmony_ci [INTEL_PT_ERR_MISMAT] = "Trace doesn't match instruction", 4218c2ecf20Sopenharmony_ci [INTEL_PT_ERR_OVR] = "Overflow packet", 4228c2ecf20Sopenharmony_ci [INTEL_PT_ERR_LOST] = "Lost trace data", 4238c2ecf20Sopenharmony_ci [INTEL_PT_ERR_UNK] = "Unknown error!", 4248c2ecf20Sopenharmony_ci [INTEL_PT_ERR_NELOOP] = "Never-ending loop", 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ciint intel_pt__strerror(int code, char *buf, size_t buflen) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci if (code < 1 || code >= INTEL_PT_ERR_MAX) 4308c2ecf20Sopenharmony_ci code = INTEL_PT_ERR_UNK; 4318c2ecf20Sopenharmony_ci strlcpy(buf, intel_pt_err_msgs[code], buflen); 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic uint64_t intel_pt_calc_ip(const struct intel_pt_pkt *packet, 4368c2ecf20Sopenharmony_ci uint64_t last_ip) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci uint64_t ip; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci switch (packet->count) { 4418c2ecf20Sopenharmony_ci case 1: 4428c2ecf20Sopenharmony_ci ip = (last_ip & (uint64_t)0xffffffffffff0000ULL) | 4438c2ecf20Sopenharmony_ci packet->payload; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci case 2: 4468c2ecf20Sopenharmony_ci ip = (last_ip & (uint64_t)0xffffffff00000000ULL) | 4478c2ecf20Sopenharmony_ci packet->payload; 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci case 3: 4508c2ecf20Sopenharmony_ci ip = packet->payload; 4518c2ecf20Sopenharmony_ci /* Sign-extend 6-byte ip */ 4528c2ecf20Sopenharmony_ci if (ip & (uint64_t)0x800000000000ULL) 4538c2ecf20Sopenharmony_ci ip |= (uint64_t)0xffff000000000000ULL; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci case 4: 4568c2ecf20Sopenharmony_ci ip = (last_ip & (uint64_t)0xffff000000000000ULL) | 4578c2ecf20Sopenharmony_ci packet->payload; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci case 6: 4608c2ecf20Sopenharmony_ci ip = packet->payload; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci default: 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return ip; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); 4728c2ecf20Sopenharmony_ci decoder->have_last_ip = true; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 4788c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void intel_pt_decoder_log_packet(struct intel_pt_decoder *decoder) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci intel_pt_log_packet(&decoder->packet, decoder->pkt_len, decoder->pos, 4848c2ecf20Sopenharmony_ci decoder->buf); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int intel_pt_bug(struct intel_pt_decoder *decoder) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Internal error\n"); 4908c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_NO_PSB; 4918c2ecf20Sopenharmony_ci return -ENOSYS; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic inline void intel_pt_clear_tx_flags(struct intel_pt_decoder *decoder) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci decoder->tx_flags = 0; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic inline void intel_pt_update_in_tx(struct intel_pt_decoder *decoder) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci decoder->tx_flags = decoder->packet.payload & INTEL_PT_IN_TX; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int intel_pt_bad_packet(struct intel_pt_decoder *decoder) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci intel_pt_clear_tx_flags(decoder); 5078c2ecf20Sopenharmony_ci decoder->have_tma = false; 5088c2ecf20Sopenharmony_ci decoder->pkt_len = 1; 5098c2ecf20Sopenharmony_ci decoder->pkt_step = 1; 5108c2ecf20Sopenharmony_ci intel_pt_decoder_log_packet(decoder); 5118c2ecf20Sopenharmony_ci if (decoder->pkt_state != INTEL_PT_STATE_NO_PSB) { 5128c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Bad packet\n"); 5138c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR1; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci return -EBADMSG; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic inline void intel_pt_update_sample_time(struct intel_pt_decoder *decoder) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci decoder->sample_timestamp = decoder->timestamp; 5218c2ecf20Sopenharmony_ci decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void intel_pt_reposition(struct intel_pt_decoder *decoder) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci decoder->ip = 0; 5278c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_NO_PSB; 5288c2ecf20Sopenharmony_ci decoder->timestamp = 0; 5298c2ecf20Sopenharmony_ci decoder->have_tma = false; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int intel_pt_get_data(struct intel_pt_decoder *decoder, bool reposition) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct intel_pt_buffer buffer = { .buf = 0, }; 5358c2ecf20Sopenharmony_ci int ret; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci decoder->pkt_step = 0; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci intel_pt_log("Getting more data\n"); 5408c2ecf20Sopenharmony_ci ret = decoder->get_trace(&buffer, decoder->data); 5418c2ecf20Sopenharmony_ci if (ret) 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci decoder->buf = buffer.buf; 5448c2ecf20Sopenharmony_ci decoder->len = buffer.len; 5458c2ecf20Sopenharmony_ci if (!decoder->len) { 5468c2ecf20Sopenharmony_ci intel_pt_log("No more data\n"); 5478c2ecf20Sopenharmony_ci return -ENODATA; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci decoder->buf_timestamp = buffer.ref_timestamp; 5508c2ecf20Sopenharmony_ci if (!buffer.consecutive || reposition) { 5518c2ecf20Sopenharmony_ci intel_pt_reposition(decoder); 5528c2ecf20Sopenharmony_ci decoder->ref_timestamp = buffer.ref_timestamp; 5538c2ecf20Sopenharmony_ci decoder->state.trace_nr = buffer.trace_nr; 5548c2ecf20Sopenharmony_ci intel_pt_log("Reference timestamp 0x%" PRIx64 "\n", 5558c2ecf20Sopenharmony_ci decoder->ref_timestamp); 5568c2ecf20Sopenharmony_ci return -ENOLINK; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int intel_pt_get_next_data(struct intel_pt_decoder *decoder, 5638c2ecf20Sopenharmony_ci bool reposition) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci if (!decoder->next_buf) 5668c2ecf20Sopenharmony_ci return intel_pt_get_data(decoder, reposition); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci decoder->buf = decoder->next_buf; 5698c2ecf20Sopenharmony_ci decoder->len = decoder->next_len; 5708c2ecf20Sopenharmony_ci decoder->next_buf = 0; 5718c2ecf20Sopenharmony_ci decoder->next_len = 0; 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int intel_pt_get_split_packet(struct intel_pt_decoder *decoder) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci unsigned char *buf = decoder->temp_buf; 5788c2ecf20Sopenharmony_ci size_t old_len, len, n; 5798c2ecf20Sopenharmony_ci int ret; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci old_len = decoder->len; 5828c2ecf20Sopenharmony_ci len = decoder->len; 5838c2ecf20Sopenharmony_ci memcpy(buf, decoder->buf, len); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ret = intel_pt_get_data(decoder, false); 5868c2ecf20Sopenharmony_ci if (ret) { 5878c2ecf20Sopenharmony_ci decoder->pos += old_len; 5888c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci n = INTEL_PT_PKT_MAX_SZ - len; 5928c2ecf20Sopenharmony_ci if (n > decoder->len) 5938c2ecf20Sopenharmony_ci n = decoder->len; 5948c2ecf20Sopenharmony_ci memcpy(buf + len, decoder->buf, n); 5958c2ecf20Sopenharmony_ci len += n; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci decoder->prev_pkt_ctx = decoder->pkt_ctx; 5988c2ecf20Sopenharmony_ci ret = intel_pt_get_packet(buf, len, &decoder->packet, &decoder->pkt_ctx); 5998c2ecf20Sopenharmony_ci if (ret < (int)old_len) { 6008c2ecf20Sopenharmony_ci decoder->next_buf = decoder->buf; 6018c2ecf20Sopenharmony_ci decoder->next_len = decoder->len; 6028c2ecf20Sopenharmony_ci decoder->buf = buf; 6038c2ecf20Sopenharmony_ci decoder->len = old_len; 6048c2ecf20Sopenharmony_ci return intel_pt_bad_packet(decoder); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci decoder->next_buf = decoder->buf + (ret - old_len); 6088c2ecf20Sopenharmony_ci decoder->next_len = decoder->len - (ret - old_len); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci decoder->buf = buf; 6118c2ecf20Sopenharmony_ci decoder->len = ret; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci return ret; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistruct intel_pt_pkt_info { 6178c2ecf20Sopenharmony_ci struct intel_pt_decoder *decoder; 6188c2ecf20Sopenharmony_ci struct intel_pt_pkt packet; 6198c2ecf20Sopenharmony_ci uint64_t pos; 6208c2ecf20Sopenharmony_ci int pkt_len; 6218c2ecf20Sopenharmony_ci int last_packet_type; 6228c2ecf20Sopenharmony_ci void *data; 6238c2ecf20Sopenharmony_ci}; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_citypedef int (*intel_pt_pkt_cb_t)(struct intel_pt_pkt_info *pkt_info); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/* Lookahead packets in current buffer */ 6288c2ecf20Sopenharmony_cistatic int intel_pt_pkt_lookahead(struct intel_pt_decoder *decoder, 6298c2ecf20Sopenharmony_ci intel_pt_pkt_cb_t cb, void *data) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct intel_pt_pkt_info pkt_info; 6328c2ecf20Sopenharmony_ci const unsigned char *buf = decoder->buf; 6338c2ecf20Sopenharmony_ci enum intel_pt_pkt_ctx pkt_ctx = decoder->pkt_ctx; 6348c2ecf20Sopenharmony_ci size_t len = decoder->len; 6358c2ecf20Sopenharmony_ci int ret; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci pkt_info.decoder = decoder; 6388c2ecf20Sopenharmony_ci pkt_info.pos = decoder->pos; 6398c2ecf20Sopenharmony_ci pkt_info.pkt_len = decoder->pkt_step; 6408c2ecf20Sopenharmony_ci pkt_info.last_packet_type = decoder->last_packet_type; 6418c2ecf20Sopenharmony_ci pkt_info.data = data; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci while (1) { 6448c2ecf20Sopenharmony_ci do { 6458c2ecf20Sopenharmony_ci pkt_info.pos += pkt_info.pkt_len; 6468c2ecf20Sopenharmony_ci buf += pkt_info.pkt_len; 6478c2ecf20Sopenharmony_ci len -= pkt_info.pkt_len; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (!len) 6508c2ecf20Sopenharmony_ci return INTEL_PT_NEED_MORE_BYTES; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ret = intel_pt_get_packet(buf, len, &pkt_info.packet, 6538c2ecf20Sopenharmony_ci &pkt_ctx); 6548c2ecf20Sopenharmony_ci if (!ret) 6558c2ecf20Sopenharmony_ci return INTEL_PT_NEED_MORE_BYTES; 6568c2ecf20Sopenharmony_ci if (ret < 0) 6578c2ecf20Sopenharmony_ci return ret; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci pkt_info.pkt_len = ret; 6608c2ecf20Sopenharmony_ci } while (pkt_info.packet.type == INTEL_PT_PAD); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ret = cb(&pkt_info); 6638c2ecf20Sopenharmony_ci if (ret) 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci pkt_info.last_packet_type = pkt_info.packet.type; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistruct intel_pt_calc_cyc_to_tsc_info { 6718c2ecf20Sopenharmony_ci uint64_t cycle_cnt; 6728c2ecf20Sopenharmony_ci unsigned int cbr; 6738c2ecf20Sopenharmony_ci uint32_t last_mtc; 6748c2ecf20Sopenharmony_ci uint64_t ctc_timestamp; 6758c2ecf20Sopenharmony_ci uint64_t ctc_delta; 6768c2ecf20Sopenharmony_ci uint64_t tsc_timestamp; 6778c2ecf20Sopenharmony_ci uint64_t timestamp; 6788c2ecf20Sopenharmony_ci bool have_tma; 6798c2ecf20Sopenharmony_ci bool fixup_last_mtc; 6808c2ecf20Sopenharmony_ci bool from_mtc; 6818c2ecf20Sopenharmony_ci double cbr_cyc_to_tsc; 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/* 6858c2ecf20Sopenharmony_ci * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower 6868c2ecf20Sopenharmony_ci * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC 6878c2ecf20Sopenharmony_ci * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA 6888c2ecf20Sopenharmony_ci * packet by copying the missing bits from the current MTC assuming the least 6898c2ecf20Sopenharmony_ci * difference between the two, and that the current MTC comes after last_mtc. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_cistatic void intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift, 6928c2ecf20Sopenharmony_ci uint32_t *last_mtc) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci uint32_t first_missing_bit = 1U << (16 - mtc_shift); 6958c2ecf20Sopenharmony_ci uint32_t mask = ~(first_missing_bit - 1); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci *last_mtc |= mtc & mask; 6988c2ecf20Sopenharmony_ci if (*last_mtc >= mtc) { 6998c2ecf20Sopenharmony_ci *last_mtc -= first_missing_bit; 7008c2ecf20Sopenharmony_ci *last_mtc &= 0xff; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct intel_pt_decoder *decoder = pkt_info->decoder; 7078c2ecf20Sopenharmony_ci struct intel_pt_calc_cyc_to_tsc_info *data = pkt_info->data; 7088c2ecf20Sopenharmony_ci uint64_t timestamp; 7098c2ecf20Sopenharmony_ci double cyc_to_tsc; 7108c2ecf20Sopenharmony_ci unsigned int cbr; 7118c2ecf20Sopenharmony_ci uint32_t mtc, mtc_delta, ctc, fc, ctc_rem; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci switch (pkt_info->packet.type) { 7148c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 7158c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 7168c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 7178c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 7188c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 7198c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 7208c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 7218c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 7228c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 7238c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 7248c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 7258c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 7268c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 7278c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 7288c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 7298c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 7308c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 7318c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 7328c2ecf20Sopenharmony_ci return 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 7358c2ecf20Sopenharmony_ci if (!data->have_tma) 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci mtc = pkt_info->packet.payload; 7398c2ecf20Sopenharmony_ci if (decoder->mtc_shift > 8 && data->fixup_last_mtc) { 7408c2ecf20Sopenharmony_ci data->fixup_last_mtc = false; 7418c2ecf20Sopenharmony_ci intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift, 7428c2ecf20Sopenharmony_ci &data->last_mtc); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci if (mtc > data->last_mtc) 7458c2ecf20Sopenharmony_ci mtc_delta = mtc - data->last_mtc; 7468c2ecf20Sopenharmony_ci else 7478c2ecf20Sopenharmony_ci mtc_delta = mtc + 256 - data->last_mtc; 7488c2ecf20Sopenharmony_ci data->ctc_delta += mtc_delta << decoder->mtc_shift; 7498c2ecf20Sopenharmony_ci data->last_mtc = mtc; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (decoder->tsc_ctc_mult) { 7528c2ecf20Sopenharmony_ci timestamp = data->ctc_timestamp + 7538c2ecf20Sopenharmony_ci data->ctc_delta * decoder->tsc_ctc_mult; 7548c2ecf20Sopenharmony_ci } else { 7558c2ecf20Sopenharmony_ci timestamp = data->ctc_timestamp + 7568c2ecf20Sopenharmony_ci multdiv(data->ctc_delta, 7578c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_n, 7588c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (timestamp < data->timestamp) 7628c2ecf20Sopenharmony_ci return 1; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (pkt_info->last_packet_type != INTEL_PT_CYC) { 7658c2ecf20Sopenharmony_ci data->timestamp = timestamp; 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 7728c2ecf20Sopenharmony_ci /* 7738c2ecf20Sopenharmony_ci * For now, do not support using TSC packets - refer 7748c2ecf20Sopenharmony_ci * intel_pt_calc_cyc_to_tsc(). 7758c2ecf20Sopenharmony_ci */ 7768c2ecf20Sopenharmony_ci if (data->from_mtc) 7778c2ecf20Sopenharmony_ci return 1; 7788c2ecf20Sopenharmony_ci timestamp = pkt_info->packet.payload | 7798c2ecf20Sopenharmony_ci (data->timestamp & (0xffULL << 56)); 7808c2ecf20Sopenharmony_ci if (data->from_mtc && timestamp < data->timestamp && 7818c2ecf20Sopenharmony_ci data->timestamp - timestamp < decoder->tsc_slip) 7828c2ecf20Sopenharmony_ci return 1; 7838c2ecf20Sopenharmony_ci if (timestamp < data->timestamp) 7848c2ecf20Sopenharmony_ci timestamp += (1ULL << 56); 7858c2ecf20Sopenharmony_ci if (pkt_info->last_packet_type != INTEL_PT_CYC) { 7868c2ecf20Sopenharmony_ci if (data->from_mtc) 7878c2ecf20Sopenharmony_ci return 1; 7888c2ecf20Sopenharmony_ci data->tsc_timestamp = timestamp; 7898c2ecf20Sopenharmony_ci data->timestamp = timestamp; 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 7958c2ecf20Sopenharmony_ci if (data->from_mtc) 7968c2ecf20Sopenharmony_ci return 1; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (!decoder->tsc_ctc_ratio_d) 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ctc = pkt_info->packet.payload; 8028c2ecf20Sopenharmony_ci fc = pkt_info->packet.count; 8038c2ecf20Sopenharmony_ci ctc_rem = ctc & decoder->ctc_rem_mask; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci data->last_mtc = (ctc >> decoder->mtc_shift) & 0xff; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci data->ctc_timestamp = data->tsc_timestamp - fc; 8088c2ecf20Sopenharmony_ci if (decoder->tsc_ctc_mult) { 8098c2ecf20Sopenharmony_ci data->ctc_timestamp -= ctc_rem * decoder->tsc_ctc_mult; 8108c2ecf20Sopenharmony_ci } else { 8118c2ecf20Sopenharmony_ci data->ctc_timestamp -= 8128c2ecf20Sopenharmony_ci multdiv(ctc_rem, decoder->tsc_ctc_ratio_n, 8138c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci data->ctc_delta = 0; 8178c2ecf20Sopenharmony_ci data->have_tma = true; 8188c2ecf20Sopenharmony_ci data->fixup_last_mtc = true; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return 0; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 8238c2ecf20Sopenharmony_ci data->cycle_cnt += pkt_info->packet.payload; 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 8278c2ecf20Sopenharmony_ci cbr = pkt_info->packet.payload; 8288c2ecf20Sopenharmony_ci if (data->cbr && data->cbr != cbr) 8298c2ecf20Sopenharmony_ci return 1; 8308c2ecf20Sopenharmony_ci data->cbr = cbr; 8318c2ecf20Sopenharmony_ci data->cbr_cyc_to_tsc = decoder->max_non_turbo_ratio_fp / cbr; 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 8358c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 8368c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 8378c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 8388c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 8398c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 8408c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 8418c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 8428c2ecf20Sopenharmony_ci case INTEL_PT_BAD: /* Does not happen */ 8438c2ecf20Sopenharmony_ci default: 8448c2ecf20Sopenharmony_ci return 1; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (!data->cbr && decoder->cbr) { 8488c2ecf20Sopenharmony_ci data->cbr = decoder->cbr; 8498c2ecf20Sopenharmony_ci data->cbr_cyc_to_tsc = decoder->cbr_cyc_to_tsc; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (!data->cycle_cnt) 8538c2ecf20Sopenharmony_ci return 1; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci cyc_to_tsc = (double)(timestamp - decoder->timestamp) / data->cycle_cnt; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (data->cbr && cyc_to_tsc > data->cbr_cyc_to_tsc && 8588c2ecf20Sopenharmony_ci cyc_to_tsc / data->cbr_cyc_to_tsc > 1.25) { 8598c2ecf20Sopenharmony_ci intel_pt_log("Timestamp: calculated %g TSC ticks per cycle too big (c.f. CBR-based value %g), pos " x64_fmt "\n", 8608c2ecf20Sopenharmony_ci cyc_to_tsc, data->cbr_cyc_to_tsc, pkt_info->pos); 8618c2ecf20Sopenharmony_ci return 1; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci decoder->calc_cyc_to_tsc = cyc_to_tsc; 8658c2ecf20Sopenharmony_ci decoder->have_calc_cyc_to_tsc = true; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (data->cbr) { 8688c2ecf20Sopenharmony_ci intel_pt_log("Timestamp: calculated %g TSC ticks per cycle c.f. CBR-based value %g, pos " x64_fmt "\n", 8698c2ecf20Sopenharmony_ci cyc_to_tsc, data->cbr_cyc_to_tsc, pkt_info->pos); 8708c2ecf20Sopenharmony_ci } else { 8718c2ecf20Sopenharmony_ci intel_pt_log("Timestamp: calculated %g TSC ticks per cycle c.f. unknown CBR-based value, pos " x64_fmt "\n", 8728c2ecf20Sopenharmony_ci cyc_to_tsc, pkt_info->pos); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return 1; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder, 8798c2ecf20Sopenharmony_ci bool from_mtc) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct intel_pt_calc_cyc_to_tsc_info data = { 8828c2ecf20Sopenharmony_ci .cycle_cnt = 0, 8838c2ecf20Sopenharmony_ci .cbr = 0, 8848c2ecf20Sopenharmony_ci .last_mtc = decoder->last_mtc, 8858c2ecf20Sopenharmony_ci .ctc_timestamp = decoder->ctc_timestamp, 8868c2ecf20Sopenharmony_ci .ctc_delta = decoder->ctc_delta, 8878c2ecf20Sopenharmony_ci .tsc_timestamp = decoder->tsc_timestamp, 8888c2ecf20Sopenharmony_ci .timestamp = decoder->timestamp, 8898c2ecf20Sopenharmony_ci .have_tma = decoder->have_tma, 8908c2ecf20Sopenharmony_ci .fixup_last_mtc = decoder->fixup_last_mtc, 8918c2ecf20Sopenharmony_ci .from_mtc = from_mtc, 8928c2ecf20Sopenharmony_ci .cbr_cyc_to_tsc = 0, 8938c2ecf20Sopenharmony_ci }; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* 8968c2ecf20Sopenharmony_ci * For now, do not support using TSC packets for at least the reasons: 8978c2ecf20Sopenharmony_ci * 1) timing might have stopped 8988c2ecf20Sopenharmony_ci * 2) TSC packets within PSB+ can slip against CYC packets 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci if (!from_mtc) 9018c2ecf20Sopenharmony_ci return; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int intel_pt_get_next_packet(struct intel_pt_decoder *decoder) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci int ret; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci decoder->last_packet_type = decoder->packet.type; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci do { 9138c2ecf20Sopenharmony_ci decoder->pos += decoder->pkt_step; 9148c2ecf20Sopenharmony_ci decoder->buf += decoder->pkt_step; 9158c2ecf20Sopenharmony_ci decoder->len -= decoder->pkt_step; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (!decoder->len) { 9188c2ecf20Sopenharmony_ci ret = intel_pt_get_next_data(decoder, false); 9198c2ecf20Sopenharmony_ci if (ret) 9208c2ecf20Sopenharmony_ci return ret; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci decoder->prev_pkt_ctx = decoder->pkt_ctx; 9248c2ecf20Sopenharmony_ci ret = intel_pt_get_packet(decoder->buf, decoder->len, 9258c2ecf20Sopenharmony_ci &decoder->packet, &decoder->pkt_ctx); 9268c2ecf20Sopenharmony_ci if (ret == INTEL_PT_NEED_MORE_BYTES && BITS_PER_LONG == 32 && 9278c2ecf20Sopenharmony_ci decoder->len < INTEL_PT_PKT_MAX_SZ && !decoder->next_buf) { 9288c2ecf20Sopenharmony_ci ret = intel_pt_get_split_packet(decoder); 9298c2ecf20Sopenharmony_ci if (ret < 0) 9308c2ecf20Sopenharmony_ci return ret; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci if (ret <= 0) 9338c2ecf20Sopenharmony_ci return intel_pt_bad_packet(decoder); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci decoder->pkt_len = ret; 9368c2ecf20Sopenharmony_ci decoder->pkt_step = ret; 9378c2ecf20Sopenharmony_ci intel_pt_decoder_log_packet(decoder); 9388c2ecf20Sopenharmony_ci } while (decoder->packet.type == INTEL_PT_PAD); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic uint64_t intel_pt_next_period(struct intel_pt_decoder *decoder) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci uint64_t timestamp, masked_timestamp; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; 9488c2ecf20Sopenharmony_ci masked_timestamp = timestamp & decoder->period_mask; 9498c2ecf20Sopenharmony_ci if (decoder->continuous_period) { 9508c2ecf20Sopenharmony_ci if (masked_timestamp > decoder->last_masked_timestamp) 9518c2ecf20Sopenharmony_ci return 1; 9528c2ecf20Sopenharmony_ci } else { 9538c2ecf20Sopenharmony_ci timestamp += 1; 9548c2ecf20Sopenharmony_ci masked_timestamp = timestamp & decoder->period_mask; 9558c2ecf20Sopenharmony_ci if (masked_timestamp > decoder->last_masked_timestamp) { 9568c2ecf20Sopenharmony_ci decoder->last_masked_timestamp = masked_timestamp; 9578c2ecf20Sopenharmony_ci decoder->continuous_period = true; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (masked_timestamp < decoder->last_masked_timestamp) 9628c2ecf20Sopenharmony_ci return decoder->period_ticks; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return decoder->period_ticks - (timestamp - masked_timestamp); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic uint64_t intel_pt_next_sample(struct intel_pt_decoder *decoder) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci switch (decoder->period_type) { 9708c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_INSTRUCTIONS: 9718c2ecf20Sopenharmony_ci return decoder->period - decoder->period_insn_cnt; 9728c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_TICKS: 9738c2ecf20Sopenharmony_ci return intel_pt_next_period(decoder); 9748c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_NONE: 9758c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_MTC: 9768c2ecf20Sopenharmony_ci default: 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic void intel_pt_sample_insn(struct intel_pt_decoder *decoder) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci uint64_t timestamp, masked_timestamp; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci switch (decoder->period_type) { 9868c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_INSTRUCTIONS: 9878c2ecf20Sopenharmony_ci decoder->period_insn_cnt = 0; 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_TICKS: 9908c2ecf20Sopenharmony_ci timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; 9918c2ecf20Sopenharmony_ci masked_timestamp = timestamp & decoder->period_mask; 9928c2ecf20Sopenharmony_ci if (masked_timestamp > decoder->last_masked_timestamp) 9938c2ecf20Sopenharmony_ci decoder->last_masked_timestamp = masked_timestamp; 9948c2ecf20Sopenharmony_ci else 9958c2ecf20Sopenharmony_ci decoder->last_masked_timestamp += decoder->period_ticks; 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_NONE: 9988c2ecf20Sopenharmony_ci case INTEL_PT_PERIOD_MTC: 9998c2ecf20Sopenharmony_ci default: 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_INSTRUCTION; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int intel_pt_walk_insn(struct intel_pt_decoder *decoder, 10078c2ecf20Sopenharmony_ci struct intel_pt_insn *intel_pt_insn, uint64_t ip) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci uint64_t max_insn_cnt, insn_cnt = 0; 10108c2ecf20Sopenharmony_ci int err; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (!decoder->mtc_insn) 10138c2ecf20Sopenharmony_ci decoder->mtc_insn = true; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci max_insn_cnt = intel_pt_next_sample(decoder); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci err = decoder->walk_insn(intel_pt_insn, &insn_cnt, &decoder->ip, ip, 10188c2ecf20Sopenharmony_ci max_insn_cnt, decoder->data); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci decoder->tot_insn_cnt += insn_cnt; 10218c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt += insn_cnt; 10228c2ecf20Sopenharmony_ci decoder->sample_insn_cnt += insn_cnt; 10238c2ecf20Sopenharmony_ci decoder->period_insn_cnt += insn_cnt; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (err) { 10268c2ecf20Sopenharmony_ci decoder->no_progress = 0; 10278c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR2; 10288c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Failed to get instruction", 10298c2ecf20Sopenharmony_ci decoder->ip); 10308c2ecf20Sopenharmony_ci if (err == -ENOENT) 10318c2ecf20Sopenharmony_ci return -ENOLINK; 10328c2ecf20Sopenharmony_ci return -EILSEQ; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (ip && decoder->ip == ip) { 10368c2ecf20Sopenharmony_ci err = -EAGAIN; 10378c2ecf20Sopenharmony_ci goto out; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (max_insn_cnt && insn_cnt >= max_insn_cnt) 10418c2ecf20Sopenharmony_ci intel_pt_sample_insn(decoder); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (intel_pt_insn->branch == INTEL_PT_BR_NO_BRANCH) { 10448c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 10458c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 10468c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 10478c2ecf20Sopenharmony_ci decoder->ip += intel_pt_insn->length; 10488c2ecf20Sopenharmony_ci err = INTEL_PT_RETURN; 10498c2ecf20Sopenharmony_ci goto out; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (intel_pt_insn->op == INTEL_PT_OP_CALL) { 10538c2ecf20Sopenharmony_ci /* Zero-length calls are excluded */ 10548c2ecf20Sopenharmony_ci if (intel_pt_insn->branch != INTEL_PT_BR_UNCONDITIONAL || 10558c2ecf20Sopenharmony_ci intel_pt_insn->rel) { 10568c2ecf20Sopenharmony_ci err = intel_pt_push(&decoder->stack, decoder->ip + 10578c2ecf20Sopenharmony_ci intel_pt_insn->length); 10588c2ecf20Sopenharmony_ci if (err) 10598c2ecf20Sopenharmony_ci goto out; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } else if (intel_pt_insn->op == INTEL_PT_OP_RET) { 10628c2ecf20Sopenharmony_ci decoder->ret_addr = intel_pt_pop(&decoder->stack); 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (intel_pt_insn->branch == INTEL_PT_BR_UNCONDITIONAL) { 10668c2ecf20Sopenharmony_ci int cnt = decoder->no_progress++; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 10698c2ecf20Sopenharmony_ci decoder->ip += intel_pt_insn->length + 10708c2ecf20Sopenharmony_ci intel_pt_insn->rel; 10718c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 10728c2ecf20Sopenharmony_ci err = INTEL_PT_RETURN; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* 10758c2ecf20Sopenharmony_ci * Check for being stuck in a loop. This can happen if a 10768c2ecf20Sopenharmony_ci * decoder error results in the decoder erroneously setting the 10778c2ecf20Sopenharmony_ci * ip to an address that is itself in an infinite loop that 10788c2ecf20Sopenharmony_ci * consumes no packets. When that happens, there must be an 10798c2ecf20Sopenharmony_ci * unconditional branch. 10808c2ecf20Sopenharmony_ci */ 10818c2ecf20Sopenharmony_ci if (cnt) { 10828c2ecf20Sopenharmony_ci if (cnt == 1) { 10838c2ecf20Sopenharmony_ci decoder->stuck_ip = decoder->state.to_ip; 10848c2ecf20Sopenharmony_ci decoder->stuck_ip_prd = 1; 10858c2ecf20Sopenharmony_ci decoder->stuck_ip_cnt = 1; 10868c2ecf20Sopenharmony_ci } else if (cnt > INTEL_PT_MAX_LOOPS || 10878c2ecf20Sopenharmony_ci decoder->state.to_ip == decoder->stuck_ip) { 10888c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Never-ending loop", 10898c2ecf20Sopenharmony_ci decoder->state.to_ip); 10908c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; 10918c2ecf20Sopenharmony_ci err = -ELOOP; 10928c2ecf20Sopenharmony_ci goto out; 10938c2ecf20Sopenharmony_ci } else if (!--decoder->stuck_ip_cnt) { 10948c2ecf20Sopenharmony_ci decoder->stuck_ip_prd += 1; 10958c2ecf20Sopenharmony_ci decoder->stuck_ip_cnt = decoder->stuck_ip_prd; 10968c2ecf20Sopenharmony_ci decoder->stuck_ip = decoder->state.to_ip; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci goto out_no_progress; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ciout: 11028c2ecf20Sopenharmony_ci decoder->no_progress = 0; 11038c2ecf20Sopenharmony_ciout_no_progress: 11048c2ecf20Sopenharmony_ci decoder->state.insn_op = intel_pt_insn->op; 11058c2ecf20Sopenharmony_ci decoder->state.insn_len = intel_pt_insn->length; 11068c2ecf20Sopenharmony_ci memcpy(decoder->state.insn, intel_pt_insn->buf, 11078c2ecf20Sopenharmony_ci INTEL_PT_INSN_BUF_SZ); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (decoder->tx_flags & INTEL_PT_IN_TX) 11108c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_IN_TX; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return err; 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic bool intel_pt_fup_event(struct intel_pt_decoder *decoder) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci enum intel_pt_sample_type type = decoder->state.type; 11188c2ecf20Sopenharmony_ci bool ret = false; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci decoder->state.type &= ~INTEL_PT_BRANCH; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (decoder->set_fup_tx_flags) { 11238c2ecf20Sopenharmony_ci decoder->set_fup_tx_flags = false; 11248c2ecf20Sopenharmony_ci decoder->tx_flags = decoder->fup_tx_flags; 11258c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRANSACTION; 11268c2ecf20Sopenharmony_ci if (decoder->fup_tx_flags & INTEL_PT_ABORT_TX) 11278c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_BRANCH; 11288c2ecf20Sopenharmony_ci decoder->state.flags = decoder->fup_tx_flags; 11298c2ecf20Sopenharmony_ci ret = true; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if (decoder->set_fup_ptw) { 11328c2ecf20Sopenharmony_ci decoder->set_fup_ptw = false; 11338c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_PTW; 11348c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_FUP_IP; 11358c2ecf20Sopenharmony_ci decoder->state.ptw_payload = decoder->fup_ptw_payload; 11368c2ecf20Sopenharmony_ci ret = true; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci if (decoder->set_fup_mwait) { 11398c2ecf20Sopenharmony_ci decoder->set_fup_mwait = false; 11408c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_MWAIT_OP; 11418c2ecf20Sopenharmony_ci decoder->state.mwait_payload = decoder->fup_mwait_payload; 11428c2ecf20Sopenharmony_ci ret = true; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci if (decoder->set_fup_pwre) { 11458c2ecf20Sopenharmony_ci decoder->set_fup_pwre = false; 11468c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_PWR_ENTRY; 11478c2ecf20Sopenharmony_ci decoder->state.pwre_payload = decoder->fup_pwre_payload; 11488c2ecf20Sopenharmony_ci ret = true; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci if (decoder->set_fup_exstop) { 11518c2ecf20Sopenharmony_ci decoder->set_fup_exstop = false; 11528c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_EX_STOP; 11538c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_FUP_IP; 11548c2ecf20Sopenharmony_ci ret = true; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci if (decoder->set_fup_bep) { 11578c2ecf20Sopenharmony_ci decoder->set_fup_bep = false; 11588c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_BLK_ITEMS; 11598c2ecf20Sopenharmony_ci ret = true; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci if (decoder->overflow) { 11628c2ecf20Sopenharmony_ci decoder->overflow = false; 11638c2ecf20Sopenharmony_ci if (!ret && !decoder->pge) { 11648c2ecf20Sopenharmony_ci if (decoder->hop) { 11658c2ecf20Sopenharmony_ci decoder->state.type = 0; 11668c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci decoder->pge = true; 11698c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_BRANCH | INTEL_PT_TRACE_BEGIN; 11708c2ecf20Sopenharmony_ci decoder->state.from_ip = 0; 11718c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 11728c2ecf20Sopenharmony_ci return true; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci if (ret) { 11768c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 11778c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 11788c2ecf20Sopenharmony_ci } else { 11798c2ecf20Sopenharmony_ci decoder->state.type = type; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci return ret; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder, 11858c2ecf20Sopenharmony_ci struct intel_pt_insn *intel_pt_insn, 11868c2ecf20Sopenharmony_ci uint64_t ip, int err) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err && 11898c2ecf20Sopenharmony_ci intel_pt_insn->branch == INTEL_PT_BR_INDIRECT && 11908c2ecf20Sopenharmony_ci ip == decoder->ip + intel_pt_insn->length; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic int intel_pt_walk_fup(struct intel_pt_decoder *decoder) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct intel_pt_insn intel_pt_insn; 11968c2ecf20Sopenharmony_ci uint64_t ip; 11978c2ecf20Sopenharmony_ci int err; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci ip = decoder->last_ip; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci while (1) { 12028c2ecf20Sopenharmony_ci err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); 12038c2ecf20Sopenharmony_ci if (err == INTEL_PT_RETURN) 12048c2ecf20Sopenharmony_ci return 0; 12058c2ecf20Sopenharmony_ci if (err == -EAGAIN || 12068c2ecf20Sopenharmony_ci intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) { 12078c2ecf20Sopenharmony_ci bool no_tip = decoder->pkt_state != INTEL_PT_STATE_FUP; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 12108c2ecf20Sopenharmony_ci if (intel_pt_fup_event(decoder) && no_tip) 12118c2ecf20Sopenharmony_ci return 0; 12128c2ecf20Sopenharmony_ci return -EAGAIN; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci decoder->set_fup_tx_flags = false; 12158c2ecf20Sopenharmony_ci if (err) 12168c2ecf20Sopenharmony_ci return err; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_INDIRECT) { 12198c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Unexpected indirect branch", 12208c2ecf20Sopenharmony_ci decoder->ip); 12218c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; 12228c2ecf20Sopenharmony_ci return -ENOENT; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { 12268c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Unexpected conditional branch", 12278c2ecf20Sopenharmony_ci decoder->ip); 12288c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; 12298c2ecf20Sopenharmony_ci return -ENOENT; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci intel_pt_bug(decoder); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int intel_pt_walk_tip(struct intel_pt_decoder *decoder) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct intel_pt_insn intel_pt_insn; 12398c2ecf20Sopenharmony_ci int err; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci err = intel_pt_walk_insn(decoder, &intel_pt_insn, 0); 12428c2ecf20Sopenharmony_ci if (err == INTEL_PT_RETURN && 12438c2ecf20Sopenharmony_ci decoder->pgd_ip && 12448c2ecf20Sopenharmony_ci decoder->pkt_state == INTEL_PT_STATE_TIP_PGD && 12458c2ecf20Sopenharmony_ci (decoder->state.type & INTEL_PT_BRANCH) && 12468c2ecf20Sopenharmony_ci decoder->pgd_ip(decoder->state.to_ip, decoder->data)) { 12478c2ecf20Sopenharmony_ci /* Unconditional branch leaving filter region */ 12488c2ecf20Sopenharmony_ci decoder->no_progress = 0; 12498c2ecf20Sopenharmony_ci decoder->pge = false; 12508c2ecf20Sopenharmony_ci decoder->continuous_period = false; 12518c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 12528c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 12538c2ecf20Sopenharmony_ci return 0; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci if (err == INTEL_PT_RETURN) 12568c2ecf20Sopenharmony_ci return 0; 12578c2ecf20Sopenharmony_ci if (err) 12588c2ecf20Sopenharmony_ci return err; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_INDIRECT) { 12618c2ecf20Sopenharmony_ci if (decoder->pkt_state == INTEL_PT_STATE_TIP_PGD) { 12628c2ecf20Sopenharmony_ci decoder->pge = false; 12638c2ecf20Sopenharmony_ci decoder->continuous_period = false; 12648c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 12658c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 12668c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 12678c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 12688c2ecf20Sopenharmony_ci } else { 12698c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->last_ip; 12708c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 12738c2ecf20Sopenharmony_ci } else { 12748c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 12758c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 12768c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 12778c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 12788c2ecf20Sopenharmony_ci } else { 12798c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->last_ip; 12808c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci return 0; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { 12878c2ecf20Sopenharmony_ci uint64_t to_ip = decoder->ip + intel_pt_insn.length + 12888c2ecf20Sopenharmony_ci intel_pt_insn.rel; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (decoder->pgd_ip && 12918c2ecf20Sopenharmony_ci decoder->pkt_state == INTEL_PT_STATE_TIP_PGD && 12928c2ecf20Sopenharmony_ci decoder->pgd_ip(to_ip, decoder->data)) { 12938c2ecf20Sopenharmony_ci /* Conditional branch leaving filter region */ 12948c2ecf20Sopenharmony_ci decoder->pge = false; 12958c2ecf20Sopenharmony_ci decoder->continuous_period = false; 12968c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 12978c2ecf20Sopenharmony_ci decoder->ip = to_ip; 12988c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 12998c2ecf20Sopenharmony_ci decoder->state.to_ip = to_ip; 13008c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Conditional branch when expecting indirect branch", 13048c2ecf20Sopenharmony_ci decoder->ip); 13058c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; 13068c2ecf20Sopenharmony_ci return -ENOENT; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct intel_pt_insn intel_pt_insn; 13158c2ecf20Sopenharmony_ci int err; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci while (1) { 13188c2ecf20Sopenharmony_ci err = intel_pt_walk_insn(decoder, &intel_pt_insn, 0); 13198c2ecf20Sopenharmony_ci if (err == INTEL_PT_RETURN) 13208c2ecf20Sopenharmony_ci return 0; 13218c2ecf20Sopenharmony_ci if (err) 13228c2ecf20Sopenharmony_ci return err; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (intel_pt_insn.op == INTEL_PT_OP_RET) { 13258c2ecf20Sopenharmony_ci if (!decoder->return_compression) { 13268c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: RET when expecting conditional branch", 13278c2ecf20Sopenharmony_ci decoder->ip); 13288c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 13298c2ecf20Sopenharmony_ci return -ENOENT; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci if (!decoder->ret_addr) { 13328c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Bad RET compression (stack empty)", 13338c2ecf20Sopenharmony_ci decoder->ip); 13348c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 13358c2ecf20Sopenharmony_ci return -ENOENT; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci if (!(decoder->tnt.payload & BIT63)) { 13388c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Bad RET compression (TNT=N)", 13398c2ecf20Sopenharmony_ci decoder->ip); 13408c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 13418c2ecf20Sopenharmony_ci return -ENOENT; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci decoder->tnt.count -= 1; 13448c2ecf20Sopenharmony_ci if (decoder->tnt.count) 13458c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; 13468c2ecf20Sopenharmony_ci else 13478c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 13488c2ecf20Sopenharmony_ci decoder->tnt.payload <<= 1; 13498c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 13508c2ecf20Sopenharmony_ci decoder->ip = decoder->ret_addr; 13518c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 13528c2ecf20Sopenharmony_ci return 0; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_INDIRECT) { 13568c2ecf20Sopenharmony_ci /* Handle deferred TIPs */ 13578c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 13588c2ecf20Sopenharmony_ci if (err) 13598c2ecf20Sopenharmony_ci return err; 13608c2ecf20Sopenharmony_ci if (decoder->packet.type != INTEL_PT_TIP || 13618c2ecf20Sopenharmony_ci decoder->packet.count == 0) { 13628c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Missing deferred TIP for indirect branch", 13638c2ecf20Sopenharmony_ci decoder->ip); 13648c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 13658c2ecf20Sopenharmony_ci decoder->pkt_step = 0; 13668c2ecf20Sopenharmony_ci return -ENOENT; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 13698c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 13708c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->last_ip; 13718c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 13728c2ecf20Sopenharmony_ci return 0; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { 13768c2ecf20Sopenharmony_ci decoder->tnt.count -= 1; 13778c2ecf20Sopenharmony_ci if (decoder->tnt.count) 13788c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; 13798c2ecf20Sopenharmony_ci else 13808c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 13818c2ecf20Sopenharmony_ci if (decoder->tnt.payload & BIT63) { 13828c2ecf20Sopenharmony_ci decoder->tnt.payload <<= 1; 13838c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 13848c2ecf20Sopenharmony_ci decoder->ip += intel_pt_insn.length + 13858c2ecf20Sopenharmony_ci intel_pt_insn.rel; 13868c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 13878c2ecf20Sopenharmony_ci return 0; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci /* Instruction sample for a non-taken branch */ 13908c2ecf20Sopenharmony_ci if (decoder->state.type & INTEL_PT_INSTRUCTION) { 13918c2ecf20Sopenharmony_ci decoder->tnt.payload <<= 1; 13928c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 13938c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 13948c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 13958c2ecf20Sopenharmony_ci decoder->ip += intel_pt_insn.length; 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci decoder->sample_cyc = false; 13998c2ecf20Sopenharmony_ci decoder->ip += intel_pt_insn.length; 14008c2ecf20Sopenharmony_ci if (!decoder->tnt.count) { 14018c2ecf20Sopenharmony_ci intel_pt_update_sample_time(decoder); 14028c2ecf20Sopenharmony_ci return -EAGAIN; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci decoder->tnt.payload <<= 1; 14058c2ecf20Sopenharmony_ci continue; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic int intel_pt_mode_tsx(struct intel_pt_decoder *decoder, bool *no_tip) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci unsigned int fup_tx_flags; 14158c2ecf20Sopenharmony_ci int err; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci fup_tx_flags = decoder->packet.payload & 14188c2ecf20Sopenharmony_ci (INTEL_PT_IN_TX | INTEL_PT_ABORT_TX); 14198c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 14208c2ecf20Sopenharmony_ci if (err) 14218c2ecf20Sopenharmony_ci return err; 14228c2ecf20Sopenharmony_ci if (decoder->packet.type == INTEL_PT_FUP) { 14238c2ecf20Sopenharmony_ci decoder->fup_tx_flags = fup_tx_flags; 14248c2ecf20Sopenharmony_ci decoder->set_fup_tx_flags = true; 14258c2ecf20Sopenharmony_ci if (!(decoder->fup_tx_flags & INTEL_PT_ABORT_TX)) 14268c2ecf20Sopenharmony_ci *no_tip = true; 14278c2ecf20Sopenharmony_ci } else { 14288c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Missing FUP after MODE.TSX", 14298c2ecf20Sopenharmony_ci decoder->pos); 14308c2ecf20Sopenharmony_ci intel_pt_update_in_tx(decoder); 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic uint64_t intel_pt_8b_tsc(uint64_t timestamp, uint64_t ref_timestamp) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci timestamp |= (ref_timestamp & (0xffULL << 56)); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (timestamp < ref_timestamp) { 14408c2ecf20Sopenharmony_ci if (ref_timestamp - timestamp > (1ULL << 55)) 14418c2ecf20Sopenharmony_ci timestamp += (1ULL << 56); 14428c2ecf20Sopenharmony_ci } else { 14438c2ecf20Sopenharmony_ci if (timestamp - ref_timestamp > (1ULL << 55)) 14448c2ecf20Sopenharmony_ci timestamp -= (1ULL << 56); 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci return timestamp; 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic void intel_pt_calc_tsc_timestamp(struct intel_pt_decoder *decoder) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci uint64_t timestamp; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci decoder->have_tma = false; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (decoder->ref_timestamp) { 14578c2ecf20Sopenharmony_ci timestamp = intel_pt_8b_tsc(decoder->packet.payload, 14588c2ecf20Sopenharmony_ci decoder->ref_timestamp); 14598c2ecf20Sopenharmony_ci decoder->tsc_timestamp = timestamp; 14608c2ecf20Sopenharmony_ci decoder->timestamp = timestamp; 14618c2ecf20Sopenharmony_ci decoder->ref_timestamp = 0; 14628c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt = 0; 14638c2ecf20Sopenharmony_ci } else if (decoder->timestamp) { 14648c2ecf20Sopenharmony_ci timestamp = decoder->packet.payload | 14658c2ecf20Sopenharmony_ci (decoder->timestamp & (0xffULL << 56)); 14668c2ecf20Sopenharmony_ci decoder->tsc_timestamp = timestamp; 14678c2ecf20Sopenharmony_ci if (timestamp < decoder->timestamp && 14688c2ecf20Sopenharmony_ci decoder->timestamp - timestamp < decoder->tsc_slip) { 14698c2ecf20Sopenharmony_ci intel_pt_log_to("Suppressing backwards timestamp", 14708c2ecf20Sopenharmony_ci timestamp); 14718c2ecf20Sopenharmony_ci timestamp = decoder->timestamp; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci if (timestamp < decoder->timestamp) { 14748c2ecf20Sopenharmony_ci intel_pt_log_to("Wraparound timestamp", timestamp); 14758c2ecf20Sopenharmony_ci timestamp += (1ULL << 56); 14768c2ecf20Sopenharmony_ci decoder->tsc_timestamp = timestamp; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci decoder->timestamp = timestamp; 14798c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt = 0; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (decoder->last_packet_type == INTEL_PT_CYC) { 14838c2ecf20Sopenharmony_ci decoder->cyc_ref_timestamp = decoder->timestamp; 14848c2ecf20Sopenharmony_ci decoder->cycle_cnt = 0; 14858c2ecf20Sopenharmony_ci decoder->have_calc_cyc_to_tsc = false; 14868c2ecf20Sopenharmony_ci intel_pt_calc_cyc_to_tsc(decoder, false); 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci intel_pt_log_to("Setting timestamp", decoder->timestamp); 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic int intel_pt_overflow(struct intel_pt_decoder *decoder) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Buffer overflow\n"); 14958c2ecf20Sopenharmony_ci intel_pt_clear_tx_flags(decoder); 14968c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt = 0; 14978c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 14988c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 14998c2ecf20Sopenharmony_ci decoder->ip = 0; 15008c2ecf20Sopenharmony_ci decoder->pge = false; 15018c2ecf20Sopenharmony_ci decoder->set_fup_tx_flags = false; 15028c2ecf20Sopenharmony_ci decoder->set_fup_ptw = false; 15038c2ecf20Sopenharmony_ci decoder->set_fup_mwait = false; 15048c2ecf20Sopenharmony_ci decoder->set_fup_pwre = false; 15058c2ecf20Sopenharmony_ci decoder->set_fup_exstop = false; 15068c2ecf20Sopenharmony_ci decoder->set_fup_bep = false; 15078c2ecf20Sopenharmony_ci decoder->overflow = true; 15088c2ecf20Sopenharmony_ci return -EOVERFLOW; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic inline void intel_pt_mtc_cyc_cnt_pge(struct intel_pt_decoder *decoder) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci if (decoder->have_cyc) 15148c2ecf20Sopenharmony_ci return; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci decoder->cyc_cnt_timestamp = decoder->timestamp; 15178c2ecf20Sopenharmony_ci decoder->base_cyc_cnt = decoder->tot_cyc_cnt; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic inline void intel_pt_mtc_cyc_cnt_cbr(struct intel_pt_decoder *decoder) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci decoder->tsc_to_cyc = decoder->cbr / decoder->max_non_turbo_ratio_fp; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (decoder->pge) 15258c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_pge(decoder); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic inline void intel_pt_mtc_cyc_cnt_upd(struct intel_pt_decoder *decoder) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci uint64_t tot_cyc_cnt, tsc_delta; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (decoder->have_cyc) 15338c2ecf20Sopenharmony_ci return; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci decoder->sample_cyc = true; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (!decoder->pge || decoder->timestamp <= decoder->cyc_cnt_timestamp) 15388c2ecf20Sopenharmony_ci return; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci tsc_delta = decoder->timestamp - decoder->cyc_cnt_timestamp; 15418c2ecf20Sopenharmony_ci tot_cyc_cnt = tsc_delta * decoder->tsc_to_cyc + decoder->base_cyc_cnt; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (tot_cyc_cnt > decoder->tot_cyc_cnt) 15448c2ecf20Sopenharmony_ci decoder->tot_cyc_cnt = tot_cyc_cnt; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cistatic void intel_pt_calc_tma(struct intel_pt_decoder *decoder) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci uint32_t ctc = decoder->packet.payload; 15508c2ecf20Sopenharmony_ci uint32_t fc = decoder->packet.count; 15518c2ecf20Sopenharmony_ci uint32_t ctc_rem = ctc & decoder->ctc_rem_mask; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (!decoder->tsc_ctc_ratio_d) 15548c2ecf20Sopenharmony_ci return; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (decoder->pge && !decoder->in_psb) 15578c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_pge(decoder); 15588c2ecf20Sopenharmony_ci else 15598c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_upd(decoder); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci decoder->last_mtc = (ctc >> decoder->mtc_shift) & 0xff; 15628c2ecf20Sopenharmony_ci decoder->ctc_timestamp = decoder->tsc_timestamp - fc; 15638c2ecf20Sopenharmony_ci if (decoder->tsc_ctc_mult) { 15648c2ecf20Sopenharmony_ci decoder->ctc_timestamp -= ctc_rem * decoder->tsc_ctc_mult; 15658c2ecf20Sopenharmony_ci } else { 15668c2ecf20Sopenharmony_ci decoder->ctc_timestamp -= multdiv(ctc_rem, 15678c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_n, 15688c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d); 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci decoder->ctc_delta = 0; 15718c2ecf20Sopenharmony_ci decoder->have_tma = true; 15728c2ecf20Sopenharmony_ci decoder->fixup_last_mtc = true; 15738c2ecf20Sopenharmony_ci intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n", 15748c2ecf20Sopenharmony_ci decoder->ctc_timestamp, decoder->last_mtc, ctc_rem); 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci uint64_t timestamp; 15808c2ecf20Sopenharmony_ci uint32_t mtc, mtc_delta; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (!decoder->have_tma) 15838c2ecf20Sopenharmony_ci return; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci mtc = decoder->packet.payload; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (decoder->mtc_shift > 8 && decoder->fixup_last_mtc) { 15888c2ecf20Sopenharmony_ci decoder->fixup_last_mtc = false; 15898c2ecf20Sopenharmony_ci intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift, 15908c2ecf20Sopenharmony_ci &decoder->last_mtc); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (mtc > decoder->last_mtc) 15948c2ecf20Sopenharmony_ci mtc_delta = mtc - decoder->last_mtc; 15958c2ecf20Sopenharmony_ci else 15968c2ecf20Sopenharmony_ci mtc_delta = mtc + 256 - decoder->last_mtc; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci decoder->ctc_delta += mtc_delta << decoder->mtc_shift; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (decoder->tsc_ctc_mult) { 16018c2ecf20Sopenharmony_ci timestamp = decoder->ctc_timestamp + 16028c2ecf20Sopenharmony_ci decoder->ctc_delta * decoder->tsc_ctc_mult; 16038c2ecf20Sopenharmony_ci } else { 16048c2ecf20Sopenharmony_ci timestamp = decoder->ctc_timestamp + 16058c2ecf20Sopenharmony_ci multdiv(decoder->ctc_delta, 16068c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_n, 16078c2ecf20Sopenharmony_ci decoder->tsc_ctc_ratio_d); 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (timestamp < decoder->timestamp) 16118c2ecf20Sopenharmony_ci intel_pt_log("Suppressing MTC timestamp " x64_fmt " less than current timestamp " x64_fmt "\n", 16128c2ecf20Sopenharmony_ci timestamp, decoder->timestamp); 16138c2ecf20Sopenharmony_ci else 16148c2ecf20Sopenharmony_ci decoder->timestamp = timestamp; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_upd(decoder); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt = 0; 16198c2ecf20Sopenharmony_ci decoder->last_mtc = mtc; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (decoder->last_packet_type == INTEL_PT_CYC) { 16228c2ecf20Sopenharmony_ci decoder->cyc_ref_timestamp = decoder->timestamp; 16238c2ecf20Sopenharmony_ci decoder->cycle_cnt = 0; 16248c2ecf20Sopenharmony_ci decoder->have_calc_cyc_to_tsc = false; 16258c2ecf20Sopenharmony_ci intel_pt_calc_cyc_to_tsc(decoder, true); 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci intel_pt_log_to("Setting timestamp", decoder->timestamp); 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_cistatic void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci unsigned int cbr = decoder->packet.payload & 0xff; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci decoder->cbr_payload = decoder->packet.payload; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (decoder->cbr == cbr) 16388c2ecf20Sopenharmony_ci return; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci decoder->cbr = cbr; 16418c2ecf20Sopenharmony_ci decoder->cbr_cyc_to_tsc = decoder->max_non_turbo_ratio_fp / cbr; 16428c2ecf20Sopenharmony_ci decoder->cyc_ref_timestamp = decoder->timestamp; 16438c2ecf20Sopenharmony_ci decoder->cycle_cnt = 0; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_cbr(decoder); 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci uint64_t timestamp = decoder->cyc_ref_timestamp; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci decoder->have_cyc = true; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci decoder->cycle_cnt += decoder->packet.payload; 16558c2ecf20Sopenharmony_ci if (decoder->pge) 16568c2ecf20Sopenharmony_ci decoder->tot_cyc_cnt += decoder->packet.payload; 16578c2ecf20Sopenharmony_ci decoder->sample_cyc = true; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci if (!decoder->cyc_ref_timestamp) 16608c2ecf20Sopenharmony_ci return; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (decoder->have_calc_cyc_to_tsc) 16638c2ecf20Sopenharmony_ci timestamp += decoder->cycle_cnt * decoder->calc_cyc_to_tsc; 16648c2ecf20Sopenharmony_ci else if (decoder->cbr) 16658c2ecf20Sopenharmony_ci timestamp += decoder->cycle_cnt * decoder->cbr_cyc_to_tsc; 16668c2ecf20Sopenharmony_ci else 16678c2ecf20Sopenharmony_ci return; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (timestamp < decoder->timestamp) 16708c2ecf20Sopenharmony_ci intel_pt_log("Suppressing CYC timestamp " x64_fmt " less than current timestamp " x64_fmt "\n", 16718c2ecf20Sopenharmony_ci timestamp, decoder->timestamp); 16728c2ecf20Sopenharmony_ci else 16738c2ecf20Sopenharmony_ci decoder->timestamp = timestamp; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci decoder->timestamp_insn_cnt = 0; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci intel_pt_log_to("Setting timestamp", decoder->timestamp); 16788c2ecf20Sopenharmony_ci} 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_cistatic void intel_pt_bbp(struct intel_pt_decoder *decoder) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci if (decoder->prev_pkt_ctx == INTEL_PT_NO_CTX) { 16838c2ecf20Sopenharmony_ci memset(decoder->state.items.mask, 0, sizeof(decoder->state.items.mask)); 16848c2ecf20Sopenharmony_ci decoder->state.items.is_32_bit = false; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci decoder->blk_type = decoder->packet.payload; 16878c2ecf20Sopenharmony_ci decoder->blk_type_pos = intel_pt_blk_type_pos(decoder->blk_type); 16888c2ecf20Sopenharmony_ci if (decoder->blk_type == INTEL_PT_GP_REGS) 16898c2ecf20Sopenharmony_ci decoder->state.items.is_32_bit = decoder->packet.count; 16908c2ecf20Sopenharmony_ci if (decoder->blk_type_pos < 0) { 16918c2ecf20Sopenharmony_ci intel_pt_log("WARNING: Unknown block type %u\n", 16928c2ecf20Sopenharmony_ci decoder->blk_type); 16938c2ecf20Sopenharmony_ci } else if (decoder->state.items.mask[decoder->blk_type_pos]) { 16948c2ecf20Sopenharmony_ci intel_pt_log("WARNING: Duplicate block type %u\n", 16958c2ecf20Sopenharmony_ci decoder->blk_type); 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci} 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cistatic void intel_pt_bip(struct intel_pt_decoder *decoder) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci uint32_t id = decoder->packet.count; 17028c2ecf20Sopenharmony_ci uint32_t bit = 1 << id; 17038c2ecf20Sopenharmony_ci int pos = decoder->blk_type_pos; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (pos < 0 || id >= INTEL_PT_BLK_ITEM_ID_CNT) { 17068c2ecf20Sopenharmony_ci intel_pt_log("WARNING: Unknown block item %u type %d\n", 17078c2ecf20Sopenharmony_ci id, decoder->blk_type); 17088c2ecf20Sopenharmony_ci return; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (decoder->state.items.mask[pos] & bit) { 17128c2ecf20Sopenharmony_ci intel_pt_log("WARNING: Duplicate block item %u type %d\n", 17138c2ecf20Sopenharmony_ci id, decoder->blk_type); 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci decoder->state.items.mask[pos] |= bit; 17178c2ecf20Sopenharmony_ci decoder->state.items.val[pos][id] = decoder->packet.payload; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci/* Walk PSB+ packets when already in sync. */ 17218c2ecf20Sopenharmony_cistatic int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci int err; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci decoder->in_psb = true; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci while (1) { 17288c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 17298c2ecf20Sopenharmony_ci if (err) 17308c2ecf20Sopenharmony_ci goto out; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 17338c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 17348c2ecf20Sopenharmony_ci err = 0; 17358c2ecf20Sopenharmony_ci goto out; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 17388c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 17398c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 17408c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 17418c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 17428c2ecf20Sopenharmony_ci case INTEL_PT_BAD: 17438c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 17448c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 17458c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 17468c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 17478c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 17488c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 17498c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 17508c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 17518c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 17528c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 17538c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 17548c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 17558c2ecf20Sopenharmony_ci decoder->have_tma = false; 17568c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Unexpected packet\n"); 17578c2ecf20Sopenharmony_ci err = -EAGAIN; 17588c2ecf20Sopenharmony_ci goto out; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 17618c2ecf20Sopenharmony_ci err = intel_pt_overflow(decoder); 17628c2ecf20Sopenharmony_ci goto out; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 17658c2ecf20Sopenharmony_ci intel_pt_calc_tsc_timestamp(decoder); 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 17698c2ecf20Sopenharmony_ci intel_pt_calc_tma(decoder); 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 17738c2ecf20Sopenharmony_ci intel_pt_calc_cbr(decoder); 17748c2ecf20Sopenharmony_ci break; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 17778c2ecf20Sopenharmony_ci decoder->exec_mode = decoder->packet.payload; 17788c2ecf20Sopenharmony_ci break; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 17818c2ecf20Sopenharmony_ci decoder->cr3 = decoder->packet.payload & (BIT63 - 1); 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 17858c2ecf20Sopenharmony_ci decoder->pge = true; 17868c2ecf20Sopenharmony_ci if (decoder->packet.count) { 17878c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 17888c2ecf20Sopenharmony_ci if (decoder->hop) { 17898c2ecf20Sopenharmony_ci /* Act on FUP at PSBEND */ 17908c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 17918c2ecf20Sopenharmony_ci decoder->hop_psb_fup = true; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 17978c2ecf20Sopenharmony_ci intel_pt_update_in_tx(decoder); 17988c2ecf20Sopenharmony_ci break; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 18018c2ecf20Sopenharmony_ci intel_pt_calc_mtc_timestamp(decoder); 18028c2ecf20Sopenharmony_ci if (decoder->period_type == INTEL_PT_PERIOD_MTC) 18038c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_INSTRUCTION; 18048c2ecf20Sopenharmony_ci break; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 18078c2ecf20Sopenharmony_ci intel_pt_calc_cyc_timestamp(decoder); 18088c2ecf20Sopenharmony_ci break; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 18118c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 18128c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 18138c2ecf20Sopenharmony_ci default: 18148c2ecf20Sopenharmony_ci break; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ciout: 18188c2ecf20Sopenharmony_ci decoder->in_psb = false; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci return err; 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci int err; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (decoder->tx_flags & INTEL_PT_ABORT_TX) { 18288c2ecf20Sopenharmony_ci decoder->tx_flags = 0; 18298c2ecf20Sopenharmony_ci decoder->state.flags &= ~INTEL_PT_IN_TX; 18308c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_ABORT_TX; 18318c2ecf20Sopenharmony_ci } else { 18328c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_ASYNC; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci while (1) { 18368c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 18378c2ecf20Sopenharmony_ci if (err) 18388c2ecf20Sopenharmony_ci return err; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 18418c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 18428c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 18438c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 18448c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 18458c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 18468c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 18478c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 18488c2ecf20Sopenharmony_ci case INTEL_PT_BAD: 18498c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 18508c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 18518c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 18528c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 18538c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 18548c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 18558c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 18568c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 18578c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 18588c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 18598c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 18608c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 18618c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Missing TIP after FUP\n"); 18628c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 18638c2ecf20Sopenharmony_ci decoder->pkt_step = 0; 18648c2ecf20Sopenharmony_ci return -ENOENT; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 18678c2ecf20Sopenharmony_ci intel_pt_calc_cbr(decoder); 18688c2ecf20Sopenharmony_ci break; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 18718c2ecf20Sopenharmony_ci return intel_pt_overflow(decoder); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 18748c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 18758c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 18768c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 18778c2ecf20Sopenharmony_ci } else { 18788c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 18798c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci decoder->pge = false; 18828c2ecf20Sopenharmony_ci decoder->continuous_period = false; 18838c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 18848c2ecf20Sopenharmony_ci return 0; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 18878c2ecf20Sopenharmony_ci decoder->pge = true; 18888c2ecf20Sopenharmony_ci intel_pt_log("Omitting PGE ip " x64_fmt "\n", 18898c2ecf20Sopenharmony_ci decoder->ip); 18908c2ecf20Sopenharmony_ci decoder->state.from_ip = 0; 18918c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 18928c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 18938c2ecf20Sopenharmony_ci } else { 18948c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 18958c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_BEGIN; 18988c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_pge(decoder); 18998c2ecf20Sopenharmony_ci return 0; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 19028c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 19038c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 19048c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 19058c2ecf20Sopenharmony_ci } else { 19068c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 19078c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 19128c2ecf20Sopenharmony_ci decoder->cr3 = decoder->packet.payload & (BIT63 - 1); 19138c2ecf20Sopenharmony_ci break; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 19168c2ecf20Sopenharmony_ci intel_pt_calc_mtc_timestamp(decoder); 19178c2ecf20Sopenharmony_ci if (decoder->period_type == INTEL_PT_PERIOD_MTC) 19188c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_INSTRUCTION; 19198c2ecf20Sopenharmony_ci break; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 19228c2ecf20Sopenharmony_ci intel_pt_calc_cyc_timestamp(decoder); 19238c2ecf20Sopenharmony_ci break; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 19268c2ecf20Sopenharmony_ci decoder->exec_mode = decoder->packet.payload; 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 19308c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 19318c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 19328c2ecf20Sopenharmony_ci break; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci default: 19358c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic int intel_pt_resample(struct intel_pt_decoder *decoder) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 19438c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 19448c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 19458c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 19468c2ecf20Sopenharmony_ci return 0; 19478c2ecf20Sopenharmony_ci} 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci#define HOP_PROCESS 0 19508c2ecf20Sopenharmony_ci#define HOP_IGNORE 1 19518c2ecf20Sopenharmony_ci#define HOP_RETURN 2 19528c2ecf20Sopenharmony_ci#define HOP_AGAIN 3 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_cistatic int intel_pt_scan_for_psb(struct intel_pt_decoder *decoder); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci/* Hop mode: Ignore TNT, do not walk code, but get ip from FUPs and TIPs */ 19578c2ecf20Sopenharmony_cistatic int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, int *err) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci *err = 0; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Leap from PSB to PSB, getting ip from FUP within PSB+ */ 19628c2ecf20Sopenharmony_ci if (decoder->leap && !decoder->in_psb && decoder->packet.type != INTEL_PT_PSB) { 19638c2ecf20Sopenharmony_ci *err = intel_pt_scan_for_psb(decoder); 19648c2ecf20Sopenharmony_ci if (*err) 19658c2ecf20Sopenharmony_ci return HOP_RETURN; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 19698c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 19708c2ecf20Sopenharmony_ci return HOP_IGNORE; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 19738c2ecf20Sopenharmony_ci decoder->pge = false; 19748c2ecf20Sopenharmony_ci if (!decoder->packet.count) 19758c2ecf20Sopenharmony_ci return HOP_IGNORE; 19768c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 19778c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 19788c2ecf20Sopenharmony_ci decoder->state.from_ip = 0; 19798c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 19808c2ecf20Sopenharmony_ci return HOP_RETURN; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 19838c2ecf20Sopenharmony_ci if (!decoder->packet.count) 19848c2ecf20Sopenharmony_ci return HOP_IGNORE; 19858c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 19868c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 19878c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 19888c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 19898c2ecf20Sopenharmony_ci return HOP_RETURN; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 19928c2ecf20Sopenharmony_ci if (!decoder->packet.count) 19938c2ecf20Sopenharmony_ci return HOP_IGNORE; 19948c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 19958c2ecf20Sopenharmony_ci if (decoder->set_fup_mwait || decoder->set_fup_pwre) 19968c2ecf20Sopenharmony_ci *no_tip = true; 19978c2ecf20Sopenharmony_ci if (!decoder->branch_enable || !decoder->pge) 19988c2ecf20Sopenharmony_ci *no_tip = true; 19998c2ecf20Sopenharmony_ci if (*no_tip) { 20008c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 20018c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 20028c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 20038c2ecf20Sopenharmony_ci intel_pt_fup_event(decoder); 20048c2ecf20Sopenharmony_ci return HOP_RETURN; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci intel_pt_fup_event(decoder); 20078c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_INSTRUCTION | INTEL_PT_BRANCH; 20088c2ecf20Sopenharmony_ci *err = intel_pt_walk_fup_tip(decoder); 20098c2ecf20Sopenharmony_ci if (!*err && decoder->state.to_ip) 20108c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; 20118c2ecf20Sopenharmony_ci return HOP_RETURN; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 20148c2ecf20Sopenharmony_ci decoder->last_ip = 0; 20158c2ecf20Sopenharmony_ci decoder->have_last_ip = true; 20168c2ecf20Sopenharmony_ci decoder->hop_psb_fup = false; 20178c2ecf20Sopenharmony_ci *err = intel_pt_walk_psbend(decoder); 20188c2ecf20Sopenharmony_ci if (*err == -EAGAIN) 20198c2ecf20Sopenharmony_ci return HOP_AGAIN; 20208c2ecf20Sopenharmony_ci if (*err) 20218c2ecf20Sopenharmony_ci return HOP_RETURN; 20228c2ecf20Sopenharmony_ci if (decoder->hop_psb_fup) { 20238c2ecf20Sopenharmony_ci decoder->hop_psb_fup = false; 20248c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 20258c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 20268c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 20278c2ecf20Sopenharmony_ci return HOP_RETURN; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci if (decoder->cbr != decoder->cbr_seen) { 20308c2ecf20Sopenharmony_ci decoder->state.type = 0; 20318c2ecf20Sopenharmony_ci return HOP_RETURN; 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci return HOP_IGNORE; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci case INTEL_PT_BAD: 20368c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 20378c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 20388c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 20398c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 20408c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 20418c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 20428c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 20438c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 20448c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 20458c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 20468c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 20478c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 20488c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 20498c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 20508c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 20518c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 20528c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 20538c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 20548c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 20558c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 20568c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 20578c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 20588c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 20598c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 20608c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 20618c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 20628c2ecf20Sopenharmony_ci default: 20638c2ecf20Sopenharmony_ci return HOP_PROCESS; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci} 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_cistatic int intel_pt_walk_trace(struct intel_pt_decoder *decoder) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci int last_packet_type = INTEL_PT_PAD; 20708c2ecf20Sopenharmony_ci bool no_tip = false; 20718c2ecf20Sopenharmony_ci int err; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci while (1) { 20748c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 20758c2ecf20Sopenharmony_ci if (err) 20768c2ecf20Sopenharmony_ci return err; 20778c2ecf20Sopenharmony_cinext: 20788c2ecf20Sopenharmony_ci err = 0; 20798c2ecf20Sopenharmony_ci if (decoder->cyc_threshold) { 20808c2ecf20Sopenharmony_ci if (decoder->sample_cyc && last_packet_type != INTEL_PT_CYC) 20818c2ecf20Sopenharmony_ci decoder->sample_cyc = false; 20828c2ecf20Sopenharmony_ci last_packet_type = decoder->packet.type; 20838c2ecf20Sopenharmony_ci } 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci if (decoder->hop) { 20868c2ecf20Sopenharmony_ci switch (intel_pt_hop_trace(decoder, &no_tip, &err)) { 20878c2ecf20Sopenharmony_ci case HOP_IGNORE: 20888c2ecf20Sopenharmony_ci continue; 20898c2ecf20Sopenharmony_ci case HOP_RETURN: 20908c2ecf20Sopenharmony_ci return err; 20918c2ecf20Sopenharmony_ci case HOP_AGAIN: 20928c2ecf20Sopenharmony_ci goto next; 20938c2ecf20Sopenharmony_ci default: 20948c2ecf20Sopenharmony_ci break; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 20998c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 21008c2ecf20Sopenharmony_ci if (!decoder->packet.count) 21018c2ecf20Sopenharmony_ci break; 21028c2ecf20Sopenharmony_ci decoder->tnt = decoder->packet; 21038c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_TNT; 21048c2ecf20Sopenharmony_ci err = intel_pt_walk_tnt(decoder); 21058c2ecf20Sopenharmony_ci if (err == -EAGAIN) 21068c2ecf20Sopenharmony_ci break; 21078c2ecf20Sopenharmony_ci return err; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 21108c2ecf20Sopenharmony_ci if (decoder->packet.count != 0) 21118c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 21128c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_TIP_PGD; 21138c2ecf20Sopenharmony_ci return intel_pt_walk_tip(decoder); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: { 21168c2ecf20Sopenharmony_ci decoder->pge = true; 21178c2ecf20Sopenharmony_ci decoder->overflow = false; 21188c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_pge(decoder); 21198c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 21208c2ecf20Sopenharmony_ci intel_pt_log_at("Skipping zero TIP.PGE", 21218c2ecf20Sopenharmony_ci decoder->pos); 21228c2ecf20Sopenharmony_ci break; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 21258c2ecf20Sopenharmony_ci decoder->state.from_ip = 0; 21268c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 21278c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_BEGIN; 21288c2ecf20Sopenharmony_ci /* 21298c2ecf20Sopenharmony_ci * In hop mode, resample to get the to_ip as an 21308c2ecf20Sopenharmony_ci * "instruction" sample. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_ci if (decoder->hop) 21338c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; 21348c2ecf20Sopenharmony_ci return 0; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 21388c2ecf20Sopenharmony_ci return intel_pt_overflow(decoder); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 21418c2ecf20Sopenharmony_ci if (decoder->packet.count != 0) 21428c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 21438c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_TIP; 21448c2ecf20Sopenharmony_ci return intel_pt_walk_tip(decoder); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 21478c2ecf20Sopenharmony_ci if (decoder->packet.count == 0) { 21488c2ecf20Sopenharmony_ci intel_pt_log_at("Skipping zero FUP", 21498c2ecf20Sopenharmony_ci decoder->pos); 21508c2ecf20Sopenharmony_ci no_tip = false; 21518c2ecf20Sopenharmony_ci break; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci intel_pt_set_last_ip(decoder); 21548c2ecf20Sopenharmony_ci if (!decoder->branch_enable || !decoder->pge) { 21558c2ecf20Sopenharmony_ci decoder->ip = decoder->last_ip; 21568c2ecf20Sopenharmony_ci if (intel_pt_fup_event(decoder)) 21578c2ecf20Sopenharmony_ci return 0; 21588c2ecf20Sopenharmony_ci no_tip = false; 21598c2ecf20Sopenharmony_ci break; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci if (decoder->set_fup_mwait) 21628c2ecf20Sopenharmony_ci no_tip = true; 21638c2ecf20Sopenharmony_ci if (no_tip) 21648c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_FUP_NO_TIP; 21658c2ecf20Sopenharmony_ci else 21668c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_FUP; 21678c2ecf20Sopenharmony_ci err = intel_pt_walk_fup(decoder); 21688c2ecf20Sopenharmony_ci if (err != -EAGAIN) 21698c2ecf20Sopenharmony_ci return err; 21708c2ecf20Sopenharmony_ci if (no_tip) { 21718c2ecf20Sopenharmony_ci no_tip = false; 21728c2ecf20Sopenharmony_ci break; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci return intel_pt_walk_fup_tip(decoder); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 21778c2ecf20Sopenharmony_ci decoder->pge = false; 21788c2ecf20Sopenharmony_ci decoder->continuous_period = false; 21798c2ecf20Sopenharmony_ci intel_pt_clear_tx_flags(decoder); 21808c2ecf20Sopenharmony_ci decoder->have_tma = false; 21818c2ecf20Sopenharmony_ci break; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 21848c2ecf20Sopenharmony_ci decoder->last_ip = 0; 21858c2ecf20Sopenharmony_ci decoder->have_last_ip = true; 21868c2ecf20Sopenharmony_ci intel_pt_clear_stack(&decoder->stack); 21878c2ecf20Sopenharmony_ci err = intel_pt_walk_psbend(decoder); 21888c2ecf20Sopenharmony_ci if (err == -EAGAIN) 21898c2ecf20Sopenharmony_ci goto next; 21908c2ecf20Sopenharmony_ci if (err) 21918c2ecf20Sopenharmony_ci return err; 21928c2ecf20Sopenharmony_ci /* 21938c2ecf20Sopenharmony_ci * PSB+ CBR will not have changed but cater for the 21948c2ecf20Sopenharmony_ci * possibility of another CBR change that gets caught up 21958c2ecf20Sopenharmony_ci * in the PSB+. 21968c2ecf20Sopenharmony_ci */ 21978c2ecf20Sopenharmony_ci if (decoder->cbr != decoder->cbr_seen) { 21988c2ecf20Sopenharmony_ci decoder->state.type = 0; 21998c2ecf20Sopenharmony_ci return 0; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci break; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 22048c2ecf20Sopenharmony_ci decoder->cr3 = decoder->packet.payload & (BIT63 - 1); 22058c2ecf20Sopenharmony_ci break; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 22088c2ecf20Sopenharmony_ci intel_pt_calc_mtc_timestamp(decoder); 22098c2ecf20Sopenharmony_ci if (decoder->period_type != INTEL_PT_PERIOD_MTC) 22108c2ecf20Sopenharmony_ci break; 22118c2ecf20Sopenharmony_ci /* 22128c2ecf20Sopenharmony_ci * Ensure that there has been an instruction since the 22138c2ecf20Sopenharmony_ci * last MTC. 22148c2ecf20Sopenharmony_ci */ 22158c2ecf20Sopenharmony_ci if (!decoder->mtc_insn) 22168c2ecf20Sopenharmony_ci break; 22178c2ecf20Sopenharmony_ci decoder->mtc_insn = false; 22188c2ecf20Sopenharmony_ci /* Ensure that there is a timestamp */ 22198c2ecf20Sopenharmony_ci if (!decoder->timestamp) 22208c2ecf20Sopenharmony_ci break; 22218c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_INSTRUCTION; 22228c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 22238c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 22248c2ecf20Sopenharmony_ci decoder->mtc_insn = false; 22258c2ecf20Sopenharmony_ci return 0; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 22288c2ecf20Sopenharmony_ci intel_pt_calc_tsc_timestamp(decoder); 22298c2ecf20Sopenharmony_ci break; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 22328c2ecf20Sopenharmony_ci intel_pt_calc_tma(decoder); 22338c2ecf20Sopenharmony_ci break; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 22368c2ecf20Sopenharmony_ci intel_pt_calc_cyc_timestamp(decoder); 22378c2ecf20Sopenharmony_ci break; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 22408c2ecf20Sopenharmony_ci intel_pt_calc_cbr(decoder); 22418c2ecf20Sopenharmony_ci if (decoder->cbr != decoder->cbr_seen) { 22428c2ecf20Sopenharmony_ci decoder->state.type = 0; 22438c2ecf20Sopenharmony_ci return 0; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci break; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 22488c2ecf20Sopenharmony_ci decoder->exec_mode = decoder->packet.payload; 22498c2ecf20Sopenharmony_ci break; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 22528c2ecf20Sopenharmony_ci /* MODE_TSX need not be followed by FUP */ 22538c2ecf20Sopenharmony_ci if (!decoder->pge || decoder->in_psb) { 22548c2ecf20Sopenharmony_ci intel_pt_update_in_tx(decoder); 22558c2ecf20Sopenharmony_ci break; 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci err = intel_pt_mode_tsx(decoder, &no_tip); 22588c2ecf20Sopenharmony_ci if (err) 22598c2ecf20Sopenharmony_ci return err; 22608c2ecf20Sopenharmony_ci goto next; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci case INTEL_PT_BAD: /* Does not happen */ 22638c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 22668c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 22678c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 22688c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 22698c2ecf20Sopenharmony_ci break; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 22728c2ecf20Sopenharmony_ci decoder->fup_ptw_payload = decoder->packet.payload; 22738c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 22748c2ecf20Sopenharmony_ci if (err) 22758c2ecf20Sopenharmony_ci return err; 22768c2ecf20Sopenharmony_ci if (decoder->packet.type == INTEL_PT_FUP) { 22778c2ecf20Sopenharmony_ci decoder->set_fup_ptw = true; 22788c2ecf20Sopenharmony_ci no_tip = true; 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Missing FUP after PTWRITE", 22818c2ecf20Sopenharmony_ci decoder->pos); 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci goto next; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 22868c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_PTW; 22878c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 22888c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 22898c2ecf20Sopenharmony_ci decoder->state.ptw_payload = decoder->packet.payload; 22908c2ecf20Sopenharmony_ci return 0; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 22938c2ecf20Sopenharmony_ci decoder->fup_mwait_payload = decoder->packet.payload; 22948c2ecf20Sopenharmony_ci decoder->set_fup_mwait = true; 22958c2ecf20Sopenharmony_ci break; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 22988c2ecf20Sopenharmony_ci if (decoder->set_fup_mwait) { 22998c2ecf20Sopenharmony_ci decoder->fup_pwre_payload = 23008c2ecf20Sopenharmony_ci decoder->packet.payload; 23018c2ecf20Sopenharmony_ci decoder->set_fup_pwre = true; 23028c2ecf20Sopenharmony_ci break; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_PWR_ENTRY; 23058c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 23068c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 23078c2ecf20Sopenharmony_ci decoder->state.pwrx_payload = decoder->packet.payload; 23088c2ecf20Sopenharmony_ci return 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 23118c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 23128c2ecf20Sopenharmony_ci if (err) 23138c2ecf20Sopenharmony_ci return err; 23148c2ecf20Sopenharmony_ci if (decoder->packet.type == INTEL_PT_FUP) { 23158c2ecf20Sopenharmony_ci decoder->set_fup_exstop = true; 23168c2ecf20Sopenharmony_ci no_tip = true; 23178c2ecf20Sopenharmony_ci } else { 23188c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Missing FUP after EXSTOP", 23198c2ecf20Sopenharmony_ci decoder->pos); 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci goto next; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 23248c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_EX_STOP; 23258c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 23268c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 23278c2ecf20Sopenharmony_ci return 0; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 23308c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_PWR_EXIT; 23318c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 23328c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 23338c2ecf20Sopenharmony_ci decoder->state.pwrx_payload = decoder->packet.payload; 23348c2ecf20Sopenharmony_ci return 0; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 23378c2ecf20Sopenharmony_ci intel_pt_bbp(decoder); 23388c2ecf20Sopenharmony_ci break; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 23418c2ecf20Sopenharmony_ci intel_pt_bip(decoder); 23428c2ecf20Sopenharmony_ci break; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 23458c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_BLK_ITEMS; 23468c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 23478c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 23488c2ecf20Sopenharmony_ci return 0; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 23518c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 23528c2ecf20Sopenharmony_ci if (err) 23538c2ecf20Sopenharmony_ci return err; 23548c2ecf20Sopenharmony_ci if (decoder->packet.type == INTEL_PT_FUP) { 23558c2ecf20Sopenharmony_ci decoder->set_fup_bep = true; 23568c2ecf20Sopenharmony_ci no_tip = true; 23578c2ecf20Sopenharmony_ci } else { 23588c2ecf20Sopenharmony_ci intel_pt_log_at("ERROR: Missing FUP after BEP", 23598c2ecf20Sopenharmony_ci decoder->pos); 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci goto next; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci default: 23648c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci} 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cistatic inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci return decoder->packet.count && 23728c2ecf20Sopenharmony_ci (decoder->have_last_ip || decoder->packet.count == 3 || 23738c2ecf20Sopenharmony_ci decoder->packet.count == 6); 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci/* Walk PSB+ packets to get in sync. */ 23778c2ecf20Sopenharmony_cistatic int intel_pt_walk_psb(struct intel_pt_decoder *decoder) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci int err; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci decoder->in_psb = true; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci while (1) { 23848c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 23858c2ecf20Sopenharmony_ci if (err) 23868c2ecf20Sopenharmony_ci goto out; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 23898c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 23908c2ecf20Sopenharmony_ci decoder->continuous_period = false; 23918c2ecf20Sopenharmony_ci __fallthrough; 23928c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 23938c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 23948c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 23958c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 23968c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 23978c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 23988c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 23998c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 24008c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 24018c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 24028c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 24038c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 24048c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 24058c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Unexpected packet\n"); 24068c2ecf20Sopenharmony_ci err = -ENOENT; 24078c2ecf20Sopenharmony_ci goto out; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 24108c2ecf20Sopenharmony_ci decoder->pge = true; 24118c2ecf20Sopenharmony_ci if (intel_pt_have_ip(decoder)) { 24128c2ecf20Sopenharmony_ci uint64_t current_ip = decoder->ip; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 24158c2ecf20Sopenharmony_ci if (current_ip) 24168c2ecf20Sopenharmony_ci intel_pt_log_to("Setting IP", 24178c2ecf20Sopenharmony_ci decoder->ip); 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci break; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 24228c2ecf20Sopenharmony_ci intel_pt_calc_mtc_timestamp(decoder); 24238c2ecf20Sopenharmony_ci break; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 24268c2ecf20Sopenharmony_ci intel_pt_calc_tsc_timestamp(decoder); 24278c2ecf20Sopenharmony_ci break; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 24308c2ecf20Sopenharmony_ci intel_pt_calc_tma(decoder); 24318c2ecf20Sopenharmony_ci break; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 24348c2ecf20Sopenharmony_ci intel_pt_calc_cyc_timestamp(decoder); 24358c2ecf20Sopenharmony_ci break; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 24388c2ecf20Sopenharmony_ci intel_pt_calc_cbr(decoder); 24398c2ecf20Sopenharmony_ci break; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 24428c2ecf20Sopenharmony_ci decoder->cr3 = decoder->packet.payload & (BIT63 - 1); 24438c2ecf20Sopenharmony_ci break; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 24468c2ecf20Sopenharmony_ci decoder->exec_mode = decoder->packet.payload; 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 24508c2ecf20Sopenharmony_ci intel_pt_update_in_tx(decoder); 24518c2ecf20Sopenharmony_ci break; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 24548c2ecf20Sopenharmony_ci decoder->pge = false; 24558c2ecf20Sopenharmony_ci decoder->continuous_period = false; 24568c2ecf20Sopenharmony_ci intel_pt_clear_tx_flags(decoder); 24578c2ecf20Sopenharmony_ci __fallthrough; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 24608c2ecf20Sopenharmony_ci decoder->have_tma = false; 24618c2ecf20Sopenharmony_ci intel_pt_log("ERROR: Unexpected packet\n"); 24628c2ecf20Sopenharmony_ci if (decoder->ip) 24638c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR4; 24648c2ecf20Sopenharmony_ci else 24658c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_ERR3; 24668c2ecf20Sopenharmony_ci err = -ENOENT; 24678c2ecf20Sopenharmony_ci goto out; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci case INTEL_PT_BAD: /* Does not happen */ 24708c2ecf20Sopenharmony_ci err = intel_pt_bug(decoder); 24718c2ecf20Sopenharmony_ci goto out; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 24748c2ecf20Sopenharmony_ci err = intel_pt_overflow(decoder); 24758c2ecf20Sopenharmony_ci goto out; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 24788c2ecf20Sopenharmony_ci err = 0; 24798c2ecf20Sopenharmony_ci goto out; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 24828c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 24838c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 24848c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 24858c2ecf20Sopenharmony_ci default: 24868c2ecf20Sopenharmony_ci break; 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ciout: 24908c2ecf20Sopenharmony_ci decoder->in_psb = false; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci return err; 24938c2ecf20Sopenharmony_ci} 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_cistatic int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) 24968c2ecf20Sopenharmony_ci{ 24978c2ecf20Sopenharmony_ci int err; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci while (1) { 25008c2ecf20Sopenharmony_ci err = intel_pt_get_next_packet(decoder); 25018c2ecf20Sopenharmony_ci if (err) 25028c2ecf20Sopenharmony_ci return err; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci switch (decoder->packet.type) { 25058c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGD: 25068c2ecf20Sopenharmony_ci decoder->continuous_period = false; 25078c2ecf20Sopenharmony_ci decoder->pge = false; 25088c2ecf20Sopenharmony_ci if (intel_pt_have_ip(decoder)) 25098c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 25108c2ecf20Sopenharmony_ci if (!decoder->ip) 25118c2ecf20Sopenharmony_ci break; 25128c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_END; 25138c2ecf20Sopenharmony_ci return 0; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci case INTEL_PT_TIP_PGE: 25168c2ecf20Sopenharmony_ci decoder->pge = true; 25178c2ecf20Sopenharmony_ci intel_pt_mtc_cyc_cnt_pge(decoder); 25188c2ecf20Sopenharmony_ci if (intel_pt_have_ip(decoder)) 25198c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 25208c2ecf20Sopenharmony_ci if (!decoder->ip) 25218c2ecf20Sopenharmony_ci break; 25228c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_TRACE_BEGIN; 25238c2ecf20Sopenharmony_ci return 0; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci case INTEL_PT_TIP: 25268c2ecf20Sopenharmony_ci decoder->pge = true; 25278c2ecf20Sopenharmony_ci if (intel_pt_have_ip(decoder)) 25288c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 25298c2ecf20Sopenharmony_ci if (!decoder->ip) 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci return 0; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci case INTEL_PT_FUP: 25348c2ecf20Sopenharmony_ci if (intel_pt_have_ip(decoder)) 25358c2ecf20Sopenharmony_ci intel_pt_set_ip(decoder); 25368c2ecf20Sopenharmony_ci if (decoder->ip) 25378c2ecf20Sopenharmony_ci return 0; 25388c2ecf20Sopenharmony_ci break; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci case INTEL_PT_MTC: 25418c2ecf20Sopenharmony_ci intel_pt_calc_mtc_timestamp(decoder); 25428c2ecf20Sopenharmony_ci break; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci case INTEL_PT_TSC: 25458c2ecf20Sopenharmony_ci intel_pt_calc_tsc_timestamp(decoder); 25468c2ecf20Sopenharmony_ci break; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci case INTEL_PT_TMA: 25498c2ecf20Sopenharmony_ci intel_pt_calc_tma(decoder); 25508c2ecf20Sopenharmony_ci break; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci case INTEL_PT_CYC: 25538c2ecf20Sopenharmony_ci intel_pt_calc_cyc_timestamp(decoder); 25548c2ecf20Sopenharmony_ci break; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci case INTEL_PT_CBR: 25578c2ecf20Sopenharmony_ci intel_pt_calc_cbr(decoder); 25588c2ecf20Sopenharmony_ci break; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci case INTEL_PT_PIP: 25618c2ecf20Sopenharmony_ci decoder->cr3 = decoder->packet.payload & (BIT63 - 1); 25628c2ecf20Sopenharmony_ci break; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci case INTEL_PT_MODE_EXEC: 25658c2ecf20Sopenharmony_ci decoder->exec_mode = decoder->packet.payload; 25668c2ecf20Sopenharmony_ci break; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci case INTEL_PT_MODE_TSX: 25698c2ecf20Sopenharmony_ci intel_pt_update_in_tx(decoder); 25708c2ecf20Sopenharmony_ci break; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci case INTEL_PT_OVF: 25738c2ecf20Sopenharmony_ci return intel_pt_overflow(decoder); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci case INTEL_PT_BAD: /* Does not happen */ 25768c2ecf20Sopenharmony_ci return intel_pt_bug(decoder); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci case INTEL_PT_TRACESTOP: 25798c2ecf20Sopenharmony_ci decoder->pge = false; 25808c2ecf20Sopenharmony_ci decoder->continuous_period = false; 25818c2ecf20Sopenharmony_ci intel_pt_clear_tx_flags(decoder); 25828c2ecf20Sopenharmony_ci decoder->have_tma = false; 25838c2ecf20Sopenharmony_ci break; 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci case INTEL_PT_PSB: 25868c2ecf20Sopenharmony_ci decoder->last_ip = 0; 25878c2ecf20Sopenharmony_ci decoder->have_last_ip = true; 25888c2ecf20Sopenharmony_ci intel_pt_clear_stack(&decoder->stack); 25898c2ecf20Sopenharmony_ci err = intel_pt_walk_psb(decoder); 25908c2ecf20Sopenharmony_ci if (err) 25918c2ecf20Sopenharmony_ci return err; 25928c2ecf20Sopenharmony_ci if (decoder->ip) { 25938c2ecf20Sopenharmony_ci /* Do not have a sample */ 25948c2ecf20Sopenharmony_ci decoder->state.type = 0; 25958c2ecf20Sopenharmony_ci return 0; 25968c2ecf20Sopenharmony_ci } 25978c2ecf20Sopenharmony_ci break; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci case INTEL_PT_TNT: 26008c2ecf20Sopenharmony_ci case INTEL_PT_PSBEND: 26018c2ecf20Sopenharmony_ci case INTEL_PT_VMCS: 26028c2ecf20Sopenharmony_ci case INTEL_PT_MNT: 26038c2ecf20Sopenharmony_ci case INTEL_PT_PAD: 26048c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE: 26058c2ecf20Sopenharmony_ci case INTEL_PT_PTWRITE_IP: 26068c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP: 26078c2ecf20Sopenharmony_ci case INTEL_PT_EXSTOP_IP: 26088c2ecf20Sopenharmony_ci case INTEL_PT_MWAIT: 26098c2ecf20Sopenharmony_ci case INTEL_PT_PWRE: 26108c2ecf20Sopenharmony_ci case INTEL_PT_PWRX: 26118c2ecf20Sopenharmony_ci case INTEL_PT_BBP: 26128c2ecf20Sopenharmony_ci case INTEL_PT_BIP: 26138c2ecf20Sopenharmony_ci case INTEL_PT_BEP: 26148c2ecf20Sopenharmony_ci case INTEL_PT_BEP_IP: 26158c2ecf20Sopenharmony_ci default: 26168c2ecf20Sopenharmony_ci break; 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci} 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_cistatic int intel_pt_sync_ip(struct intel_pt_decoder *decoder) 26228c2ecf20Sopenharmony_ci{ 26238c2ecf20Sopenharmony_ci int err; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci decoder->set_fup_tx_flags = false; 26268c2ecf20Sopenharmony_ci decoder->set_fup_ptw = false; 26278c2ecf20Sopenharmony_ci decoder->set_fup_mwait = false; 26288c2ecf20Sopenharmony_ci decoder->set_fup_pwre = false; 26298c2ecf20Sopenharmony_ci decoder->set_fup_exstop = false; 26308c2ecf20Sopenharmony_ci decoder->set_fup_bep = false; 26318c2ecf20Sopenharmony_ci decoder->overflow = false; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (!decoder->branch_enable) { 26348c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 26358c2ecf20Sopenharmony_ci decoder->state.type = 0; /* Do not have a sample */ 26368c2ecf20Sopenharmony_ci return 0; 26378c2ecf20Sopenharmony_ci } 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci intel_pt_log("Scanning for full IP\n"); 26408c2ecf20Sopenharmony_ci err = intel_pt_walk_to_ip(decoder); 26418c2ecf20Sopenharmony_ci if (err) 26428c2ecf20Sopenharmony_ci return err; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci /* In hop mode, resample to get the to_ip as an "instruction" sample */ 26458c2ecf20Sopenharmony_ci if (decoder->hop) 26468c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; 26478c2ecf20Sopenharmony_ci else 26488c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci decoder->state.from_ip = 0; 26518c2ecf20Sopenharmony_ci decoder->state.to_ip = decoder->ip; 26528c2ecf20Sopenharmony_ci intel_pt_log_to("Setting IP", decoder->ip); 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci return 0; 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic int intel_pt_part_psb(struct intel_pt_decoder *decoder) 26588c2ecf20Sopenharmony_ci{ 26598c2ecf20Sopenharmony_ci const unsigned char *end = decoder->buf + decoder->len; 26608c2ecf20Sopenharmony_ci size_t i; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci for (i = INTEL_PT_PSB_LEN - 1; i; i--) { 26638c2ecf20Sopenharmony_ci if (i > decoder->len) 26648c2ecf20Sopenharmony_ci continue; 26658c2ecf20Sopenharmony_ci if (!memcmp(end - i, INTEL_PT_PSB_STR, i)) 26668c2ecf20Sopenharmony_ci return i; 26678c2ecf20Sopenharmony_ci } 26688c2ecf20Sopenharmony_ci return 0; 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_cistatic int intel_pt_rest_psb(struct intel_pt_decoder *decoder, int part_psb) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci size_t rest_psb = INTEL_PT_PSB_LEN - part_psb; 26748c2ecf20Sopenharmony_ci const char *psb = INTEL_PT_PSB_STR; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci if (rest_psb > decoder->len || 26778c2ecf20Sopenharmony_ci memcmp(decoder->buf, psb + part_psb, rest_psb)) 26788c2ecf20Sopenharmony_ci return 0; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci return rest_psb; 26818c2ecf20Sopenharmony_ci} 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_cistatic int intel_pt_get_split_psb(struct intel_pt_decoder *decoder, 26848c2ecf20Sopenharmony_ci int part_psb) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci int rest_psb, ret; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci decoder->pos += decoder->len; 26898c2ecf20Sopenharmony_ci decoder->len = 0; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci ret = intel_pt_get_next_data(decoder, false); 26928c2ecf20Sopenharmony_ci if (ret) 26938c2ecf20Sopenharmony_ci return ret; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci rest_psb = intel_pt_rest_psb(decoder, part_psb); 26968c2ecf20Sopenharmony_ci if (!rest_psb) 26978c2ecf20Sopenharmony_ci return 0; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci decoder->pos -= part_psb; 27008c2ecf20Sopenharmony_ci decoder->next_buf = decoder->buf + rest_psb; 27018c2ecf20Sopenharmony_ci decoder->next_len = decoder->len - rest_psb; 27028c2ecf20Sopenharmony_ci memcpy(decoder->temp_buf, INTEL_PT_PSB_STR, INTEL_PT_PSB_LEN); 27038c2ecf20Sopenharmony_ci decoder->buf = decoder->temp_buf; 27048c2ecf20Sopenharmony_ci decoder->len = INTEL_PT_PSB_LEN; 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci return 0; 27078c2ecf20Sopenharmony_ci} 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_cistatic int intel_pt_scan_for_psb(struct intel_pt_decoder *decoder) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci unsigned char *next; 27128c2ecf20Sopenharmony_ci int ret; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci intel_pt_log("Scanning for PSB\n"); 27158c2ecf20Sopenharmony_ci while (1) { 27168c2ecf20Sopenharmony_ci if (!decoder->len) { 27178c2ecf20Sopenharmony_ci ret = intel_pt_get_next_data(decoder, false); 27188c2ecf20Sopenharmony_ci if (ret) 27198c2ecf20Sopenharmony_ci return ret; 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci next = memmem(decoder->buf, decoder->len, INTEL_PT_PSB_STR, 27238c2ecf20Sopenharmony_ci INTEL_PT_PSB_LEN); 27248c2ecf20Sopenharmony_ci if (!next) { 27258c2ecf20Sopenharmony_ci int part_psb; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci part_psb = intel_pt_part_psb(decoder); 27288c2ecf20Sopenharmony_ci if (part_psb) { 27298c2ecf20Sopenharmony_ci ret = intel_pt_get_split_psb(decoder, part_psb); 27308c2ecf20Sopenharmony_ci if (ret) 27318c2ecf20Sopenharmony_ci return ret; 27328c2ecf20Sopenharmony_ci } else { 27338c2ecf20Sopenharmony_ci decoder->pos += decoder->len; 27348c2ecf20Sopenharmony_ci decoder->len = 0; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci continue; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci decoder->pkt_step = next - decoder->buf; 27408c2ecf20Sopenharmony_ci return intel_pt_get_next_packet(decoder); 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci} 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_cistatic int intel_pt_sync(struct intel_pt_decoder *decoder) 27458c2ecf20Sopenharmony_ci{ 27468c2ecf20Sopenharmony_ci int err; 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci decoder->pge = false; 27498c2ecf20Sopenharmony_ci decoder->continuous_period = false; 27508c2ecf20Sopenharmony_ci decoder->have_last_ip = false; 27518c2ecf20Sopenharmony_ci decoder->last_ip = 0; 27528c2ecf20Sopenharmony_ci decoder->ip = 0; 27538c2ecf20Sopenharmony_ci intel_pt_clear_stack(&decoder->stack); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_cileap: 27568c2ecf20Sopenharmony_ci err = intel_pt_scan_for_psb(decoder); 27578c2ecf20Sopenharmony_ci if (err) 27588c2ecf20Sopenharmony_ci return err; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci decoder->have_last_ip = true; 27618c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci err = intel_pt_walk_psb(decoder); 27648c2ecf20Sopenharmony_ci if (err) 27658c2ecf20Sopenharmony_ci return err; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci if (decoder->ip) { 27688c2ecf20Sopenharmony_ci decoder->state.type = 0; /* Do not have a sample */ 27698c2ecf20Sopenharmony_ci /* 27708c2ecf20Sopenharmony_ci * In hop mode, resample to get the PSB FUP ip as an 27718c2ecf20Sopenharmony_ci * "instruction" sample. 27728c2ecf20Sopenharmony_ci */ 27738c2ecf20Sopenharmony_ci if (decoder->hop) 27748c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_RESAMPLE; 27758c2ecf20Sopenharmony_ci else 27768c2ecf20Sopenharmony_ci decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; 27778c2ecf20Sopenharmony_ci } else if (decoder->leap) { 27788c2ecf20Sopenharmony_ci /* 27798c2ecf20Sopenharmony_ci * In leap mode, only PSB+ is decoded, so keeping leaping to the 27808c2ecf20Sopenharmony_ci * next PSB until there is an ip. 27818c2ecf20Sopenharmony_ci */ 27828c2ecf20Sopenharmony_ci goto leap; 27838c2ecf20Sopenharmony_ci } else { 27848c2ecf20Sopenharmony_ci return intel_pt_sync_ip(decoder); 27858c2ecf20Sopenharmony_ci } 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci return 0; 27888c2ecf20Sopenharmony_ci} 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_cistatic uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) 27918c2ecf20Sopenharmony_ci{ 27928c2ecf20Sopenharmony_ci uint64_t est = decoder->sample_insn_cnt << 1; 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (!decoder->cbr || !decoder->max_non_turbo_ratio) 27958c2ecf20Sopenharmony_ci goto out; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci est *= decoder->max_non_turbo_ratio; 27988c2ecf20Sopenharmony_ci est /= decoder->cbr; 27998c2ecf20Sopenharmony_ciout: 28008c2ecf20Sopenharmony_ci return decoder->sample_timestamp + est; 28018c2ecf20Sopenharmony_ci} 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ciconst struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci int err; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci do { 28088c2ecf20Sopenharmony_ci decoder->state.type = INTEL_PT_BRANCH; 28098c2ecf20Sopenharmony_ci decoder->state.flags = 0; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci switch (decoder->pkt_state) { 28128c2ecf20Sopenharmony_ci case INTEL_PT_STATE_NO_PSB: 28138c2ecf20Sopenharmony_ci err = intel_pt_sync(decoder); 28148c2ecf20Sopenharmony_ci break; 28158c2ecf20Sopenharmony_ci case INTEL_PT_STATE_NO_IP: 28168c2ecf20Sopenharmony_ci decoder->have_last_ip = false; 28178c2ecf20Sopenharmony_ci decoder->last_ip = 0; 28188c2ecf20Sopenharmony_ci decoder->ip = 0; 28198c2ecf20Sopenharmony_ci __fallthrough; 28208c2ecf20Sopenharmony_ci case INTEL_PT_STATE_ERR_RESYNC: 28218c2ecf20Sopenharmony_ci err = intel_pt_sync_ip(decoder); 28228c2ecf20Sopenharmony_ci break; 28238c2ecf20Sopenharmony_ci case INTEL_PT_STATE_IN_SYNC: 28248c2ecf20Sopenharmony_ci err = intel_pt_walk_trace(decoder); 28258c2ecf20Sopenharmony_ci break; 28268c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TNT: 28278c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TNT_CONT: 28288c2ecf20Sopenharmony_ci err = intel_pt_walk_tnt(decoder); 28298c2ecf20Sopenharmony_ci if (err == -EAGAIN) 28308c2ecf20Sopenharmony_ci err = intel_pt_walk_trace(decoder); 28318c2ecf20Sopenharmony_ci break; 28328c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TIP: 28338c2ecf20Sopenharmony_ci case INTEL_PT_STATE_TIP_PGD: 28348c2ecf20Sopenharmony_ci err = intel_pt_walk_tip(decoder); 28358c2ecf20Sopenharmony_ci break; 28368c2ecf20Sopenharmony_ci case INTEL_PT_STATE_FUP: 28378c2ecf20Sopenharmony_ci err = intel_pt_walk_fup(decoder); 28388c2ecf20Sopenharmony_ci if (err == -EAGAIN) 28398c2ecf20Sopenharmony_ci err = intel_pt_walk_fup_tip(decoder); 28408c2ecf20Sopenharmony_ci break; 28418c2ecf20Sopenharmony_ci case INTEL_PT_STATE_FUP_NO_TIP: 28428c2ecf20Sopenharmony_ci err = intel_pt_walk_fup(decoder); 28438c2ecf20Sopenharmony_ci if (err == -EAGAIN) 28448c2ecf20Sopenharmony_ci err = intel_pt_walk_trace(decoder); 28458c2ecf20Sopenharmony_ci break; 28468c2ecf20Sopenharmony_ci case INTEL_PT_STATE_RESAMPLE: 28478c2ecf20Sopenharmony_ci err = intel_pt_resample(decoder); 28488c2ecf20Sopenharmony_ci break; 28498c2ecf20Sopenharmony_ci default: 28508c2ecf20Sopenharmony_ci err = intel_pt_bug(decoder); 28518c2ecf20Sopenharmony_ci break; 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci } while (err == -ENOLINK); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci if (err) { 28568c2ecf20Sopenharmony_ci decoder->state.err = intel_pt_ext_err(err); 28578c2ecf20Sopenharmony_ci if (err != -EOVERFLOW) 28588c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 28598c2ecf20Sopenharmony_ci intel_pt_update_sample_time(decoder); 28608c2ecf20Sopenharmony_ci decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt; 28618c2ecf20Sopenharmony_ci } else { 28628c2ecf20Sopenharmony_ci decoder->state.err = 0; 28638c2ecf20Sopenharmony_ci if (decoder->cbr != decoder->cbr_seen) { 28648c2ecf20Sopenharmony_ci decoder->cbr_seen = decoder->cbr; 28658c2ecf20Sopenharmony_ci if (!decoder->state.type) { 28668c2ecf20Sopenharmony_ci decoder->state.from_ip = decoder->ip; 28678c2ecf20Sopenharmony_ci decoder->state.to_ip = 0; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci decoder->state.type |= INTEL_PT_CBR_CHG; 28708c2ecf20Sopenharmony_ci decoder->state.cbr_payload = decoder->cbr_payload; 28718c2ecf20Sopenharmony_ci decoder->state.cbr = decoder->cbr; 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci if (intel_pt_sample_time(decoder->pkt_state)) { 28748c2ecf20Sopenharmony_ci intel_pt_update_sample_time(decoder); 28758c2ecf20Sopenharmony_ci if (decoder->sample_cyc) { 28768c2ecf20Sopenharmony_ci decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt; 28778c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_SAMPLE_IPC; 28788c2ecf20Sopenharmony_ci decoder->sample_cyc = false; 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci /* 28828c2ecf20Sopenharmony_ci * When using only TSC/MTC to compute cycles, IPC can be 28838c2ecf20Sopenharmony_ci * sampled as soon as the cycle count changes. 28848c2ecf20Sopenharmony_ci */ 28858c2ecf20Sopenharmony_ci if (!decoder->have_cyc) 28868c2ecf20Sopenharmony_ci decoder->state.flags |= INTEL_PT_SAMPLE_IPC; 28878c2ecf20Sopenharmony_ci } 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci decoder->state.timestamp = decoder->sample_timestamp; 28908c2ecf20Sopenharmony_ci decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); 28918c2ecf20Sopenharmony_ci decoder->state.cr3 = decoder->cr3; 28928c2ecf20Sopenharmony_ci decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; 28938c2ecf20Sopenharmony_ci decoder->state.tot_cyc_cnt = decoder->sample_tot_cyc_cnt; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci return &decoder->state; 28968c2ecf20Sopenharmony_ci} 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci/** 28998c2ecf20Sopenharmony_ci * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet. 29008c2ecf20Sopenharmony_ci * @buf: pointer to buffer pointer 29018c2ecf20Sopenharmony_ci * @len: size of buffer 29028c2ecf20Sopenharmony_ci * 29038c2ecf20Sopenharmony_ci * Updates the buffer pointer to point to the start of the next PSB packet if 29048c2ecf20Sopenharmony_ci * there is one, otherwise the buffer pointer is unchanged. If @buf is updated, 29058c2ecf20Sopenharmony_ci * @len is adjusted accordingly. 29068c2ecf20Sopenharmony_ci * 29078c2ecf20Sopenharmony_ci * Return: %true if a PSB packet is found, %false otherwise. 29088c2ecf20Sopenharmony_ci */ 29098c2ecf20Sopenharmony_cistatic bool intel_pt_next_psb(unsigned char **buf, size_t *len) 29108c2ecf20Sopenharmony_ci{ 29118c2ecf20Sopenharmony_ci unsigned char *next; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci next = memmem(*buf, *len, INTEL_PT_PSB_STR, INTEL_PT_PSB_LEN); 29148c2ecf20Sopenharmony_ci if (next) { 29158c2ecf20Sopenharmony_ci *len -= next - *buf; 29168c2ecf20Sopenharmony_ci *buf = next; 29178c2ecf20Sopenharmony_ci return true; 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci return false; 29208c2ecf20Sopenharmony_ci} 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci/** 29238c2ecf20Sopenharmony_ci * intel_pt_step_psb - move buffer pointer to the start of the following PSB 29248c2ecf20Sopenharmony_ci * packet. 29258c2ecf20Sopenharmony_ci * @buf: pointer to buffer pointer 29268c2ecf20Sopenharmony_ci * @len: size of buffer 29278c2ecf20Sopenharmony_ci * 29288c2ecf20Sopenharmony_ci * Updates the buffer pointer to point to the start of the following PSB packet 29298c2ecf20Sopenharmony_ci * (skipping the PSB at @buf itself) if there is one, otherwise the buffer 29308c2ecf20Sopenharmony_ci * pointer is unchanged. If @buf is updated, @len is adjusted accordingly. 29318c2ecf20Sopenharmony_ci * 29328c2ecf20Sopenharmony_ci * Return: %true if a PSB packet is found, %false otherwise. 29338c2ecf20Sopenharmony_ci */ 29348c2ecf20Sopenharmony_cistatic bool intel_pt_step_psb(unsigned char **buf, size_t *len) 29358c2ecf20Sopenharmony_ci{ 29368c2ecf20Sopenharmony_ci unsigned char *next; 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci if (!*len) 29398c2ecf20Sopenharmony_ci return false; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci next = memmem(*buf + 1, *len - 1, INTEL_PT_PSB_STR, INTEL_PT_PSB_LEN); 29428c2ecf20Sopenharmony_ci if (next) { 29438c2ecf20Sopenharmony_ci *len -= next - *buf; 29448c2ecf20Sopenharmony_ci *buf = next; 29458c2ecf20Sopenharmony_ci return true; 29468c2ecf20Sopenharmony_ci } 29478c2ecf20Sopenharmony_ci return false; 29488c2ecf20Sopenharmony_ci} 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci/** 29518c2ecf20Sopenharmony_ci * intel_pt_last_psb - find the last PSB packet in a buffer. 29528c2ecf20Sopenharmony_ci * @buf: buffer 29538c2ecf20Sopenharmony_ci * @len: size of buffer 29548c2ecf20Sopenharmony_ci * 29558c2ecf20Sopenharmony_ci * This function finds the last PSB in a buffer. 29568c2ecf20Sopenharmony_ci * 29578c2ecf20Sopenharmony_ci * Return: A pointer to the last PSB in @buf if found, %NULL otherwise. 29588c2ecf20Sopenharmony_ci */ 29598c2ecf20Sopenharmony_cistatic unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) 29608c2ecf20Sopenharmony_ci{ 29618c2ecf20Sopenharmony_ci const char *n = INTEL_PT_PSB_STR; 29628c2ecf20Sopenharmony_ci unsigned char *p; 29638c2ecf20Sopenharmony_ci size_t k; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci if (len < INTEL_PT_PSB_LEN) 29668c2ecf20Sopenharmony_ci return NULL; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci k = len - INTEL_PT_PSB_LEN + 1; 29698c2ecf20Sopenharmony_ci while (1) { 29708c2ecf20Sopenharmony_ci p = memrchr(buf, n[0], k); 29718c2ecf20Sopenharmony_ci if (!p) 29728c2ecf20Sopenharmony_ci return NULL; 29738c2ecf20Sopenharmony_ci if (!memcmp(p + 1, n + 1, INTEL_PT_PSB_LEN - 1)) 29748c2ecf20Sopenharmony_ci return p; 29758c2ecf20Sopenharmony_ci k = p - buf; 29768c2ecf20Sopenharmony_ci if (!k) 29778c2ecf20Sopenharmony_ci return NULL; 29788c2ecf20Sopenharmony_ci } 29798c2ecf20Sopenharmony_ci} 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci/** 29828c2ecf20Sopenharmony_ci * intel_pt_next_tsc - find and return next TSC. 29838c2ecf20Sopenharmony_ci * @buf: buffer 29848c2ecf20Sopenharmony_ci * @len: size of buffer 29858c2ecf20Sopenharmony_ci * @tsc: TSC value returned 29868c2ecf20Sopenharmony_ci * @rem: returns remaining size when TSC is found 29878c2ecf20Sopenharmony_ci * 29888c2ecf20Sopenharmony_ci * Find a TSC packet in @buf and return the TSC value. This function assumes 29898c2ecf20Sopenharmony_ci * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a 29908c2ecf20Sopenharmony_ci * PSBEND packet is found. 29918c2ecf20Sopenharmony_ci * 29928c2ecf20Sopenharmony_ci * Return: %true if TSC is found, false otherwise. 29938c2ecf20Sopenharmony_ci */ 29948c2ecf20Sopenharmony_cistatic bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc, 29958c2ecf20Sopenharmony_ci size_t *rem) 29968c2ecf20Sopenharmony_ci{ 29978c2ecf20Sopenharmony_ci enum intel_pt_pkt_ctx ctx = INTEL_PT_NO_CTX; 29988c2ecf20Sopenharmony_ci struct intel_pt_pkt packet; 29998c2ecf20Sopenharmony_ci int ret; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci while (len) { 30028c2ecf20Sopenharmony_ci ret = intel_pt_get_packet(buf, len, &packet, &ctx); 30038c2ecf20Sopenharmony_ci if (ret <= 0) 30048c2ecf20Sopenharmony_ci return false; 30058c2ecf20Sopenharmony_ci if (packet.type == INTEL_PT_TSC) { 30068c2ecf20Sopenharmony_ci *tsc = packet.payload; 30078c2ecf20Sopenharmony_ci *rem = len; 30088c2ecf20Sopenharmony_ci return true; 30098c2ecf20Sopenharmony_ci } 30108c2ecf20Sopenharmony_ci if (packet.type == INTEL_PT_PSBEND) 30118c2ecf20Sopenharmony_ci return false; 30128c2ecf20Sopenharmony_ci buf += ret; 30138c2ecf20Sopenharmony_ci len -= ret; 30148c2ecf20Sopenharmony_ci } 30158c2ecf20Sopenharmony_ci return false; 30168c2ecf20Sopenharmony_ci} 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci/** 30198c2ecf20Sopenharmony_ci * intel_pt_tsc_cmp - compare 7-byte TSCs. 30208c2ecf20Sopenharmony_ci * @tsc1: first TSC to compare 30218c2ecf20Sopenharmony_ci * @tsc2: second TSC to compare 30228c2ecf20Sopenharmony_ci * 30238c2ecf20Sopenharmony_ci * This function compares 7-byte TSC values allowing for the possibility that 30248c2ecf20Sopenharmony_ci * TSC wrapped around. Generally it is not possible to know if TSC has wrapped 30258c2ecf20Sopenharmony_ci * around so for that purpose this function assumes the absolute difference is 30268c2ecf20Sopenharmony_ci * less than half the maximum difference. 30278c2ecf20Sopenharmony_ci * 30288c2ecf20Sopenharmony_ci * Return: %-1 if @tsc1 is before @tsc2, %0 if @tsc1 == @tsc2, %1 if @tsc1 is 30298c2ecf20Sopenharmony_ci * after @tsc2. 30308c2ecf20Sopenharmony_ci */ 30318c2ecf20Sopenharmony_cistatic int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) 30328c2ecf20Sopenharmony_ci{ 30338c2ecf20Sopenharmony_ci const uint64_t halfway = (1ULL << 55); 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci if (tsc1 == tsc2) 30368c2ecf20Sopenharmony_ci return 0; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci if (tsc1 < tsc2) { 30398c2ecf20Sopenharmony_ci if (tsc2 - tsc1 < halfway) 30408c2ecf20Sopenharmony_ci return -1; 30418c2ecf20Sopenharmony_ci else 30428c2ecf20Sopenharmony_ci return 1; 30438c2ecf20Sopenharmony_ci } else { 30448c2ecf20Sopenharmony_ci if (tsc1 - tsc2 < halfway) 30458c2ecf20Sopenharmony_ci return 1; 30468c2ecf20Sopenharmony_ci else 30478c2ecf20Sopenharmony_ci return -1; 30488c2ecf20Sopenharmony_ci } 30498c2ecf20Sopenharmony_ci} 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci#define MAX_PADDING (PERF_AUXTRACE_RECORD_ALIGNMENT - 1) 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci/** 30548c2ecf20Sopenharmony_ci * adj_for_padding - adjust overlap to account for padding. 30558c2ecf20Sopenharmony_ci * @buf_b: second buffer 30568c2ecf20Sopenharmony_ci * @buf_a: first buffer 30578c2ecf20Sopenharmony_ci * @len_a: size of first buffer 30588c2ecf20Sopenharmony_ci * 30598c2ecf20Sopenharmony_ci * @buf_a might have up to 7 bytes of padding appended. Adjust the overlap 30608c2ecf20Sopenharmony_ci * accordingly. 30618c2ecf20Sopenharmony_ci * 30628c2ecf20Sopenharmony_ci * Return: A pointer into @buf_b from where non-overlapped data starts 30638c2ecf20Sopenharmony_ci */ 30648c2ecf20Sopenharmony_cistatic unsigned char *adj_for_padding(unsigned char *buf_b, 30658c2ecf20Sopenharmony_ci unsigned char *buf_a, size_t len_a) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci unsigned char *p = buf_b - MAX_PADDING; 30688c2ecf20Sopenharmony_ci unsigned char *q = buf_a + len_a - MAX_PADDING; 30698c2ecf20Sopenharmony_ci int i; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci for (i = MAX_PADDING; i; i--, p++, q++) { 30728c2ecf20Sopenharmony_ci if (*p != *q) 30738c2ecf20Sopenharmony_ci break; 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci return p; 30778c2ecf20Sopenharmony_ci} 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci/** 30808c2ecf20Sopenharmony_ci * intel_pt_find_overlap_tsc - determine start of non-overlapped trace data 30818c2ecf20Sopenharmony_ci * using TSC. 30828c2ecf20Sopenharmony_ci * @buf_a: first buffer 30838c2ecf20Sopenharmony_ci * @len_a: size of first buffer 30848c2ecf20Sopenharmony_ci * @buf_b: second buffer 30858c2ecf20Sopenharmony_ci * @len_b: size of second buffer 30868c2ecf20Sopenharmony_ci * @consecutive: returns true if there is data in buf_b that is consecutive 30878c2ecf20Sopenharmony_ci * to buf_a 30888c2ecf20Sopenharmony_ci * 30898c2ecf20Sopenharmony_ci * If the trace contains TSC we can look at the last TSC of @buf_a and the 30908c2ecf20Sopenharmony_ci * first TSC of @buf_b in order to determine if the buffers overlap, and then 30918c2ecf20Sopenharmony_ci * walk forward in @buf_b until a later TSC is found. A precondition is that 30928c2ecf20Sopenharmony_ci * @buf_a and @buf_b are positioned at a PSB. 30938c2ecf20Sopenharmony_ci * 30948c2ecf20Sopenharmony_ci * Return: A pointer into @buf_b from where non-overlapped data starts, or 30958c2ecf20Sopenharmony_ci * @buf_b + @len_b if there is no non-overlapped data. 30968c2ecf20Sopenharmony_ci */ 30978c2ecf20Sopenharmony_cistatic unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, 30988c2ecf20Sopenharmony_ci size_t len_a, 30998c2ecf20Sopenharmony_ci unsigned char *buf_b, 31008c2ecf20Sopenharmony_ci size_t len_b, bool *consecutive) 31018c2ecf20Sopenharmony_ci{ 31028c2ecf20Sopenharmony_ci uint64_t tsc_a, tsc_b; 31038c2ecf20Sopenharmony_ci unsigned char *p; 31048c2ecf20Sopenharmony_ci size_t len, rem_a, rem_b; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci p = intel_pt_last_psb(buf_a, len_a); 31078c2ecf20Sopenharmony_ci if (!p) 31088c2ecf20Sopenharmony_ci return buf_b; /* No PSB in buf_a => no overlap */ 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci len = len_a - (p - buf_a); 31118c2ecf20Sopenharmony_ci if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) { 31128c2ecf20Sopenharmony_ci /* The last PSB+ in buf_a is incomplete, so go back one more */ 31138c2ecf20Sopenharmony_ci len_a -= len; 31148c2ecf20Sopenharmony_ci p = intel_pt_last_psb(buf_a, len_a); 31158c2ecf20Sopenharmony_ci if (!p) 31168c2ecf20Sopenharmony_ci return buf_b; /* No full PSB+ => assume no overlap */ 31178c2ecf20Sopenharmony_ci len = len_a - (p - buf_a); 31188c2ecf20Sopenharmony_ci if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) 31198c2ecf20Sopenharmony_ci return buf_b; /* No TSC in buf_a => assume no overlap */ 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci while (1) { 31238c2ecf20Sopenharmony_ci /* Ignore PSB+ with no TSC */ 31248c2ecf20Sopenharmony_ci if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) { 31258c2ecf20Sopenharmony_ci int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci /* Same TSC, so buffers are consecutive */ 31288c2ecf20Sopenharmony_ci if (!cmp && rem_b >= rem_a) { 31298c2ecf20Sopenharmony_ci unsigned char *start; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci *consecutive = true; 31328c2ecf20Sopenharmony_ci start = buf_b + len_b - (rem_b - rem_a); 31338c2ecf20Sopenharmony_ci return adj_for_padding(start, buf_a, len_a); 31348c2ecf20Sopenharmony_ci } 31358c2ecf20Sopenharmony_ci if (cmp < 0) 31368c2ecf20Sopenharmony_ci return buf_b; /* tsc_a < tsc_b => no overlap */ 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (!intel_pt_step_psb(&buf_b, &len_b)) 31408c2ecf20Sopenharmony_ci return buf_b + len_b; /* No PSB in buf_b => no data */ 31418c2ecf20Sopenharmony_ci } 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci/** 31458c2ecf20Sopenharmony_ci * intel_pt_find_overlap - determine start of non-overlapped trace data. 31468c2ecf20Sopenharmony_ci * @buf_a: first buffer 31478c2ecf20Sopenharmony_ci * @len_a: size of first buffer 31488c2ecf20Sopenharmony_ci * @buf_b: second buffer 31498c2ecf20Sopenharmony_ci * @len_b: size of second buffer 31508c2ecf20Sopenharmony_ci * @have_tsc: can use TSC packets to detect overlap 31518c2ecf20Sopenharmony_ci * @consecutive: returns true if there is data in buf_b that is consecutive 31528c2ecf20Sopenharmony_ci * to buf_a 31538c2ecf20Sopenharmony_ci * 31548c2ecf20Sopenharmony_ci * When trace samples or snapshots are recorded there is the possibility that 31558c2ecf20Sopenharmony_ci * the data overlaps. Note that, for the purposes of decoding, data is only 31568c2ecf20Sopenharmony_ci * useful if it begins with a PSB packet. 31578c2ecf20Sopenharmony_ci * 31588c2ecf20Sopenharmony_ci * Return: A pointer into @buf_b from where non-overlapped data starts, or 31598c2ecf20Sopenharmony_ci * @buf_b + @len_b if there is no non-overlapped data. 31608c2ecf20Sopenharmony_ci */ 31618c2ecf20Sopenharmony_ciunsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, 31628c2ecf20Sopenharmony_ci unsigned char *buf_b, size_t len_b, 31638c2ecf20Sopenharmony_ci bool have_tsc, bool *consecutive) 31648c2ecf20Sopenharmony_ci{ 31658c2ecf20Sopenharmony_ci unsigned char *found; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci /* Buffer 'b' must start at PSB so throw away everything before that */ 31688c2ecf20Sopenharmony_ci if (!intel_pt_next_psb(&buf_b, &len_b)) 31698c2ecf20Sopenharmony_ci return buf_b + len_b; /* No PSB */ 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci if (!intel_pt_next_psb(&buf_a, &len_a)) 31728c2ecf20Sopenharmony_ci return buf_b; /* No overlap */ 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (have_tsc) { 31758c2ecf20Sopenharmony_ci found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b, 31768c2ecf20Sopenharmony_ci consecutive); 31778c2ecf20Sopenharmony_ci if (found) 31788c2ecf20Sopenharmony_ci return found; 31798c2ecf20Sopenharmony_ci } 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci /* 31828c2ecf20Sopenharmony_ci * Buffer 'b' cannot end within buffer 'a' so, for comparison purposes, 31838c2ecf20Sopenharmony_ci * we can ignore the first part of buffer 'a'. 31848c2ecf20Sopenharmony_ci */ 31858c2ecf20Sopenharmony_ci while (len_b < len_a) { 31868c2ecf20Sopenharmony_ci if (!intel_pt_step_psb(&buf_a, &len_a)) 31878c2ecf20Sopenharmony_ci return buf_b; /* No overlap */ 31888c2ecf20Sopenharmony_ci } 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci /* Now len_b >= len_a */ 31918c2ecf20Sopenharmony_ci while (1) { 31928c2ecf20Sopenharmony_ci /* Potential overlap so check the bytes */ 31938c2ecf20Sopenharmony_ci found = memmem(buf_a, len_a, buf_b, len_a); 31948c2ecf20Sopenharmony_ci if (found) { 31958c2ecf20Sopenharmony_ci *consecutive = true; 31968c2ecf20Sopenharmony_ci return adj_for_padding(buf_b + len_a, buf_a, len_a); 31978c2ecf20Sopenharmony_ci } 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci /* Try again at next PSB in buffer 'a' */ 32008c2ecf20Sopenharmony_ci if (!intel_pt_step_psb(&buf_a, &len_a)) 32018c2ecf20Sopenharmony_ci return buf_b; /* No overlap */ 32028c2ecf20Sopenharmony_ci } 32038c2ecf20Sopenharmony_ci} 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci/** 32068c2ecf20Sopenharmony_ci * struct fast_forward_data - data used by intel_pt_ff_cb(). 32078c2ecf20Sopenharmony_ci * @timestamp: timestamp to fast forward towards 32088c2ecf20Sopenharmony_ci * @buf_timestamp: buffer timestamp of last buffer with trace data earlier than 32098c2ecf20Sopenharmony_ci * the fast forward timestamp. 32108c2ecf20Sopenharmony_ci */ 32118c2ecf20Sopenharmony_cistruct fast_forward_data { 32128c2ecf20Sopenharmony_ci uint64_t timestamp; 32138c2ecf20Sopenharmony_ci uint64_t buf_timestamp; 32148c2ecf20Sopenharmony_ci}; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci/** 32178c2ecf20Sopenharmony_ci * intel_pt_ff_cb - fast forward lookahead callback. 32188c2ecf20Sopenharmony_ci * @buffer: Intel PT trace buffer 32198c2ecf20Sopenharmony_ci * @data: opaque pointer to fast forward data (struct fast_forward_data) 32208c2ecf20Sopenharmony_ci * 32218c2ecf20Sopenharmony_ci * Determine if @buffer trace is past the fast forward timestamp. 32228c2ecf20Sopenharmony_ci * 32238c2ecf20Sopenharmony_ci * Return: 1 (stop lookahead) if @buffer trace is past the fast forward 32248c2ecf20Sopenharmony_ci * timestamp, and 0 otherwise. 32258c2ecf20Sopenharmony_ci */ 32268c2ecf20Sopenharmony_cistatic int intel_pt_ff_cb(struct intel_pt_buffer *buffer, void *data) 32278c2ecf20Sopenharmony_ci{ 32288c2ecf20Sopenharmony_ci struct fast_forward_data *d = data; 32298c2ecf20Sopenharmony_ci unsigned char *buf; 32308c2ecf20Sopenharmony_ci uint64_t tsc; 32318c2ecf20Sopenharmony_ci size_t rem; 32328c2ecf20Sopenharmony_ci size_t len; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci buf = (unsigned char *)buffer->buf; 32358c2ecf20Sopenharmony_ci len = buffer->len; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci if (!intel_pt_next_psb(&buf, &len) || 32388c2ecf20Sopenharmony_ci !intel_pt_next_tsc(buf, len, &tsc, &rem)) 32398c2ecf20Sopenharmony_ci return 0; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci tsc = intel_pt_8b_tsc(tsc, buffer->ref_timestamp); 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci intel_pt_log("Buffer 1st timestamp " x64_fmt " ref timestamp " x64_fmt "\n", 32448c2ecf20Sopenharmony_ci tsc, buffer->ref_timestamp); 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci /* 32478c2ecf20Sopenharmony_ci * If the buffer contains a timestamp earlier that the fast forward 32488c2ecf20Sopenharmony_ci * timestamp, then record it, else stop. 32498c2ecf20Sopenharmony_ci */ 32508c2ecf20Sopenharmony_ci if (tsc < d->timestamp) 32518c2ecf20Sopenharmony_ci d->buf_timestamp = buffer->ref_timestamp; 32528c2ecf20Sopenharmony_ci else 32538c2ecf20Sopenharmony_ci return 1; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci return 0; 32568c2ecf20Sopenharmony_ci} 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci/** 32598c2ecf20Sopenharmony_ci * intel_pt_fast_forward - reposition decoder forwards. 32608c2ecf20Sopenharmony_ci * @decoder: Intel PT decoder 32618c2ecf20Sopenharmony_ci * @timestamp: timestamp to fast forward towards 32628c2ecf20Sopenharmony_ci * 32638c2ecf20Sopenharmony_ci * Reposition decoder at the last PSB with a timestamp earlier than @timestamp. 32648c2ecf20Sopenharmony_ci * 32658c2ecf20Sopenharmony_ci * Return: 0 on success or negative error code on failure. 32668c2ecf20Sopenharmony_ci */ 32678c2ecf20Sopenharmony_ciint intel_pt_fast_forward(struct intel_pt_decoder *decoder, uint64_t timestamp) 32688c2ecf20Sopenharmony_ci{ 32698c2ecf20Sopenharmony_ci struct fast_forward_data d = { .timestamp = timestamp }; 32708c2ecf20Sopenharmony_ci unsigned char *buf; 32718c2ecf20Sopenharmony_ci size_t len; 32728c2ecf20Sopenharmony_ci int err; 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci intel_pt_log("Fast forward towards timestamp " x64_fmt "\n", timestamp); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci /* Find buffer timestamp of buffer to fast forward to */ 32778c2ecf20Sopenharmony_ci err = decoder->lookahead(decoder->data, intel_pt_ff_cb, &d); 32788c2ecf20Sopenharmony_ci if (err < 0) 32798c2ecf20Sopenharmony_ci return err; 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci /* Walk to buffer with same buffer timestamp */ 32828c2ecf20Sopenharmony_ci if (d.buf_timestamp) { 32838c2ecf20Sopenharmony_ci do { 32848c2ecf20Sopenharmony_ci decoder->pos += decoder->len; 32858c2ecf20Sopenharmony_ci decoder->len = 0; 32868c2ecf20Sopenharmony_ci err = intel_pt_get_next_data(decoder, true); 32878c2ecf20Sopenharmony_ci /* -ENOLINK means non-consecutive trace */ 32888c2ecf20Sopenharmony_ci if (err && err != -ENOLINK) 32898c2ecf20Sopenharmony_ci return err; 32908c2ecf20Sopenharmony_ci } while (decoder->buf_timestamp != d.buf_timestamp); 32918c2ecf20Sopenharmony_ci } 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci if (!decoder->buf) 32948c2ecf20Sopenharmony_ci return 0; 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci buf = (unsigned char *)decoder->buf; 32978c2ecf20Sopenharmony_ci len = decoder->len; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci if (!intel_pt_next_psb(&buf, &len)) 33008c2ecf20Sopenharmony_ci return 0; 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci /* 33038c2ecf20Sopenharmony_ci * Walk PSBs while the PSB timestamp is less than the fast forward 33048c2ecf20Sopenharmony_ci * timestamp. 33058c2ecf20Sopenharmony_ci */ 33068c2ecf20Sopenharmony_ci do { 33078c2ecf20Sopenharmony_ci uint64_t tsc; 33088c2ecf20Sopenharmony_ci size_t rem; 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci if (!intel_pt_next_tsc(buf, len, &tsc, &rem)) 33118c2ecf20Sopenharmony_ci break; 33128c2ecf20Sopenharmony_ci tsc = intel_pt_8b_tsc(tsc, decoder->buf_timestamp); 33138c2ecf20Sopenharmony_ci /* 33148c2ecf20Sopenharmony_ci * A TSC packet can slip past MTC packets but, after fast 33158c2ecf20Sopenharmony_ci * forward, decoding starts at the TSC timestamp. That means 33168c2ecf20Sopenharmony_ci * the timestamps may not be exactly the same as the timestamps 33178c2ecf20Sopenharmony_ci * that would have been decoded without fast forward. 33188c2ecf20Sopenharmony_ci */ 33198c2ecf20Sopenharmony_ci if (tsc < timestamp) { 33208c2ecf20Sopenharmony_ci intel_pt_log("Fast forward to next PSB timestamp " x64_fmt "\n", tsc); 33218c2ecf20Sopenharmony_ci decoder->pos += decoder->len - len; 33228c2ecf20Sopenharmony_ci decoder->buf = buf; 33238c2ecf20Sopenharmony_ci decoder->len = len; 33248c2ecf20Sopenharmony_ci intel_pt_reposition(decoder); 33258c2ecf20Sopenharmony_ci } else { 33268c2ecf20Sopenharmony_ci break; 33278c2ecf20Sopenharmony_ci } 33288c2ecf20Sopenharmony_ci } while (intel_pt_step_psb(&buf, &len)); 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci return 0; 33318c2ecf20Sopenharmony_ci} 3332