arm-trusted-firmware/plat/qemu/common/qemu_bl31_setup.c
Mathieu Poirier d079d65d42 feat(qemu-sbsa): configure GPT based on system RAM
The amount of memory supported by the SBSA platform is dynamic
and dependent on user input.  Since the configuration of the GPT
needs to reflect the system memory, QEMU_PAS_NS0 needs to be set
based on the information found in the device tree.

Change-Id: I5d1411ac00020b7b38a652ba2904c8a70fa64d18
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
2024-12-06 11:20:43 -07:00

321 lines
8 KiB
C

/*
* Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/bl_common.h>
#include <drivers/arm/pl061_gpio.h>
#include <lib/gpt_rme/gpt_rme.h>
#include <lib/transfer_list.h>
#include <plat/common/platform.h>
#if ENABLE_RME
#ifdef PLAT_qemu
#include <qemu_pas_def.h>
#elif PLAT_qemu_sbsa
#include <qemu_sbsa_pas_def.h>
#endif /* PLAT_qemu */
#endif /* ENABLE_RME */
#ifdef PLAT_qemu_sbsa
#include <sbsa_platform.h>
#endif
#include "qemu_private.h"
#define MAP_BL31_TOTAL MAP_REGION_FLAT( \
BL31_BASE, \
BL31_END - BL31_BASE, \
MT_MEMORY | MT_RW | EL3_PAS)
#define MAP_BL31_RO MAP_REGION_FLAT( \
BL_CODE_BASE, \
BL_CODE_END - BL_CODE_BASE, \
MT_CODE | EL3_PAS), \
MAP_REGION_FLAT( \
BL_RO_DATA_BASE, \
BL_RO_DATA_END \
- BL_RO_DATA_BASE, \
MT_RO_DATA | EL3_PAS)
#if USE_COHERENT_MEM
#define MAP_BL_COHERENT_RAM MAP_REGION_FLAT( \
BL_COHERENT_RAM_BASE, \
BL_COHERENT_RAM_END \
- BL_COHERENT_RAM_BASE, \
MT_DEVICE | MT_RW | EL3_PAS)
#endif
/*
* Placeholder variables for copying the arguments that have been passed to
* BL3-1 from BL2.
*/
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
#if ENABLE_RME
static entry_point_info_t rmm_image_ep_info;
#endif
static struct transfer_list_header *bl31_tl;
/*******************************************************************************
* Perform any BL3-1 early platform setup. Here is an opportunity to copy
* parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
* they are lost (potentially). This needs to be done before the MMU is
* initialized so that the memory layout can be used while creating page
* tables. BL2 has flushed this information to memory, so we are guaranteed
* to pick up good data.
******************************************************************************/
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
/* Initialize the console to provide early debug support */
qemu_console_init();
/* Platform names have to be lowercase. */
#ifdef PLAT_qemu_sbsa
sbsa_platform_init();
#endif
/*
* Check params passed from BL2
*/
bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
assert(params_from_bl2);
assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
assert(params_from_bl2->h.version >= VERSION_2);
bl_params_node_t *bl_params = params_from_bl2->head;
/*
* Copy BL33, BL32 and RMM (if present), entry point information.
* They are stored in Secure RAM, in BL2's address space.
*/
while (bl_params) {
if (bl_params->image_id == BL32_IMAGE_ID)
bl32_image_ep_info = *bl_params->ep_info;
#if ENABLE_RME
if (bl_params->image_id == RMM_IMAGE_ID)
rmm_image_ep_info = *bl_params->ep_info;
#endif
if (bl_params->image_id == BL33_IMAGE_ID)
bl33_image_ep_info = *bl_params->ep_info;
bl_params = bl_params->next_params_info;
}
if (!bl33_image_ep_info.pc)
panic();
#if ENABLE_RME
if (!rmm_image_ep_info.pc)
panic();
#endif
if (TRANSFER_LIST && arg1 == (TRANSFER_LIST_SIGNATURE |
REGISTER_CONVENTION_VERSION_MASK) &&
transfer_list_check_header((void *)arg3) != TL_OPS_NON) {
bl31_tl = (void *)arg3; /* saved TL address from BL2 */
}
}
#if ENABLE_RME
#if PLAT_qemu
/*
* The GPT library might modify the gpt regions structure to optimize
* the layout, so the array cannot be constant.
*/
static pas_region_t pas_regions[] = {
QEMU_PAS_ROOT,
QEMU_PAS_SECURE,
QEMU_PAS_GPTS,
QEMU_PAS_NS0,
QEMU_PAS_REALM,
QEMU_PAS_NS1,
};
static inline void bl31_adjust_pas_regions(void) {}
#elif PLAT_qemu_sbsa
/*
* The GPT library might modify the gpt regions structure to optimize
* the layout, so the array cannot be constant.
*/
static pas_region_t pas_regions[] = {
QEMU_PAS_ROOT,
QEMU_PAS_SECURE,
QEMU_PAS_GPTS,
QEMU_PAS_REALM,
QEMU_PAS_NS0,
};
static void bl31_adjust_pas_regions(void)
{
uint64_t base_addr = 0, total_size = 0;
struct platform_memory_data data;
uint32_t node;
/*
* The amount of memory supported by the SBSA platform is dynamic
* and dependent on user input. Since the configuration of the GPT
* needs to reflect the system memory, QEMU_PAS_NS0 needs to be set
* based on the information found in the device tree.
*/
for (node = 0; node < sbsa_platform_num_memnodes(); node++) {
data = sbsa_platform_memory_node(node);
if (data.nodeid == 0) {
base_addr = data.addr_base;
}
total_size += data.addr_size;
}
/* Index '4' correspond to QEMU_PAS_NS0, see pas_regions[] above */
pas_regions[4].base_pa = base_addr;
pas_regions[4].size = total_size;
}
#endif /* PLAT_qemu */
static void bl31_plat_gpt_setup(void)
{
/*
* Initialize entire protected space to GPT_GPI_ANY. With each L0 entry
* covering 1GB (currently the only supported option), then covering
* 256TB of RAM (48-bit PA) would require a 2MB L0 region. At the
* moment we use a 8KB table, which covers 1TB of RAM (40-bit PA).
*/
if (gpt_init_l0_tables(PLATFORM_GPCCR_PPS, PLAT_QEMU_L0_GPT_BASE,
PLAT_QEMU_L0_GPT_SIZE +
PLAT_QEMU_GPT_BITLOCK_SIZE) < 0) {
ERROR("gpt_init_l0_tables() failed!\n");
panic();
}
bl31_adjust_pas_regions();
/* Carve out defined PAS ranges. */
if (gpt_init_pas_l1_tables(GPCCR_PGS_4K,
PLAT_QEMU_L1_GPT_BASE,
PLAT_QEMU_L1_GPT_SIZE,
pas_regions,
(unsigned int)(sizeof(pas_regions) /
sizeof(pas_region_t))) < 0) {
ERROR("gpt_init_pas_l1_tables() failed!\n");
panic();
}
INFO("Enabling Granule Protection Checks\n");
if (gpt_enable() < 0) {
ERROR("gpt_enable() failed!\n");
panic();
}
}
#endif
void bl31_plat_arch_setup(void)
{
const mmap_region_t bl_regions[] = {
MAP_BL31_TOTAL,
MAP_BL31_RO,
#if USE_COHERENT_MEM
MAP_BL_COHERENT_RAM,
#endif
#if ENABLE_RME
MAP_GPT_L0_REGION,
MAP_GPT_L1_REGION,
MAP_RMM_SHARED_MEM,
#endif
{0}
};
setup_page_tables(bl_regions, plat_qemu_get_mmap());
enable_mmu_el3(0);
#if ENABLE_RME
/* Initialise and enable granule protection after MMU. */
bl31_plat_gpt_setup();
/*
* Initialise Granule Protection library and enable GPC for the primary
* processor. The tables have already been initialized by a previous BL
* stage, so there is no need to provide any PAS here. This function
* sets up pointers to those tables.
*/
if (gpt_runtime_init() < 0) {
ERROR("gpt_runtime_init() failed!\n");
panic();
}
#endif /* ENABLE_RME */
}
static void qemu_gpio_init(void)
{
#ifdef SECURE_GPIO_BASE
pl061_gpio_init();
pl061_gpio_register(SECURE_GPIO_BASE, 0);
#endif
}
void bl31_platform_setup(void)
{
plat_qemu_gic_init();
qemu_gpio_init();
}
unsigned int plat_get_syscnt_freq2(void)
{
return read_cntfrq_el0();
}
/*******************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image
* for the security state specified. BL3-3 corresponds to the non-secure
* image type while BL3-2 corresponds to the secure image type. A NULL
* pointer is returned if the image does not exist.
******************************************************************************/
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
entry_point_info_t *next_image_info;
assert(sec_state_is_valid(type));
if (type == NON_SECURE) {
next_image_info = &bl33_image_ep_info;
}
#if ENABLE_RME
else if (type == REALM) {
next_image_info = &rmm_image_ep_info;
}
#endif
else {
next_image_info = &bl32_image_ep_info;
}
/*
* None of the images on the ARM development platforms can have 0x0
* as the entrypoint
*/
if (next_image_info->pc)
return next_image_info;
else
return NULL;
}
void bl31_plat_runtime_setup(void)
{
#if TRANSFER_LIST
if (bl31_tl) {
/*
* update the TL from S to NS memory before jump to BL33
* to reflect all changes in TL done by BL32
*/
memcpy((void *)FW_NS_HANDOFF_BASE, bl31_tl, bl31_tl->max_size);
}
#endif
console_flush();
console_switch_state(CONSOLE_FLAG_RUNTIME);
}