xref: /optee_os/core/arch/arm/lsp/lsp_ras_inject.c (revision 4d0b6a60dabc7df0fd49d21e22cb38ce0046e10b)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2026, Arm Limited.
4  */
5 
6 #include <arm64.h>
7 #include <ffa.h>
8 #include <initcall.h>
9 #include <inttypes.h>
10 #include <kernel/thread_spmc.h>
11 #include <sm/optee_smc.h>
12 #include <trace.h>
13 #include <util.h>
14 
15 #define CORE_RAM_ERR_RECORD	    U(1)
16 #define ERXPFGCDN_CDN		    U(0xF)
17 
18 /* Predefined ERXMISC0 value for CE (correctable error) injection */
19 #define ERX_MISC0_CE_INJ	    0x200810000000001ULL
20 
21 /* Supported RAS components */
22 #define RAS_COMPONENT_CPU	    U(0x01)
23 
24 /*
25  * ACPI EINJ error types are encoded as a bitmap.
26  * Firmware-communication and deferred-error are local extensions.
27  */
28 #define RAS_ERROR_PROCESSOR_CORRECTABLE			    BIT32(0)
29 #define RAS_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL	BIT32(1)
30 #define RAS_ERROR_PROCESSOR_UNCORRECTABLE_FATAL		BIT32(2)
31 #define RAS_ERROR_MEMORY_CORRECTABLE			    BIT32(3)
32 #define RAS_ERROR_MEMORY_UNCORRECTABLE_NONFATAL		BIT32(4)
33 #define RAS_ERROR_MEMORY_UNCORRECTABLE_FATAL		BIT32(5)
34 #define RAS_ERROR_PCI_CORRECTABLE			        BIT32(6)
35 #define RAS_ERROR_PCI_UNCORRECTABLE_NONFATAL		BIT32(7)
36 #define RAS_ERROR_PCI_UNCORRECTABLE_FATAL		    BIT32(8)
37 #define RAS_ERROR_PLATFORM_CORRECTABLE			    BIT32(9)
38 #define RAS_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL	BIT32(10)
39 #define RAS_ERROR_PLATFORM_UNCORRECTABLE_FATAL		BIT32(11)
40 #define RAS_ERROR_VENDOR_DEFINED_START			    BIT32(31)
41 
42 /*
43  * Program a CPU RAS error record for later error injection.
44  *
45  * This is an internal direct request ABI used by SP clients of the RAS LSP.
46  *
47  * error_type selects the processor error class to arm.
48  * The current supported values are:
49  * - RAS_ERROR_PROCESSOR_CORRECTABLE
50  * - RAS_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL
51  * - RAS_ERROR_PROCESSOR_UNCORRECTABLE_FATAL
52  *
53  * component selects the target component.
54  * Only RAS_COMPONENT_CPU is currently supported.
55  *
56  * data is currently unused.
57  *
58  * The handler selects the Core RAM error record and programs the associated
59  * RAS Error Record and PFG registers for the requested injection type.
60  * The direct response reports only whether this programming step succeeded.
61  *
62  * The actual error is expected to be observed later, when the programmed
63  * condition is triggered and the CPU reports it through
64  * the RAS handling path. This handler does not consume that exception
65  * and does not return it synchronously to the caller.
66  */
ras_injection_handler(uint32_t error_type,uint32_t component,uint32_t data __unused)67 static TEE_Result ras_injection_handler(uint32_t error_type, uint32_t component,
68 					uint32_t data __unused)
69 {
70 	TEE_Result ret = TEE_ERROR_NOT_SUPPORTED;
71 	uint64_t erx_status;
72 	uint64_t v = 0;
73 
74 	FMSG("RAS LSP: error_type: %"PRIx32" component: %"PRIx32
75 	     " data: %"PRIx32, error_type, component, data);
76 
77 	if (component != RAS_COMPONENT_CPU)
78 		return TEE_ERROR_NOT_SUPPORTED;
79 
80 	/* Select error record 1, which contains Core RAM errors. */
81 	write_errselr_el1(CORE_RAM_ERR_RECORD);
82 	write_erxpfgctl_el1(0);
83 
84 	/* Clear any sticky status bits in the selected error record. */
85 	erx_status = read_erxstatus_el1();
86 	write_erxstatus_el1(erx_status);
87 	write_erxpfgcdn_el1(ERXPFGCDN_CDN);
88 
89 	switch (error_type) {
90 	case RAS_ERROR_PROCESSOR_CORRECTABLE:
91 		v = read_erxmisc0_el1();
92 		write_erxmisc0_el1(v | ERX_MISC0_CE_INJ);
93 		v = read_erxpfgctl_el1();
94 		v |= ERXPFGCTL_CDNEN_BIT | ERXPFGCTL_R_BIT |
95 		     ERXPFGCTL_CE_BIT;
96 		write_erxpfgctl_el1(v);
97 		return TEE_SUCCESS;
98 	case RAS_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL:
99 		v = read_erxpfgctl_el1();
100 		v |= ERXPFGCTL_CDNEN_BIT | ERXPFGCTL_DE_BIT;
101 		write_erxpfgctl_el1(v);
102 		return TEE_SUCCESS;
103 	case RAS_ERROR_PROCESSOR_UNCORRECTABLE_FATAL:
104 		v = read_erxpfgctl_el1();
105 		v |= ERXPFGCTL_CDNEN_BIT | ERXPFGCTL_UC_BIT;
106 		write_erxpfgctl_el1(v);
107 		return TEE_SUCCESS;
108 	default:
109 		EMSG("RAS LSP: Unsupported error type: 0x%"PRIx32,
110 		     error_type);
111 	}
112 
113 	return ret;
114 }
115 
ras_direct_req_handler(struct thread_smc_1_2_regs * args,struct sp_session * caller_sp __unused)116 static void ras_direct_req_handler(struct thread_smc_1_2_regs *args,
117 				   struct sp_session *caller_sp __unused)
118 {
119 	TEE_Result ret = TEE_ERROR_NOT_SUPPORTED;
120 	uint32_t error_type = args->a5;
121 	uint32_t component = args->a6;
122 	uint32_t data = args->a7;
123 
124 	ret = ras_injection_handler(error_type, component, data);
125 
126 	if (OPTEE_SMC_IS_64(args->a0))
127 		args->a0 = FFA_MSG_SEND_DIRECT_RESP_64;
128 	else
129 		args->a0 = FFA_MSG_SEND_DIRECT_RESP_32;
130 
131 	args->a2 = FFA_DST(args->a1);
132 	args->a3 = ret;
133 }
134 
135 static struct spmc_lsp_desc ras_lsp __nex_data = {
136 	.name = "ras_lsp",
137 	.direct_req = ras_direct_req_handler,
138 	.properties = FFA_PART_PROP_DIRECT_REQ_RECV |
139 		      FFA_PART_PROP_DIRECT_REQ_SEND,
140 	.uuid_words = { 0x7011a688, 0x4dde4053, 0xa5a97bac, 0xf13b8cd4 },
141 };
142 
ras_lsp_init(void)143 static TEE_Result ras_lsp_init(void)
144 {
145 	uint64_t pfr0 = read_id_aa64pfr0_el1();
146 
147 	/* Register the LSP only when the CPU advertises architectural RAS. */
148 	if (!((pfr0 >> ID_AA64PFR0_EL1_RAS_SHIFT) &
149 	      ID_AA64PFR0_EL1_RAS_MASK))
150 		return TEE_ERROR_NOT_SUPPORTED;
151 
152 	return spmc_register_lsp(&ras_lsp);
153 }
154 
155 nex_service_init_late(ras_lsp_init);
156