Commit d927ef50 authored by James Clark's avatar James Clark Committed by Arnaldo Carvalho de Melo

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: default avatarJames 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 8d3031d3
...@@ -52,15 +52,15 @@ struct cs_etm_decoder { ...@@ -52,15 +52,15 @@ struct cs_etm_decoder {
static u32 static u32
cs_etm_decoder__mem_access(const void *context, cs_etm_decoder__mem_access(const void *context,
const ocsd_vaddr_t address, const ocsd_vaddr_t address,
const ocsd_mem_space_acc_t mem_space __maybe_unused, const ocsd_mem_space_acc_t mem_space,
const u8 trace_chan_id, const u8 trace_chan_id,
const u32 req_size, const u32 req_size,
u8 *buffer) u8 *buffer)
{ {
struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context; struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
return decoder->mem_access(decoder->data, trace_chan_id, return decoder->mem_access(decoder->data, trace_chan_id, address,
address, req_size, buffer); req_size, buffer, mem_space);
} }
int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder, int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define INCLUDE__CS_ETM_DECODER_H__ #define INCLUDE__CS_ETM_DECODER_H__
#include <linux/types.h> #include <linux/types.h>
#include <opencsd/ocsd_if_types.h>
#include <stdio.h> #include <stdio.h>
struct cs_etm_decoder; struct cs_etm_decoder;
...@@ -19,7 +20,8 @@ struct cs_etm_packet_queue; ...@@ -19,7 +20,8 @@ struct cs_etm_packet_queue;
struct cs_etm_queue; struct cs_etm_queue;
typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *); typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *,
const ocsd_mem_space_acc_t);
struct cs_etmv3_trace_params { struct cs_etmv3_trace_params {
u32 reg_ctrl; u32 reg_ctrl;
......
...@@ -951,7 +951,8 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address, ...@@ -951,7 +951,8 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
} }
static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
u64 address, size_t size, u8 *buffer) u64 address, size_t size, u8 *buffer,
const ocsd_mem_space_acc_t mem_space)
{ {
u8 cpumode; u8 cpumode;
u64 offset; u64 offset;
...@@ -969,6 +970,24 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -969,6 +970,24 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
if (!tidq) if (!tidq)
goto out; goto out;
/*
* We've already tracked EL along side the PID in cs_etm__set_thread()
* so double check that it matches what OpenCSD thinks as well. It
* doesn't distinguish between EL0 and EL1 for this mem access callback
* so we had to do the extra tracking. Skip validation if it's any of
* the 'any' values.
*/
if (!(mem_space == OCSD_MEM_SPACE_ANY ||
mem_space == OCSD_MEM_SPACE_N || mem_space == OCSD_MEM_SPACE_S)) {
if (mem_space & OCSD_MEM_SPACE_EL1N) {
/* Includes both non secure EL1 and EL0 */
assert(tidq->el == ocsd_EL1 || tidq->el == ocsd_EL0);
} else if (mem_space & OCSD_MEM_SPACE_EL2)
assert(tidq->el == ocsd_EL2);
else if (mem_space & OCSD_MEM_SPACE_EL3)
assert(tidq->el == ocsd_EL3);
}
cpumode = cs_etm__cpu_mode(etmq, address, tidq->el); cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
if (!thread__find_map(tidq->thread, cpumode, address, &al)) if (!thread__find_map(tidq->thread, cpumode, address, &al))
...@@ -1219,8 +1238,8 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq, ...@@ -1219,8 +1238,8 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
{ {
u8 instrBytes[2]; u8 instrBytes[2];
cs_etm__mem_access(etmq, trace_chan_id, addr, cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes),
ARRAY_SIZE(instrBytes), instrBytes); instrBytes, 0);
/* /*
* T32 instruction size is indicated by bits[15:11] of the first * T32 instruction size is indicated by bits[15:11] of the first
* 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111 * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111
...@@ -1411,8 +1430,8 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq, ...@@ -1411,8 +1430,8 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
else else
sample->insn_len = 4; sample->insn_len = 4;
cs_etm__mem_access(etmq, trace_chan_id, sample->ip, cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len,
sample->insn_len, (void *)sample->insn); (void *)sample->insn, 0);
} }
u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp) u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp)
...@@ -1965,8 +1984,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -1965,8 +1984,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* so below only read 2 bytes as instruction size for T32. * so below only read 2 bytes as instruction size for T32.
*/ */
addr = end_addr - 2; addr = end_addr - 2;
cs_etm__mem_access(etmq, trace_chan_id, addr, cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16),
sizeof(instr16), (u8 *)&instr16); (u8 *)&instr16, 0);
if ((instr16 & 0xFF00) == 0xDF00) if ((instr16 & 0xFF00) == 0xDF00)
return true; return true;
...@@ -1981,8 +2000,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -1981,8 +2000,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* +---------+---------+-------------------------+ * +---------+---------+-------------------------+
*/ */
addr = end_addr - 4; addr = end_addr - 4;
cs_etm__mem_access(etmq, trace_chan_id, addr, cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
sizeof(instr32), (u8 *)&instr32); (u8 *)&instr32, 0);
if ((instr32 & 0x0F000000) == 0x0F000000 && if ((instr32 & 0x0F000000) == 0x0F000000 &&
(instr32 & 0xF0000000) != 0xF0000000) (instr32 & 0xF0000000) != 0xF0000000)
return true; return true;
...@@ -1998,8 +2017,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -1998,8 +2017,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* +-----------------------+---------+-----------+ * +-----------------------+---------+-----------+
*/ */
addr = end_addr - 4; addr = end_addr - 4;
cs_etm__mem_access(etmq, trace_chan_id, addr, cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
sizeof(instr32), (u8 *)&instr32); (u8 *)&instr32, 0);
if ((instr32 & 0xFFE0001F) == 0xd4000001) if ((instr32 & 0xFFE0001F) == 0xd4000001)
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment