Madhukar Pappireddy | e17c82a | 2024-01-10 14:01:37 -0600 | [diff] [blame^] | 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); |