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