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