blob: 18894ee7aa0b17205fea1648ed92dbc127cbc80b [file] [log] [blame]
Mathieu Poirier440a23b2018-01-17 10:52:11 -07001/*
2 * SPDX-License-Identifier: GPL-2.0
3 *
4 * Copyright(C) 2015-2018 Linaro Limited.
5 *
6 * Author: Tor Jeremiassen <tor@ti.com>
7 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
8 */
9
10#include <linux/bitops.h>
11#include <linux/err.h>
12#include <linux/kernel.h>
13#include <linux/log2.h>
14#include <linux/types.h>
15
16#include <stdlib.h>
17
18#include "auxtrace.h"
19#include "color.h"
20#include "cs-etm.h"
21#include "debug.h"
22#include "evlist.h"
23#include "intlist.h"
24#include "machine.h"
25#include "map.h"
26#include "perf.h"
27#include "thread.h"
28#include "thread_map.h"
29#include "thread-stack.h"
30#include "util.h"
31
32#define MAX_TIMESTAMP (~0ULL)
33
34struct cs_etm_auxtrace {
35 struct auxtrace auxtrace;
36 struct auxtrace_queues queues;
37 struct auxtrace_heap heap;
38 struct itrace_synth_opts synth_opts;
39 struct perf_session *session;
40 struct machine *machine;
41 struct thread *unknown_thread;
42
43 u8 timeless_decoding;
44 u8 snapshot_mode;
45 u8 data_queued;
46 u8 sample_branches;
47
48 int num_cpu;
49 u32 auxtrace_type;
50 u64 branches_sample_type;
51 u64 branches_id;
52 u64 **metadata;
53 u64 kernel_start;
54 unsigned int pmu_type;
55};
56
57struct cs_etm_queue {
58 struct cs_etm_auxtrace *etm;
59 struct thread *thread;
60 struct cs_etm_decoder *decoder;
61 struct auxtrace_buffer *buffer;
62 const struct cs_etm_state *state;
63 union perf_event *event_buf;
64 unsigned int queue_nr;
65 pid_t pid, tid;
66 int cpu;
67 u64 time;
68 u64 timestamp;
69 u64 offset;
70};
71
72static int cs_etm__flush_events(struct perf_session *session,
73 struct perf_tool *tool)
74{
75 (void) session;
76 (void) tool;
77 return 0;
78}
79
80static void cs_etm__free_queue(void *priv)
81{
82 struct cs_etm_queue *etmq = priv;
83
84 free(etmq);
85}
86
87static void cs_etm__free_events(struct perf_session *session)
88{
89 unsigned int i;
90 struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
91 struct cs_etm_auxtrace,
92 auxtrace);
93 struct auxtrace_queues *queues = &aux->queues;
94
95 for (i = 0; i < queues->nr_queues; i++) {
96 cs_etm__free_queue(queues->queue_array[i].priv);
97 queues->queue_array[i].priv = NULL;
98 }
99
100 auxtrace_queues__free(queues);
101}
102
103static void cs_etm__free(struct perf_session *session)
104{
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700105 int i;
106 struct int_node *inode, *tmp;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700107 struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
108 struct cs_etm_auxtrace,
109 auxtrace);
110 cs_etm__free_events(session);
111 session->auxtrace = NULL;
112
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700113 /* First remove all traceID/CPU# nodes for the RB tree */
114 intlist__for_each_entry_safe(inode, tmp, traceid_list)
115 intlist__remove(traceid_list, inode);
116 /* Then the RB tree itself */
117 intlist__delete(traceid_list);
118
119 for (i = 0; i < aux->num_cpu; i++)
120 zfree(&aux->metadata[i]);
121
122 zfree(&aux->metadata);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700123 zfree(&aux);
124}
125
126static int cs_etm__process_event(struct perf_session *session,
127 union perf_event *event,
128 struct perf_sample *sample,
129 struct perf_tool *tool)
130{
131 (void) session;
132 (void) event;
133 (void) sample;
134 (void) tool;
135 return 0;
136}
137
138static int cs_etm__process_auxtrace_event(struct perf_session *session,
139 union perf_event *event,
140 struct perf_tool *tool)
141{
142 (void) session;
143 (void) event;
144 (void) tool;
145 return 0;
146}
147
148static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
149{
150 struct perf_evsel *evsel;
151 struct perf_evlist *evlist = etm->session->evlist;
152 bool timeless_decoding = true;
153
154 /*
155 * Circle through the list of event and complain if we find one
156 * with the time bit set.
157 */
158 evlist__for_each_entry(evlist, evsel) {
159 if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
160 timeless_decoding = false;
161 }
162
163 return timeless_decoding;
164}
165
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700166static const char * const cs_etm_global_header_fmts[] = {
167 [CS_HEADER_VERSION_0] = " Header version %llx\n",
168 [CS_PMU_TYPE_CPUS] = " PMU type/num cpus %llx\n",
169 [CS_ETM_SNAPSHOT] = " Snapshot %llx\n",
170};
171
172static const char * const cs_etm_priv_fmts[] = {
173 [CS_ETM_MAGIC] = " Magic number %llx\n",
174 [CS_ETM_CPU] = " CPU %lld\n",
175 [CS_ETM_ETMCR] = " ETMCR %llx\n",
176 [CS_ETM_ETMTRACEIDR] = " ETMTRACEIDR %llx\n",
177 [CS_ETM_ETMCCER] = " ETMCCER %llx\n",
178 [CS_ETM_ETMIDR] = " ETMIDR %llx\n",
179};
180
181static const char * const cs_etmv4_priv_fmts[] = {
182 [CS_ETM_MAGIC] = " Magic number %llx\n",
183 [CS_ETM_CPU] = " CPU %lld\n",
184 [CS_ETMV4_TRCCONFIGR] = " TRCCONFIGR %llx\n",
185 [CS_ETMV4_TRCTRACEIDR] = " TRCTRACEIDR %llx\n",
186 [CS_ETMV4_TRCIDR0] = " TRCIDR0 %llx\n",
187 [CS_ETMV4_TRCIDR1] = " TRCIDR1 %llx\n",
188 [CS_ETMV4_TRCIDR2] = " TRCIDR2 %llx\n",
189 [CS_ETMV4_TRCIDR8] = " TRCIDR8 %llx\n",
190 [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n",
191};
192
193static void cs_etm__print_auxtrace_info(u64 *val, int num)
194{
195 int i, j, cpu = 0;
196
197 for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
198 fprintf(stdout, cs_etm_global_header_fmts[i], val[i]);
199
200 for (i = CS_HEADER_VERSION_0_MAX; cpu < num; cpu++) {
201 if (val[i] == __perf_cs_etmv3_magic)
202 for (j = 0; j < CS_ETM_PRIV_MAX; j++, i++)
203 fprintf(stdout, cs_etm_priv_fmts[j], val[i]);
204 else if (val[i] == __perf_cs_etmv4_magic)
205 for (j = 0; j < CS_ETMV4_PRIV_MAX; j++, i++)
206 fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]);
207 else
208 /* failure.. return */
209 return;
210 }
211}
212
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700213int cs_etm__process_auxtrace_info(union perf_event *event,
214 struct perf_session *session)
215{
216 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
217 struct cs_etm_auxtrace *etm = NULL;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700218 struct int_node *inode;
219 unsigned int pmu_type;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700220 int event_header_size = sizeof(struct perf_event_header);
221 int info_header_size;
222 int total_size = auxtrace_info->header.size;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700223 int priv_size = 0;
224 int num_cpu;
225 int err = 0, idx = -1;
226 int i, j, k;
227 u64 *ptr, *hdr = NULL;
228 u64 **metadata = NULL;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700229
230 /*
231 * sizeof(auxtrace_info_event::type) +
232 * sizeof(auxtrace_info_event::reserved) == 8
233 */
234 info_header_size = 8;
235
236 if (total_size < (event_header_size + info_header_size))
237 return -EINVAL;
238
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700239 priv_size = total_size - event_header_size - info_header_size;
240
241 /* First the global part */
242 ptr = (u64 *) auxtrace_info->priv;
243
244 /* Look for version '0' of the header */
245 if (ptr[0] != 0)
246 return -EINVAL;
247
248 hdr = zalloc(sizeof(*hdr) * CS_HEADER_VERSION_0_MAX);
249 if (!hdr)
250 return -ENOMEM;
251
252 /* Extract header information - see cs-etm.h for format */
253 for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
254 hdr[i] = ptr[i];
255 num_cpu = hdr[CS_PMU_TYPE_CPUS] & 0xffffffff;
256 pmu_type = (unsigned int) ((hdr[CS_PMU_TYPE_CPUS] >> 32) &
257 0xffffffff);
258
259 /*
260 * Create an RB tree for traceID-CPU# tuple. Since the conversion has
261 * to be made for each packet that gets decoded, optimizing access in
262 * anything other than a sequential array is worth doing.
263 */
264 traceid_list = intlist__new(NULL);
265 if (!traceid_list) {
266 err = -ENOMEM;
267 goto err_free_hdr;
268 }
269
270 metadata = zalloc(sizeof(*metadata) * num_cpu);
271 if (!metadata) {
272 err = -ENOMEM;
273 goto err_free_traceid_list;
274 }
275
276 /*
277 * The metadata is stored in the auxtrace_info section and encodes
278 * the configuration of the ARM embedded trace macrocell which is
279 * required by the trace decoder to properly decode the trace due
280 * to its highly compressed nature.
281 */
282 for (j = 0; j < num_cpu; j++) {
283 if (ptr[i] == __perf_cs_etmv3_magic) {
284 metadata[j] = zalloc(sizeof(*metadata[j]) *
285 CS_ETM_PRIV_MAX);
286 if (!metadata[j]) {
287 err = -ENOMEM;
288 goto err_free_metadata;
289 }
290 for (k = 0; k < CS_ETM_PRIV_MAX; k++)
291 metadata[j][k] = ptr[i + k];
292
293 /* The traceID is our handle */
294 idx = metadata[j][CS_ETM_ETMTRACEIDR];
295 i += CS_ETM_PRIV_MAX;
296 } else if (ptr[i] == __perf_cs_etmv4_magic) {
297 metadata[j] = zalloc(sizeof(*metadata[j]) *
298 CS_ETMV4_PRIV_MAX);
299 if (!metadata[j]) {
300 err = -ENOMEM;
301 goto err_free_metadata;
302 }
303 for (k = 0; k < CS_ETMV4_PRIV_MAX; k++)
304 metadata[j][k] = ptr[i + k];
305
306 /* The traceID is our handle */
307 idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
308 i += CS_ETMV4_PRIV_MAX;
309 }
310
311 /* Get an RB node for this CPU */
312 inode = intlist__findnew(traceid_list, idx);
313
314 /* Something went wrong, no need to continue */
315 if (!inode) {
316 err = PTR_ERR(inode);
317 goto err_free_metadata;
318 }
319
320 /*
321 * The node for that CPU should not be taken.
322 * Back out if that's the case.
323 */
324 if (inode->priv) {
325 err = -EINVAL;
326 goto err_free_metadata;
327 }
328 /* All good, associate the traceID with the CPU# */
329 inode->priv = &metadata[j][CS_ETM_CPU];
330 }
331
332 /*
333 * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
334 * CS_ETMV4_PRIV_MAX mark how many double words are in the
335 * global metadata, and each cpu's metadata respectively.
336 * The following tests if the correct number of double words was
337 * present in the auxtrace info section.
338 */
339 if (i * 8 != priv_size) {
340 err = -EINVAL;
341 goto err_free_metadata;
342 }
343
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700344 etm = zalloc(sizeof(*etm));
345
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700346 if (!etm) {
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700347 err = -ENOMEM;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700348 goto err_free_metadata;
349 }
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700350
351 err = auxtrace_queues__init(&etm->queues);
352 if (err)
353 goto err_free_etm;
354
355 etm->session = session;
356 etm->machine = &session->machines.host;
357
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700358 etm->num_cpu = num_cpu;
359 etm->pmu_type = pmu_type;
360 etm->snapshot_mode = (hdr[CS_ETM_SNAPSHOT] != 0);
361 etm->metadata = metadata;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700362 etm->auxtrace_type = auxtrace_info->type;
363 etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
364
365 etm->auxtrace.process_event = cs_etm__process_event;
366 etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
367 etm->auxtrace.flush_events = cs_etm__flush_events;
368 etm->auxtrace.free_events = cs_etm__free_events;
369 etm->auxtrace.free = cs_etm__free;
370 session->auxtrace = &etm->auxtrace;
371
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700372 if (dump_trace) {
373 cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700374 return 0;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700375 }
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700376
377 err = auxtrace_queues__process_index(&etm->queues, session);
378 if (err)
379 goto err_free_queues;
380
381 etm->data_queued = etm->queues.populated;
382
383 return 0;
384
385err_free_queues:
386 auxtrace_queues__free(&etm->queues);
387 session->auxtrace = NULL;
388err_free_etm:
389 zfree(&etm);
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700390err_free_metadata:
391 /* No need to check @metadata[j], free(NULL) is supported */
392 for (j = 0; j < num_cpu; j++)
393 free(metadata[j]);
394 zfree(&metadata);
395err_free_traceid_list:
396 intlist__delete(traceid_list);
397err_free_hdr:
398 zfree(&hdr);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700399
400 return -EINVAL;
401}