mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +00:00

Currently, reference design platforms such as RD-N2, RD-N1-Edge, RD-V1-MC, RD-V1 and SGI-575 utilize "css/sgi" as the common source directory. The "sgi" prefix originated from the System Guidance for Infrastructure (SGI) and was initially associated with the SGI-575 platform. However, subsequent platforms released were under the Neoverse Reference Design product name. To align with the Neoverse Reference Design nomenclature, rename the common source directory from "css/sgi" to "css/neoverse_rd" and update all file prefixes from "sgi" to "nrd." Signed-off-by: Rohit Mathew <Rohit.Mathew@arm.com> Change-Id: I3dcbb31b9ab202e82caf25218ba33c520dcea4e4
211 lines
7.1 KiB
C
211 lines
7.1 KiB
C
/*
|
|
* Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include <bl31/interrupt_mgmt.h>
|
|
#include <lib/el3_runtime/context_mgmt.h>
|
|
#include <lib/extensions/ras.h>
|
|
#include <plat/common/platform.h>
|
|
#include <services/sdei.h>
|
|
#include <services/spm_mm_svc.h>
|
|
|
|
#include <nrd_ras.h>
|
|
|
|
#define CPU_CONTEXT_REG_GPR_ARR_SIZE 32
|
|
#define CPU_CONTEXT_REG_EL1_ARR_SIZE 17
|
|
#define CPU_CONTEXT_REG_EL2_ARR_SIZE 16
|
|
#define CPU_CONTEXT_REG_EL3_ARR_SIZE 10
|
|
|
|
/*
|
|
* MM Communicate message header GUID to indicate the payload is intended for
|
|
* CPU MM driver.
|
|
*/
|
|
struct efi_guid cpu_ecc_event_guid = {
|
|
0x2c1b3bfc, 0x42cd, 0x4a66,
|
|
{0xac, 0xd1, 0xa4, 0xd1, 0x63, 0xe9, 0x90, 0xf6}
|
|
};
|
|
|
|
/*
|
|
* CPU error information data structure communicated as part of MM
|
|
* Communication data payload.
|
|
*/
|
|
typedef struct {
|
|
uint64_t ErrStatus;
|
|
uint64_t ErrMisc0;
|
|
uint64_t ErrAddr;
|
|
uint64_t SecurityState;
|
|
uint64_t ErrCtxGpr[CPU_CONTEXT_REG_GPR_ARR_SIZE];
|
|
uint64_t ErrCtxEl1Reg[CPU_CONTEXT_REG_EL1_ARR_SIZE];
|
|
uint64_t ErrCtxEl2Reg[CPU_CONTEXT_REG_EL2_ARR_SIZE];
|
|
uint64_t ErrCtxEl3Reg[CPU_CONTEXT_REG_EL3_ARR_SIZE];
|
|
} cpu_err_info;
|
|
|
|
/*
|
|
* Reads the CPU context and error information from the relevant registers and
|
|
* populates the CPU error information data structure.
|
|
*/
|
|
static void populate_cpu_err_data(cpu_err_info *cpu_info,
|
|
uint64_t security_state)
|
|
{
|
|
void *ctx;
|
|
|
|
ctx = cm_get_context(security_state);
|
|
|
|
cpu_info->ErrStatus = read_erxstatus_el1();
|
|
cpu_info->ErrMisc0 = read_erxmisc0_el1();
|
|
cpu_info->ErrAddr = read_erxaddr_el1();
|
|
cpu_info->SecurityState = security_state;
|
|
|
|
/* populate CPU EL1 context information. */
|
|
cpu_info->ErrCtxEl1Reg[0] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_ELR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[1] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_ESR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[2] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_FAR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[3] = read_isr_el1();
|
|
cpu_info->ErrCtxEl1Reg[4] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_MAIR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[5] = read_midr_el1();
|
|
cpu_info->ErrCtxEl1Reg[6] = read_mpidr_el1();
|
|
cpu_info->ErrCtxEl1Reg[7] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_SCTLR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[8] = read_ctx_reg(get_gpregs_ctx(ctx),
|
|
CTX_GPREG_SP_EL0);
|
|
cpu_info->ErrCtxEl1Reg[9] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_SP_EL1);
|
|
cpu_info->ErrCtxEl1Reg[10] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_SPSR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[11] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TCR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[12] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TPIDR_EL0);
|
|
cpu_info->ErrCtxEl1Reg[13] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TPIDR_EL1);
|
|
cpu_info->ErrCtxEl1Reg[14] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TPIDRRO_EL0);
|
|
cpu_info->ErrCtxEl1Reg[15] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TTBR0_EL1);
|
|
cpu_info->ErrCtxEl1Reg[16] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
|
|
CTX_TTBR1_EL1);
|
|
|
|
#if CTX_INCLUDE_EL2_REGS
|
|
cpu_info->ErrCtxEl2Reg[0] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_ELR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[1] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_ESR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[2] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_FAR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[3] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_HACR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[4] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_HCR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[5] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_HPFAR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[6] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_MAIR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[7] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_SCTLR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[8] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_SP_EL2);
|
|
cpu_info->ErrCtxEl2Reg[9] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_SPSR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[10] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_TCR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[11] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_TPIDR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[12] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_TTBR0_EL2);
|
|
cpu_info->ErrCtxEl2Reg[13] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_VTCR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[14] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_VTTBR_EL2);
|
|
cpu_info->ErrCtxEl2Reg[15] = read_ctx_reg(get_el2_sysregs_ctx(ctx),
|
|
CTX_ESR_EL2);
|
|
#endif
|
|
|
|
cpu_info->ErrCtxEl3Reg[0] = read_ctx_reg(get_el3state_ctx(ctx),
|
|
CTX_ELR_EL3);
|
|
cpu_info->ErrCtxEl3Reg[1] = read_ctx_reg(get_el3state_ctx(ctx),
|
|
CTX_ESR_EL3);
|
|
cpu_info->ErrCtxEl3Reg[2] = read_far_el3();
|
|
cpu_info->ErrCtxEl3Reg[4] = read_mair_el3();
|
|
cpu_info->ErrCtxEl3Reg[5] = read_sctlr_el3();
|
|
cpu_info->ErrCtxEl3Reg[6] = 0; /* sp_el3 */
|
|
cpu_info->ErrCtxEl3Reg[7] = read_tcr_el3();
|
|
cpu_info->ErrCtxEl3Reg[8] = read_tpidr_el3();
|
|
cpu_info->ErrCtxEl3Reg[9] = read_ttbr0_el3();
|
|
}
|
|
|
|
/* CPU RAS interrupt handler */
|
|
int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec,
|
|
int probe_data,
|
|
const struct err_handler_data *const data)
|
|
{
|
|
struct sgi_ras_ev_map *ras_map;
|
|
mm_communicate_header_t *header;
|
|
cpu_err_info cpu_info = {0};
|
|
uint64_t clear_status;
|
|
uint32_t intr;
|
|
int ret;
|
|
|
|
cm_el1_sysregs_context_save(NON_SECURE);
|
|
intr = data->interrupt;
|
|
|
|
INFO("[CPU RAS] CPU intr received = %d on cpu_id = %d\n",
|
|
intr, plat_my_core_pos());
|
|
|
|
INFO("[CPU RAS] ERXMISC0_EL1 = 0x%lx\n", read_erxmisc0_el1());
|
|
INFO("[CPU RAS] ERXSTATUS_EL1 = 0x%lx\n", read_erxstatus_el1());
|
|
INFO("[CPU RAS] ERXADDR_EL1 = 0x%lx\n", read_erxaddr_el1());
|
|
|
|
/* Populate CPU Error Source Information. */
|
|
populate_cpu_err_data(&cpu_info, get_interrupt_src_ss(data->flags));
|
|
|
|
/* Clear the interrupt. */
|
|
clear_status = read_erxstatus_el1();
|
|
write_erxstatus_el1(clear_status);
|
|
plat_ic_end_of_interrupt(intr);
|
|
|
|
header = (void *) PLAT_SPM_BUF_BASE;
|
|
memset(header, 0, sizeof(*header));
|
|
memcpy(&header->data, &cpu_info, sizeof(cpu_info));
|
|
header->message_len = sizeof(cpu_info);
|
|
memcpy(&header->header_guid, (void *) &cpu_ecc_event_guid,
|
|
sizeof(struct efi_guid));
|
|
|
|
spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
|
|
plat_my_core_pos());
|
|
|
|
/*
|
|
* Find if this is a RAS interrupt. There must be an event against
|
|
* this interrupt
|
|
*/
|
|
ras_map = sgi_find_ras_event_map_by_intr(intr);
|
|
if (ras_map == NULL) {
|
|
ERROR("SGI: RAS error info for interrupt id: %d not found\n",
|
|
intr);
|
|
return -1;
|
|
}
|
|
|
|
/* Dispatch the event to the SDEI client */
|
|
ret = sdei_dispatch_event(ras_map->sdei_ev_num);
|
|
if (ret != 0) {
|
|
/*
|
|
* sdei_dispatch_event() may return failing result in some
|
|
* cases, for example kernel may not have registered a handler
|
|
* or RAS event may happen early during boot. We restore the NS
|
|
* context when sdei_dispatch_event() returns failing result.
|
|
*/
|
|
ERROR("SDEI dispatch failed: %d", ret);
|
|
cm_el1_sysregs_context_restore(NON_SECURE);
|
|
cm_set_next_eret_context(NON_SECURE);
|
|
}
|
|
|
|
return ret;
|
|
}
|