From 6eaf928d66fbded8e190aaa189e1a0810ba79252 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 19 Sep 2019 10:45:28 +0100 Subject: FDT helper functions: Add function documentation Since we moved some functions that amend a DT blob in memory to common code, let's add proper function documentation. This covers the three exported functions in common/fdt_fixup.c. Change-Id: I67d7d27344e62172c789d308662f78d54903cf57 Signed-off-by: Andre Przywara --- common/fdt_fixup.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c index 8843404d..48ae9751 100644 --- a/common/fdt_fixup.c +++ b/common/fdt_fixup.c @@ -29,6 +29,20 @@ static int append_psci_compatible(void *fdt, int offs, const char *str) return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1); } +/******************************************************************************* + * dt_add_psci_node() - Add a PSCI node into an existing device tree + * @fdt: pointer to the device tree blob in memory + * + * Add a device tree node describing PSCI into the root level of an existing + * device tree blob in memory. + * This will add v0.1, v0.2 and v1.0 compatible strings and the standard + * function IDs for v0.1 compatibility. + * An existing PSCI node will not be touched, the function will return success + * in this case. This function will not touch the /cpus enable methods, use + * dt_add_psci_cpu_enable_methods() for that. + * + * Return: 0 on success, -1 otherwise. + ******************************************************************************/ int dt_add_psci_node(void *fdt) { int offs; @@ -113,6 +127,17 @@ static int dt_update_one_cpu_node(void *fdt, int offset) return offs; } +/******************************************************************************* + * dt_add_psci_cpu_enable_methods() - switch CPU nodes in DT to use PSCI + * @fdt: pointer to the device tree blob in memory + * + * Iterate over all CPU device tree nodes (/cpus/cpu@x) in memory to change + * the enable-method to PSCI. This will add the enable-method properties, if + * required, or will change existing properties to read "psci". + * + * Return: 0 on success, or a negative error value otherwise. + ******************************************************************************/ + int dt_add_psci_cpu_enable_methods(void *fdt) { int offs, ret; @@ -130,6 +155,25 @@ int dt_add_psci_cpu_enable_methods(void *fdt) #define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0) +/******************************************************************************* + * fdt_add_reserved_memory() - reserve (secure) memory regions in DT + * @dtb: pointer to the device tree blob in memory + * @node_name: name of the subnode to be used + * @base: physical base address of the reserved region + * @size: size of the reserved region + * + * Add a region of memory to the /reserved-memory node in a device tree in + * memory, creating that node if required. Each region goes into a subnode + * of that node and has a @node_name, a @base address and a @size. + * This will prevent any device tree consumer from using that memory. It + * can be used to announce secure memory regions, as it adds the "no-map" + * property to prevent mapping and speculative operations on that region. + * + * See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding + * documentation for details. + * + * Return: 0 on success, a negative error value otherwise. + ******************************************************************************/ int fdt_add_reserved_memory(void *dtb, const char *node_name, uintptr_t base, size_t size) { -- cgit v1.2.3 From 66799507c4bbade3a58b833b55bcbe195370fd87 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 19 Sep 2019 10:55:25 +0100 Subject: FDT helper functions: Respect architecture in PSCI function IDs PSCI uses different function IDs for CPU_SUSPEND and CPU_ON, depending on the architecture used (AArch64 or AArch32). For recent PSCI versions the client will determine the right version, but for PSCI v0.1 we need to put some ID in the DT node. At the moment we always add the 64-bit IDs, which is not correct if TF-A is built for AArch32. Use the function IDs matching the TF-A build architecture, for the two IDs where this differs. This only affects legacy OSes using PSCI v0.1. On the way remove the sys_poweroff and sys_reset properties, which were never described in the official PSCI DT binding. Change-Id: If77bc6daec215faeb2dc67112e765aacafd17f33 Signed-off-by: Andre Przywara --- common/fdt_fixup.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c index 48ae9751..99d0eee9 100644 --- a/common/fdt_fixup.c +++ b/common/fdt_fixup.c @@ -29,6 +29,19 @@ static int append_psci_compatible(void *fdt, int offs, const char *str) return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1); } +/* + * Those defines are for PSCI v0.1 legacy clients, which we expect to use + * the same execution state (AArch32/AArch64) as TF-A. + * Kernels running in AArch32 on an AArch64 TF-A should use PSCI v0.2. + */ +#ifdef __aarch64__ +#define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH64 +#define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH64 +#else +#define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH32 +#define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH32 +#endif + /******************************************************************************* * dt_add_psci_node() - Add a PSCI node into an existing device tree * @fdt: pointer to the device tree blob in memory @@ -66,15 +79,11 @@ int dt_add_psci_node(void *fdt) return -1; if (fdt_setprop_string(fdt, offs, "method", "smc")) return -1; - if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_AARCH64)) + if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_FNID)) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF)) return -1; - if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64)) - return -1; - if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF)) - return -1; - if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET)) + if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID)) return -1; return 0; } -- cgit v1.2.3 From 7c0a1877e76b5dc7b6326e3cb670c5156d4d4383 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 4 Aug 2019 10:46:21 +0100 Subject: rpi3: Allow runtime determination of UART base clock rate At the moment the UART input clock rate is hard coded at compile time. This works as long as the GPU firmware always sets up the same rate, which does not seem to be true for the Raspberry Pi 4. In preparation for being able to change this at runtime, add a base clock parameter to the console setup function. This is still hardcoded for the Raspberry Pi 3. Change-Id: I398bc2f1e9b46f7af9a84cb0b33cbe8e78f2d900 Signed-off-by: Andre Przywara --- plat/rpi/common/include/rpi_shared.h | 2 +- plat/rpi/common/rpi3_common.c | 4 ++-- plat/rpi/rpi3/rpi3_bl1_setup.c | 2 +- plat/rpi/rpi3/rpi3_bl2_setup.c | 2 +- plat/rpi/rpi3/rpi3_bl31_setup.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plat/rpi/common/include/rpi_shared.h b/plat/rpi/common/include/rpi_shared.h index 68634389..de835716 100644 --- a/plat/rpi/common/include/rpi_shared.h +++ b/plat/rpi/common/include/rpi_shared.h @@ -14,7 +14,7 @@ ******************************************************************************/ /* Utility functions */ -void rpi3_console_init(void); +void rpi3_console_init(unsigned int base_clk_rate); void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c index ab63d98f..4317b3a2 100644 --- a/plat/rpi/common/rpi3_common.c +++ b/plat/rpi/common/rpi3_common.c @@ -104,14 +104,14 @@ static const mmap_region_t plat_rpi3_mmap[] = { ******************************************************************************/ static console_16550_t rpi3_console; -void rpi3_console_init(void) +void rpi3_console_init(unsigned int base_clk_rate) { int console_scope = CONSOLE_FLAG_BOOT; #if RPI3_RUNTIME_UART != -1 console_scope |= CONSOLE_FLAG_RUNTIME; #endif int rc = console_16550_register(PLAT_RPI3_UART_BASE, - PLAT_RPI3_UART_CLK_IN_HZ, + base_clk_rate, PLAT_RPI3_UART_BAUDRATE, &rpi3_console); if (rc == 0) { diff --git a/plat/rpi/rpi3/rpi3_bl1_setup.c b/plat/rpi/rpi3/rpi3_bl1_setup.c index 3ac30e0f..dcce76e4 100644 --- a/plat/rpi/rpi3/rpi3_bl1_setup.c +++ b/plat/rpi/rpi3/rpi3_bl1_setup.c @@ -35,7 +35,7 @@ void bl1_early_platform_setup(void) 0x80000000); /* Initialize the console to provide early debug support */ - rpi3_console_init(); + rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL_RAM_BASE; diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c index 991c0fcb..44827c63 100644 --- a/plat/rpi/rpi3/rpi3_bl2_setup.c +++ b/plat/rpi/rpi3/rpi3_bl2_setup.c @@ -62,7 +62,7 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, meminfo_t *mem_layout = (meminfo_t *) arg1; /* Initialize the console to provide early debug support */ - rpi3_console_init(); + rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* Enable arch timer */ generic_delay_timer_init(); diff --git a/plat/rpi/rpi3/rpi3_bl31_setup.c b/plat/rpi/rpi3/rpi3_bl31_setup.c index a9efc52b..c16dbffa 100644 --- a/plat/rpi/rpi3/rpi3_bl31_setup.c +++ b/plat/rpi/rpi3/rpi3_bl31_setup.c @@ -60,7 +60,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, { /* Initialize the console to provide early debug support */ - rpi3_console_init(); + rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* * In debug builds, a special value is passed in 'arg1' to verify -- cgit v1.2.3 From f5cb15b0c886afaa41c5d3dad8e859b6a41f76ab Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 9 Jul 2019 11:25:57 +0100 Subject: Add basic support for Raspberry Pi 4 The Raspberry Pi 4 is a single board computer with four Cortex-A72 cores. From a TF-A perspective it is quite similar to the Raspberry Pi 3, although it comes with more memory (up to 4GB) and has a GIC. This initial port though differs quite a lot from the existing rpi3 platform port, mainly due to taking a much simpler and more robust approach to loading the non-secure payload: The GPU firmware of the SoC, which is responsible for initial platform setup (including DRAM initialisation), already loads the kernel, device tree and the "armstub" into DRAM. We take advantage of this, by placing just a BL31 component into the armstub8.bin component, which will be executed first, in AArch64 EL3. The non-secure payload can be a kernel or a boot loader (U-Boot or EDK-2), disguised as the "kernel" image and loaded by the GPU firmware. So this is just a BL31-only port, which directly drops into EL2 and executes whatever has been loaded as the "kernel" image, handing over the DTB address in x0. Change-Id: I636f4d1f661821566ad9e341d69ba36f6bbfb546 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/aarch64/plat_helpers.S | 187 +++++++++++++++++++++++++++++++++ plat/rpi/rpi4/include/plat_macros.S | 20 ++++ plat/rpi/rpi4/include/platform_def.h | 197 +++++++++++++++++++++++++++++++++++ plat/rpi/rpi4/include/rpi_hw.h | 115 ++++++++++++++++++++ plat/rpi/rpi4/platform.mk | 108 +++++++++++++++++++ plat/rpi/rpi4/rpi4_bl31_setup.c | 162 ++++++++++++++++++++++++++++ 6 files changed, 789 insertions(+) create mode 100644 plat/rpi/rpi4/aarch64/plat_helpers.S create mode 100644 plat/rpi/rpi4/include/plat_macros.S create mode 100644 plat/rpi/rpi4/include/platform_def.h create mode 100644 plat/rpi/rpi4/include/rpi_hw.h create mode 100644 plat/rpi/rpi4/platform.mk create mode 100644 plat/rpi/rpi4/rpi4_bl31_setup.c diff --git a/plat/rpi/rpi4/aarch64/plat_helpers.S b/plat/rpi/rpi4/aarch64/plat_helpers.S new file mode 100644 index 00000000..46073b79 --- /dev/null +++ b/plat/rpi/rpi4/aarch64/plat_helpers.S @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "../include/rpi_hw.h" + + .globl plat_crash_console_flush + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl platform_mem_init + .globl plat_get_my_entrypoint + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_reset_handler + .globl plat_rpi3_calc_core_pos + .globl plat_secondary_cold_boot_setup + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * + * This function uses the plat_rpi3_calc_core_pos() + * definition to get the index of the calling CPU. + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_rpi3_calc_core_pos +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); + * + * CorePos = (ClusterId * 4) + CoreId + * ----------------------------------------------------- + */ +func plat_rpi3_calc_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_rpi3_calc_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_is_my_cpu_primary (void); + * + * Find out whether the current cpu is the primary + * cpu. + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) + cmp x0, #RPI4_PRIMARY_CPU + cset w0, eq + ret +endfunc plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset e.g + * mark the cpu's presence, mechanism to place it in a + * holding pen etc. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + /* Calculate address of our hold entry */ + bl plat_my_core_pos + lsl x0, x0, #3 + mov_imm x2, PLAT_RPI3_TM_HOLD_BASE + add x0, x0, x2 + + /* + * This code runs way before requesting the warmboot of this core, + * so it is possible to clear the mailbox before getting a request + * to boot. + */ + mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT + str x1,[x0] + + /* Wait until we have a go */ +poll_mailbox: + wfe + ldr x1, [x0] + cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO + bne poll_mailbox + + /* Jump to the provided entrypoint */ + mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT + ldr x1, [x0] + br x1 +endfunc plat_secondary_cold_boot_setup + + /* --------------------------------------------------------------------- + * uintptr_t plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between a cold and a warm + * boot. + * + * This functions returns: + * - 0 for a cold boot. + * - Any other value for a warm boot. + * --------------------------------------------------------------------- + */ +func plat_get_my_entrypoint + /* TODO: support warm boot */ + mov x0, #0 + ret +endfunc plat_get_my_entrypoint + + /* --------------------------------------------- + * void platform_mem_init (void); + * + * No need to carry out any memory initialization. + * --------------------------------------------- + */ +func platform_mem_init + ret +endfunc platform_mem_init + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * Function to initialize the crash console + * without a C Runtime to print crash report. + * Clobber list : x0 - x3 + * --------------------------------------------- + */ +func plat_crash_console_init + mov_imm x0, PLAT_RPI3_UART_BASE + mov_imm x1, PLAT_RPI4_VPU_CLK_RATE + mov_imm x2, PLAT_RPI3_UART_BAUDRATE + b console_16550_core_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * Function to print a character on the crash + * console without a C Runtime. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func plat_crash_console_putc + mov_imm x1, PLAT_RPI3_UART_BASE + b console_16550_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * int plat_crash_console_flush() + * Function to force a write of all buffered + * data that hasn't been output. + * Out : return -1 on error else return 0. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x0, PLAT_RPI3_UART_BASE + b console_16550_core_flush +endfunc plat_crash_console_flush + + /* --------------------------------------------- + * void plat_reset_handler(void); + * --------------------------------------------- + */ +func plat_reset_handler + /* ------------------------------------------------ + * Set L2 read/write cache latency: + * - L2 Data RAM latency: 3 cycles (0b010) + * - L2 Data RAM setup: 1 cycle (bit 5) + * ------------------------------------------------ + */ + mrs x0, CORTEX_A72_L2CTLR_EL1 + mov x1, #0x22 + orr x0, x0, x1 + msr CORTEX_A72_L2CTLR_EL1, x0 + isb + + ret +endfunc plat_reset_handler diff --git a/plat/rpi/rpi4/include/plat_macros.S b/plat/rpi/rpi4/include/plat_macros.S new file mode 100644 index 00000000..6007d031 --- /dev/null +++ b/plat/rpi/rpi4/include/plat_macros.S @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant platform registers + * whenever an unhandled exception is taken in + * BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + .endm + +#endif /* PLAT_MACROS_S */ diff --git a/plat/rpi/rpi4/include/platform_def.h b/plat/rpi/rpi4/include/platform_def.h new file mode 100644 index 00000000..831d1c3f --- /dev/null +++ b/plat/rpi/rpi4/include/platform_def.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include +#include +#include +#include + +#include "rpi_hw.h" + +/* Special value used to verify platform parameters from BL2 to BL31 */ +#define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) + +#define PLATFORM_STACK_SIZE ULL(0x1000) + +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER +#define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT + +#define RPI4_PRIMARY_CPU U(0) + +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_RET_STATE U(1) +#define PLAT_MAX_OFF_STATE U(2) + +/* Local power state for power domains in Run state. */ +#define PLAT_LOCAL_STATE_RUN U(0) +/* Local power state for retention. Valid only for CPU power domains */ +#define PLAT_LOCAL_STATE_RET U(1) +/* + * Local power state for OFF/power-down. Valid for CPU and cluster power + * domains. + */ +#define PLAT_LOCAL_STATE_OFF U(2) + +/* + * Macros used to parse state information from State-ID if it is using the + * recommended encoding for State-ID. + */ +#define PLAT_LOCAL_PSTATE_WIDTH U(4) +#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) + +/* + * Some data must be aligned on the biggest cache line size in the platform. + * This is known only to the platform as it might have a combination of + * integrated and external caches. + */ +#define CACHE_WRITEBACK_SHIFT U(6) +#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) + +/* + * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and + * secure DRAM. Note that this is all actually DRAM with different names, + * there is no Secure RAM in the Raspberry Pi 4. + */ +#if RPI3_USE_UEFI_MAP +#define SEC_ROM_BASE ULL(0x00000000) +#define SEC_ROM_SIZE ULL(0x00010000) + +/* FIP placed after ROM to append it to BL1 with very little padding. */ +#define PLAT_RPI3_FIP_BASE ULL(0x00020000) +#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x00010000) + +/* Reserve 2M of secure SRAM and DRAM, starting at 2M */ +#define SEC_SRAM_BASE ULL(0x00200000) +#define SEC_SRAM_SIZE ULL(0x00100000) + +#define SEC_DRAM0_BASE ULL(0x00300000) +#define SEC_DRAM0_SIZE ULL(0x00100000) + +/* Windows on ARM requires some RAM at 4M */ +#define NS_DRAM0_BASE ULL(0x00400000) +#define NS_DRAM0_SIZE ULL(0x00C00000) +#else +#define SEC_ROM_BASE ULL(0x00000000) +#define SEC_ROM_SIZE ULL(0x00020000) + +/* FIP placed after ROM to append it to BL1 with very little padding. */ +#define PLAT_RPI3_FIP_BASE ULL(0x00020000) +#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001E0000) + +/* We have 16M of memory reserved starting at 256M */ +#define SEC_SRAM_BASE ULL(0x10000000) +#define SEC_SRAM_SIZE ULL(0x00100000) + +#define SEC_DRAM0_BASE ULL(0x10100000) +#define SEC_DRAM0_SIZE ULL(0x00F00000) +/* End of reserved memory */ + +#define NS_DRAM0_BASE ULL(0x11000000) +#define NS_DRAM0_SIZE ULL(0x01000000) +#endif /* RPI3_USE_UEFI_MAP */ + +/* + * BL33 entrypoint. + */ +#define PLAT_RPI3_NS_IMAGE_OFFSET NS_DRAM0_BASE +#define PLAT_RPI3_NS_IMAGE_MAX_SIZE NS_DRAM0_SIZE + +/* + * I/O registers. + */ +#define DEVICE0_BASE RPI_IO_BASE +#define DEVICE0_SIZE RPI_IO_SIZE + +/* + * TF-A lives in SRAM, partition it here + */ +#define SHARED_RAM_BASE SEC_SRAM_BASE +#define SHARED_RAM_SIZE ULL(0x00001000) + +#define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) +#define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) + +/* + * Mailbox to control the secondary cores. All secondary cores are held in a + * wait loop in cold boot. To release them perform the following steps (plus + * any additional barriers that may be needed): + * + * uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT; + * *entrypoint = ADDRESS_TO_JUMP_TO; + * + * uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; + * mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO; + * + * sev(); + */ +#define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE + +/* The secure entry point to be used on warm reset by all CPUs. */ +#define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE +#define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8) + +/* Hold entries for each CPU. */ +#define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \ + PLAT_RPI3_TM_ENTRYPOINT_SIZE) +#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8) +#define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \ + PLATFORM_CORE_COUNT) + +#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \ + PLAT_RPI3_TM_HOLD_SIZE) + +#define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0) +#define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1) + +/* + * BL31 specific defines. + * + * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the + * current BL31 debug size plus a little space for growth. + */ +#define PLAT_MAX_BL31_SIZE ULL(0x20000) + +#define BL31_BASE ULL(0x1000) +#define BL31_LIMIT ULL(0x100000) +#define BL31_PROGBITS_LIMIT ULL(0x100000) + +#define SEC_SRAM_ID 0 +#define SEC_DRAM_ID 1 + +/* + * Other memory-related defines. + */ +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + +#define MAX_MMAP_REGIONS 8 +#define MAX_XLAT_TABLES 4 + +#define MAX_IO_DEVICES U(3) +#define MAX_IO_HANDLES U(4) + +#define MAX_IO_BLOCK_DEVICES U(1) + +/* + * Serial-related constants. + */ +#define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE +#define PLAT_RPI3_UART_BAUDRATE ULL(115200) + +/* + * System counter + */ +#define SYS_COUNTER_FREQ_IN_TICKS ULL(54000000) + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/rpi/rpi4/include/rpi_hw.h b/plat/rpi/rpi4/include/rpi_hw.h new file mode 100644 index 00000000..ed367ee2 --- /dev/null +++ b/plat/rpi/rpi4/include/rpi_hw.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPI_HW_H +#define RPI_HW_H + +#include + +/* + * Peripherals + */ + +#define RPI_IO_BASE ULL(0xFE000000) +#define RPI_IO_SIZE ULL(0x02000000) + +/* + * ARM <-> VideoCore mailboxes + */ +#define RPI3_MBOX_OFFSET ULL(0x0000B880) +#define RPI3_MBOX_BASE (RPI_IO_BASE + RPI3_MBOX_OFFSET) +/* VideoCore -> ARM */ +#define RPI3_MBOX0_READ_OFFSET ULL(0x00000000) +#define RPI3_MBOX0_PEEK_OFFSET ULL(0x00000010) +#define RPI3_MBOX0_SENDER_OFFSET ULL(0x00000014) +#define RPI3_MBOX0_STATUS_OFFSET ULL(0x00000018) +#define RPI3_MBOX0_CONFIG_OFFSET ULL(0x0000001C) +/* ARM -> VideoCore */ +#define RPI3_MBOX1_WRITE_OFFSET ULL(0x00000020) +#define RPI3_MBOX1_PEEK_OFFSET ULL(0x00000030) +#define RPI3_MBOX1_SENDER_OFFSET ULL(0x00000034) +#define RPI3_MBOX1_STATUS_OFFSET ULL(0x00000038) +#define RPI3_MBOX1_CONFIG_OFFSET ULL(0x0000003C) +/* Mailbox status constants */ +#define RPI3_MBOX_STATUS_FULL_MASK U(0x80000000) /* Set if full */ +#define RPI3_MBOX_STATUS_EMPTY_MASK U(0x40000000) /* Set if empty */ + +/* + * Power management, reset controller, watchdog. + */ +#define RPI3_IO_PM_OFFSET ULL(0x00100000) +#define RPI3_PM_BASE (RPI_IO_BASE + RPI3_IO_PM_OFFSET) +/* Registers on top of RPI3_PM_BASE. */ +#define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) +#define RPI3_PM_RSTS_OFFSET ULL(0x00000020) +#define RPI3_PM_WDOG_OFFSET ULL(0x00000024) +/* Watchdog constants */ +#define RPI3_PM_PASSWORD U(0x5A000000) +#define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030) +#define RPI3_PM_RSTC_WRCFG_FULL_RESET U(0x00000020) +/* + * The RSTS register is used by the VideoCore firmware when booting the + * Raspberry Pi to know which partition to boot from. The partition value is + * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware + * to indicate halt. + */ +#define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555) + +/* + * Clock controller + */ +#define RPI4_IO_CLOCK_OFFSET ULL(0x00101000) +#define RPI4_CLOCK_BASE (RPI_IO_BASE + RPI4_IO_CLOCK_OFFSET) +#define RPI4_VPU_CLOCK_DIVIDER ULL(0x0000000c) + +/* + * Hardware random number generator. + */ +#define RPI3_IO_RNG_OFFSET ULL(0x00104000) +#define RPI3_RNG_BASE (RPI_IO_BASE + RPI3_IO_RNG_OFFSET) +#define RPI3_RNG_CTRL_OFFSET ULL(0x00000000) +#define RPI3_RNG_STATUS_OFFSET ULL(0x00000004) +#define RPI3_RNG_DATA_OFFSET ULL(0x00000008) +#define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010) +/* Enable/disable RNG */ +#define RPI3_RNG_CTRL_ENABLE U(0x1) +#define RPI3_RNG_CTRL_DISABLE U(0x0) +/* Number of currently available words */ +#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24) +#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF) +/* Value to mask interrupts caused by the RNG */ +#define RPI3_RNG_INT_MASK_DISABLE U(0x1) + +/* + * Serial port (called 'Mini UART' in the Broadcom documentation). + */ +#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) +#define RPI3_MINI_UART_BASE (RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET) +#define PLAT_RPI4_VPU_CLK_RATE ULL(1000000000) + +/* + * GPIO controller + */ +#define RPI3_IO_GPIO_OFFSET ULL(0x00200000) +#define RPI3_GPIO_BASE (RPI_IO_BASE + RPI3_IO_GPIO_OFFSET) + +/* + * SDHost controller + */ +#define RPI3_IO_SDHOST_OFFSET ULL(0x00202000) +#define RPI3_SDHOST_BASE (RPI_IO_BASE + RPI3_IO_SDHOST_OFFSET) + +/* + * GIC interrupt controller + */ +#define RPI_HAVE_GIC +#define RPI4_GIC_GICD_BASE ULL(0xff841000) +#define RPI4_GIC_GICC_BASE ULL(0xff842000) + +#define RPI4_LOCAL_CONTROL_BASE_ADDRESS ULL(0xff800000) +#define RPI4_LOCAL_CONTROL_PRESCALER ULL(0xff800008) + +#endif /* RPI_HW_H */ diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk new file mode 100644 index 00000000..3ff180ea --- /dev/null +++ b/plat/rpi/rpi4/platform.mk @@ -0,0 +1,108 @@ +# +# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include lib/libfdt/libfdt.mk +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_INCLUDES := -Iplat/rpi/common/include \ + -Iplat/rpi/rpi4/include + +PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \ + plat/rpi/common/rpi3_common.c \ + ${XLAT_TABLES_LIB_SRCS} + +BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \ + plat/rpi/rpi4/aarch64/plat_helpers.S \ + drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + drivers/arm/gic/v2/gicv2_main.c \ + plat/common/plat_gicv2.c \ + plat/rpi/rpi4/rpi4_bl31_setup.c \ + plat/rpi/common/rpi3_pm.c \ + plat/common/plat_psci_common.c \ + plat/rpi/common/rpi3_topology.c \ + ${LIBFDT_SRCS} + +# For now we only support BL31, using the kernel loaded by the GPU firmware. +RESET_TO_BL31 := 1 + +# All CPUs enter armstub8.bin. +COLD_BOOT_SINGLE_CPU := 0 + +# Tune compiler for Cortex-A72 +ifeq ($(notdir $(CC)),armclang) + TF_CFLAGS_aarch64 += -mcpu=cortex-a72 +else ifneq ($(findstring clang,$(notdir $(CC))),) + TF_CFLAGS_aarch64 += -mcpu=cortex-a72 +else + TF_CFLAGS_aarch64 += -mtune=cortex-a72 +endif + + +# Enable all errata workarounds for Cortex-A72 +ERRATA_A72_859971 := 1 + +WORKAROUND_CVE_2017_5715 := 1 + +# Add new default target when compiling this platform +all: bl31 + +# Build config flags +# ------------------ + +# Disable stack protector by default +ENABLE_STACK_PROTECTOR := 0 + +# Have different sections for code and rodata +SEPARATE_CODE_AND_RODATA := 1 + +# Use Coherent memory +USE_COHERENT_MEM := 1 + +# Platform build flags +# -------------------- + +# Assume that BL33 isn't the Linux kernel by default +RPI3_DIRECT_LINUX_BOOT := 0 + +# BL33 images are in AArch64 by default +RPI3_BL33_IN_AARCH32 := 0 + +# UART to use at runtime. -1 means the runtime UART is disabled. +# Any other value means the default UART will be used. +RPI3_RUNTIME_UART := 0 + +# Use normal memory mapping for ROM, FIP, SRAM and DRAM +RPI3_USE_UEFI_MAP := 0 + +# Process platform flags +# ---------------------- + +$(eval $(call add_define,RPI3_BL33_IN_AARCH32)) +$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT)) +ifdef RPI3_PRELOADED_DTB_BASE +$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE)) +endif +$(eval $(call add_define,RPI3_RUNTIME_UART)) +$(eval $(call add_define,RPI3_USE_UEFI_MAP)) + +# Verify build config +# ------------------- +# +ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0) + ifndef RPI3_PRELOADED_DTB_BASE + $(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1) + endif +endif + +ifeq (${ARCH},aarch32) + $(error Error: AArch32 not supported on rpi4) +endif + +ifneq ($(ENABLE_STACK_PROTECTOR), 0) +PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \ + plat/rpi/common/rpi3_stack_protector.c +endif diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c new file mode 100644 index 00000000..de582b32 --- /dev/null +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +static const gicv2_driver_data_t rpi4_gic_data = { + .gicd_base = RPI4_GIC_GICD_BASE, + .gicc_base = RPI4_GIC_GICC_BASE, +}; + +/* + * To be filled by the code below. At the moment BL32 is not supported. + * In the future these might be passed down from BL2. + */ +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 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) != 0); + + next_image_info = (type == NON_SECURE) + ? &bl33_image_ep_info : &bl32_image_ep_info; + + /* None of the images can have 0x0 as the entrypoint. */ + if (next_image_info->pc) { + return next_image_info; + } else { + return NULL; + } +} + +static void ldelay(register_t delay) +{ + __asm__ volatile ( + "1:\tcbz %0, 2f\n\t" + "sub %0, %0, #1\n\t" + "b 1b\n" + "2:" + : "=&r" (delay) : "0" (delay) + ); +} + +/******************************************************************************* + * Perform any BL31 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) + +{ + uint32_t div_reg; + + /* + * LOCAL_CONTROL: + * Bit 9 clear: Increment by 1 (vs. 2). + * Bit 8 clear: Timer source is 19.2MHz crystal (vs. APB). + */ + mmio_write_32(RPI4_LOCAL_CONTROL_BASE_ADDRESS, 0); + + /* LOCAL_PRESCALER; divide-by (0x80000000 / register_val) == 1 */ + mmio_write_32(RPI4_LOCAL_CONTROL_PRESCALER, 0x80000000); + + /* Early GPU firmware revisions need a little break here. */ + ldelay(100000); + + /* + * Initialize the console to provide early debug support. + * Different GPU firmware revisions set up the VPU divider differently, + * so read the actual divider register to learn the UART base clock + * rate. The divider is encoded as a 12.12 fixed point number, but we + * just care about the integer part of it. + */ + div_reg = mmio_read_32(RPI4_CLOCK_BASE + RPI4_VPU_CLOCK_DIVIDER); + div_reg = (div_reg >> 12) & 0xfff; + if (div_reg == 0) + div_reg = 1; + rpi3_console_init(PLAT_RPI4_VPU_CLK_RATE / div_reg); + +#if RPI3_DIRECT_LINUX_BOOT + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + +# if RPI3_BL33_IN_AARCH32 + /* + * According to the file ``Documentation/arm/Booting`` of the Linux + * kernel tree, Linux expects: + * r0 = 0 + * r1 = machine type number, optional in DT-only platforms (~0 if so) + * r2 = Physical address of the device tree blob + */ + VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n"); + bl33_image_ep_info.args.arg0 = 0U; + bl33_image_ep_info.args.arg1 = ~0U; + bl33_image_ep_info.args.arg2 = (u_register_t) RPI3_PRELOADED_DTB_BASE; +# else + /* + * According to the file ``Documentation/arm64/booting.txt`` of the + * Linux kernel tree, Linux expects the physical address of the device + * tree blob (DTB) in x0, while x1-x3 are reserved for future use and + * must be 0. + */ + VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n"); + bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE; + bl33_image_ep_info.args.arg1 = 0ULL; + bl33_image_ep_info.args.arg2 = 0ULL; + bl33_image_ep_info.args.arg3 = 0ULL; +# endif /* RPI3_BL33_IN_AARCH32 */ +#endif /* RPI3_DIRECT_LINUX_BOOT */ +} + +void bl31_plat_arch_setup(void) +{ + rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, + BL_CODE_BASE, BL_CODE_END, + BL_RO_DATA_BASE, BL_RO_DATA_END +#if USE_COHERENT_MEM + , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END +#endif + ); + + enable_mmu_el3(0); +} + +void bl31_platform_setup(void) +{ + /* Configure the interrupt controller */ + gicv2_driver_init(&rpi4_gic_data); + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} -- cgit v1.2.3 From c4597e13a2925cc6bf802d9376238f5de18b292a Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 10 Jul 2019 18:09:18 +0100 Subject: rpi4: Accommodate "armstub8.bin" header at the beginning of BL31 image The Raspberry Pi GPU firmware checks for a magic value at offset 240 (0xf0) of the armstub8.bin image it loads. If that value matches, it writes the kernel load address and the DTB address into subsequent memory locations. We can use these addresses to avoid hardcoding these values into the BL31 image, to make it more flexible and a drop-in replacement for the official armstub8.bin. Reserving just 16 bytes at offset 240 of the final image file is not easily possible, though, as this location is in the middle of the generic BL31 entry point code. However we can prepend an extra section before the actual BL31 image, to contain the magic and addresses. This needs to be 4KB, because the actual BL31 entry point needs to be page aligned. Use the platform linker script hook that the generic code provides, to add an almost empty 4KB code block before the entry point code. The very first word contains a branch instruction to jump over this page, into the actual entry code. This also gives us plenty of room for the SMP pens later. Change-Id: I38caa5e7195fa39cbef8600933a03d86f09263d6 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/aarch64/armstub8_header.S | 37 +++++++++++++++++++++++++++++++++ plat/rpi/rpi4/include/plat.ld.S | 23 ++++++++++++++++++++ plat/rpi/rpi4/platform.mk | 3 +++ plat/rpi/rpi4/rpi4_bl31_setup.c | 17 +++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 plat/rpi/rpi4/aarch64/armstub8_header.S create mode 100644 plat/rpi/rpi4/include/plat.ld.S diff --git a/plat/rpi/rpi4/aarch64/armstub8_header.S b/plat/rpi/rpi4/aarch64/armstub8_header.S new file mode 100644 index 00000000..246358d0 --- /dev/null +++ b/plat/rpi/rpi4/aarch64/armstub8_header.S @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * armstub8.bin header to let the GPU firmware recognise this code. + * It will then write the load address of the kernel image and the DT + * after the header magic in RAM, so we can read those addresses at runtime. + */ + +.text + b armstub8_end + +.global stub_magic +.global dtb_ptr32 +.global kernel_entry32 + +.org 0xf0 +armstub8: +stub_magic: + .word 0x5afe570b +stub_version: + .word 0 +dtb_ptr32: + .word 0x0 +kernel_entry32: + .word 0x0 + +/* + * Technically an offset of 0x100 would suffice, but the follow-up code + * (bl31_entrypoint.S at BL31_BASE) needs to be page aligned, so pad here + * till the end of the first 4K page. + */ +.org 0x1000 +armstub8_end: diff --git a/plat/rpi/rpi4/include/plat.ld.S b/plat/rpi/rpi4/include/plat.ld.S new file mode 100644 index 00000000..9262fad8 --- /dev/null +++ b/plat/rpi/rpi4/include/plat.ld.S @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Stub linker script to provide the armstub8.bin header before the actual + * code. If the GPU firmware finds a magic value at offset 240 in + * armstub8.bin, it will put the DTB and kernel load address in subsequent + * words. We can then read those values to find the proper NS entry point + * and find our DTB more flexibly. + */ + +MEMORY { + PRERAM (rwx): ORIGIN = 0, LENGTH = 4096 +} + +SECTIONS +{ + .armstub8 . : { + *armstub8_header.o(.text*) + KEEP(*(.armstub8)) + } >PRERAM +} diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk index 3ff180ea..b20251cf 100644 --- a/plat/rpi/rpi4/platform.mk +++ b/plat/rpi/rpi4/platform.mk @@ -16,6 +16,7 @@ PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \ BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \ plat/rpi/rpi4/aarch64/plat_helpers.S \ + plat/rpi/rpi4/aarch64/armstub8_header.S \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ @@ -41,6 +42,8 @@ else TF_CFLAGS_aarch64 += -mtune=cortex-a72 endif +# Add support for platform supplied linker script for BL31 build +$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Enable all errata workarounds for Cortex-A72 ERRATA_A72_859971 := 1 diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index de582b32..58025b27 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -13,12 +13,21 @@ #include #include #include +#include #include #include #include +/* + * Fields at the beginning of armstub8.bin. + * While building the BL31 image, we put the stub magic into the binary. + * The GPU firmware detects this at boot time, clears that field as a + * confirmation and puts the kernel and DT address in the following words. + */ +extern uint32_t stub_magic; + static const gicv2_driver_data_t rpi4_gic_data = { .gicd_base = RPI4_GIC_GICD_BASE, .gicc_base = RPI4_GIC_GICC_BASE, @@ -141,6 +150,14 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, void bl31_plat_arch_setup(void) { + /* + * Add the first page of memory, which holds the stub magic, + * the kernel and the DT address. + * This is read-only, as the GPU already populated the header, + * we just need to read it. + */ + mmap_add_region(0, 0, 4096, MT_MEMORY | MT_RO | MT_SECURE); + rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END -- cgit v1.2.3 From 448fb352f9be697e40b1224df3e33bca863326c6 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 11 Jul 2019 01:42:12 +0100 Subject: rpi4: Determine BL33 entry point at runtime Now that we have the armstub magic value in place, the GPU firmware will write the kernel load address (and DTB address) into our special page, so we can always easily access the actual location without hardcoding any addresses into the BL31 image. Make the compile-time defined PRELOADED_BL33_BASE macro optional, and read the BL33 entry point from the magic location, if the macro was not defined. We do the same for the DTB address. This also splits the currently "common" definition of plat_get_ns_image_entrypoint() to be separate between RPi3 and RPi4. Change-Id: I6f26c0adc6fce2df47786b271c490928b4529abb Signed-off-by: Andre Przywara --- plat/rpi/common/rpi3_common.c | 12 ------------ plat/rpi/rpi3/rpi3_bl31_setup.c | 12 ++++++++++++ plat/rpi/rpi4/platform.mk | 13 ++----------- plat/rpi/rpi4/rpi4_bl31_setup.c | 39 ++++++++++++++++++++++++++++++++++----- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c index 4317b3a2..ff336942 100644 --- a/plat/rpi/common/rpi3_common.c +++ b/plat/rpi/common/rpi3_common.c @@ -175,18 +175,6 @@ void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size, init_xlat_tables(); } -/******************************************************************************* - * Return entrypoint of BL33. - ******************************************************************************/ -uintptr_t plat_get_ns_image_entrypoint(void) -{ -#ifdef PRELOADED_BL33_BASE - return PRELOADED_BL33_BASE; -#else - return PLAT_RPI3_NS_IMAGE_OFFSET; -#endif -} - /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ diff --git a/plat/rpi/rpi3/rpi3_bl31_setup.c b/plat/rpi/rpi3/rpi3_bl31_setup.c index c16dbffa..24a56139 100644 --- a/plat/rpi/rpi3/rpi3_bl31_setup.c +++ b/plat/rpi/rpi3/rpi3_bl31_setup.c @@ -47,6 +47,18 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) } } +/******************************************************************************* + * Return entrypoint of BL33. + ******************************************************************************/ +uintptr_t plat_get_ns_image_entrypoint(void) +{ +#ifdef PRELOADED_BL33_BASE + return PRELOADED_BL33_BASE; +#else + return PLAT_RPI3_NS_IMAGE_OFFSET; +#endif +} + /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk index b20251cf..6ac21691 100644 --- a/plat/rpi/rpi4/platform.mk +++ b/plat/rpi/rpi4/platform.mk @@ -68,8 +68,8 @@ USE_COHERENT_MEM := 1 # Platform build flags # -------------------- -# Assume that BL33 isn't the Linux kernel by default -RPI3_DIRECT_LINUX_BOOT := 0 +# There is not much else than a Linux kernel to load at the moment. +RPI3_DIRECT_LINUX_BOOT := 1 # BL33 images are in AArch64 by default RPI3_BL33_IN_AARCH32 := 0 @@ -92,15 +92,6 @@ endif $(eval $(call add_define,RPI3_RUNTIME_UART)) $(eval $(call add_define,RPI3_USE_UEFI_MAP)) -# Verify build config -# ------------------- -# -ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0) - ifndef RPI3_PRELOADED_DTB_BASE - $(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1) - endif -endif - ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on rpi4) endif diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index 58025b27..f5f74bdd 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -27,6 +27,8 @@ * confirmation and puts the kernel and DT address in the following words. */ extern uint32_t stub_magic; +extern uint32_t dtb_ptr32; +extern uint32_t kernel_entry32; static const gicv2_driver_data_t rpi4_gic_data = { .gicd_base = RPI4_GIC_GICD_BASE, @@ -63,6 +65,34 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) } } +uintptr_t plat_get_ns_image_entrypoint(void) +{ +#ifdef PRELOADED_BL33_BASE + return PRELOADED_BL33_BASE; +#else + /* Cleared by the GPU if kernel address is valid. */ + if (stub_magic == 0) + return kernel_entry32; + + WARN("Stub magic failure, using default kernel address 0x80000\n"); + return 0x80000; +#endif +} + +static uintptr_t rpi4_get_dtb_address(void) +{ +#ifdef RPI3_PRELOADED_DTB_BASE + return RPI3_PRELOADED_DTB_BASE; +#else + /* Cleared by the GPU if DTB address is valid. */ + if (stub_magic == 0) + return dtb_ptr32; + + WARN("Stub magic failure, DTB address unknown\n"); + return 0; +#endif +} + static void ldelay(register_t delay) { __asm__ volatile ( @@ -114,12 +144,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, div_reg = 1; rpi3_console_init(PLAT_RPI4_VPU_CLK_RATE / div_reg); -#if RPI3_DIRECT_LINUX_BOOT bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); - bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, - DISABLE_ALL_EXCEPTIONS); + bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); +#if RPI3_DIRECT_LINUX_BOOT # if RPI3_BL33_IN_AARCH32 /* * According to the file ``Documentation/arm/Booting`` of the Linux @@ -131,7 +160,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n"); bl33_image_ep_info.args.arg0 = 0U; bl33_image_ep_info.args.arg1 = ~0U; - bl33_image_ep_info.args.arg2 = (u_register_t) RPI3_PRELOADED_DTB_BASE; + bl33_image_ep_info.args.arg2 = rpi4_get_dtb_address(); # else /* * According to the file ``Documentation/arm64/booting.txt`` of the @@ -140,7 +169,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, * must be 0. */ VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n"); - bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE; + bl33_image_ep_info.args.arg0 = rpi4_get_dtb_address(); bl33_image_ep_info.args.arg1 = 0ULL; bl33_image_ep_info.args.arg2 = 0ULL; bl33_image_ep_info.args.arg3 = 0ULL; -- cgit v1.2.3 From f67fa69cb6937a7fc559bbec4a7acce5edefa888 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 11 Jul 2019 01:45:39 +0100 Subject: rpi4: Amend DTB to advertise PSCI The device tree provided by the official Raspberry Pi firmware uses spin tables for SMP bringup. One of the benefit of having TF-A is that it provides PSCI services, so let's rewrite the DTB to advertise PSCI instead of spin tables. This uses the (newly exported) routine from the QEMU platform port. Change-Id: Ifddcb14041ca253a333f8c2d5e97a42db152470c Signed-off-by: Andre Przywara --- plat/rpi/rpi4/platform.mk | 1 + plat/rpi/rpi4/rpi4_bl31_setup.c | 57 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk index 6ac21691..2038021a 100644 --- a/plat/rpi/rpi4/platform.mk +++ b/plat/rpi/rpi4/platform.mk @@ -25,6 +25,7 @@ BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \ plat/rpi/common/rpi3_pm.c \ plat/common/plat_psci_common.c \ plat/rpi/common/rpi3_topology.c \ + common/fdt_fixup.c \ ${LIBFDT_SRCS} # For now we only support BL31, using the kernel loaded by the GPU firmware. diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index f5f74bdd..e1b6c897 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -9,12 +9,15 @@ #include #include +#include #include #include #include #include #include #include +#include +#include #include @@ -179,6 +182,18 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, void bl31_plat_arch_setup(void) { + /* + * Is the dtb_ptr32 pointer valid? If yes, map the DTB region. + * We map the 2MB region the DTB start address lives in, plus + * the next 2MB, to have enough room for expansion. + */ + if (stub_magic == 0) { + unsigned long long dtb_region = dtb_ptr32; + + dtb_region &= ~0x1fffff; /* Align to 2 MB. */ + mmap_add_region(dtb_region, dtb_region, 4U << 20, + MT_MEMORY | MT_RW | MT_NS); + } /* * Add the first page of memory, which holds the stub magic, * the kernel and the DT address. @@ -198,8 +213,50 @@ void bl31_plat_arch_setup(void) enable_mmu_el3(0); } +static uint32_t dtb_size(const void *dtb) +{ + const uint32_t *dtb_header = dtb; + + return fdt32_to_cpu(dtb_header[1]); +} + +static void rpi4_prepare_dtb(void) +{ + void *dtb = (void *)rpi4_get_dtb_address(); + int ret; + + /* Return if no device tree is detected */ + if (fdt_check_header(dtb) != 0) + return; + + ret = fdt_open_into(dtb, dtb, 0x100000); + if (ret < 0) { + ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret); + return; + } + + if (dt_add_psci_node(dtb)) { + ERROR("Failed to add PSCI Device Tree node\n"); + return; + } + + if (dt_add_psci_cpu_enable_methods(dtb)) { + ERROR("Failed to add PSCI cpu enable methods in Device Tree\n"); + return; + } + + ret = fdt_pack(dtb); + if (ret < 0) + ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret); + + clean_dcache_range((uintptr_t)dtb, dtb_size(dtb)); + INFO("Changed device tree to advertise PSCI.\n"); +} + void bl31_platform_setup(void) { + rpi4_prepare_dtb(); + /* Configure the interrupt controller */ gicv2_driver_init(&rpi4_gic_data); gicv2_distif_init(); -- cgit v1.2.3 From 2b19e2f361ac9be69f0f19ed7a25b1a038d91fc3 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 22 Jul 2019 00:04:40 +0100 Subject: rpi4: Reserve resident BL31 region from non-secure world The GPU firmware loads the armstub8.bin (BL31) image at address 0, the beginning of DRAM. As this holds the resident PSCI code and the SMP pens, the non-secure world should better know about this, to avoid accessing memory owned by TF-A. This is particularly criticial as the Raspberry Pi 4 does not feature a secure memory controller, so overwriting code is a very real danger. Use the newly introduced function to add a node into reserved-memory node, where non-secure world can check for regions to be excluded from its mappings. Reserve the first 512KB of memory for now. We can refine this later if need be. Change-Id: I00e55e70c5c02615320d79ff35bc32b805d30770 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/rpi4_bl31_setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index e1b6c897..8dfadf73 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -245,6 +245,10 @@ static void rpi4_prepare_dtb(void) return; } + /* Reserve memory used by Trusted Firmware. */ + if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000)) + WARN("Failed to add reserved memory nodes to DT.\n"); + ret = fdt_pack(dtb); if (ret < 0) ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret); -- cgit v1.2.3 From 882c0ff6ba65800046a851735cc848b76810196a Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 15 Jul 2019 09:04:27 +0100 Subject: rpi4: Cleanup memory regions, move pens to first page Now that we have the SMP pens in the first page of DRAM, we can get rid of all the fancy RPi3 memory regions that our RPi4 port does not really need. This avoids using up memory all over the place, restricting ATF to just run in the first 512KB of DRAM. Remove the now unused regions. This also moves the SMP pens into our first memory page (holding the firmware magic), where the original firmware put them, but where there is also enough space for them. Since the pens will require code execution privileges, we amend the memory attributes used for that page to include write and execution rights. Change-Id: I131633abeb4a4d7b9057e737b9b0d163b73e47c6 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/include/platform_def.h | 68 +++--------------------------------- plat/rpi/rpi4/rpi4_bl31_setup.c | 5 ++- 2 files changed, 6 insertions(+), 67 deletions(-) diff --git a/plat/rpi/rpi4/include/platform_def.h b/plat/rpi/rpi4/include/platform_def.h index 831d1c3f..a9ecdba2 100644 --- a/plat/rpi/rpi4/include/platform_def.h +++ b/plat/rpi/rpi4/include/platform_def.h @@ -58,70 +58,12 @@ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) -/* - * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and - * secure DRAM. Note that this is all actually DRAM with different names, - * there is no Secure RAM in the Raspberry Pi 4. - */ -#if RPI3_USE_UEFI_MAP -#define SEC_ROM_BASE ULL(0x00000000) -#define SEC_ROM_SIZE ULL(0x00010000) - -/* FIP placed after ROM to append it to BL1 with very little padding. */ -#define PLAT_RPI3_FIP_BASE ULL(0x00020000) -#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x00010000) - -/* Reserve 2M of secure SRAM and DRAM, starting at 2M */ -#define SEC_SRAM_BASE ULL(0x00200000) -#define SEC_SRAM_SIZE ULL(0x00100000) - -#define SEC_DRAM0_BASE ULL(0x00300000) -#define SEC_DRAM0_SIZE ULL(0x00100000) - -/* Windows on ARM requires some RAM at 4M */ -#define NS_DRAM0_BASE ULL(0x00400000) -#define NS_DRAM0_SIZE ULL(0x00C00000) -#else -#define SEC_ROM_BASE ULL(0x00000000) -#define SEC_ROM_SIZE ULL(0x00020000) - -/* FIP placed after ROM to append it to BL1 with very little padding. */ -#define PLAT_RPI3_FIP_BASE ULL(0x00020000) -#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001E0000) - -/* We have 16M of memory reserved starting at 256M */ -#define SEC_SRAM_BASE ULL(0x10000000) -#define SEC_SRAM_SIZE ULL(0x00100000) - -#define SEC_DRAM0_BASE ULL(0x10100000) -#define SEC_DRAM0_SIZE ULL(0x00F00000) -/* End of reserved memory */ - -#define NS_DRAM0_BASE ULL(0x11000000) -#define NS_DRAM0_SIZE ULL(0x01000000) -#endif /* RPI3_USE_UEFI_MAP */ - -/* - * BL33 entrypoint. - */ -#define PLAT_RPI3_NS_IMAGE_OFFSET NS_DRAM0_BASE -#define PLAT_RPI3_NS_IMAGE_MAX_SIZE NS_DRAM0_SIZE - /* * I/O registers. */ #define DEVICE0_BASE RPI_IO_BASE #define DEVICE0_SIZE RPI_IO_SIZE -/* - * TF-A lives in SRAM, partition it here - */ -#define SHARED_RAM_BASE SEC_SRAM_BASE -#define SHARED_RAM_SIZE ULL(0x00001000) - -#define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) -#define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) - /* * Mailbox to control the secondary cores. All secondary cores are held in a * wait loop in cold boot. To release them perform the following steps (plus @@ -135,10 +77,8 @@ * * sev(); */ -#define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE - /* The secure entry point to be used on warm reset by all CPUs. */ -#define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE +#define PLAT_RPI3_TM_ENTRYPOINT 0x100 #define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8) /* Hold entries for each CPU. */ @@ -160,11 +100,11 @@ * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL31 debug size plus a little space for growth. */ -#define PLAT_MAX_BL31_SIZE ULL(0x20000) +#define PLAT_MAX_BL31_SIZE ULL(0x80000) #define BL31_BASE ULL(0x1000) -#define BL31_LIMIT ULL(0x100000) -#define BL31_PROGBITS_LIMIT ULL(0x100000) +#define BL31_LIMIT ULL(0x80000) +#define BL31_PROGBITS_LIMIT ULL(0x80000) #define SEC_SRAM_ID 0 #define SEC_DRAM_ID 1 diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index 8dfadf73..f8bc259f 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -197,10 +197,9 @@ void bl31_plat_arch_setup(void) /* * Add the first page of memory, which holds the stub magic, * the kernel and the DT address. - * This is read-only, as the GPU already populated the header, - * we just need to read it. + * This also holds the secondary CPU's entrypoints and mailboxes. */ - mmap_add_region(0, 0, 4096, MT_MEMORY | MT_RO | MT_SECURE); + mmap_add_region(0, 0, 4096, MT_NON_CACHEABLE | MT_RW | MT_SECURE); rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, -- cgit v1.2.3 From 3903a8cd108188dc2dcfc5b3cb820b639c5fce01 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 21 Jul 2019 01:45:31 +0100 Subject: rpi4: Add GIC maintenance interrupt to GIC DT node For being able to use the virtualisation support the GIC offers, we need to know the interrupt number of the maintenance interrupt. This information is missing from the official RPi4 device tree. Use libfdt to add the "interrupts" property to the GIC node, which allows hypervisors like KVM or Xen to be able to use the GIC's help on virtualising interrupts. Change-Id: Iab84f0885a5bf29fb84ca8f385e8a39d27700c75 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/rpi4_bl31_setup.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index f8bc259f..39aa3e45 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -222,7 +222,8 @@ static uint32_t dtb_size(const void *dtb) static void rpi4_prepare_dtb(void) { void *dtb = (void *)rpi4_get_dtb_address(); - int ret; + uint32_t gic_int_prop[3]; + int ret, offs; /* Return if no device tree is detected */ if (fdt_check_header(dtb) != 0) @@ -248,6 +249,12 @@ static void rpi4_prepare_dtb(void) if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000)) WARN("Failed to add reserved memory nodes to DT.\n"); + offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400"); + gic_int_prop[0] = cpu_to_fdt32(1); // PPI + gic_int_prop[1] = cpu_to_fdt32(9); // PPI #9 + gic_int_prop[2] = cpu_to_fdt32(0x0f04); // all cores, level high + fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12); + ret = fdt_pack(dtb); if (ret < 0) ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret); -- cgit v1.2.3 From 1a7422ebd092342fa1f4d420eb4642b0134f36ca Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 15 Jul 2019 18:07:51 +0100 Subject: rpi4: Add stdout-path to device tree Some device tree users like to find a pointer to the standard serial console in the device tree, in the "stdout-path" property of the /chosen node. Add the location of the Mini UART in that property, so that DT users are happy, for instance Linux' earlycon detection. Change-Id: I178e55016e5640de5ab0bc6e061944bd3583ea96 Signed-off-by: Andre Przywara --- plat/rpi/rpi4/rpi4_bl31_setup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c index 39aa3e45..53ab0c2e 100644 --- a/plat/rpi/rpi4/rpi4_bl31_setup.c +++ b/plat/rpi/rpi4/rpi4_bl31_setup.c @@ -255,6 +255,9 @@ static void rpi4_prepare_dtb(void) gic_int_prop[2] = cpu_to_fdt32(0x0f04); // all cores, level high fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12); + offs = fdt_path_offset(dtb, "/chosen"); + fdt_setprop_string(dtb, offs, "stdout-path", "serial0"); + ret = fdt_pack(dtb); if (ret < 0) ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret); -- cgit v1.2.3 From e0dea671dceebe935201f1c4796cac5774af152f Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 22 Jul 2019 10:31:10 +0100 Subject: rpi4: Add initial documentation file As the Raspberry Pi4 port is now in a usable state, add the build instructions together with some background information to the documentation directory. The port differs quite a bit from the Raspberry Pi 3, so we use a separate file for that. Change-Id: I7d9f5967fdf3ec3bfe97d78141f59cbcf03388d4 Signed-off-by: Andre Przywara --- docs/plat/rpi4.rst | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 docs/plat/rpi4.rst diff --git a/docs/plat/rpi4.rst b/docs/plat/rpi4.rst new file mode 100644 index 00000000..0f529c10 --- /dev/null +++ b/docs/plat/rpi4.rst @@ -0,0 +1,85 @@ +Raspberry Pi 4 +============== + +The `Raspberry Pi 4`_ is an inexpensive single-board computer that contains four +Arm Cortex-A72 cores. Also in contrast to previous Raspberry Pi versions this +model has a GICv2 interrupt controller. + +This port is a minimal port to support loading non-secure EL2 payloads such +as a 64-bit Linux kernel. Other payloads such as U-Boot or EDK-II should work +as well, but have not been tested at this point. + +**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM, +which is available from both the Non-secure and Secure worlds. The SoC does +not seem to feature a secure memory controller of any kind, so portions of +DRAM can't be protected properly from the Non-secure world. + +Build Instructions +------------------ + +There are no real configuration options at this point, so there is only +one universal binary (bl31.bin), which can be built with: + +.. code:: shell + + CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi4 DEBUG=1 + +Copy the generated build/rpi4/debug/bl31.bin to the SD card, either +renaming it to ``armstub8.bin`` or adding an entry starting with ``armstub=``, +then followed by the respective file name to ``config.txt``. +You should have AArch64 code in the file loaded as the "kernel", as BL31 +will drop into AArch64/EL2 to the respective load address. +arm64 Linux kernels are known to work this way. + +Other options that should be set in ``config.txt`` to properly boot 64-bit +kernels are: + +:: + + enable_uart=1 + arm_64bit=1 + enable_gic=1 + +The BL31 code will patch the provided device tree blob in memory to advertise +PSCI support, also will add a reserved-memory node to the DT to tell the +non-secure payload to not touch the resident TF-A code. + +If you connect a serial cable between the Mini UART and your computer, and +connect to it (for example, with ``screen /dev/ttyUSB0 115200``) you should +see some text from BL31, followed by the output of the EL2 payload. +The command line provided is read from the ``cmdline.txt`` file on the SD card. + +TF-A port design +---------------- + +In contrast to the existing Raspberry Pi 3 port this one here is a BL31-only +port, also it deviates quite a lot from the RPi3 port in many other ways. +There is not so much difference between the two models, so eventually those +two could be (more) unified in the future. + +As with the previous models, the GPU and its firmware are the first entity to +run after the SoC gets its power. The on-chip Boot ROM loads the next stage +(bootcode.bin) from flash (EEPROM), which is again GPU code. +This part knows how to access the MMC controller and how to parse a FAT +filesystem, so it will load further compononents and configuration files +from the first FAT partition on the SD card. + +To accommodate this existing way of configuring and setting up the board, +we use as much of this workflow as possible. +If bootcode.bin finds a file called ``armstub8.bin`` on the SD card or it gets +pointed to such code by finding a ``armstub=`` key in ``config.txt``, it will +load this file to the beginning of DRAM (address 0) and execute it in +AArch64 EL3. +But before doing that, it will also load a "kernel" and the device tree into +memory. The load addresses have a default, but can also be changed by +setting them in ``config.txt``. If the GPU firmware finds a magic value in the +armstub image file, it will put those two load addresses in memory locations +near the beginning of memory, where TF-A code picks them up. + +To keep things simple, we will just use the kernel load address as the BL33 +entry point, also put the DTB address in the x0 register, as requested by +the arm64 Linux kernel boot protocol. This does not necessarily mean that +the EL2 payload needs to be a Linux kernel, a bootloader or any other kernel +would work as well, as long as it can cope with having the DT address in +register x0. If the payload has other means of finding the device tree, it +could ignore this address as well. -- cgit v1.2.3