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