blob: cad429ce3c0021087a4a78310c5de3916c451581 [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"
Mathieu Poirier68ffe392018-01-17 10:52:13 -070021#include "cs-etm-decoder/cs-etm-decoder.h"
Mathieu Poirier440a23b2018-01-17 10:52:11 -070022#include "debug.h"
23#include "evlist.h"
24#include "intlist.h"
25#include "machine.h"
26#include "map.h"
27#include "perf.h"
28#include "thread.h"
29#include "thread_map.h"
30#include "thread-stack.h"
31#include "util.h"
32
33#define MAX_TIMESTAMP (~0ULL)
34
35struct cs_etm_auxtrace {
36 struct auxtrace auxtrace;
37 struct auxtrace_queues queues;
38 struct auxtrace_heap heap;
39 struct itrace_synth_opts synth_opts;
40 struct perf_session *session;
41 struct machine *machine;
42 struct thread *unknown_thread;
43
44 u8 timeless_decoding;
45 u8 snapshot_mode;
46 u8 data_queued;
47 u8 sample_branches;
48
49 int num_cpu;
50 u32 auxtrace_type;
51 u64 branches_sample_type;
52 u64 branches_id;
53 u64 **metadata;
54 u64 kernel_start;
55 unsigned int pmu_type;
56};
57
58struct cs_etm_queue {
59 struct cs_etm_auxtrace *etm;
60 struct thread *thread;
61 struct cs_etm_decoder *decoder;
62 struct auxtrace_buffer *buffer;
63 const struct cs_etm_state *state;
64 union perf_event *event_buf;
65 unsigned int queue_nr;
66 pid_t pid, tid;
67 int cpu;
68 u64 time;
69 u64 timestamp;
70 u64 offset;
71};
72
Mathieu Poirier68ffe392018-01-17 10:52:13 -070073static void cs_etm__packet_dump(const char *pkt_string)
74{
75 const char *color = PERF_COLOR_BLUE;
76 int len = strlen(pkt_string);
77
78 if (len && (pkt_string[len-1] == '\n'))
79 color_fprintf(stdout, color, " %s", pkt_string);
80 else
81 color_fprintf(stdout, color, " %s\n", pkt_string);
82
83 fflush(stdout);
84}
85
86static void cs_etm__dump_event(struct cs_etm_auxtrace *etm,
87 struct auxtrace_buffer *buffer)
88{
89 int i, ret;
90 const char *color = PERF_COLOR_BLUE;
91 struct cs_etm_decoder_params d_params;
92 struct cs_etm_trace_params *t_params;
93 struct cs_etm_decoder *decoder;
94 size_t buffer_used = 0;
95
96 fprintf(stdout, "\n");
97 color_fprintf(stdout, color,
98 ". ... CoreSight ETM Trace data: size %zu bytes\n",
99 buffer->size);
100
101 /* Use metadata to fill in trace parameters for trace decoder */
102 t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
103 for (i = 0; i < etm->num_cpu; i++) {
104 t_params[i].protocol = CS_ETM_PROTO_ETMV4i;
105 t_params[i].etmv4.reg_idr0 = etm->metadata[i][CS_ETMV4_TRCIDR0];
106 t_params[i].etmv4.reg_idr1 = etm->metadata[i][CS_ETMV4_TRCIDR1];
107 t_params[i].etmv4.reg_idr2 = etm->metadata[i][CS_ETMV4_TRCIDR2];
108 t_params[i].etmv4.reg_idr8 = etm->metadata[i][CS_ETMV4_TRCIDR8];
109 t_params[i].etmv4.reg_configr =
110 etm->metadata[i][CS_ETMV4_TRCCONFIGR];
111 t_params[i].etmv4.reg_traceidr =
112 etm->metadata[i][CS_ETMV4_TRCTRACEIDR];
113 }
114
115 /* Set decoder parameters to simply print the trace packets */
116 d_params.packet_printer = cs_etm__packet_dump;
117 d_params.operation = CS_ETM_OPERATION_PRINT;
118 d_params.formatted = true;
119 d_params.fsyncs = false;
120 d_params.hsyncs = false;
121 d_params.frame_aligned = true;
122
123 decoder = cs_etm_decoder__new(etm->num_cpu, &d_params, t_params);
124
125 zfree(&t_params);
126
127 if (!decoder)
128 return;
129 do {
130 size_t consumed;
131
132 ret = cs_etm_decoder__process_data_block(
133 decoder, buffer->offset,
134 &((u8 *)buffer->data)[buffer_used],
135 buffer->size - buffer_used, &consumed);
136 if (ret)
137 break;
138
139 buffer_used += consumed;
140 } while (buffer_used < buffer->size);
141
142 cs_etm_decoder__free(decoder);
143}
144
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700145static int cs_etm__flush_events(struct perf_session *session,
146 struct perf_tool *tool)
147{
148 (void) session;
149 (void) tool;
150 return 0;
151}
152
153static void cs_etm__free_queue(void *priv)
154{
155 struct cs_etm_queue *etmq = priv;
156
157 free(etmq);
158}
159
160static void cs_etm__free_events(struct perf_session *session)
161{
162 unsigned int i;
163 struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
164 struct cs_etm_auxtrace,
165 auxtrace);
166 struct auxtrace_queues *queues = &aux->queues;
167
168 for (i = 0; i < queues->nr_queues; i++) {
169 cs_etm__free_queue(queues->queue_array[i].priv);
170 queues->queue_array[i].priv = NULL;
171 }
172
173 auxtrace_queues__free(queues);
174}
175
176static void cs_etm__free(struct perf_session *session)
177{
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700178 int i;
179 struct int_node *inode, *tmp;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700180 struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
181 struct cs_etm_auxtrace,
182 auxtrace);
183 cs_etm__free_events(session);
184 session->auxtrace = NULL;
185
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700186 /* First remove all traceID/CPU# nodes for the RB tree */
187 intlist__for_each_entry_safe(inode, tmp, traceid_list)
188 intlist__remove(traceid_list, inode);
189 /* Then the RB tree itself */
190 intlist__delete(traceid_list);
191
192 for (i = 0; i < aux->num_cpu; i++)
193 zfree(&aux->metadata[i]);
194
195 zfree(&aux->metadata);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700196 zfree(&aux);
197}
198
199static int cs_etm__process_event(struct perf_session *session,
200 union perf_event *event,
201 struct perf_sample *sample,
202 struct perf_tool *tool)
203{
204 (void) session;
205 (void) event;
206 (void) sample;
207 (void) tool;
208 return 0;
209}
210
211static int cs_etm__process_auxtrace_event(struct perf_session *session,
212 union perf_event *event,
Mathieu Poirier68ffe392018-01-17 10:52:13 -0700213 struct perf_tool *tool __maybe_unused)
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700214{
Mathieu Poirier68ffe392018-01-17 10:52:13 -0700215 struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
216 struct cs_etm_auxtrace,
217 auxtrace);
218 if (!etm->data_queued) {
219 struct auxtrace_buffer *buffer;
220 off_t data_offset;
221 int fd = perf_data__fd(session->data);
222 bool is_pipe = perf_data__is_pipe(session->data);
223 int err;
224
225 if (is_pipe)
226 data_offset = 0;
227 else {
228 data_offset = lseek(fd, 0, SEEK_CUR);
229 if (data_offset == -1)
230 return -errno;
231 }
232
233 err = auxtrace_queues__add_event(&etm->queues, session,
234 event, data_offset, &buffer);
235 if (err)
236 return err;
237
238 if (dump_trace)
239 if (auxtrace_buffer__get_data(buffer, fd)) {
240 cs_etm__dump_event(etm, buffer);
241 auxtrace_buffer__put_data(buffer);
242 }
243 }
244
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700245 return 0;
246}
247
248static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
249{
250 struct perf_evsel *evsel;
251 struct perf_evlist *evlist = etm->session->evlist;
252 bool timeless_decoding = true;
253
254 /*
255 * Circle through the list of event and complain if we find one
256 * with the time bit set.
257 */
258 evlist__for_each_entry(evlist, evsel) {
259 if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
260 timeless_decoding = false;
261 }
262
263 return timeless_decoding;
264}
265
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700266static const char * const cs_etm_global_header_fmts[] = {
267 [CS_HEADER_VERSION_0] = " Header version %llx\n",
268 [CS_PMU_TYPE_CPUS] = " PMU type/num cpus %llx\n",
269 [CS_ETM_SNAPSHOT] = " Snapshot %llx\n",
270};
271
272static const char * const cs_etm_priv_fmts[] = {
273 [CS_ETM_MAGIC] = " Magic number %llx\n",
274 [CS_ETM_CPU] = " CPU %lld\n",
275 [CS_ETM_ETMCR] = " ETMCR %llx\n",
276 [CS_ETM_ETMTRACEIDR] = " ETMTRACEIDR %llx\n",
277 [CS_ETM_ETMCCER] = " ETMCCER %llx\n",
278 [CS_ETM_ETMIDR] = " ETMIDR %llx\n",
279};
280
281static const char * const cs_etmv4_priv_fmts[] = {
282 [CS_ETM_MAGIC] = " Magic number %llx\n",
283 [CS_ETM_CPU] = " CPU %lld\n",
284 [CS_ETMV4_TRCCONFIGR] = " TRCCONFIGR %llx\n",
285 [CS_ETMV4_TRCTRACEIDR] = " TRCTRACEIDR %llx\n",
286 [CS_ETMV4_TRCIDR0] = " TRCIDR0 %llx\n",
287 [CS_ETMV4_TRCIDR1] = " TRCIDR1 %llx\n",
288 [CS_ETMV4_TRCIDR2] = " TRCIDR2 %llx\n",
289 [CS_ETMV4_TRCIDR8] = " TRCIDR8 %llx\n",
290 [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n",
291};
292
293static void cs_etm__print_auxtrace_info(u64 *val, int num)
294{
295 int i, j, cpu = 0;
296
297 for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
298 fprintf(stdout, cs_etm_global_header_fmts[i], val[i]);
299
300 for (i = CS_HEADER_VERSION_0_MAX; cpu < num; cpu++) {
301 if (val[i] == __perf_cs_etmv3_magic)
302 for (j = 0; j < CS_ETM_PRIV_MAX; j++, i++)
303 fprintf(stdout, cs_etm_priv_fmts[j], val[i]);
304 else if (val[i] == __perf_cs_etmv4_magic)
305 for (j = 0; j < CS_ETMV4_PRIV_MAX; j++, i++)
306 fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]);
307 else
308 /* failure.. return */
309 return;
310 }
311}
312
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700313int cs_etm__process_auxtrace_info(union perf_event *event,
314 struct perf_session *session)
315{
316 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
317 struct cs_etm_auxtrace *etm = NULL;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700318 struct int_node *inode;
319 unsigned int pmu_type;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700320 int event_header_size = sizeof(struct perf_event_header);
321 int info_header_size;
322 int total_size = auxtrace_info->header.size;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700323 int priv_size = 0;
324 int num_cpu;
325 int err = 0, idx = -1;
326 int i, j, k;
327 u64 *ptr, *hdr = NULL;
328 u64 **metadata = NULL;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700329
330 /*
331 * sizeof(auxtrace_info_event::type) +
332 * sizeof(auxtrace_info_event::reserved) == 8
333 */
334 info_header_size = 8;
335
336 if (total_size < (event_header_size + info_header_size))
337 return -EINVAL;
338
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700339 priv_size = total_size - event_header_size - info_header_size;
340
341 /* First the global part */
342 ptr = (u64 *) auxtrace_info->priv;
343
344 /* Look for version '0' of the header */
345 if (ptr[0] != 0)
346 return -EINVAL;
347
348 hdr = zalloc(sizeof(*hdr) * CS_HEADER_VERSION_0_MAX);
349 if (!hdr)
350 return -ENOMEM;
351
352 /* Extract header information - see cs-etm.h for format */
353 for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
354 hdr[i] = ptr[i];
355 num_cpu = hdr[CS_PMU_TYPE_CPUS] & 0xffffffff;
356 pmu_type = (unsigned int) ((hdr[CS_PMU_TYPE_CPUS] >> 32) &
357 0xffffffff);
358
359 /*
360 * Create an RB tree for traceID-CPU# tuple. Since the conversion has
361 * to be made for each packet that gets decoded, optimizing access in
362 * anything other than a sequential array is worth doing.
363 */
364 traceid_list = intlist__new(NULL);
365 if (!traceid_list) {
366 err = -ENOMEM;
367 goto err_free_hdr;
368 }
369
370 metadata = zalloc(sizeof(*metadata) * num_cpu);
371 if (!metadata) {
372 err = -ENOMEM;
373 goto err_free_traceid_list;
374 }
375
376 /*
377 * The metadata is stored in the auxtrace_info section and encodes
378 * the configuration of the ARM embedded trace macrocell which is
379 * required by the trace decoder to properly decode the trace due
380 * to its highly compressed nature.
381 */
382 for (j = 0; j < num_cpu; j++) {
383 if (ptr[i] == __perf_cs_etmv3_magic) {
384 metadata[j] = zalloc(sizeof(*metadata[j]) *
385 CS_ETM_PRIV_MAX);
386 if (!metadata[j]) {
387 err = -ENOMEM;
388 goto err_free_metadata;
389 }
390 for (k = 0; k < CS_ETM_PRIV_MAX; k++)
391 metadata[j][k] = ptr[i + k];
392
393 /* The traceID is our handle */
394 idx = metadata[j][CS_ETM_ETMTRACEIDR];
395 i += CS_ETM_PRIV_MAX;
396 } else if (ptr[i] == __perf_cs_etmv4_magic) {
397 metadata[j] = zalloc(sizeof(*metadata[j]) *
398 CS_ETMV4_PRIV_MAX);
399 if (!metadata[j]) {
400 err = -ENOMEM;
401 goto err_free_metadata;
402 }
403 for (k = 0; k < CS_ETMV4_PRIV_MAX; k++)
404 metadata[j][k] = ptr[i + k];
405
406 /* The traceID is our handle */
407 idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
408 i += CS_ETMV4_PRIV_MAX;
409 }
410
411 /* Get an RB node for this CPU */
412 inode = intlist__findnew(traceid_list, idx);
413
414 /* Something went wrong, no need to continue */
415 if (!inode) {
416 err = PTR_ERR(inode);
417 goto err_free_metadata;
418 }
419
420 /*
421 * The node for that CPU should not be taken.
422 * Back out if that's the case.
423 */
424 if (inode->priv) {
425 err = -EINVAL;
426 goto err_free_metadata;
427 }
428 /* All good, associate the traceID with the CPU# */
429 inode->priv = &metadata[j][CS_ETM_CPU];
430 }
431
432 /*
433 * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
434 * CS_ETMV4_PRIV_MAX mark how many double words are in the
435 * global metadata, and each cpu's metadata respectively.
436 * The following tests if the correct number of double words was
437 * present in the auxtrace info section.
438 */
439 if (i * 8 != priv_size) {
440 err = -EINVAL;
441 goto err_free_metadata;
442 }
443
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700444 etm = zalloc(sizeof(*etm));
445
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700446 if (!etm) {
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700447 err = -ENOMEM;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700448 goto err_free_metadata;
449 }
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700450
451 err = auxtrace_queues__init(&etm->queues);
452 if (err)
453 goto err_free_etm;
454
455 etm->session = session;
456 etm->machine = &session->machines.host;
457
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700458 etm->num_cpu = num_cpu;
459 etm->pmu_type = pmu_type;
460 etm->snapshot_mode = (hdr[CS_ETM_SNAPSHOT] != 0);
461 etm->metadata = metadata;
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700462 etm->auxtrace_type = auxtrace_info->type;
463 etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
464
465 etm->auxtrace.process_event = cs_etm__process_event;
466 etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
467 etm->auxtrace.flush_events = cs_etm__flush_events;
468 etm->auxtrace.free_events = cs_etm__free_events;
469 etm->auxtrace.free = cs_etm__free;
470 session->auxtrace = &etm->auxtrace;
471
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700472 if (dump_trace) {
473 cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700474 return 0;
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700475 }
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700476
477 err = auxtrace_queues__process_index(&etm->queues, session);
478 if (err)
479 goto err_free_queues;
480
481 etm->data_queued = etm->queues.populated;
482
483 return 0;
484
485err_free_queues:
486 auxtrace_queues__free(&etm->queues);
487 session->auxtrace = NULL;
488err_free_etm:
489 zfree(&etm);
Tor Jeremiassencd8bfd82018-01-17 10:52:12 -0700490err_free_metadata:
491 /* No need to check @metadata[j], free(NULL) is supported */
492 for (j = 0; j < num_cpu; j++)
493 free(metadata[j]);
494 zfree(&metadata);
495err_free_traceid_list:
496 intlist__delete(traceid_list);
497err_free_hdr:
498 zfree(&hdr);
Mathieu Poirier440a23b2018-01-17 10:52:11 -0700499
500 return -EINVAL;
501}