Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf cs-etm: Add exception level consistency check

Assert that our own tracking of the exception level matches what
OpenCSD provides. OpenCSD doesn't distinguish between EL0 and EL1 in the
memory access callback so the extra tracking was required. But a rough
assert can still be done.

Signed-off-by: James Clark <james.clark@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20230612111403.100613-6-james.clark@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

James Clark and committed by
Arnaldo Carvalho de Melo
d927ef50 8d3031d3

+36 -15
+3 -3
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
··· 52 52 static u32 53 53 cs_etm_decoder__mem_access(const void *context, 54 54 const ocsd_vaddr_t address, 55 - const ocsd_mem_space_acc_t mem_space __maybe_unused, 55 + const ocsd_mem_space_acc_t mem_space, 56 56 const u8 trace_chan_id, 57 57 const u32 req_size, 58 58 u8 *buffer) 59 59 { 60 60 struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context; 61 61 62 - return decoder->mem_access(decoder->data, trace_chan_id, 63 - address, req_size, buffer); 62 + return decoder->mem_access(decoder->data, trace_chan_id, address, 63 + req_size, buffer, mem_space); 64 64 } 65 65 66 66 int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder,
+3 -1
tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
··· 11 11 #define INCLUDE__CS_ETM_DECODER_H__ 12 12 13 13 #include <linux/types.h> 14 + #include <opencsd/ocsd_if_types.h> 14 15 #include <stdio.h> 15 16 16 17 struct cs_etm_decoder; ··· 20 19 21 20 struct cs_etm_queue; 22 21 23 - typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *); 22 + typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *, 23 + const ocsd_mem_space_acc_t); 24 24 25 25 struct cs_etmv3_trace_params { 26 26 u32 reg_ctrl;
+30 -11
tools/perf/util/cs-etm.c
··· 951 951 } 952 952 953 953 static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, 954 - u64 address, size_t size, u8 *buffer) 954 + u64 address, size_t size, u8 *buffer, 955 + const ocsd_mem_space_acc_t mem_space) 955 956 { 956 957 u8 cpumode; 957 958 u64 offset; ··· 969 968 tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id); 970 969 if (!tidq) 971 970 goto out; 971 + 972 + /* 973 + * We've already tracked EL along side the PID in cs_etm__set_thread() 974 + * so double check that it matches what OpenCSD thinks as well. It 975 + * doesn't distinguish between EL0 and EL1 for this mem access callback 976 + * so we had to do the extra tracking. Skip validation if it's any of 977 + * the 'any' values. 978 + */ 979 + if (!(mem_space == OCSD_MEM_SPACE_ANY || 980 + mem_space == OCSD_MEM_SPACE_N || mem_space == OCSD_MEM_SPACE_S)) { 981 + if (mem_space & OCSD_MEM_SPACE_EL1N) { 982 + /* Includes both non secure EL1 and EL0 */ 983 + assert(tidq->el == ocsd_EL1 || tidq->el == ocsd_EL0); 984 + } else if (mem_space & OCSD_MEM_SPACE_EL2) 985 + assert(tidq->el == ocsd_EL2); 986 + else if (mem_space & OCSD_MEM_SPACE_EL3) 987 + assert(tidq->el == ocsd_EL3); 988 + } 972 989 973 990 cpumode = cs_etm__cpu_mode(etmq, address, tidq->el); 974 991 ··· 1238 1219 { 1239 1220 u8 instrBytes[2]; 1240 1221 1241 - cs_etm__mem_access(etmq, trace_chan_id, addr, 1242 - ARRAY_SIZE(instrBytes), instrBytes); 1222 + cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes), 1223 + instrBytes, 0); 1243 1224 /* 1244 1225 * T32 instruction size is indicated by bits[15:11] of the first 1245 1226 * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111 ··· 1430 1411 else 1431 1412 sample->insn_len = 4; 1432 1413 1433 - cs_etm__mem_access(etmq, trace_chan_id, sample->ip, 1434 - sample->insn_len, (void *)sample->insn); 1414 + cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len, 1415 + (void *)sample->insn, 0); 1435 1416 } 1436 1417 1437 1418 u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp) ··· 1984 1965 * so below only read 2 bytes as instruction size for T32. 1985 1966 */ 1986 1967 addr = end_addr - 2; 1987 - cs_etm__mem_access(etmq, trace_chan_id, addr, 1988 - sizeof(instr16), (u8 *)&instr16); 1968 + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16), 1969 + (u8 *)&instr16, 0); 1989 1970 if ((instr16 & 0xFF00) == 0xDF00) 1990 1971 return true; 1991 1972 ··· 2000 1981 * +---------+---------+-------------------------+ 2001 1982 */ 2002 1983 addr = end_addr - 4; 2003 - cs_etm__mem_access(etmq, trace_chan_id, addr, 2004 - sizeof(instr32), (u8 *)&instr32); 1984 + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32), 1985 + (u8 *)&instr32, 0); 2005 1986 if ((instr32 & 0x0F000000) == 0x0F000000 && 2006 1987 (instr32 & 0xF0000000) != 0xF0000000) 2007 1988 return true; ··· 2017 1998 * +-----------------------+---------+-----------+ 2018 1999 */ 2019 2000 addr = end_addr - 4; 2020 - cs_etm__mem_access(etmq, trace_chan_id, addr, 2021 - sizeof(instr32), (u8 *)&instr32); 2001 + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32), 2002 + (u8 *)&instr32, 0); 2022 2003 if ((instr32 & 0xFFE0001F) == 0xd4000001) 2023 2004 return true; 2024 2005