xref: /rk3399_ARM-atf/plat/nvidia/tegra/lib/debug/profiler.c (revision e2469d823bfc633a32782a8c018d3b55eb2b23a1)
1*e2469d82SVarun Wadekar /*
2*e2469d82SVarun Wadekar  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*e2469d82SVarun Wadekar  *
4*e2469d82SVarun Wadekar  * SPDX-License-Identifier: BSD-3-Clause
5*e2469d82SVarun Wadekar  */
6*e2469d82SVarun Wadekar 
7*e2469d82SVarun Wadekar /*******************************************************************************
8*e2469d82SVarun Wadekar  * The profiler stores the timestamps captured during cold boot to the shared
9*e2469d82SVarun Wadekar  * memory for the non-secure world. The non-secure world driver parses the
10*e2469d82SVarun Wadekar  * shared memory block and writes the contents to a file on the device, which
11*e2469d82SVarun Wadekar  * can be later extracted for analysis.
12*e2469d82SVarun Wadekar  *
13*e2469d82SVarun Wadekar  * Profiler memory map
14*e2469d82SVarun Wadekar  *
15*e2469d82SVarun Wadekar  * TOP     ---------------------------      ---
16*e2469d82SVarun Wadekar  *            Trusted OS timestamps         3KB
17*e2469d82SVarun Wadekar  *         ---------------------------      ---
18*e2469d82SVarun Wadekar  *         Trusted Firmware timestamps      1KB
19*e2469d82SVarun Wadekar  * BASE    ---------------------------      ---
20*e2469d82SVarun Wadekar  *
21*e2469d82SVarun Wadekar  ******************************************************************************/
22*e2469d82SVarun Wadekar 
23*e2469d82SVarun Wadekar #include <arch.h>
24*e2469d82SVarun Wadekar #include <arch_helpers.h>
25*e2469d82SVarun Wadekar #include <assert.h>
26*e2469d82SVarun Wadekar #include <lib/mmio.h>
27*e2469d82SVarun Wadekar #include <lib/utils_def.h>
28*e2469d82SVarun Wadekar #include <lib/xlat_tables/xlat_tables_v2.h>
29*e2469d82SVarun Wadekar #include <profiler.h>
30*e2469d82SVarun Wadekar #include <stdbool.h>
31*e2469d82SVarun Wadekar #include <string.h>
32*e2469d82SVarun Wadekar 
33*e2469d82SVarun Wadekar static uint64_t shmem_base_addr;
34*e2469d82SVarun Wadekar 
35*e2469d82SVarun Wadekar #define MAX_PROFILER_RECORDS	U(16)
36*e2469d82SVarun Wadekar #define TAG_LEN_BYTES		U(56)
37*e2469d82SVarun Wadekar 
38*e2469d82SVarun Wadekar /*******************************************************************************
39*e2469d82SVarun Wadekar  * Profiler entry format
40*e2469d82SVarun Wadekar  ******************************************************************************/
41*e2469d82SVarun Wadekar typedef struct {
42*e2469d82SVarun Wadekar 	/* text explaining the timestamp location in code */
43*e2469d82SVarun Wadekar 	uint8_t tag[TAG_LEN_BYTES];
44*e2469d82SVarun Wadekar 	/* timestamp value */
45*e2469d82SVarun Wadekar 	uint64_t timestamp;
46*e2469d82SVarun Wadekar } profiler_rec_t;
47*e2469d82SVarun Wadekar 
48*e2469d82SVarun Wadekar static profiler_rec_t *head, *cur, *tail;
49*e2469d82SVarun Wadekar static uint32_t tmr;
50*e2469d82SVarun Wadekar static bool is_shmem_buf_mapped;
51*e2469d82SVarun Wadekar 
52*e2469d82SVarun Wadekar /*******************************************************************************
53*e2469d82SVarun Wadekar  * Initialise the profiling library
54*e2469d82SVarun Wadekar  ******************************************************************************/
55*e2469d82SVarun Wadekar void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
56*e2469d82SVarun Wadekar {
57*e2469d82SVarun Wadekar 	uint64_t shmem_end_base;
58*e2469d82SVarun Wadekar 
59*e2469d82SVarun Wadekar 	assert(shmem_base != ULL(0));
60*e2469d82SVarun Wadekar 	assert(tmr_base != U(0));
61*e2469d82SVarun Wadekar 
62*e2469d82SVarun Wadekar 	/* store the buffer address */
63*e2469d82SVarun Wadekar 	shmem_base_addr = shmem_base;
64*e2469d82SVarun Wadekar 
65*e2469d82SVarun Wadekar 	/* calculate the base address of the last record */
66*e2469d82SVarun Wadekar 	shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
67*e2469d82SVarun Wadekar 			 (MAX_PROFILER_RECORDS - U(1)));
68*e2469d82SVarun Wadekar 
69*e2469d82SVarun Wadekar 	/* calculate the head, tail and cur values */
70*e2469d82SVarun Wadekar 	head = (profiler_rec_t *)shmem_base;
71*e2469d82SVarun Wadekar 	tail = (profiler_rec_t *)shmem_end_base;
72*e2469d82SVarun Wadekar 	cur = head;
73*e2469d82SVarun Wadekar 
74*e2469d82SVarun Wadekar 	/* timer used to get the current timestamp */
75*e2469d82SVarun Wadekar 	tmr = tmr_base;
76*e2469d82SVarun Wadekar }
77*e2469d82SVarun Wadekar 
78*e2469d82SVarun Wadekar /*******************************************************************************
79*e2469d82SVarun Wadekar  * Add tag and timestamp to profiler
80*e2469d82SVarun Wadekar  ******************************************************************************/
81*e2469d82SVarun Wadekar void boot_profiler_add_record(const char *str)
82*e2469d82SVarun Wadekar {
83*e2469d82SVarun Wadekar 	unsigned int len;
84*e2469d82SVarun Wadekar 
85*e2469d82SVarun Wadekar 	/* calculate the length of the tag */
86*e2469d82SVarun Wadekar 	if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
87*e2469d82SVarun Wadekar 		len = TAG_LEN_BYTES;
88*e2469d82SVarun Wadekar 	} else {
89*e2469d82SVarun Wadekar 		len = (unsigned int)strlen(str) + U(1);
90*e2469d82SVarun Wadekar 	}
91*e2469d82SVarun Wadekar 
92*e2469d82SVarun Wadekar 	if (head != NULL) {
93*e2469d82SVarun Wadekar 
94*e2469d82SVarun Wadekar 		/*
95*e2469d82SVarun Wadekar 		 * The profiler runs with/without MMU enabled. Check
96*e2469d82SVarun Wadekar 		 * if MMU is enabled and memmap the shmem buffer, in
97*e2469d82SVarun Wadekar 		 * case it is.
98*e2469d82SVarun Wadekar 		 */
99*e2469d82SVarun Wadekar 		if ((!is_shmem_buf_mapped) &&
100*e2469d82SVarun Wadekar 		    ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
101*e2469d82SVarun Wadekar 
102*e2469d82SVarun Wadekar 			(void)mmap_add_dynamic_region(shmem_base_addr,
103*e2469d82SVarun Wadekar 					shmem_base_addr,
104*e2469d82SVarun Wadekar 					PROFILER_SIZE_BYTES,
105*e2469d82SVarun Wadekar 					(MT_NS | MT_RW | MT_EXECUTE_NEVER));
106*e2469d82SVarun Wadekar 
107*e2469d82SVarun Wadekar 			is_shmem_buf_mapped = true;
108*e2469d82SVarun Wadekar 		}
109*e2469d82SVarun Wadekar 
110*e2469d82SVarun Wadekar 		/* write the tag and timestamp to buffer */
111*e2469d82SVarun Wadekar 		(void)snprintf((char *)cur->tag, len, "%s", str);
112*e2469d82SVarun Wadekar 		cur->timestamp = mmio_read_32(tmr);
113*e2469d82SVarun Wadekar 
114*e2469d82SVarun Wadekar 		/* start from head if we reached the end */
115*e2469d82SVarun Wadekar 		if (cur == tail) {
116*e2469d82SVarun Wadekar 			cur = head;
117*e2469d82SVarun Wadekar 		} else {
118*e2469d82SVarun Wadekar 			cur++;
119*e2469d82SVarun Wadekar 		}
120*e2469d82SVarun Wadekar 	}
121*e2469d82SVarun Wadekar }
122*e2469d82SVarun Wadekar 
123*e2469d82SVarun Wadekar /*******************************************************************************
124*e2469d82SVarun Wadekar  * Deinint the profiler
125*e2469d82SVarun Wadekar  ******************************************************************************/
126*e2469d82SVarun Wadekar void boot_profiler_deinit(void)
127*e2469d82SVarun Wadekar {
128*e2469d82SVarun Wadekar 	if (shmem_base_addr != ULL(0)) {
129*e2469d82SVarun Wadekar 
130*e2469d82SVarun Wadekar 		/* clean up resources */
131*e2469d82SVarun Wadekar 		cur = NULL;
132*e2469d82SVarun Wadekar 		head = NULL;
133*e2469d82SVarun Wadekar 		tail = NULL;
134*e2469d82SVarun Wadekar 
135*e2469d82SVarun Wadekar 		/* flush the shmem for it to be visible to the NS world */
136*e2469d82SVarun Wadekar 		flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
137*e2469d82SVarun Wadekar 
138*e2469d82SVarun Wadekar 		/* unmap the shmem buffer */
139*e2469d82SVarun Wadekar 		if (is_shmem_buf_mapped) {
140*e2469d82SVarun Wadekar 			(void)mmap_remove_dynamic_region(shmem_base_addr,
141*e2469d82SVarun Wadekar 					PROFILER_SIZE_BYTES);
142*e2469d82SVarun Wadekar 		}
143*e2469d82SVarun Wadekar 	}
144*e2469d82SVarun Wadekar }
145