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