xref: /rk3399_ARM-atf/plat/arm/board/fvp/aarch64/fvp_lsp_ras_sp.c (revision db5fe4f4934208ac8f8ae9283df2fbac6066e24e)
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