1c86f218cSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2c86f218cSJens Wiklander /*
3c86f218cSJens Wiklander * Copyright (c) 2019, Linaro Limited
4c86f218cSJens Wiklander */
5c86f218cSJens Wiklander
6c86f218cSJens Wiklander #include <assert.h>
7c86f218cSJens Wiklander #include <printk.h>
8*5c2c0fb3SJerome Forissier #include <string.h>
9c86f218cSJens Wiklander #include <sys/queue.h>
10c86f218cSJens Wiklander #include <types_ext.h>
11*5c2c0fb3SJerome Forissier #include <user_ta_header.h>
12c86f218cSJens Wiklander #include <util.h>
13c86f218cSJens Wiklander
14c86f218cSJens Wiklander #include "ftrace.h"
15c86f218cSJens Wiklander #include "ta_elf.h"
16c86f218cSJens Wiklander
17c86f218cSJens Wiklander #define MIN_FTRACE_BUF_SIZE 1024
18c86f218cSJens Wiklander #define MAX_HEADER_STRLEN 128
19c86f218cSJens Wiklander
20c86f218cSJens Wiklander static struct ftrace_buf *fbuf;
21c86f218cSJens Wiklander
ftrace_init(struct ftrace_buf ** fbuf_ptr)22f90488afSSumit Garg bool ftrace_init(struct ftrace_buf **fbuf_ptr)
23c86f218cSJens Wiklander {
24f90488afSSumit Garg struct __ftrace_info *finfo = NULL;
25c86f218cSJens Wiklander struct ta_elf *elf = TAILQ_FIRST(&main_elf_queue);
26c86f218cSJens Wiklander TEE_Result res = TEE_SUCCESS;
27c86f218cSJens Wiklander vaddr_t val = 0;
28c86f218cSJens Wiklander int count = 0;
29c86f218cSJens Wiklander size_t fbuf_size = 0;
30*5c2c0fb3SJerome Forissier size_t pad = 0;
31*5c2c0fb3SJerome Forissier char *p = NULL;
32*5c2c0fb3SJerome Forissier char magic[] = { 'F', 'T', 'R', 'A', 'C', 'E', 0x00, 0x01 };
33c86f218cSJens Wiklander
34c88ba125SJerome Forissier res = ta_elf_resolve_sym("__ftrace_info", &val, NULL, NULL);
35c86f218cSJens Wiklander if (res)
36c86f218cSJens Wiklander return false;
37c86f218cSJens Wiklander
38c86f218cSJens Wiklander finfo = (struct __ftrace_info *)val;
39c86f218cSJens Wiklander
40c86f218cSJens Wiklander assert(elf && elf->is_main);
41c86f218cSJens Wiklander
42c96d7091SSumit Garg if (SUB_OVERFLOW(finfo->buf_end.ptr64, finfo->buf_start.ptr64,
43c96d7091SSumit Garg &fbuf_size))
44c86f218cSJens Wiklander return false;
45c86f218cSJens Wiklander
46c86f218cSJens Wiklander if (fbuf_size < MIN_FTRACE_BUF_SIZE) {
47c86f218cSJens Wiklander DMSG("ftrace buffer too small");
48c86f218cSJens Wiklander return false;
49c86f218cSJens Wiklander }
50c86f218cSJens Wiklander
51e260ea8dSJens Wiklander fbuf = (struct ftrace_buf *)(vaddr_t)finfo->buf_start.ptr64;
52c86f218cSJens Wiklander fbuf->head_off = sizeof(struct ftrace_buf);
53*5c2c0fb3SJerome Forissier p = (char *)fbuf + fbuf->head_off;
54*5c2c0fb3SJerome Forissier count = snprintk(p, MAX_HEADER_STRLEN,
55c86f218cSJens Wiklander "Function graph for TA: %pUl @ %lx\n",
56c86f218cSJens Wiklander (void *)&elf->uuid, elf->load_addr);
57c86f218cSJens Wiklander assert(count < MAX_HEADER_STRLEN);
58*5c2c0fb3SJerome Forissier p += count;
59c86f218cSJens Wiklander
60c96d7091SSumit Garg fbuf->ret_func_ptr = finfo->ret_ptr.ptr64;
61c86f218cSJens Wiklander fbuf->ret_idx = 0;
62c86f218cSJens Wiklander fbuf->lr_idx = 0;
63f5df167cSSumit Garg fbuf->suspend_time = 0;
64c86f218cSJens Wiklander fbuf->buf_off = fbuf->head_off + count;
65*5c2c0fb3SJerome Forissier /* For proper alignment of uint64_t values in the ftrace buffer */
66*5c2c0fb3SJerome Forissier pad = 8 - (vaddr_t)p % 8;
67*5c2c0fb3SJerome Forissier if (pad == 8)
68*5c2c0fb3SJerome Forissier pad = 0;
69*5c2c0fb3SJerome Forissier while (pad--) {
70*5c2c0fb3SJerome Forissier *p++ = 0;
71*5c2c0fb3SJerome Forissier fbuf->buf_off++;
72*5c2c0fb3SJerome Forissier count++;
73*5c2c0fb3SJerome Forissier }
74*5c2c0fb3SJerome Forissier /* Delimiter for easier decoding */
75*5c2c0fb3SJerome Forissier memcpy(p, magic, sizeof(magic));
76*5c2c0fb3SJerome Forissier fbuf->buf_off += sizeof(magic);
77*5c2c0fb3SJerome Forissier count += sizeof(magic);
78*5c2c0fb3SJerome Forissier fbuf->curr_idx = 0;
79c86f218cSJens Wiklander fbuf->max_size = fbuf_size - sizeof(struct ftrace_buf) - count;
80099918f6SSumit Garg fbuf->syscall_trace_enabled = false;
81099918f6SSumit Garg fbuf->syscall_trace_suspended = false;
82c86f218cSJens Wiklander
83f90488afSSumit Garg *fbuf_ptr = fbuf;
84f90488afSSumit Garg
85c86f218cSJens Wiklander return true;
86c86f218cSJens Wiklander }
87c86f218cSJens Wiklander
ftrace_copy_buf(void * pctx,void (* copy_func)(void * pctx,void * b,size_t bl))88c86f218cSJens Wiklander void ftrace_copy_buf(void *pctx, void (*copy_func)(void *pctx, void *b,
89c86f218cSJens Wiklander size_t bl))
90c86f218cSJens Wiklander {
91c86f218cSJens Wiklander if (fbuf) {
92c86f218cSJens Wiklander struct ta_elf *elf = TAILQ_FIRST(&main_elf_queue);
93*5c2c0fb3SJerome Forissier char *hstart = (char *)fbuf + fbuf->head_off;
94*5c2c0fb3SJerome Forissier char *cstart = (char *)fbuf + fbuf->buf_off;
95*5c2c0fb3SJerome Forissier char *ccurr = cstart + fbuf->curr_idx * sizeof(uint64_t);
96*5c2c0fb3SJerome Forissier size_t csize = 0;
97*5c2c0fb3SJerome Forissier size_t dump_size = 0;
98*5c2c0fb3SJerome Forissier char *end = NULL;
99c86f218cSJens Wiklander
100c86f218cSJens Wiklander assert(elf && elf->is_main);
101*5c2c0fb3SJerome Forissier
102*5c2c0fb3SJerome Forissier if (fbuf->overflow)
103*5c2c0fb3SJerome Forissier csize = fbuf->max_size;
104*5c2c0fb3SJerome Forissier else
105*5c2c0fb3SJerome Forissier csize = fbuf->curr_idx * sizeof(uint64_t);
106*5c2c0fb3SJerome Forissier dump_size = fbuf->buf_off - fbuf->head_off + csize;
107*5c2c0fb3SJerome Forissier end = hstart + dump_size;
108*5c2c0fb3SJerome Forissier
109*5c2c0fb3SJerome Forissier /* Header */
110*5c2c0fb3SJerome Forissier copy_func(pctx, hstart, fbuf->buf_off - fbuf->head_off);
111*5c2c0fb3SJerome Forissier if (fbuf->overflow) {
112*5c2c0fb3SJerome Forissier /* From current index to end of circular buffer */
113*5c2c0fb3SJerome Forissier copy_func(pctx, ccurr, end - ccurr);
114*5c2c0fb3SJerome Forissier }
115*5c2c0fb3SJerome Forissier /* From start of circular buffer to current index */
116*5c2c0fb3SJerome Forissier copy_func(pctx, cstart, ccurr - cstart);
117c86f218cSJens Wiklander }
118c86f218cSJens Wiklander }
119c86f218cSJens Wiklander
ftrace_map_lr(uint64_t * lr)120c86f218cSJens Wiklander void ftrace_map_lr(uint64_t *lr)
121c86f218cSJens Wiklander {
122c86f218cSJens Wiklander if (fbuf) {
123c86f218cSJens Wiklander if (*lr == fbuf->ret_func_ptr &&
124c86f218cSJens Wiklander fbuf->lr_idx < fbuf->ret_idx) {
125c86f218cSJens Wiklander fbuf->lr_idx++;
126c86f218cSJens Wiklander *lr = fbuf->ret_stack[fbuf->ret_idx - fbuf->lr_idx];
127c86f218cSJens Wiklander }
128c86f218cSJens Wiklander }
129c86f218cSJens Wiklander }
130