linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] perf cs-etm: Track exception level
@ 2023-06-08 10:59 James Clark
  2023-06-08 10:59 ` [PATCH v2 1/5] perf cs-etm: Only track threads instead of PID and TIDs James Clark
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Suzuki K Poulose, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

Changes since v1:

  * Always assume host kernel when the trace was captured at EL1 (nVHE)
  * Fix EL validation to work with ETMv3
  * Add a commit to make PID format accessible from struct
    cs_etm_auxtrace

======

Some fixes to support an issue reported by Denis Nikitin where decoding
trace that contains different EL1 and EL2 kernels can crash or go into
an infinite loop because the wrong kernel maps are used for the decode.

This still doesn't support distinguishing guest and host userspace,
we'd still have to fix the timestamps and do a bit more work to
correlate that. And I've removed PERF_RECORD_MISC_HYPERVISOR as a
possible outcome of cs_etm__cpu_mode(). As far as I know this could
never have been returned anyway because machine__is_host(machine) was
always true due to session.machines.host being hard coded. And I'm not
sure of the relevance of the difference between PERF_RECORD_MISC_KERNEL
and PERF_RECORD_MISC_HYPERVISOR in this scenario.

The first commit is a tidy up, second fixes a bug that I found when
comparing the exception level and thread of branch records, the third
is the main fix, and the last commit is some extra error checking. 

Applies to acme/perf-tools (48b1320a67)

James Clark (5):
  perf cs-etm: Only track threads instead of PID and TIDs
  perf cs-etm: Use previous thread for branch sample source IP
  perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace
  perf cs-etm: Track exception level
  perf cs-etm: Add exception level consistency check

 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  33 +--
 .../perf/util/cs-etm-decoder/cs-etm-decoder.h |   4 +-
 tools/perf/util/cs-etm.c                      | 273 ++++++++++--------
 tools/perf/util/cs-etm.h                      |  13 +-
 4 files changed, 175 insertions(+), 148 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/5] perf cs-etm: Only track threads instead of PID and TIDs
  2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
@ 2023-06-08 10:59 ` James Clark
  2023-06-08 10:59 ` [PATCH v2 2/5] perf cs-etm: Use previous thread for branch sample source IP James Clark
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Suzuki K Poulose, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

PIDs and TIDs are already contained within the thread struct, so to
avoid inconsistencies drop the extra members on the etm queue and only
use the thread struct.

At the same time stop using the 'unknown' thread. In a later commit
we will be making samples from multiple machines so it will be better
to use the idle thread of each machine rather than overlapping unknown
threads. Using the idle thread is also better because kernel addresses
with a previously unknown thread will now be assigned to a real kernel
thread.

Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Reviewed-by: Leo Yan <leo.yan@linaro.org>
Signed-off-by: James Clark <james.clark@arm.com>
---
 tools/perf/util/cs-etm.c | 124 ++++++++++++---------------------------
 1 file changed, 38 insertions(+), 86 deletions(-)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 91299cc56bf7..ebffc9052561 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -46,8 +46,6 @@ struct cs_etm_auxtrace {
 	struct auxtrace_heap heap;
 	struct itrace_synth_opts synth_opts;
 	struct perf_session *session;
-	struct machine *machine;
-	struct thread *unknown_thread;
 	struct perf_tsc_conversion tc;
 
 	/*
@@ -84,7 +82,6 @@ struct cs_etm_auxtrace {
 
 struct cs_etm_traceid_queue {
 	u8 trace_chan_id;
-	pid_t pid, tid;
 	u64 period_instructions;
 	size_t last_branch_pos;
 	union perf_event *event_buf;
@@ -480,9 +477,9 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 	cs_etm__clear_packet_queue(&tidq->packet_queue);
 
 	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
-	tidq->tid = queue->tid;
-	tidq->pid = -1;
 	tidq->trace_chan_id = trace_chan_id;
+	tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
+					       queue->tid);
 
 	tidq->packet = zalloc(sizeof(struct cs_etm_packet));
 	if (!tidq->packet)
@@ -863,7 +860,6 @@ static void cs_etm__free(struct perf_session *session)
 	for (i = 0; i < aux->num_cpu; i++)
 		zfree(&aux->metadata[i]);
 
-	thread__zput(aux->unknown_thread);
 	zfree(&aux->metadata);
 	zfree(&aux);
 }
@@ -882,7 +878,7 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
 {
 	struct machine *machine;
 
-	machine = etmq->etm->machine;
+	machine = &etmq->etm->session->machines.host;
 
 	if (address >= machine__kernel_start(machine)) {
 		if (machine__is_host(machine))
@@ -905,8 +901,6 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
 	u8  cpumode;
 	u64 offset;
 	int len;
-	struct thread *thread;
-	struct machine *machine;
 	struct addr_location al;
 	struct dso *dso;
 	struct cs_etm_traceid_queue *tidq;
@@ -914,20 +908,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
 	if (!etmq)
 		return 0;
 
-	machine = etmq->etm->machine;
 	cpumode = cs_etm__cpu_mode(etmq, address);
 	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
 	if (!tidq)
 		return 0;
 
-	thread = tidq->thread;
-	if (!thread) {
-		if (cpumode != PERF_RECORD_MISC_KERNEL)
-			return 0;
-		thread = etmq->etm->unknown_thread;
-	}
-
-	if (!thread__find_map(thread, cpumode, address, &al))
+	if (!thread__find_map(tidq->thread, cpumode, address, &al))
 		return 0;
 
 	dso = map__dso(al.map);
@@ -942,7 +928,8 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
 
 	map__load(al.map);
 
-	len = dso__data_read_offset(dso, machine, offset, buffer, size);
+	len = dso__data_read_offset(dso, maps__machine(tidq->thread->maps),
+				    offset, buffer, size);
 
 	if (len <= 0) {
 		ui__warning_once("CS ETM Trace: Missing DSO. Use 'perf archive' or debuginfod to export data from the traced system.\n"
@@ -1303,39 +1290,31 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
 	return etmq->buf_len;
 }
 
-static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm,
-				    struct cs_etm_traceid_queue *tidq)
+static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
+			       struct cs_etm_traceid_queue *tidq, pid_t tid)
 {
-	if ((!tidq->thread) && (tidq->tid != -1))
-		tidq->thread = machine__find_thread(etm->machine, -1,
-						    tidq->tid);
+	struct machine *machine = &etm->session->machines.host;
+
+	if (tid != -1) {
+		thread__zput(tidq->thread);
+		tidq->thread = machine__find_thread(machine, -1, tid);
+	}
 
-	if (tidq->thread)
-		tidq->pid = tidq->thread->pid_;
+	/* Couldn't find a known thread */
+	if (!tidq->thread)
+		tidq->thread = machine__idle_thread(machine);
 }
 
 int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
 			 pid_t tid, u8 trace_chan_id)
 {
-	int cpu, err = -EINVAL;
-	struct cs_etm_auxtrace *etm = etmq->etm;
 	struct cs_etm_traceid_queue *tidq;
 
 	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
 	if (!tidq)
-		return err;
-
-	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
-		return err;
-
-	err = machine__set_current_tid(etm->machine, cpu, tid, tid);
-	if (err)
-		return err;
-
-	tidq->tid = tid;
-	thread__zput(tidq->thread);
+		return -EINVAL;
 
-	cs_etm__set_pid_tid_cpu(etm, tidq);
+	cs_etm__set_thread(etmq->etm, tidq, tid);
 	return 0;
 }
 
@@ -1412,8 +1391,8 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
 	sample.time = cs_etm__resolve_sample_time(etmq, tidq);
 
 	sample.ip = addr;
-	sample.pid = tidq->pid;
-	sample.tid = tidq->tid;
+	sample.pid = tidq->thread->pid_;
+	sample.tid = tidq->thread->tid;
 	sample.id = etmq->etm->instructions_id;
 	sample.stream_id = etmq->etm->instructions_id;
 	sample.period = period;
@@ -1471,8 +1450,8 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
 	sample.time = cs_etm__resolve_sample_time(etmq, tidq);
 
 	sample.ip = ip;
-	sample.pid = tidq->pid;
-	sample.tid = tidq->tid;
+	sample.pid = tidq->thread->pid_;
+	sample.tid = tidq->thread->tid;
 	sample.addr = cs_etm__first_executed_instr(tidq->packet);
 	sample.id = etmq->etm->branches_id;
 	sample.stream_id = etmq->etm->branches_id;
@@ -2466,11 +2445,6 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
 		if (!etmq)
 			continue;
 
-		/*
-		 * Per-cpu mode has contextIDs in the trace and the decoder
-		 * calls cs_etm__set_pid_tid_cpu() automatically so no need
-		 * to do this here
-		 */
 		if (etm->per_thread_decoding) {
 			tidq = cs_etm__etmq_get_traceid_queue(
 				etmq, CS_ETM_PER_THREAD_TRACEID);
@@ -2478,10 +2452,8 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
 			if (!tidq)
 				continue;
 
-			if ((tid == -1) || (tidq->tid == tid)) {
-				cs_etm__set_pid_tid_cpu(etm, tidq);
+			if (tid == -1 || tidq->thread->tid == tid)
 				cs_etm__run_per_thread_timeless_decoder(etmq);
-			}
 		} else
 			cs_etm__run_per_cpu_timeless_decoder(etmq);
 	}
@@ -2611,10 +2583,12 @@ static int cs_etm__process_itrace_start(struct cs_etm_auxtrace *etm,
 		return 0;
 
 	/*
-	 * Add the tid/pid to the log so that we can get a match when
-	 * we get a contextID from the decoder.
+	 * Add the tid/pid to the log so that we can get a match when we get a
+	 * contextID from the decoder. Only track for the host: only kernel
+	 * trace is supported for guests which wouldn't need pids so this should
+	 * be fine.
 	 */
-	th = machine__findnew_thread(etm->machine,
+	th = machine__findnew_thread(&etm->session->machines.host,
 				     event->itrace_start.pid,
 				     event->itrace_start.tid);
 	if (!th)
@@ -2647,10 +2621,12 @@ static int cs_etm__process_switch_cpu_wide(struct cs_etm_auxtrace *etm,
 		return 0;
 
 	/*
-	 * Add the tid/pid to the log so that we can get a match when
-	 * we get a contextID from the decoder.
+	 * Add the tid/pid to the log so that we can get a match when we get a
+	 * contextID from the decoder. Only track for the host: only kernel
+	 * trace is supported for guests which wouldn't need pids so this should
+	 * be fine.
 	 */
-	th = machine__findnew_thread(etm->machine,
+	th = machine__findnew_thread(&etm->session->machines.host,
 				     event->context_switch.next_prev_pid,
 				     event->context_switch.next_prev_tid);
 	if (!th)
@@ -3259,7 +3235,6 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 	}
 
 	etm->session = session;
-	etm->machine = &session->machines.host;
 
 	etm->num_cpu = num_cpu;
 	etm->pmu_type = (unsigned int) ((ptr[CS_PMU_TYPE_CPUS] >> 32) & 0xffffffff);
@@ -3286,27 +3261,6 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 	if (err)
 		return err;
 
-	etm->unknown_thread = thread__new(999999999, 999999999);
-	if (!etm->unknown_thread) {
-		err = -ENOMEM;
-		goto err_free_queues;
-	}
-
-	/*
-	 * Initialize list node so that at thread__zput() we can avoid
-	 * segmentation fault at list_del_init().
-	 */
-	INIT_LIST_HEAD(&etm->unknown_thread->node);
-
-	err = thread__set_comm(etm->unknown_thread, "unknown", 0);
-	if (err)
-		goto err_delete_thread;
-
-	if (thread__init_maps(etm->unknown_thread, etm->machine)) {
-		err = -ENOMEM;
-		goto err_delete_thread;
-	}
-
 	etm->tc.time_shift = tc->time_shift;
 	etm->tc.time_mult = tc->time_mult;
 	etm->tc.time_zero = tc->time_zero;
@@ -3318,7 +3272,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 	}
 	err = cs_etm__synth_events(etm, session);
 	if (err)
-		goto err_delete_thread;
+		goto err_free_queues;
 
 	/*
 	 * Map Trace ID values to CPU metadata.
@@ -3348,7 +3302,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 					session->header.data_size,
 					cs_etm__process_aux_hw_id_cb, &aux_hw_id_found);
 	if (err)
-		goto err_delete_thread;
+		goto err_free_queues;
 
 	/* if HW ID found then clear any unused metadata ID values */
 	if (aux_hw_id_found)
@@ -3358,17 +3312,15 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 		err = cs_etm__map_trace_ids_metadata(num_cpu, metadata);
 
 	if (err)
-		goto err_delete_thread;
+		goto err_free_queues;
 
 	err = cs_etm__queue_aux_records(session);
 	if (err)
-		goto err_delete_thread;
+		goto err_free_queues;
 
 	etm->data_queued = etm->queues.populated;
 	return 0;
 
-err_delete_thread:
-	thread__zput(etm->unknown_thread);
 err_free_queues:
 	auxtrace_queues__free(&etm->queues);
 	session->auxtrace = NULL;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/5] perf cs-etm: Use previous thread for branch sample source IP
  2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
  2023-06-08 10:59 ` [PATCH v2 1/5] perf cs-etm: Only track threads instead of PID and TIDs James Clark
@ 2023-06-08 10:59 ` James Clark
  2023-06-08 10:59 ` [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace James Clark
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Mike Leach, Suzuki K Poulose, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

Branch samples currently use the IP of the previous packet as the from
IP, and the IP of the current packet as the to IP. But it incorrectly
uses the current thread. In some cases like a jump into a different
exception level this will attribute to the incorrect process.

Fix it by tracking the previous thread in the same way the previous
packet is tracked.

Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: James Clark <james.clark@arm.com>
---
 tools/perf/util/cs-etm.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index ebffc9052561..a997fe79d458 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -86,6 +86,7 @@ struct cs_etm_traceid_queue {
 	size_t last_branch_pos;
 	union perf_event *event_buf;
 	struct thread *thread;
+	struct thread *prev_thread;
 	struct branch_stack *last_branch;
 	struct branch_stack *last_branch_rb;
 	struct cs_etm_packet *prev_packet;
@@ -480,6 +481,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 	tidq->trace_chan_id = trace_chan_id;
 	tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
 					       queue->tid);
+	tidq->prev_thread = machine__idle_thread(&etm->session->machines.host);
 
 	tidq->packet = zalloc(sizeof(struct cs_etm_packet));
 	if (!tidq->packet)
@@ -616,6 +618,8 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
 		tmp = tidq->packet;
 		tidq->packet = tidq->prev_packet;
 		tidq->prev_packet = tmp;
+		thread__put(tidq->prev_thread);
+		tidq->prev_thread = thread__get(tidq->thread);
 	}
 }
 
@@ -791,6 +795,7 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
 		/* Free this traceid_queue from the array */
 		tidq = etmq->traceid_queues[idx];
 		thread__zput(tidq->thread);
+		thread__zput(tidq->prev_thread);
 		zfree(&tidq->event_buf);
 		zfree(&tidq->last_branch);
 		zfree(&tidq->last_branch_rb);
@@ -1450,8 +1455,8 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
 	sample.time = cs_etm__resolve_sample_time(etmq, tidq);
 
 	sample.ip = ip;
-	sample.pid = tidq->thread->pid_;
-	sample.tid = tidq->thread->tid;
+	sample.pid = tidq->prev_thread->pid_;
+	sample.tid = tidq->prev_thread->tid;
 	sample.addr = cs_etm__first_executed_instr(tidq->packet);
 	sample.id = etmq->etm->branches_id;
 	sample.stream_id = etmq->etm->branches_id;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace
  2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
  2023-06-08 10:59 ` [PATCH v2 1/5] perf cs-etm: Only track threads instead of PID and TIDs James Clark
  2023-06-08 10:59 ` [PATCH v2 2/5] perf cs-etm: Use previous thread for branch sample source IP James Clark
@ 2023-06-08 10:59 ` James Clark
  2023-06-10  1:32   ` Leo Yan
  2023-06-08 10:59 ` [PATCH v2 4/5] perf cs-etm: Track exception level James Clark
  2023-06-08 10:59 ` [PATCH v2 5/5] perf cs-etm: Add exception level consistency check James Clark
  4 siblings, 1 reply; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Suzuki K Poulose, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

To avoid every user of PID format having to use their own static
local variable, cache it on initialisation and change the accessor to
take struct cs_etm_auxtrace.

Signed-off-by: James Clark <james.clark@arm.com>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 20 ++-------
 tools/perf/util/cs-etm.c                      | 42 ++++++++++++-------
 tools/perf/util/cs-etm.h                      |  8 +++-
 3 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 82a27ab90c8b..2af641d26866 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -541,34 +541,22 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
 			const uint8_t trace_chan_id)
 {
 	pid_t tid = -1;
-	static u64 pid_fmt;
-	int ret;
-
-	/*
-	 * As all the ETMs run at the same exception level, the system should
-	 * have the same PID format crossing CPUs.  So cache the PID format
-	 * and reuse it for sequential decoding.
-	 */
-	if (!pid_fmt) {
-		ret = cs_etm__get_pid_fmt(trace_chan_id, &pid_fmt);
-		if (ret)
-			return OCSD_RESP_FATAL_SYS_ERR;
-	}
 
 	/*
 	 * Process the PE_CONTEXT packets if we have a valid contextID or VMID.
 	 * If the kernel is running at EL2, the PID is traced in CONTEXTIDR_EL2
 	 * as VMID, Bit ETM_OPT_CTXTID2 is set in this case.
 	 */
-	switch (pid_fmt) {
-	case BIT(ETM_OPT_CTXTID):
+	switch (cs_etm__get_pid_fmt(etmq)) {
+	case CS_ETM_PIDFMT_CTXTID:
 		if (elem->context.ctxt_id_valid)
 			tid = elem->context.context_id;
 		break;
-	case BIT(ETM_OPT_CTXTID2):
+	case CS_ETM_PIDFMT_CTXTID2:
 		if (elem->context.vmid_valid)
 			tid = elem->context.vmid;
 		break;
+	case CS_ETM_PIDFMT_NONE:
 	default:
 		break;
 	}
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index a997fe79d458..e0904f276e89 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -78,6 +78,7 @@ struct cs_etm_auxtrace {
 	u64 instructions_id;
 	u64 **metadata;
 	unsigned int pmu_type;
+	enum cs_etm_pid_fmt pid_fmt;
 };
 
 struct cs_etm_traceid_queue {
@@ -170,44 +171,46 @@ int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
 }
 
 /*
- * The returned PID format is presented by two bits:
+ * The returned PID format is presented as an enum:
  *
- *   Bit ETM_OPT_CTXTID: CONTEXTIDR or CONTEXTIDR_EL1 is traced;
- *   Bit ETM_OPT_CTXTID2: CONTEXTIDR_EL2 is traced.
+ *   CS_ETM_PIDFMT_CTXTID: CONTEXTIDR or CONTEXTIDR_EL1 is traced.
+ *   CS_ETM_PIDFMT_CTXTID2: CONTEXTIDR_EL2 is traced.
+ *   CS_ETM_PIDFMT_NONE: No context IDs
  *
  * It's possible that the two bits ETM_OPT_CTXTID and ETM_OPT_CTXTID2
  * are enabled at the same time when the session runs on an EL2 kernel.
  * This means the CONTEXTIDR_EL1 and CONTEXTIDR_EL2 both will be
  * recorded in the trace data, the tool will selectively use
  * CONTEXTIDR_EL2 as PID.
+ *
+ * The result is cached in etm->pid_fmt so this function only needs to be called
+ * when processing the aux info.
  */
-int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt)
+static enum cs_etm_pid_fmt cs_etm__init_pid_fmt(u64 *metadata)
 {
-	struct int_node *inode;
-	u64 *metadata, val;
-
-	inode = intlist__find(traceid_list, trace_chan_id);
-	if (!inode)
-		return -EINVAL;
-
-	metadata = inode->priv;
+	u64 val;
 
 	if (metadata[CS_ETM_MAGIC] == __perf_cs_etmv3_magic) {
 		val = metadata[CS_ETM_ETMCR];
 		/* CONTEXTIDR is traced */
 		if (val & BIT(ETM_OPT_CTXTID))
-			*pid_fmt = BIT(ETM_OPT_CTXTID);
+			return CS_ETM_PIDFMT_CTXTID;
 	} else {
 		val = metadata[CS_ETMV4_TRCCONFIGR];
 		/* CONTEXTIDR_EL2 is traced */
 		if (val & (BIT(ETM4_CFG_BIT_VMID) | BIT(ETM4_CFG_BIT_VMID_OPT)))
-			*pid_fmt = BIT(ETM_OPT_CTXTID2);
+			return CS_ETM_PIDFMT_CTXTID2;
 		/* CONTEXTIDR_EL1 is traced */
 		else if (val & BIT(ETM4_CFG_BIT_CTXTID))
-			*pid_fmt = BIT(ETM_OPT_CTXTID);
+			return CS_ETM_PIDFMT_CTXTID;
 	}
 
-	return 0;
+	return CS_ETM_PIDFMT_NONE;
+}
+
+enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq)
+{
+	return etmq->etm->pid_fmt;
 }
 
 static int cs_etm__map_trace_id(u8 trace_chan_id, u64 *cpu_metadata)
@@ -3227,6 +3230,13 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
 		goto err_free_metadata;
 	}
 
+	/*
+	 * As all the ETMs run at the same exception level, the system should
+	 * have the same PID format crossing CPUs.  So cache the PID format
+	 * and reuse it for sequential decoding.
+	 */
+	etm->pid_fmt = cs_etm__init_pid_fmt(metadata[0]);
+
 	err = auxtrace_queues__init(&etm->queues);
 	if (err)
 		goto err_free_etm;
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index ecca40787ac9..2f47f4ec5b27 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -244,9 +244,15 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
 				  struct perf_session *session);
 struct perf_event_attr *cs_etm_get_default_config(struct perf_pmu *pmu);
 
+enum cs_etm_pid_fmt {
+	CS_ETM_PIDFMT_NONE,
+	CS_ETM_PIDFMT_CTXTID,
+	CS_ETM_PIDFMT_CTXTID2
+};
+
 #ifdef HAVE_CSTRACE_SUPPORT
 int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
-int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt);
+enum pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
 int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
 			 pid_t tid, u8 trace_chan_id);
 bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/5] perf cs-etm: Track exception level
  2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
                   ` (2 preceding siblings ...)
  2023-06-08 10:59 ` [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace James Clark
@ 2023-06-08 10:59 ` James Clark
  2023-06-10  2:33   ` Leo Yan
  2023-06-08 10:59 ` [PATCH v2 5/5] perf cs-etm: Add exception level consistency check James Clark
  4 siblings, 1 reply; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Suzuki K Poulose, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

Currently we assume all trace belongs to the host machine so when
the decoder should be looking at the guest kernel maps it can crash
because it looks at the host ones instead.

Avoid one scenario (guest kernel running at EL1) by assigning the
default guest machine to this trace. For userspace trace it's still not
possible to determine guest vs host, but the PIDs should help in this
case.

Signed-off-by: James Clark <james.clark@arm.com>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  7 +-
 tools/perf/util/cs-etm.c                      | 75 +++++++++++++++----
 tools/perf/util/cs-etm.h                      |  7 +-
 3 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 2af641d26866..44c49acd6bff 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -561,12 +561,13 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
 		break;
 	}
 
+	if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
+				    elem->context.exception_level))
+		return OCSD_RESP_FATAL_SYS_ERR;
+
 	if (tid == -1)
 		return OCSD_RESP_CONT;
 
-	if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id))
-		return OCSD_RESP_FATAL_SYS_ERR;
-
 	/*
 	 * A timestamp is generated after a PE_CONTEXT element so make sure
 	 * to rely on that coming one.
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index e0904f276e89..916e86f003f4 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -14,7 +14,6 @@
 #include <linux/types.h>
 #include <linux/zalloc.h>
 
-#include <opencsd/ocsd_if_types.h>
 #include <stdlib.h>
 
 #include "auxtrace.h"
@@ -88,6 +87,8 @@ struct cs_etm_traceid_queue {
 	union perf_event *event_buf;
 	struct thread *thread;
 	struct thread *prev_thread;
+	ocsd_ex_level prev_el;
+	ocsd_ex_level el;
 	struct branch_stack *last_branch;
 	struct branch_stack *last_branch_rb;
 	struct cs_etm_packet *prev_packet;
@@ -482,6 +483,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 
 	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
 	tidq->trace_chan_id = trace_chan_id;
+	tidq->el = tidq->prev_el = ocsd_EL_unknown;
 	tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
 					       queue->tid);
 	tidq->prev_thread = machine__idle_thread(&etm->session->machines.host);
@@ -621,6 +623,7 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
 		tmp = tidq->packet;
 		tidq->packet = tidq->prev_packet;
 		tidq->prev_packet = tmp;
+		tidq->prev_el = tidq->el;
 		thread__put(tidq->prev_thread);
 		tidq->prev_thread = thread__get(tidq->thread);
 	}
@@ -882,11 +885,43 @@ static bool cs_etm__evsel_is_auxtrace(struct perf_session *session,
 	return evsel->core.attr.type == aux->pmu_type;
 }
 
-static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
+static struct machine *cs_etm__get_machine(struct cs_etm_queue *etmq,
+					   ocsd_ex_level el)
 {
-	struct machine *machine;
+	enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
 
-	machine = &etmq->etm->session->machines.host;
+	/*
+	 * For any virtualisation based on nVHE (e.g. pKVM), or host kernels
+	 * running at EL1 assume everything is the host.
+	 */
+	if (pid_fmt == CS_ETM_PIDFMT_CTXTID)
+		return &etmq->etm->session->machines.host;
+
+	/*
+	 * Not perfect, but otherwise assume anything in EL1 is the default
+	 * guest, and everything else is the host. Distinguishing between guest
+	 * and host userspaces isn't currently supported either. Neither is
+	 * multiple guest support. All this does is reduce the likeliness of
+	 * decode errors where we look into the host kernel maps when it should
+	 * have been the guest maps.
+	 */
+	switch (el) {
+	case ocsd_EL1:
+		return machines__find_guest(&etmq->etm->session->machines,
+					    DEFAULT_GUEST_KERNEL_ID);
+	case ocsd_EL3:
+	case ocsd_EL2:
+	case ocsd_EL0:
+	case ocsd_EL_unknown:
+	default:
+		return &etmq->etm->session->machines.host;
+	}
+}
+
+static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
+			   ocsd_ex_level el)
+{
+	struct machine *machine = cs_etm__get_machine(etmq, el);
 
 	if (address >= machine__kernel_start(machine)) {
 		if (machine__is_host(machine))
@@ -896,10 +931,14 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
 	} else {
 		if (machine__is_host(machine))
 			return PERF_RECORD_MISC_USER;
-		else if (perf_guest)
+		else {
+			/*
+			 * Can't really happen at the moment because
+			 * cs_etm__get_machine() will always return
+			 * machines.host for any non EL1 trace.
+			 */
 			return PERF_RECORD_MISC_GUEST_USER;
-		else
-			return PERF_RECORD_MISC_HYPERVISOR;
+		}
 	}
 }
 
@@ -916,11 +955,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
 	if (!etmq)
 		return 0;
 
-	cpumode = cs_etm__cpu_mode(etmq, address);
 	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
 	if (!tidq)
 		return 0;
 
+	cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
+
 	if (!thread__find_map(tidq->thread, cpumode, address, &al))
 		return 0;
 
@@ -1298,10 +1338,11 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
 	return etmq->buf_len;
 }
 
-static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
-			       struct cs_etm_traceid_queue *tidq, pid_t tid)
+static void cs_etm__set_thread(struct cs_etm_queue *etmq,
+			       struct cs_etm_traceid_queue *tidq, pid_t tid,
+			       ocsd_ex_level el)
 {
-	struct machine *machine = &etm->session->machines.host;
+	struct machine *machine = cs_etm__get_machine(etmq, el);
 
 	if (tid != -1) {
 		thread__zput(tidq->thread);
@@ -1311,10 +1352,12 @@ static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
 	/* Couldn't find a known thread */
 	if (!tidq->thread)
 		tidq->thread = machine__idle_thread(machine);
+
+	tidq->el = el;
 }
 
-int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
-			 pid_t tid, u8 trace_chan_id)
+int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
+			    u8 trace_chan_id, ocsd_ex_level el)
 {
 	struct cs_etm_traceid_queue *tidq;
 
@@ -1322,7 +1365,7 @@ int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
 	if (!tidq)
 		return -EINVAL;
 
-	cs_etm__set_thread(etmq->etm, tidq, tid);
+	cs_etm__set_thread(etmq, tidq, tid, el);
 	return 0;
 }
 
@@ -1392,7 +1435,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
 	struct perf_sample sample = {.ip = 0,};
 
 	event->sample.header.type = PERF_RECORD_SAMPLE;
-	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
+	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el);
 	event->sample.header.size = sizeof(struct perf_event_header);
 
 	/* Set time field based on etm auxtrace config. */
@@ -1451,7 +1494,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
 	ip = cs_etm__last_executed_instr(tidq->prev_packet);
 
 	event->sample.header.type = PERF_RECORD_SAMPLE;
-	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
+	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip, tidq->prev_el);
 	event->sample.header.size = sizeof(struct perf_event_header);
 
 	/* Set time field based on etm auxtrace config. */
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index 2f47f4ec5b27..7cca37887917 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -251,10 +251,11 @@ enum cs_etm_pid_fmt {
 };
 
 #ifdef HAVE_CSTRACE_SUPPORT
+#include <opencsd/ocsd_if_types.h>
 int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
-enum pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
-int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
-			 pid_t tid, u8 trace_chan_id);
+enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
+int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
+			    u8 trace_chan_id, ocsd_ex_level el);
 bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
 void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
 					      u8 trace_chan_id);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 5/5] perf cs-etm: Add exception level consistency check
  2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
                   ` (3 preceding siblings ...)
  2023-06-08 10:59 ` [PATCH v2 4/5] perf cs-etm: Track exception level James Clark
@ 2023-06-08 10:59 ` James Clark
  4 siblings, 0 replies; 9+ messages in thread
From: James Clark @ 2023-06-08 10:59 UTC (permalink / raw)
  To: coresight
  Cc: James Clark, Suzuki K Poulose, Mike Leach, Leo Yan,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Ian Rogers, Adrian Hunter, John Garry, Will Deacon,
	linux-arm-kernel, linux-perf-users, linux-kernel

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>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  6 +--
 .../perf/util/cs-etm-decoder/cs-etm-decoder.h |  4 +-
 tools/perf/util/cs-etm.c                      | 41 ++++++++++++++-----
 3 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 44c49acd6bff..e917985bbbe6 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -52,15 +52,15 @@ struct cs_etm_decoder {
 static u32
 cs_etm_decoder__mem_access(const void *context,
 			   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 u32 req_size,
 			   u8 *buffer)
 {
 	struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
 
-	return decoder->mem_access(decoder->data, trace_chan_id,
-				   address, req_size, buffer);
+	return decoder->mem_access(decoder->data, trace_chan_id, address,
+				   req_size, buffer, mem_space);
 }
 
 int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder,
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index 21d403f55d96..272c2efe78ee 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -11,6 +11,7 @@
 #define INCLUDE__CS_ETM_DECODER_H__
 
 #include <linux/types.h>
+#include <opencsd/ocsd_if_types.h>
 #include <stdio.h>
 
 struct cs_etm_decoder;
@@ -19,7 +20,8 @@ struct cs_etm_packet_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 {
 	u32 reg_ctrl;
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 916e86f003f4..ca01109c3fc4 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -943,7 +943,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,
-			      u64 address, size_t size, u8 *buffer)
+			      u64 address, size_t size, u8 *buffer,
+			      const ocsd_mem_space_acc_t mem_space)
 {
 	u8  cpumode;
 	u64 offset;
@@ -959,6 +960,24 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
 	if (!tidq)
 		return 0;
 
+	/*
+	 * 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);
 
 	if (!thread__find_map(tidq->thread, cpumode, address, &al))
@@ -1207,8 +1226,8 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
 {
 	u8 instrBytes[2];
 
-	cs_etm__mem_access(etmq, trace_chan_id, addr,
-			   ARRAY_SIZE(instrBytes), instrBytes);
+	cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes),
+			   instrBytes, 0);
 	/*
 	 * T32 instruction size is indicated by bits[15:11] of the first
 	 * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111
@@ -1399,8 +1418,8 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
 	else
 		sample->insn_len = 4;
 
-	cs_etm__mem_access(etmq, trace_chan_id, sample->ip,
-			   sample->insn_len, (void *)sample->insn);
+	cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len,
+			   (void *)sample->insn, 0);
 }
 
 u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp)
@@ -1952,8 +1971,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.
 		 */
 		addr = end_addr - 2;
-		cs_etm__mem_access(etmq, trace_chan_id, addr,
-				   sizeof(instr16), (u8 *)&instr16);
+		cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16),
+				   (u8 *)&instr16, 0);
 		if ((instr16 & 0xFF00) == 0xDF00)
 			return true;
 
@@ -1968,8 +1987,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
 		 * +---------+---------+-------------------------+
 		 */
 		addr = end_addr - 4;
-		cs_etm__mem_access(etmq, trace_chan_id, addr,
-				   sizeof(instr32), (u8 *)&instr32);
+		cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
+				   (u8 *)&instr32, 0);
 		if ((instr32 & 0x0F000000) == 0x0F000000 &&
 		    (instr32 & 0xF0000000) != 0xF0000000)
 			return true;
@@ -1985,8 +2004,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
 		 * +-----------------------+---------+-----------+
 		 */
 		addr = end_addr - 4;
-		cs_etm__mem_access(etmq, trace_chan_id, addr,
-				   sizeof(instr32), (u8 *)&instr32);
+		cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
+				   (u8 *)&instr32, 0);
 		if ((instr32 & 0xFFE0001F) == 0xd4000001)
 			return true;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace
  2023-06-08 10:59 ` [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace James Clark
@ 2023-06-10  1:32   ` Leo Yan
  0 siblings, 0 replies; 9+ messages in thread
From: Leo Yan @ 2023-06-10  1:32 UTC (permalink / raw)
  To: James Clark
  Cc: coresight, Suzuki K Poulose, Mike Leach, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Ian Rogers,
	Adrian Hunter, John Garry, Will Deacon, linux-arm-kernel,
	linux-perf-users, linux-kernel

On Thu, Jun 08, 2023 at 11:59:27AM +0100, James Clark wrote:
> To avoid every user of PID format having to use their own static
> local variable, cache it on initialisation and change the accessor to
> take struct cs_etm_auxtrace.
> 
> Signed-off-by: James Clark <james.clark@arm.com>

Reviewed-by: Leo Yan <leo.yan@linaro.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 4/5] perf cs-etm: Track exception level
  2023-06-08 10:59 ` [PATCH v2 4/5] perf cs-etm: Track exception level James Clark
@ 2023-06-10  2:33   ` Leo Yan
  2023-06-12 11:13     ` James Clark
  0 siblings, 1 reply; 9+ messages in thread
From: Leo Yan @ 2023-06-10  2:33 UTC (permalink / raw)
  To: James Clark
  Cc: coresight, Suzuki K Poulose, Mike Leach, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Ian Rogers,
	Adrian Hunter, John Garry, Will Deacon, linux-arm-kernel,
	linux-perf-users, linux-kernel

On Thu, Jun 08, 2023 at 11:59:28AM +0100, James Clark wrote:
> Currently we assume all trace belongs to the host machine so when
> the decoder should be looking at the guest kernel maps it can crash
> because it looks at the host ones instead.
> 
> Avoid one scenario (guest kernel running at EL1) by assigning the
> default guest machine to this trace. For userspace trace it's still not
> possible to determine guest vs host, but the PIDs should help in this
> case.
> 
> Signed-off-by: James Clark <james.clark@arm.com>

Reviewed-by: Leo Yan <leo.yan@linaro.org>

Just input a thought for support both host and guest machines, seems to
me, a feasibe solution is CoreSight can extend its capability to trace
below system registers together:

- VTTBR_EL2.vmid
- CONTEXTIDR_EL2
- CONTEXTIDR_EL1

So:

VTTBR_EL2.vmid == 0: host machine, CONTEXTIDR_EL2 is for tracing PID
VTTBR_EL2.vmid != 0: guest machine, CONTEXTIDR_EL1 is for tracing PID

So far we only can trace either CONTEXTIDR_EL2 (and it's even a bit
mess that we save CONTEXTIDR_EL2 into 'elem->context.vmid') or
CONTEXTIDR_EL1, this is the main reason it's hard for perf to
distinguish host and guest.  I know you might have discussed this yet,
here I just record some ideas in case later we can review it.

Thanks,
Leo

> ---
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  7 +-
>  tools/perf/util/cs-etm.c                      | 75 +++++++++++++++----
>  tools/perf/util/cs-etm.h                      |  7 +-
>  3 files changed, 67 insertions(+), 22 deletions(-)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index 2af641d26866..44c49acd6bff 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -561,12 +561,13 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
>  		break;
>  	}
>  
> +	if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
> +				    elem->context.exception_level))
> +		return OCSD_RESP_FATAL_SYS_ERR;
> +
>  	if (tid == -1)
>  		return OCSD_RESP_CONT;
>  
> -	if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id))
> -		return OCSD_RESP_FATAL_SYS_ERR;
> -
>  	/*
>  	 * A timestamp is generated after a PE_CONTEXT element so make sure
>  	 * to rely on that coming one.
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index e0904f276e89..916e86f003f4 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -14,7 +14,6 @@
>  #include <linux/types.h>
>  #include <linux/zalloc.h>
>  
> -#include <opencsd/ocsd_if_types.h>
>  #include <stdlib.h>
>  
>  #include "auxtrace.h"
> @@ -88,6 +87,8 @@ struct cs_etm_traceid_queue {
>  	union perf_event *event_buf;
>  	struct thread *thread;
>  	struct thread *prev_thread;
> +	ocsd_ex_level prev_el;
> +	ocsd_ex_level el;
>  	struct branch_stack *last_branch;
>  	struct branch_stack *last_branch_rb;
>  	struct cs_etm_packet *prev_packet;
> @@ -482,6 +483,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
>  
>  	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
>  	tidq->trace_chan_id = trace_chan_id;
> +	tidq->el = tidq->prev_el = ocsd_EL_unknown;
>  	tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
>  					       queue->tid);
>  	tidq->prev_thread = machine__idle_thread(&etm->session->machines.host);
> @@ -621,6 +623,7 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
>  		tmp = tidq->packet;
>  		tidq->packet = tidq->prev_packet;
>  		tidq->prev_packet = tmp;
> +		tidq->prev_el = tidq->el;
>  		thread__put(tidq->prev_thread);
>  		tidq->prev_thread = thread__get(tidq->thread);
>  	}
> @@ -882,11 +885,43 @@ static bool cs_etm__evsel_is_auxtrace(struct perf_session *session,
>  	return evsel->core.attr.type == aux->pmu_type;
>  }
>  
> -static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
> +static struct machine *cs_etm__get_machine(struct cs_etm_queue *etmq,
> +					   ocsd_ex_level el)
>  {
> -	struct machine *machine;
> +	enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
>  
> -	machine = &etmq->etm->session->machines.host;
> +	/*
> +	 * For any virtualisation based on nVHE (e.g. pKVM), or host kernels
> +	 * running at EL1 assume everything is the host.
> +	 */
> +	if (pid_fmt == CS_ETM_PIDFMT_CTXTID)
> +		return &etmq->etm->session->machines.host;
> +
> +	/*
> +	 * Not perfect, but otherwise assume anything in EL1 is the default
> +	 * guest, and everything else is the host. Distinguishing between guest
> +	 * and host userspaces isn't currently supported either. Neither is
> +	 * multiple guest support. All this does is reduce the likeliness of
> +	 * decode errors where we look into the host kernel maps when it should
> +	 * have been the guest maps.
> +	 */
> +	switch (el) {
> +	case ocsd_EL1:
> +		return machines__find_guest(&etmq->etm->session->machines,
> +					    DEFAULT_GUEST_KERNEL_ID);
> +	case ocsd_EL3:
> +	case ocsd_EL2:
> +	case ocsd_EL0:
> +	case ocsd_EL_unknown:
> +	default:
> +		return &etmq->etm->session->machines.host;
> +	}
> +}
> +
> +static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
> +			   ocsd_ex_level el)
> +{
> +	struct machine *machine = cs_etm__get_machine(etmq, el);
>  
>  	if (address >= machine__kernel_start(machine)) {
>  		if (machine__is_host(machine))
> @@ -896,10 +931,14 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
>  	} else {
>  		if (machine__is_host(machine))
>  			return PERF_RECORD_MISC_USER;
> -		else if (perf_guest)
> +		else {
> +			/*
> +			 * Can't really happen at the moment because
> +			 * cs_etm__get_machine() will always return
> +			 * machines.host for any non EL1 trace.
> +			 */
>  			return PERF_RECORD_MISC_GUEST_USER;
> -		else
> -			return PERF_RECORD_MISC_HYPERVISOR;
> +		}
>  	}
>  }
>  
> @@ -916,11 +955,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
>  	if (!etmq)
>  		return 0;
>  
> -	cpumode = cs_etm__cpu_mode(etmq, address);
>  	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
>  	if (!tidq)
>  		return 0;
>  
> +	cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
> +
>  	if (!thread__find_map(tidq->thread, cpumode, address, &al))
>  		return 0;
>  
> @@ -1298,10 +1338,11 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
>  	return etmq->buf_len;
>  }
>  
> -static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
> -			       struct cs_etm_traceid_queue *tidq, pid_t tid)
> +static void cs_etm__set_thread(struct cs_etm_queue *etmq,
> +			       struct cs_etm_traceid_queue *tidq, pid_t tid,
> +			       ocsd_ex_level el)
>  {
> -	struct machine *machine = &etm->session->machines.host;
> +	struct machine *machine = cs_etm__get_machine(etmq, el);
>  
>  	if (tid != -1) {
>  		thread__zput(tidq->thread);
> @@ -1311,10 +1352,12 @@ static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
>  	/* Couldn't find a known thread */
>  	if (!tidq->thread)
>  		tidq->thread = machine__idle_thread(machine);
> +
> +	tidq->el = el;
>  }
>  
> -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
> -			 pid_t tid, u8 trace_chan_id)
> +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
> +			    u8 trace_chan_id, ocsd_ex_level el)
>  {
>  	struct cs_etm_traceid_queue *tidq;
>  
> @@ -1322,7 +1365,7 @@ int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
>  	if (!tidq)
>  		return -EINVAL;
>  
> -	cs_etm__set_thread(etmq->etm, tidq, tid);
> +	cs_etm__set_thread(etmq, tidq, tid, el);
>  	return 0;
>  }
>  
> @@ -1392,7 +1435,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
>  	struct perf_sample sample = {.ip = 0,};
>  
>  	event->sample.header.type = PERF_RECORD_SAMPLE;
> -	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
> +	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el);
>  	event->sample.header.size = sizeof(struct perf_event_header);
>  
>  	/* Set time field based on etm auxtrace config. */
> @@ -1451,7 +1494,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
>  	ip = cs_etm__last_executed_instr(tidq->prev_packet);
>  
>  	event->sample.header.type = PERF_RECORD_SAMPLE;
> -	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
> +	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip, tidq->prev_el);
>  	event->sample.header.size = sizeof(struct perf_event_header);
>  
>  	/* Set time field based on etm auxtrace config. */
> diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
> index 2f47f4ec5b27..7cca37887917 100644
> --- a/tools/perf/util/cs-etm.h
> +++ b/tools/perf/util/cs-etm.h
> @@ -251,10 +251,11 @@ enum cs_etm_pid_fmt {
>  };
>  
>  #ifdef HAVE_CSTRACE_SUPPORT
> +#include <opencsd/ocsd_if_types.h>
>  int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
> -enum pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
> -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
> -			 pid_t tid, u8 trace_chan_id);
> +enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
> +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
> +			    u8 trace_chan_id, ocsd_ex_level el);
>  bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
>  void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
>  					      u8 trace_chan_id);
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 4/5] perf cs-etm: Track exception level
  2023-06-10  2:33   ` Leo Yan
@ 2023-06-12 11:13     ` James Clark
  0 siblings, 0 replies; 9+ messages in thread
From: James Clark @ 2023-06-12 11:13 UTC (permalink / raw)
  To: Leo Yan
  Cc: coresight, Suzuki K Poulose, Mike Leach, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Ian Rogers,
	Adrian Hunter, John Garry, Will Deacon, linux-arm-kernel,
	linux-perf-users, linux-kernel



On 10/06/2023 03:33, Leo Yan wrote:
> On Thu, Jun 08, 2023 at 11:59:28AM +0100, James Clark wrote:
>> Currently we assume all trace belongs to the host machine so when
>> the decoder should be looking at the guest kernel maps it can crash
>> because it looks at the host ones instead.
>>
>> Avoid one scenario (guest kernel running at EL1) by assigning the
>> default guest machine to this trace. For userspace trace it's still not
>> possible to determine guest vs host, but the PIDs should help in this
>> case.
>>
>> Signed-off-by: James Clark <james.clark@arm.com>
> 
> Reviewed-by: Leo Yan <leo.yan@linaro.org>
> 
> Just input a thought for support both host and guest machines, seems to
> me, a feasibe solution is CoreSight can extend its capability to trace
> below system registers together:
> 
> - VTTBR_EL2.vmid
> - CONTEXTIDR_EL2
> - CONTEXTIDR_EL1
> 
> So:
> 
> VTTBR_EL2.vmid == 0: host machine, CONTEXTIDR_EL2 is for tracing PID
> VTTBR_EL2.vmid != 0: guest machine, CONTEXTIDR_EL1 is for tracing PID
> 
> So far we only can trace either CONTEXTIDR_EL2 (and it's even a bit
> mess that we save CONTEXTIDR_EL2 into 'elem->context.vmid') or
> CONTEXTIDR_EL1, this is the main reason it's hard for perf to
> distinguish host and guest.  I know you might have discussed this yet,
> here I just record some ideas in case later we can review it.
> 
> Thanks,
> Leo
> 

I think even if we did that we wouldn't be able to distinguish between
different guests where processes have the same PID. For IntelPT it looks
like there is a way to merge two recordings from host and guest and it
uses the timestamps to attribute samples to particular guests. I don't
see why this can't work for Coresight too and it doesn't require any
changes to the driver or hardware.

James

>> ---
>>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  7 +-
>>  tools/perf/util/cs-etm.c                      | 75 +++++++++++++++----
>>  tools/perf/util/cs-etm.h                      |  7 +-
>>  3 files changed, 67 insertions(+), 22 deletions(-)
>>
>> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> index 2af641d26866..44c49acd6bff 100644
>> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> @@ -561,12 +561,13 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
>>  		break;
>>  	}
>>  
>> +	if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
>> +				    elem->context.exception_level))
>> +		return OCSD_RESP_FATAL_SYS_ERR;
>> +
>>  	if (tid == -1)
>>  		return OCSD_RESP_CONT;
>>  
>> -	if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id))
>> -		return OCSD_RESP_FATAL_SYS_ERR;
>> -
>>  	/*
>>  	 * A timestamp is generated after a PE_CONTEXT element so make sure
>>  	 * to rely on that coming one.
>> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
>> index e0904f276e89..916e86f003f4 100644
>> --- a/tools/perf/util/cs-etm.c
>> +++ b/tools/perf/util/cs-etm.c
>> @@ -14,7 +14,6 @@
>>  #include <linux/types.h>
>>  #include <linux/zalloc.h>
>>  
>> -#include <opencsd/ocsd_if_types.h>
>>  #include <stdlib.h>
>>  
>>  #include "auxtrace.h"
>> @@ -88,6 +87,8 @@ struct cs_etm_traceid_queue {
>>  	union perf_event *event_buf;
>>  	struct thread *thread;
>>  	struct thread *prev_thread;
>> +	ocsd_ex_level prev_el;
>> +	ocsd_ex_level el;
>>  	struct branch_stack *last_branch;
>>  	struct branch_stack *last_branch_rb;
>>  	struct cs_etm_packet *prev_packet;
>> @@ -482,6 +483,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
>>  
>>  	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
>>  	tidq->trace_chan_id = trace_chan_id;
>> +	tidq->el = tidq->prev_el = ocsd_EL_unknown;
>>  	tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
>>  					       queue->tid);
>>  	tidq->prev_thread = machine__idle_thread(&etm->session->machines.host);
>> @@ -621,6 +623,7 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
>>  		tmp = tidq->packet;
>>  		tidq->packet = tidq->prev_packet;
>>  		tidq->prev_packet = tmp;
>> +		tidq->prev_el = tidq->el;
>>  		thread__put(tidq->prev_thread);
>>  		tidq->prev_thread = thread__get(tidq->thread);
>>  	}
>> @@ -882,11 +885,43 @@ static bool cs_etm__evsel_is_auxtrace(struct perf_session *session,
>>  	return evsel->core.attr.type == aux->pmu_type;
>>  }
>>  
>> -static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
>> +static struct machine *cs_etm__get_machine(struct cs_etm_queue *etmq,
>> +					   ocsd_ex_level el)
>>  {
>> -	struct machine *machine;
>> +	enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
>>  
>> -	machine = &etmq->etm->session->machines.host;
>> +	/*
>> +	 * For any virtualisation based on nVHE (e.g. pKVM), or host kernels
>> +	 * running at EL1 assume everything is the host.
>> +	 */
>> +	if (pid_fmt == CS_ETM_PIDFMT_CTXTID)
>> +		return &etmq->etm->session->machines.host;
>> +
>> +	/*
>> +	 * Not perfect, but otherwise assume anything in EL1 is the default
>> +	 * guest, and everything else is the host. Distinguishing between guest
>> +	 * and host userspaces isn't currently supported either. Neither is
>> +	 * multiple guest support. All this does is reduce the likeliness of
>> +	 * decode errors where we look into the host kernel maps when it should
>> +	 * have been the guest maps.
>> +	 */
>> +	switch (el) {
>> +	case ocsd_EL1:
>> +		return machines__find_guest(&etmq->etm->session->machines,
>> +					    DEFAULT_GUEST_KERNEL_ID);
>> +	case ocsd_EL3:
>> +	case ocsd_EL2:
>> +	case ocsd_EL0:
>> +	case ocsd_EL_unknown:
>> +	default:
>> +		return &etmq->etm->session->machines.host;
>> +	}
>> +}
>> +
>> +static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
>> +			   ocsd_ex_level el)
>> +{
>> +	struct machine *machine = cs_etm__get_machine(etmq, el);
>>  
>>  	if (address >= machine__kernel_start(machine)) {
>>  		if (machine__is_host(machine))
>> @@ -896,10 +931,14 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
>>  	} else {
>>  		if (machine__is_host(machine))
>>  			return PERF_RECORD_MISC_USER;
>> -		else if (perf_guest)
>> +		else {
>> +			/*
>> +			 * Can't really happen at the moment because
>> +			 * cs_etm__get_machine() will always return
>> +			 * machines.host for any non EL1 trace.
>> +			 */
>>  			return PERF_RECORD_MISC_GUEST_USER;
>> -		else
>> -			return PERF_RECORD_MISC_HYPERVISOR;
>> +		}
>>  	}
>>  }
>>  
>> @@ -916,11 +955,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
>>  	if (!etmq)
>>  		return 0;
>>  
>> -	cpumode = cs_etm__cpu_mode(etmq, address);
>>  	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
>>  	if (!tidq)
>>  		return 0;
>>  
>> +	cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
>> +
>>  	if (!thread__find_map(tidq->thread, cpumode, address, &al))
>>  		return 0;
>>  
>> @@ -1298,10 +1338,11 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
>>  	return etmq->buf_len;
>>  }
>>  
>> -static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
>> -			       struct cs_etm_traceid_queue *tidq, pid_t tid)
>> +static void cs_etm__set_thread(struct cs_etm_queue *etmq,
>> +			       struct cs_etm_traceid_queue *tidq, pid_t tid,
>> +			       ocsd_ex_level el)
>>  {
>> -	struct machine *machine = &etm->session->machines.host;
>> +	struct machine *machine = cs_etm__get_machine(etmq, el);
>>  
>>  	if (tid != -1) {
>>  		thread__zput(tidq->thread);
>> @@ -1311,10 +1352,12 @@ static void cs_etm__set_thread(struct cs_etm_auxtrace *etm,
>>  	/* Couldn't find a known thread */
>>  	if (!tidq->thread)
>>  		tidq->thread = machine__idle_thread(machine);
>> +
>> +	tidq->el = el;
>>  }
>>  
>> -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
>> -			 pid_t tid, u8 trace_chan_id)
>> +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
>> +			    u8 trace_chan_id, ocsd_ex_level el)
>>  {
>>  	struct cs_etm_traceid_queue *tidq;
>>  
>> @@ -1322,7 +1365,7 @@ int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
>>  	if (!tidq)
>>  		return -EINVAL;
>>  
>> -	cs_etm__set_thread(etmq->etm, tidq, tid);
>> +	cs_etm__set_thread(etmq, tidq, tid, el);
>>  	return 0;
>>  }
>>  
>> @@ -1392,7 +1435,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
>>  	struct perf_sample sample = {.ip = 0,};
>>  
>>  	event->sample.header.type = PERF_RECORD_SAMPLE;
>> -	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
>> +	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el);
>>  	event->sample.header.size = sizeof(struct perf_event_header);
>>  
>>  	/* Set time field based on etm auxtrace config. */
>> @@ -1451,7 +1494,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
>>  	ip = cs_etm__last_executed_instr(tidq->prev_packet);
>>  
>>  	event->sample.header.type = PERF_RECORD_SAMPLE;
>> -	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
>> +	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip, tidq->prev_el);
>>  	event->sample.header.size = sizeof(struct perf_event_header);
>>  
>>  	/* Set time field based on etm auxtrace config. */
>> diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
>> index 2f47f4ec5b27..7cca37887917 100644
>> --- a/tools/perf/util/cs-etm.h
>> +++ b/tools/perf/util/cs-etm.h
>> @@ -251,10 +251,11 @@ enum cs_etm_pid_fmt {
>>  };
>>  
>>  #ifdef HAVE_CSTRACE_SUPPORT
>> +#include <opencsd/ocsd_if_types.h>
>>  int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
>> -enum pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
>> -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
>> -			 pid_t tid, u8 trace_chan_id);
>> +enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
>> +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
>> +			    u8 trace_chan_id, ocsd_ex_level el);
>>  bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
>>  void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
>>  					      u8 trace_chan_id);
>> -- 
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-06-12 11:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-08 10:59 [PATCH v2 0/5] perf cs-etm: Track exception level James Clark
2023-06-08 10:59 ` [PATCH v2 1/5] perf cs-etm: Only track threads instead of PID and TIDs James Clark
2023-06-08 10:59 ` [PATCH v2 2/5] perf cs-etm: Use previous thread for branch sample source IP James Clark
2023-06-08 10:59 ` [PATCH v2 3/5] perf cs-etm: Make PID format accessible from struct cs_etm_auxtrace James Clark
2023-06-10  1:32   ` Leo Yan
2023-06-08 10:59 ` [PATCH v2 4/5] perf cs-etm: Track exception level James Clark
2023-06-10  2:33   ` Leo Yan
2023-06-12 11:13     ` James Clark
2023-06-08 10:59 ` [PATCH v2 5/5] perf cs-etm: Add exception level consistency check James Clark

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).