mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 02:24:18 +00:00
Tegra: lib: library for profiling the cold boot path
The non secure world would like to profile the boot path for the EL3 and S-EL1 firmwares. To allow it to do that, a non-secure DRAM region (4K) is allocated and the base address is passed to the EL3 firmware. This patch adds a library to allow the platform code to store the tag:timestamp pair to the shared memory. The tegra platform code then uses the `record` method to add timestamps. Original change by Akshay Sharan <asharan@nvidia.com> Change-Id: Idbbef9c83ed84a508b04d85a6637775960dc94ba Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
parent
6460ed7aaa
commit
087cf68a7f
6 changed files with 230 additions and 0 deletions
|
@ -82,6 +82,8 @@ uint64\_t tzdram\_base;
|
|||
int uart\_id;
|
||||
/* L2 ECC parity protection disable flag \*/
|
||||
int l2\_ecc\_parity\_prot\_dis;
|
||||
/* SHMEM base address for storing the boot logs \*/
|
||||
uint64\_t boot\_profiler\_shmem\_base;
|
||||
} plat\_params\_from\_bl2\_t;
|
||||
|
||||
Power Management
|
||||
|
|
146
plat/nvidia/tegra/common/lib/debug/profiler.c
Normal file
146
plat/nvidia/tegra/common/lib/debug/profiler.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* The profiler stores the timestamps captured during cold boot to the shared
|
||||
* memory for the non-secure world. The non-secure world driver parses the
|
||||
* shared memory block and writes the contents to a file on the device, which
|
||||
* can be later extracted for analysis.
|
||||
*
|
||||
* Profiler memory map
|
||||
*
|
||||
* TOP --------------------------- ---
|
||||
* Trusted OS timestamps 3KB
|
||||
* --------------------------- ---
|
||||
* Trusted Firmware timestamps 1KB
|
||||
* BASE --------------------------- ---
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <mmio.h>
|
||||
#include <profiler.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <utils_def.h>
|
||||
#include <xlat_tables_v2.h>
|
||||
|
||||
static uint64_t shmem_base_addr;
|
||||
|
||||
#define MAX_PROFILER_RECORDS U(16)
|
||||
#define TAG_LEN_BYTES U(56)
|
||||
|
||||
/*******************************************************************************
|
||||
* Profiler entry format
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
/* text explaining the timestamp location in code */
|
||||
uint8_t tag[TAG_LEN_BYTES];
|
||||
/* timestamp value */
|
||||
uint64_t timestamp;
|
||||
} profiler_rec_t;
|
||||
|
||||
static profiler_rec_t *head, *cur, *tail;
|
||||
static uint32_t tmr;
|
||||
static bool is_shmem_buf_mapped;
|
||||
|
||||
/*******************************************************************************
|
||||
* Initialise the profiling library
|
||||
******************************************************************************/
|
||||
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
|
||||
{
|
||||
uint64_t shmem_end_base;
|
||||
|
||||
assert(shmem_base != ULL(0));
|
||||
assert(tmr_base != U(0));
|
||||
|
||||
/* store the buffer address */
|
||||
shmem_base_addr = shmem_base;
|
||||
|
||||
/* calculate the base address of the last record */
|
||||
shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
|
||||
(MAX_PROFILER_RECORDS - U(1)));
|
||||
|
||||
/* calculate the head, tail and cur values */
|
||||
head = (profiler_rec_t *)shmem_base;
|
||||
tail = (profiler_rec_t *)shmem_end_base;
|
||||
cur = head;
|
||||
|
||||
/* timer used to get the current timestamp */
|
||||
tmr = tmr_base;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Add tag and timestamp to profiler
|
||||
******************************************************************************/
|
||||
void boot_profiler_add_record(const char *str)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
/* calculate the length of the tag */
|
||||
if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
|
||||
len = TAG_LEN_BYTES;
|
||||
} else {
|
||||
len = (unsigned int)strlen(str) + U(1);
|
||||
}
|
||||
|
||||
if (head != NULL) {
|
||||
|
||||
/*
|
||||
* The profiler runs with/without MMU enabled. Check
|
||||
* if MMU is enabled and memmap the shmem buffer, in
|
||||
* case it is.
|
||||
*/
|
||||
if ((!is_shmem_buf_mapped) &&
|
||||
((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
|
||||
|
||||
(void)mmap_add_dynamic_region(shmem_base_addr,
|
||||
shmem_base_addr,
|
||||
PROFILER_SIZE_BYTES,
|
||||
(MT_NS | MT_RW | MT_EXECUTE_NEVER));
|
||||
|
||||
is_shmem_buf_mapped = true;
|
||||
}
|
||||
|
||||
/* write the tag and timestamp to buffer */
|
||||
(void)snprintf((char *)cur->tag, len, "%s", str);
|
||||
cur->timestamp = mmio_read_32(tmr);
|
||||
|
||||
/* start from head if we reached the end */
|
||||
if (cur == tail) {
|
||||
cur = head;
|
||||
} else {
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Deinint the profiler
|
||||
******************************************************************************/
|
||||
void boot_profiler_deinit(void)
|
||||
{
|
||||
if (shmem_base_addr != ULL(0)) {
|
||||
|
||||
/* clean up resources */
|
||||
cur = NULL;
|
||||
head = NULL;
|
||||
tail = NULL;
|
||||
|
||||
/* flush the shmem for it to be visible to the NS world */
|
||||
flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
|
||||
|
||||
/* unmap the shmem buffer */
|
||||
if (is_shmem_buf_mapped) {
|
||||
(void)mmap_remove_dynamic_region(shmem_base_addr,
|
||||
PROFILER_SIZE_BYTES);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
#include <plat/common/platform.h>
|
||||
|
||||
#include <memctrl.h>
|
||||
#include <profiler.h>
|
||||
#include <tegra_def.h>
|
||||
#include <tegra_platform.h>
|
||||
#include <tegra_private.h>
|
||||
|
@ -125,6 +126,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|||
image_info_t bl32_img_info = { {0} };
|
||||
uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
|
||||
uint32_t console_clock;
|
||||
int32_t ret;
|
||||
|
||||
/*
|
||||
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
|
||||
|
@ -194,6 +196,32 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|||
TEGRA_CONSOLE_BAUDRATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The previous bootloader passes the base address of the shared memory
|
||||
* location to store the boot profiler logs. Sanity check the
|
||||
* address and initilise the profiler library, if it looks ok.
|
||||
*/
|
||||
if (plat_params->boot_profiler_shmem_base != 0ULL) {
|
||||
|
||||
ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base,
|
||||
PROFILER_SIZE_BYTES);
|
||||
if (ret == (int32_t)0) {
|
||||
|
||||
/* store the membase for the profiler lib */
|
||||
plat_bl31_params_from_bl2.boot_profiler_shmem_base =
|
||||
plat_params->boot_profiler_shmem_base;
|
||||
|
||||
/* initialise the profiler library */
|
||||
boot_profiler_init(plat_params->boot_profiler_shmem_base,
|
||||
TEGRA_TMRUS_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add timestamp for platform early setup entry.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] early setup entry");
|
||||
|
||||
/*
|
||||
* Initialize delay timer
|
||||
*/
|
||||
|
@ -244,6 +272,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|||
/* Early platform setup for Tegra SoCs */
|
||||
plat_early_platform_setup();
|
||||
|
||||
/*
|
||||
* Add timestamp for platform early setup exit.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] early setup exit");
|
||||
|
||||
INFO("BL3-1: Boot CPU: %s Processor [%lx]\n",
|
||||
(((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK)
|
||||
== DENVER_IMPL) ? "Denver" : "ARM", read_mpidr());
|
||||
|
@ -268,6 +301,11 @@ void plat_trusty_set_boot_args(aapcs64_params_t *args)
|
|||
******************************************************************************/
|
||||
void bl31_platform_setup(void)
|
||||
{
|
||||
/*
|
||||
* Add timestamp for platform setup entry.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] plat setup entry");
|
||||
|
||||
/* Initialize the gic cpu and distributor interfaces */
|
||||
plat_gic_setup();
|
||||
|
||||
|
@ -287,6 +325,11 @@ void bl31_platform_setup(void)
|
|||
*/
|
||||
tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
|
||||
|
||||
/*
|
||||
* Add timestamp for platform setup exit.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] plat setup exit");
|
||||
|
||||
INFO("BL3-1: Tegra platform setup complete\n");
|
||||
}
|
||||
|
||||
|
@ -305,6 +348,12 @@ void bl31_plat_runtime_setup(void)
|
|||
* disabled before we jump to the non-secure world.
|
||||
*/
|
||||
tegra_memctrl_disable_ahb_redirection();
|
||||
|
||||
/*
|
||||
* Add final timestamp before exiting BL31.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] bl31 exit");
|
||||
boot_profiler_deinit();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -325,6 +374,11 @@ void bl31_plat_arch_setup(void)
|
|||
#endif
|
||||
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
|
||||
|
||||
/*
|
||||
* Add timestamp for arch setup entry.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] arch setup entry");
|
||||
|
||||
/* add memory regions */
|
||||
mmap_add_region(rw_start, rw_start,
|
||||
rw_size,
|
||||
|
@ -373,6 +427,11 @@ void bl31_plat_arch_setup(void)
|
|||
/* enable the MMU */
|
||||
enable_mmu_el3(0);
|
||||
|
||||
/*
|
||||
* Add timestamp for arch setup exit.
|
||||
*/
|
||||
boot_profiler_add_record("[TF] arch setup exit");
|
||||
|
||||
INFO("BL3-1: Tegra: MMU enabled\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
|
||||
PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \
|
||||
-Iplat/nvidia/tegra/include/lib \
|
||||
-Iplat/nvidia/tegra/include \
|
||||
-Iplat/nvidia/tegra/include/${TARGET_SOC}
|
||||
|
||||
|
@ -25,6 +26,7 @@ BL31_SOURCES += drivers/console/aarch64/console.S \
|
|||
${TEGRA_GICv2_SOURCES} \
|
||||
${COMMON_DIR}/aarch64/tegra_helpers.S \
|
||||
${COMMON_DIR}/drivers/pmc/pmc.c \
|
||||
${COMMON_DIR}/lib/debug/profiler.c \
|
||||
${COMMON_DIR}/tegra_bl31_setup.c \
|
||||
${COMMON_DIR}/tegra_delay_timer.c \
|
||||
${COMMON_DIR}/tegra_fiq_glue.c \
|
||||
|
|
19
plat/nvidia/tegra/include/lib/profiler.h
Normal file
19
plat/nvidia/tegra/include/lib/profiler.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __PROFILER_H__
|
||||
#define __PROFILER_H__
|
||||
|
||||
/*******************************************************************************
|
||||
* Number of bytes of memory used by the profiler on Tegra
|
||||
******************************************************************************/
|
||||
#define PROFILER_SIZE_BYTES U(0x1000)
|
||||
|
||||
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base);
|
||||
void boot_profiler_add_record(const char *str);
|
||||
void boot_profiler_deinit(void);
|
||||
|
||||
#endif /* __PROFILER_H__ */
|
|
@ -44,6 +44,8 @@ typedef struct plat_params_from_bl2 {
|
|||
int32_t uart_id;
|
||||
/* L2 ECC parity protection disable flag */
|
||||
int32_t l2_ecc_parity_prot_dis;
|
||||
/* SHMEM base address for storing the boot logs */
|
||||
uint64_t boot_profiler_shmem_base;
|
||||
} plat_params_from_bl2_t;
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
Loading…
Add table
Reference in a new issue