1 /* 2 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <inttypes.h> 8 #include <stdint.h> 9 10 #include <lib/el3_runtime/context_mgmt.h> 11 #include <lib/extensions/ras.h> 12 13 #include <plat/common/platform.h> 14 #include <services/el3_spmd_logical_sp.h> 15 #include <services/ffa_svc.h> 16 #include <services/sdei.h> 17 18 19 #define CACTUS_SP_RAS_DELEGATE_CMD 0x72617365 20 #define EVENT_NOTIFY_OS_RAS_ERROR U(5000) 21 22 /* 23 * Note: Typical RAS error handling flow with Firmware First Handling 24 * 25 * Step 1: Exception resulting from a RAS error in the normal world is routed to 26 * EL3. 27 * Step 2: This exception is typically signaled as either a synchronous external 28 * abort or SError or interrupt. TF-A (EL3 firmware) delegates the 29 * control to platform specific handler built on top of the RAS helper 30 * utilities. 31 * Step 3: With the help of a Logical Secure Partition, TF-A sends a direct 32 * message to dedicated S-EL0 (or S-EL1) RAS Partition managed by SPMC. 33 * TF-A also populates a shared buffer with a data structure containing 34 * enough information (such as system registers) to identify and triage 35 * the RAS error. 36 * Step 4: RAS SP generates the Common Platform Error Record (CPER) and shares 37 * it with normal world firmware and/or OS kernel through a reserved 38 * buffer memory. 39 * Step 5: RAS SP responds to the direct message with information necessary for 40 * TF-A to notify the OS kernel. 41 * Step 6: Consequently, TF-A dispatches an SDEI event to notify the OS kernel 42 * about the CPER records for further logging. 43 */ 44 45 static int injected_fault_handler(const struct err_record_info *info, 46 int probe_data, const struct err_handler_data *const data) 47 { 48 /* 49 * At the moment, an FF-A compatible SP that supports RAS firmware is 50 * not available. Hence the sequence below does not exactly follow the 51 * steps outlined above. Therefore, some steps are essentially spoofed. 52 * The handling of RAS error is completely done in EL3 firmware. 53 */ 54 uint64_t status, cactus_cmd_ret; 55 int ret, event_num; 56 cpu_context_t *ns_cpu_context; 57 58 /* Get a reference to the non-secure context */ 59 ns_cpu_context = cm_get_context(NON_SECURE); 60 assert(ns_cpu_context != NULL); 61 62 /* 63 * The faulting error record is already selected by the SER probe 64 * function. 65 */ 66 status = read_erxstatus_el1(); 67 68 ERROR("Fault reported by system error record %d on 0x%lx: status=0x%" PRIx64 "\n", 69 probe_data, read_mpidr_el1(), status); 70 ERROR(" exception reason=%u syndrome=0x%" PRIx64 "\n", data->ea_reason, 71 data->flags); 72 73 /* Clear error */ 74 write_erxstatus_el1(status); 75 76 /* 77 * Initiate an EL3 direct message from LSP to Cactus RAS Secure 78 * Partition (ID 8001). Currently, the payload is being spoofed. 79 * The direct message response contains the SDEI event ID for the 80 * associated RAS error. 81 */ 82 (void)plat_spmd_logical_sp_smc_handler(0, 0, 0, CACTUS_SP_RAS_DELEGATE_CMD, 83 EVENT_NOTIFY_OS_RAS_ERROR, 84 NULL, ns_cpu_context, 0); 85 86 cactus_cmd_ret = read_ctx_reg(get_gpregs_ctx(ns_cpu_context), CTX_GPREG_X3); 87 event_num = (int)read_ctx_reg(get_gpregs_ctx(ns_cpu_context), CTX_GPREG_X4); 88 89 if (cactus_cmd_ret != 0) { 90 ERROR("RAS error could not be handled by SP: %lx\n", cactus_cmd_ret); 91 panic(); 92 } 93 94 if (event_num != EVENT_NOTIFY_OS_RAS_ERROR) { 95 ERROR("Unexpected event id sent by RAS SP: %d\n", event_num); 96 panic(); 97 } 98 99 /* Dispatch the event to the SDEI client */ 100 ret = sdei_dispatch_event(event_num); 101 if (ret < 0) { 102 ERROR("Can't dispatch event to SDEI\n"); 103 panic(); 104 } else { 105 INFO("SDEI event dispatched\n"); 106 } 107 108 return 0; 109 } 110 111 struct ras_interrupt fvp_ras_interrupts[] = { 112 }; 113 114 struct err_record_info fvp_err_records[] = { 115 /* Record for injected fault */ 116 ERR_RECORD_SYSREG_V1(0, 2, ras_err_ser_probe_sysreg, 117 injected_fault_handler, NULL), 118 }; 119 120 REGISTER_ERR_RECORD_INFO(fvp_err_records); 121 REGISTER_RAS_INTERRUPTS(fvp_ras_interrupts); 122