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