diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
commit | be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch) | |
tree | 779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/arm/board/fvp/aarch64 | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.tar.xz arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.zip |
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/arm/board/fvp/aarch64')
-rw-r--r-- | plat/arm/board/fvp/aarch64/fvp_ea.c | 54 | ||||
-rw-r--r-- | plat/arm/board/fvp/aarch64/fvp_helpers.S | 177 | ||||
-rw-r--r-- | plat/arm/board/fvp/aarch64/fvp_ras.c | 67 |
3 files changed, 298 insertions, 0 deletions
diff --git a/plat/arm/board/fvp/aarch64/fvp_ea.c b/plat/arm/board/fvp/aarch64/fvp_ea.c new file mode 100644 index 0000000..07053a9 --- /dev/null +++ b/plat/arm/board/fvp/aarch64/fvp_ea.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <inttypes.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <bl31/ea_handle.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <plat/common/platform.h> + +/* + * This source file with custom plat_ea_handler function is compiled only when + * building TF-A with compile option PLATFORM_TEST_EA_FFH + */ + +/* Test address(non-existent) used in tftf to cause External aborts */ +#define TEST_ADDRESS UL(0x7FFFF000) + +void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, + void *handle, uint64_t flags) +{ +#ifdef PLATFORM_TEST_EA_FFH + u_register_t elr_el3; + u_register_t fault_address; + cpu_context_t *ctx = cm_get_context(NON_SECURE); + el3_state_t *el3_ctx = get_el3state_ctx(ctx); + gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); + unsigned int level = (unsigned int)GET_EL(read_spsr_el3()); + + fault_address = read_ctx_reg(gpregs_ctx, CTX_GPREG_X0); + + if ((level < MODE_EL3) && (fault_address == TEST_ADDRESS)) { + if (ea_reason == ERROR_EA_SYNC) { + INFO("Handled sync EA from lower EL at address 0x%lx\n", fault_address); + /* To avoid continuous faults, forward return address */ + elr_el3 = read_ctx_reg(el3_ctx, CTX_ELR_EL3); + elr_el3 += 4; + write_ctx_reg(el3_ctx, CTX_ELR_EL3, elr_el3); + return; + } else if (ea_reason == ERROR_EA_ASYNC) { + INFO("Handled Serror from lower EL at address 0x%lx\n", fault_address); + return; + } + } +#endif + plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags); +} diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S new file mode 100644 index 0000000..8efc238 --- /dev/null +++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <drivers/arm/gicv2.h> +#include <drivers/arm/gicv3.h> +#include <drivers/arm/fvp/fvp_pwrc.h> +#include <platform_def.h> + + .globl plat_secondary_cold_boot_setup + .globl plat_get_my_entrypoint + .globl plat_is_my_cpu_primary + .globl plat_arm_calc_core_pos + + /* ----------------------------------------------------- + * 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. + * TODO: Should we read the PSYS register to make sure + * that the request has gone through. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup +#ifndef EL3_PAYLOAD_BASE + /* --------------------------------------------- + * Power down this cpu. + * TODO: Do we need to worry about powering the + * cluster down as well here. That will need + * locks which we won't have unless an elf- + * loader zeroes out the zi section. + * --------------------------------------------- + */ + mrs x0, mpidr_el1 + mov_imm x1, PWRC_BASE + str w0, [x1, #PPOFFR_OFF] + + /* --------------------------------------------- + * There is no sane reason to come out of this + * wfi so panic if we do. This cpu will be pow- + * ered on and reset by the cpu_on pm api + * --------------------------------------------- + */ + dsb sy + wfi + no_ret plat_panic_handler +#else + mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE + + /* Wait until the entrypoint gets populated */ +poll_mailbox: + ldr x1, [x0] + cbz x1, 1f + br x1 +1: + wfe + b poll_mailbox +#endif /* EL3_PAYLOAD_BASE */ +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 warm + * boot. On FVP, this information can be queried from the power + * controller. The Power Control SYS Status Register (PSYSR) indicates + * the wake-up reason for the CPU. + * + * For a cold boot, return 0. + * For a warm boot, read the mailbox and return the address it contains. + * + * TODO: PSYSR is a common register and should be + * accessed using locks. Since it is not possible + * to use locks immediately after a cold reset + * we are relying on the fact that after a cold + * reset all cpus will read the same WK field + * --------------------------------------------------------------------- + */ +func plat_get_my_entrypoint + /* --------------------------------------------------------------------- + * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC + * WakeRequest signal" then it is a warm boot. + * --------------------------------------------------------------------- + */ + mrs x2, mpidr_el1 + mov_imm x1, PWRC_BASE + str w2, [x1, #PSYSR_OFF] + ldr w2, [x1, #PSYSR_OFF] + ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH + cmp w2, #WKUP_PPONR + beq warm_reset + cmp w2, #WKUP_GICREQ + beq warm_reset + + /* Cold reset */ + mov x0, #0 + ret + +warm_reset: + /* --------------------------------------------------------------------- + * A mailbox is maintained in the trusted SRAM. It is flushed out of the + * caches after every update using normal memory so it is safe to read + * it here with SO attributes. + * --------------------------------------------------------------------- + */ + mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE + ldr x0, [x0] + cbz x0, _panic_handler + ret + + /* --------------------------------------------------------------------- + * The power controller indicates this is a warm reset but the mailbox + * is empty. This should never happen! + * --------------------------------------------------------------------- + */ +_panic_handler: + no_ret plat_panic_handler +endfunc plat_get_my_entrypoint + + /* ----------------------------------------------------- + * 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 + mov_imm x1, MPIDR_AFFINITY_MASK + and x0, x0, x1 + cmp x0, #FVP_PRIMARY_CPU + cset w0, eq + ret +endfunc plat_is_my_cpu_primary + + /* --------------------------------------------------------------------- + * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) + * + * Function to calculate the core position on FVP. + * + * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + + * (CPUId * FVP_MAX_PE_PER_CPU) + + * ThreadId + * + * which can be simplified as: + * + * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) + * + ThreadId + * --------------------------------------------------------------------- + */ +func plat_arm_calc_core_pos + /* + * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it + * look as if in a multi-threaded implementation. + */ + tst x0, #MPIDR_MT_MASK + lsl x3, x0, #MPIDR_AFFINITY_BITS + csel x3, x3, x0, eq + + /* Extract individual affinity fields from MPIDR */ + ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS + ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS + ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS + + /* Compute linear position */ + mov x4, #FVP_MAX_CPUS_PER_CLUSTER + madd x1, x2, x4, x1 + mov x5, #FVP_MAX_PE_PER_CPU + madd x0, x1, x5, x0 + ret +endfunc plat_arm_calc_core_pos diff --git a/plat/arm/board/fvp/aarch64/fvp_ras.c b/plat/arm/board/fvp/aarch64/fvp_ras.c new file mode 100644 index 0000000..f9b9634 --- /dev/null +++ b/plat/arm/board/fvp/aarch64/fvp_ras.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <inttypes.h> +#include <stdint.h> + +#include <lib/extensions/ras.h> +#include <services/sdei.h> + +#ifdef PLATFORM_TEST_RAS_FFH +static int injected_fault_handler(const struct err_record_info *info, + int probe_data, const struct err_handler_data *const data) +{ + uint64_t status; + int ret; + + /* + * The faulting error record is already selected by the SER probe + * function. + */ + status = read_erxstatus_el1(); + + ERROR("Fault reported by system error record %d on 0x%lx: status=0x%" PRIx64 "\n", + probe_data, read_mpidr_el1(), status); + ERROR(" exception reason=%u syndrome=0x%" PRIx64 "\n", data->ea_reason, + data->flags); + + /* Clear error */ + write_erxstatus_el1(status); + + ret = sdei_dispatch_event(5000); + if (ret < 0) { + ERROR("Can't dispatch event to SDEI\n"); + panic(); + } else { + INFO("SDEI event dispatched\n"); + } + + return 0; +} + +void plat_handle_uncontainable_ea(void) +{ + /* Do not change the string, CI expects it. Wait forever */ + INFO("Injected Uncontainable Error\n"); + while (true) { + wfe(); + } +} +#endif + +struct ras_interrupt fvp_ras_interrupts[] = { +}; + +struct err_record_info fvp_err_records[] = { +#ifdef PLATFORM_TEST_RAS_FFH + /* Record for injected fault */ + ERR_RECORD_SYSREG_V1(0, 2, ras_err_ser_probe_sysreg, + injected_fault_handler, NULL), +#endif +}; + +REGISTER_ERR_RECORD_INFO(fvp_err_records); +REGISTER_RAS_INTERRUPTS(fvp_ras_interrupts); |