xref: /rk3399_ARM-atf/plat/arm/board/automotive_rd/platform/common/cper.c (revision 10d33abec01d820ad749fdc61afc8dbc6b702b05)
1 /*
2  * Copyright (c) 2025-2026, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <string.h>
8 
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <lib/el3_runtime/aarch64/context.h>
12 #include <lib/el3_runtime/context_mgmt.h>
13 #include <lib/extensions/ras.h>
14 
15 #include <cper.h>
16 #include <rdaspen_ras.h>
17 
18 /* Convert ERXSTATUS_EL1 bits to CPER severity */
esb_severity_from_erx(uint64_t err_status)19 static inline uint32_t esb_severity_from_erx(uint64_t err_status)
20 {
21 	if (err_status & ERX_STATUS_CE)
22 		return ACPI_DATA_ENTRY_SEV_CORRECTED;
23 	if (err_status & ERX_STATUS_DE)
24 		return ACPI_DATA_ENTRY_SEV_RECOVERABLE;
25 	if (err_status & ERX_STATUS_UE)
26 		return ACPI_DATA_ENTRY_SEV_FATAL;
27 	return ACPI_DATA_ENTRY_SEV_NONE;
28 }
29 
arm_error_type_from_unit(uint64_t err_misc0)30 static inline uint8_t arm_error_type_from_unit(uint64_t err_misc0)
31 {
32 	unsigned int unit = ERXMISC0_UNIT(err_misc0);
33 
34 	switch (unit) {
35 	case ERXMISC0_UNIT_L2_TLB:
36 		return ARM_ERROR_TYPE_TLB;
37 	default:
38 		return ARM_ERROR_TYPE_CACHE;
39 	}
40 }
41 
42 /*
43  * ARM CACHE ERROR STRUCTURE
44  *
45  *  - Validation Bit (bits 15:0): Set valid bits for the fields encoded
46  *  - Transaction Type (bits 17:16): INSTR / DATA / GENERIC (derived from UNIT)
47  *  - Operation (bits 21:18): set to GENERIC
48  *  - Level (bits 24:22): cache level (1 for L1, 2 for L2), derived from UNIT
49  *  - Processor Context Corrupt (bit 25): value = 0 (not corrupted)
50  *  - Corrected (bit 26): value from 'corrected' parameter
51  *  - Precise PC (bit 27): value = 0
52  *  - Restartable PC (bit 28): value = 0
53  *  - Reserved (63:29): zero
54  */
arm_cache_error_structure(uint64_t err_misc0,bool corrected)55 static inline uint64_t arm_cache_error_structure(uint64_t err_misc0,
56 						 bool corrected)
57 {
58 	uint64_t info = 0;
59 	unsigned int unit = ERXMISC0_UNIT(err_misc0);
60 
61 	uint64_t tx_value = ARM_CACHE_ERR_TX_GENERIC;
62 	uint64_t level_value = 0;
63 
64 	switch (unit) {
65 	case ERXMISC0_UNIT_L1I:
66 		/* TxType = Instruction, Level = 1 */
67 		tx_value = ARM_CACHE_ERR_TX_INSTR;
68 		level_value = 1u;
69 		break;
70 
71 	case ERXMISC0_UNIT_L1D:
72 		/* TxType = Data, Level = 1 */
73 		tx_value = ARM_CACHE_ERR_TX_DATA;
74 		level_value = 1u;
75 		break;
76 
77 	case ERXMISC0_UNIT_L2_CACHE:
78 		/* TxType = Generic, Level = 2 */
79 		tx_value = ARM_CACHE_ERR_TX_GENERIC;
80 		level_value = 2u;
81 		break;
82 
83 	default:
84 		break;
85 	}
86 
87 	/* Validation bits (bit order: 0..6) */
88 	info |= ARM_CACHE_ERR_VLD_TX_TYPE;    /* Bit 0: Transaction Type Valid */
89 	info |= ARM_CACHE_ERR_VLD_OPERATION;  /* Bit 1: Operation Valid       */
90 	info |= ARM_CACHE_ERR_VLD_LEVEL;      /* Bit 2: Level Valid           */
91 	info |= ARM_CACHE_ERR_VLD_PCC;        /* Bit 3: PCC Valid             */
92 	info |= ARM_CACHE_ERR_VLD_CORRECTED;  /* Bit 4: Corrected Valid       */
93 	info |= ARM_CACHE_ERR_VLD_PRECISE_PC; /* Bit 5: Precise PC Valid      */
94 	info |= ARM_CACHE_ERR_VLD_RESTART_PC; /* Bit 6: Restartable PC Valid  */
95 
96 	/* Transaction Type (bits 17:16) */
97 	info |= (tx_value << ARM_CACHE_ERR_TX_SHIFT) & ARM_CACHE_ERR_TX_MASK;
98 
99 	/* Level (bits 24:22) */
100 	info |= (level_value << ARM_CACHE_ERR_LEVEL_SHIFT) & ARM_CACHE_ERR_LEVEL_MASK;
101 
102 	/* Corrected (bit 26) */
103 	if (corrected)
104 		info |= (1ULL << ARM_CACHE_ERR_CORR_BIT);
105 
106 	return info;
107 }
108 
109 /*
110  * ARM PROCESSOR ERROR CONTEXT INFORMATION
111  *
112  * Context[0] Type-4: AArch64 GPRs (x0..x30 + SP_EL0)
113  * Context[1] Type-5: EL1 registers
114  */
115 static bool
fill_ns_context_blocks(struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA * sec)116 fill_ns_context_blocks(struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *sec)
117 {
118 	cpu_context_t *ns = cm_get_context(NON_SECURE);
119 
120 	if (!ns) {
121 		VERBOSE("CPER: no NON_SECURE cpu_context\n");
122 		return false;
123 	}
124 
125 	/* -------- Type 4: GPRs (x0..x30 + SP_EL0) -------- */
126 	gp_regs_t *gpr = get_gpregs_ctx(ns);
127 
128 	if (!gpr)
129 		return false;
130 
131 	sec->CpuContextInfo[0].Hdr.Version = 0;
132 	sec->CpuContextInfo[0].Hdr.RegisterContextType =
133 		EFI_ARM_CONTEXT_INFO_REG_TYPE_4;
134 	sec->CpuContextInfo[0].Hdr.RegisterArraySize =
135 		(uint32_t)sizeof(sec->CpuContextInfo[0].RegisterArray.Type4Gpr);
136 	struct EFI_ARM_AARCH64_CONTEXT_GPR *type4GprRegValues =
137 		&sec->CpuContextInfo[0].RegisterArray.Type4Gpr;
138 
139 	type4GprRegValues->X[0] = read_ctx_reg(gpr, CTX_GPREG_X0);
140 	type4GprRegValues->X[1] = read_ctx_reg(gpr, CTX_GPREG_X1);
141 	type4GprRegValues->X[2] = read_ctx_reg(gpr, CTX_GPREG_X2);
142 	type4GprRegValues->X[3] = read_ctx_reg(gpr, CTX_GPREG_X3);
143 	type4GprRegValues->X[4] = read_ctx_reg(gpr, CTX_GPREG_X4);
144 	type4GprRegValues->X[5] = read_ctx_reg(gpr, CTX_GPREG_X5);
145 	type4GprRegValues->X[6] = read_ctx_reg(gpr, CTX_GPREG_X6);
146 	type4GprRegValues->X[7] = read_ctx_reg(gpr, CTX_GPREG_X7);
147 	type4GprRegValues->X[8] = read_ctx_reg(gpr, CTX_GPREG_X8);
148 	type4GprRegValues->X[9] = read_ctx_reg(gpr, CTX_GPREG_X9);
149 	type4GprRegValues->X[10] = read_ctx_reg(gpr, CTX_GPREG_X10);
150 	type4GprRegValues->X[11] = read_ctx_reg(gpr, CTX_GPREG_X11);
151 	type4GprRegValues->X[12] = read_ctx_reg(gpr, CTX_GPREG_X12);
152 	type4GprRegValues->X[13] = read_ctx_reg(gpr, CTX_GPREG_X13);
153 	type4GprRegValues->X[14] = read_ctx_reg(gpr, CTX_GPREG_X14);
154 	type4GprRegValues->X[15] = read_ctx_reg(gpr, CTX_GPREG_X15);
155 	type4GprRegValues->X[16] = read_ctx_reg(gpr, CTX_GPREG_X16);
156 	type4GprRegValues->X[17] = read_ctx_reg(gpr, CTX_GPREG_X17);
157 	type4GprRegValues->X[18] = read_ctx_reg(gpr, CTX_GPREG_X18);
158 	type4GprRegValues->X[19] = read_ctx_reg(gpr, CTX_GPREG_X19);
159 	type4GprRegValues->X[20] = read_ctx_reg(gpr, CTX_GPREG_X20);
160 	type4GprRegValues->X[21] = read_ctx_reg(gpr, CTX_GPREG_X21);
161 	type4GprRegValues->X[22] = read_ctx_reg(gpr, CTX_GPREG_X22);
162 	type4GprRegValues->X[23] = read_ctx_reg(gpr, CTX_GPREG_X23);
163 	type4GprRegValues->X[24] = read_ctx_reg(gpr, CTX_GPREG_X24);
164 	type4GprRegValues->X[25] = read_ctx_reg(gpr, CTX_GPREG_X25);
165 	type4GprRegValues->X[26] = read_ctx_reg(gpr, CTX_GPREG_X26);
166 	type4GprRegValues->X[27] = read_ctx_reg(gpr, CTX_GPREG_X27);
167 	type4GprRegValues->X[28] = read_ctx_reg(gpr, CTX_GPREG_X28);
168 	type4GprRegValues->X[29] = read_ctx_reg(gpr, CTX_GPREG_X29);
169 	type4GprRegValues->X[30] = read_ctx_reg(gpr, CTX_GPREG_LR);
170 	type4GprRegValues->SP = read_ctx_reg(gpr, CTX_GPREG_SP_EL0);
171 
172 	/* -------- Type 5: EL1 sysregs -------- */
173 	el1_sysregs_t *el1 = get_el1_sysregs_ctx(ns);
174 
175 	if (!el1)
176 		return false;
177 
178 	sec->CpuContextInfo[1].Hdr.Version = 0;
179 	sec->CpuContextInfo[1].Hdr.RegisterContextType =
180 		EFI_ARM_CONTEXT_INFO_REG_TYPE_5;
181 	sec->CpuContextInfo[1].Hdr.RegisterArraySize = (uint32_t)sizeof(
182 		sec->CpuContextInfo[1].RegisterArray.Type5SysRegs);
183 	struct EFI_ARM_AARCH64_EL1_CONTEXT_SYSTEM_REGISTERS *type5SysRegValues =
184 		&sec->CpuContextInfo[1].RegisterArray.Type5SysRegs;
185 
186 	type5SysRegValues->SPSR_EL1 = read_el1_ctx_common(el1, spsr_el1);
187 	type5SysRegValues->ELR_EL1 = read_el1_ctx_common(el1, elr_el1);
188 	type5SysRegValues->ESR_EL1 = read_el1_ctx_common(el1, esr_el1);
189 	type5SysRegValues->FAR_EL1 = read_el1_ctx_common(el1, far_el1);
190 	type5SysRegValues->ISR_EL1 = 0;
191 
192 	type5SysRegValues->MAIR_EL1 = read_el1_ctx_common(el1, mair_el1);
193 	type5SysRegValues->MIDR_EL1 = read_midr_el1();
194 	type5SysRegValues->MPIDR_EL1 = read_mpidr_el1();
195 	type5SysRegValues->SCTLR_EL1 = read_ctx_sctlr_el1_reg_errata(ns);
196 
197 	type5SysRegValues->SP_EL0 =
198 		read_ctx_reg(get_gpregs_ctx(ns), CTX_GPREG_SP_EL0);
199 	type5SysRegValues->SP_EL1 = read_el1_ctx_common(el1, sp_el1);
200 	type5SysRegValues->SPSR_EL1 = read_el1_ctx_common(el1, spsr_el1);
201 
202 	type5SysRegValues->TCR_EL1 = read_ctx_tcr_el1_reg_errata(ns);
203 	type5SysRegValues->TPIDR_EL0 = read_el1_ctx_common(el1, tpidr_el0);
204 	type5SysRegValues->TPIDR_EL1 = read_el1_ctx_common(el1, tpidr_el1);
205 	type5SysRegValues->TPIDRRO_EL0 = read_el1_ctx_common(el1, tpidrro_el0);
206 	type5SysRegValues->TTBR0_EL1 = read_el1_ctx_common(el1, ttbr0_el1);
207 	type5SysRegValues->TTBR1_EL1 = read_el1_ctx_common(el1, ttbr1_el1);
208 
209 	return true;
210 }
211 
212 /*
213  * cper_write_cpu_record - Build a single CPER ESB + ARM CPU section into a buffer
214  *
215  * This constructs a Common Platform Error Record (CPER) with:
216  *   - 1 Error Status Block (ESB) header,
217  *   - 1 Data Entry (ARM Processor Specific Section GUID),
218  *   - 1 ARM CPU section payload containing:
219  *       * Section header (EFI_ARM_PROCESSOR_ERROR_SECTION_HEADER),
220  *       * One error info (EFI_ARM_PROCESSOR_ERROR_INFORMATION),
221  *       * One context info (EFI_ARM_PROCESSOR_ERROR_CONTEXT_INFORMATION), containing:
222  *           Type-4 (GPRs) and Type-5 (EL1) registers.
223  */
224 
cper_write_cpu_record(void * buf,size_t buf_size)225 size_t cper_write_cpu_record(void *buf, size_t buf_size)
226 {
227 	if (!buf)
228 		return 0;
229 
230 	uint64_t err_status = read_erxstatus_el1();
231 	uint64_t err_misc0 = read_erxmisc0_el1();
232 	uint64_t err_addr = read_erxaddr_el1();
233 
234 	/* Compute size of CPU payload section */
235 
236 	uint32_t context_header_size =
237 		sizeof(struct EFI_ARM_PROCESSOR_ERROR_CONTEXT_INFO_HEADER);
238 	uint32_t context0_size = context_header_size +
239 				 sizeof(struct EFI_ARM_AARCH64_CONTEXT_GPR);
240 	uint32_t context1_size =
241 		context_header_size +
242 		sizeof(struct EFI_ARM_AARCH64_EL1_CONTEXT_SYSTEM_REGISTERS);
243 	uint32_t contexts_total_size = context0_size + context1_size;
244 
245 	uint32_t section_size =
246 		(uint32_t)sizeof(
247 			struct EFI_ARM_PROCESSOR_ERROR_SECTION_HEADER) +
248 		(uint32_t)sizeof(struct EFI_ARM_PROCESSOR_ERROR_INFORMATION) *
249 			CPU_ERR_INFO_NUM + contexts_total_size;
250 
251 	/* Total size: ESB + DataEntry + CPU payload */
252 	size_t size = sizeof(struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER) +
253 		      sizeof(struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER) +
254 		      section_size;
255 
256 	if (buf_size < size) {
257 		WARN("RAS: ESB buffer too small (need %zu, have %zu)\n", size,
258 		     buf_size);
259 		return 0;
260 	}
261 
262 	struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER *esb =
263 		(struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER *)buf;
264 	struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER *de =
265 		(struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER *)(esb + 1);
266 	struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *sec =
267 		(struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *)(de + 1);
268 
269 	/* Error Status Block Header */
270 	memset(esb, 0, sizeof(*esb));
271 	esb->BlockStatus = esb_block_status((err_status & ERX_STATUS_UE) != 0,
272 					    (err_status & ERX_STATUS_CE) != 0,
273 					    false, false, 1);
274 	esb->RawDataOffset = (uint32_t)(sizeof(*esb) + sizeof(*de));
275 	esb->RawDataLength = 0;
276 	esb->DataLength = (uint32_t)(sizeof(*de) + section_size);
277 	esb->ErrorSeverity = esb_severity_from_erx(err_status);
278 
279 	/* Error Data Entry */
280 	memset(de, 0, sizeof(*de));
281 	de->SectionType = ARM_PROC_ERR_SECTION_GUID;
282 	de->ErrorSeverity = esb->ErrorSeverity;
283 	de->Revision = ACPI_DATA_ENTRY_REV_0300;
284 	de->ValidationBits = 0;
285 	de->Flags = (err_status & ERX_STATUS_DE) ? ACPI_SEC_FLAG_LATENT : 0;
286 	de->ErrorDataLength = section_size;
287 
288 	/* Payload: CPU section */
289 	memset(sec, 0, section_size);
290 
291 	/*  ARM Processor Error Section */
292 	sec->CpuInfo.ValidationBit = (EFI_ARM_PROC_ERROR_MPIDR_VALID |
293 				      EFI_ARM_PROC_ERROR_RUNNING_STATE_VALID);
294 	sec->CpuInfo.ErrInfoNum = CPU_ERR_INFO_NUM;
295 	sec->CpuInfo.ContextInfoNum = CPU_CONTEXT_INFO_NUM;
296 	sec->CpuInfo.SectionLength = section_size;
297 	sec->CpuInfo.AffinityLevel = 0;
298 	sec->CpuInfo.MPIDR_EL1 = read_mpidr_el1();
299 	sec->CpuInfo.MIDR_EL1 = read_midr_el1();
300 	sec->CpuInfo.RunState = 1;
301 	sec->CpuInfo.PsciState = 0;
302 
303 	/* ARM Processor Error Information */
304 	struct EFI_ARM_PROCESSOR_ERROR_INFORMATION *ei = &sec->CpuErrInfo[0];
305 	bool ce = (err_status & ERX_STATUS_CE) != 0;
306 	bool phys_addr_valid = ERX_STATUS_ADDRV(err_status);
307 
308 	ei->Version = 0;
309 	ei->Length = (uint8_t)sizeof(*ei);
310 	ei->ValidationBit =
311 		(EFI_ARM_PROC_ERROR_INFO_MULTIPLE_ERROR_VALID |
312 		 EFI_ARM_PROC_ERROR_INFO_FLAGS_VALID |
313 		 (phys_addr_valid ? EFI_ARM_PROC_ERROR_INFO_PHYS_ADDR_VALID :
314 				    0));
315 	ei->Type = arm_error_type_from_unit(err_misc0);
316 	ei->MultipleError = 0;
317 	ei->Flags = 0;
318 	ei->ErrorInfo = 0;
319 	ei->VirtualFaultAddress = 0;
320 	ei->PhysicalFaultAddress = err_addr;
321 	if (ei->Type == ARM_ERROR_TYPE_CACHE) {
322 		ei->ValidationBit |= EFI_ARM_PROC_ERROR_INFO_ERROR_INFO_VALID;
323 		ei->ErrorInfo = arm_cache_error_structure(err_misc0, ce);
324 	}
325 
326 	/*  ARM Processor Error Context Information (Type 4 and 5 contexts) */
327 	cm_el1_sysregs_context_save(NON_SECURE);
328 	if (!fill_ns_context_blocks(sec))
329 		WARN("CPER: Non-secure EL1 context unavailable; context blocks left zeroed\n");
330 
331 	return size;
332 }
333 
print_guid(struct efi_guid g)334 static void print_guid(struct efi_guid g)
335 {
336 	VERBOSE("  SectionType   = {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
337 		g.time_low, g.time_mid, g.time_hi_and_version,
338 		g.clock_seq_and_node[0], g.clock_seq_and_node[1],
339 		g.clock_seq_and_node[2], g.clock_seq_and_node[3],
340 		g.clock_seq_and_node[4], g.clock_seq_and_node[5],
341 		g.clock_seq_and_node[6], g.clock_seq_and_node[7]);
342 }
343 
print_cache_error_info(uint64_t info)344 static void print_cache_error_info(uint64_t info)
345 {
346 	uint64_t validation = (info & 0x7FULL);
347 	unsigned int tx = (unsigned int)((info & ARM_CACHE_ERR_TX_MASK) >>
348 				 ARM_CACHE_ERR_TX_SHIFT);
349 	unsigned int op = (unsigned int)((info & ARM_CACHE_ERR_OP_MASK) >>
350 				 ARM_CACHE_ERR_OP_SHIFT);
351 	unsigned int lvl = (unsigned int)((info & ARM_CACHE_ERR_LEVEL_MASK) >>
352 				  ARM_CACHE_ERR_LEVEL_SHIFT);
353 	unsigned int pcc = (unsigned int)((info >> ARM_CACHE_ERR_PCC_BIT) & 1U);
354 	unsigned int corr = (unsigned int)((info >> ARM_CACHE_ERR_CORR_BIT) & 1U);
355 	unsigned int ppc = (unsigned int)((info >> ARM_CACHE_ERR_PRECISE_PC_BIT) & 1U);
356 	unsigned int rpc = (unsigned int)((info >> ARM_CACHE_ERR_RESTART_PC_BIT) & 1U);
357 	uint64_t reserved = (info >> 29);
358 
359 	VERBOSE("  CacheErrorInfo:\n");
360 	VERBOSE("    ValidationBit           = 0x%04llx\n",
361 		(unsigned long long)validation);
362 	VERBOSE("    TransactionType         = %u\n", tx);
363 	VERBOSE("    Operation               = %u\n", op);
364 	VERBOSE("    Level                   = %u\n", lvl);
365 	VERBOSE("    ProcessorContextCorrupt = %u\n", pcc);
366 	VERBOSE("    Corrected               = %u\n", corr);
367 	VERBOSE("    PrecisePC               = %u\n", ppc);
368 	VERBOSE("    RestartablePC           = %u\n", rpc);
369 	VERBOSE("    Reserved[63:29]         = 0x%08llx\n",
370 		(unsigned long long)reserved);
371 }
372 
373 static void
print_esb_header(const struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER * esb)374 print_esb_header(const struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER *esb)
375 {
376 	if (esb == NULL) {
377 		WARN("CPER: null ESB header\n");
378 		return;
379 	}
380 	VERBOSE("ESB.Header:\n");
381 	VERBOSE("  BlockStatus   = 0x%08x\n", esb->BlockStatus);
382 	VERBOSE("  RawDataOffset = 0x%08x\n", esb->RawDataOffset);
383 	VERBOSE("  RawDataLength = %u\n", esb->RawDataLength);
384 	VERBOSE("  DataLength    = %u\n", esb->DataLength);
385 	VERBOSE("  ErrorSeverity = %u\n", esb->ErrorSeverity);
386 }
387 
388 static void
print_data_entry_header(const struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER * de)389 print_data_entry_header(const struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER *de)
390 {
391 	if (de == NULL) {
392 		WARN("CPER: null Data Entry header\n");
393 		return;
394 	}
395 	VERBOSE("DataEntry:\n");
396 	print_guid(de->SectionType);
397 	VERBOSE("  ErrorSeverity = %u\n", de->ErrorSeverity);
398 	VERBOSE("  Revision      = 0x%04x\n", de->Revision);
399 	VERBOSE("  ValidationBits= 0x%02x\n", de->ValidationBits);
400 	VERBOSE("  Flags         = 0x%02x\n", de->Flags);
401 	VERBOSE("  ErrorDataLen  = %u\n", de->ErrorDataLength);
402 }
403 
404 static void
print_cpu_section_header(const struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA * sec)405 print_cpu_section_header(const struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *sec)
406 {
407 	if (sec == NULL) {
408 		WARN("CPER: null CPU section\n");
409 		return;
410 	}
411 	VERBOSE("CPU Section:\n");
412 	VERBOSE("  ValidationBit = 0x%08x\n", sec->CpuInfo.ValidationBit);
413 	VERBOSE("  ErrInfoNum    = %u\n", sec->CpuInfo.ErrInfoNum);
414 	VERBOSE("  CtxtInfoNum   = %u\n", sec->CpuInfo.ContextInfoNum);
415 	VERBOSE("  SectionLength = %u\n", sec->CpuInfo.SectionLength);
416 	VERBOSE("  MPIDR_EL1     = 0x%016llx\n",
417 		(unsigned long long)sec->CpuInfo.MPIDR_EL1);
418 	VERBOSE("  MIDR_EL1      = 0x%016llx\n",
419 		(unsigned long long)sec->CpuInfo.MIDR_EL1);
420 	VERBOSE("  RunState      = %u\n", sec->CpuInfo.RunState);
421 	VERBOSE("  PsciState     = %u\n", sec->CpuInfo.PsciState);
422 }
423 
424 static void
print_error_info(const struct EFI_ARM_PROCESSOR_ERROR_INFORMATION * ei)425 print_error_info(const struct EFI_ARM_PROCESSOR_ERROR_INFORMATION *ei)
426 {
427 	if (ei == NULL) {
428 		WARN("CPER: null ErrorInfo\n");
429 		return;
430 	}
431 	VERBOSE("ErrorInfo[0]:\n");
432 	VERBOSE("  Version       = %u\n", ei->Version);
433 	VERBOSE("  Length        = %u\n", ei->Length);
434 	VERBOSE("  ValidationBit = 0x%04x\n", ei->ValidationBit);
435 	VERBOSE("  Type          = %u\n", ei->Type);
436 	VERBOSE("  MultipleError = %u\n", ei->MultipleError);
437 	VERBOSE("  Flags         = 0x%02x\n", ei->Flags);
438 	VERBOSE("  ErrorInfo     = 0x%016llx\n",
439 		(unsigned long long)ei->ErrorInfo);
440 
441 	if (ei->Type == ARM_ERROR_TYPE_CACHE &&
442 	    (ei->ValidationBit & EFI_ARM_PROC_ERROR_INFO_ERROR_INFO_VALID) &&
443 	    ei->ErrorInfo != 0) {
444 		print_cache_error_info(ei->ErrorInfo);
445 	}
446 
447 	VERBOSE("  VirtFaultAddr = 0x%016llx\n",
448 		(unsigned long long)ei->VirtualFaultAddress);
449 	VERBOSE("  PhysFaultAddr = 0x%016llx\n",
450 		(unsigned long long)ei->PhysicalFaultAddress);
451 }
452 
453 static void
print_context_block(const struct EFI_ARM_PROCESSOR_CONTEXT_INFORMATION * c,unsigned int idx)454 print_context_block(const struct EFI_ARM_PROCESSOR_CONTEXT_INFORMATION *c,
455 		    unsigned int idx)
456 {
457 	if (c == NULL) {
458 		WARN("CPER: null Context block\n");
459 		return;
460 	}
461 	VERBOSE("Context[%u]: type=%u size=%u\n", idx,
462 		c->Hdr.RegisterContextType, c->Hdr.RegisterArraySize);
463 
464 	switch (c->Hdr.RegisterContextType) {
465 	case EFI_ARM_CONTEXT_INFO_REG_TYPE_4:
466 		VERBOSE("  GPR x0..x3: %016llx %016llx %016llx %016llx\n",
467 			(unsigned long long)c->RegisterArray.Type4Gpr.X[0],
468 			(unsigned long long)c->RegisterArray.Type4Gpr.X[1],
469 			(unsigned long long)c->RegisterArray.Type4Gpr.X[2],
470 			(unsigned long long)c->RegisterArray.Type4Gpr.X[3]);
471 		VERBOSE("  SP = 0x%016llx\n",
472 			(unsigned long long)c->RegisterArray.Type4Gpr.SP);
473 		break;
474 
475 	case EFI_ARM_CONTEXT_INFO_REG_TYPE_5:
476 		VERBOSE("  EL1: SPSR=0x%016llx\n",
477 			(unsigned long long)
478 				c->RegisterArray.Type5SysRegs.SPSR_EL1);
479 		VERBOSE("  EL1: ELR=0x%016llx\n",
480 			(unsigned long long)
481 				c->RegisterArray.Type5SysRegs.ELR_EL1);
482 		VERBOSE("  EL1: ESR=0x%016llx\n",
483 			(unsigned long long)
484 				c->RegisterArray.Type5SysRegs.ESR_EL1);
485 		VERBOSE("  EL1: FAR=0x%016llx\n",
486 			(unsigned long long)
487 				c->RegisterArray.Type5SysRegs.FAR_EL1);
488 		VERBOSE("  ISR_EL1    = 0x%016llx\n",
489 			(unsigned long long)
490 				c->RegisterArray.Type5SysRegs.ISR_EL1);
491 		VERBOSE("  MAIR_EL1   = 0x%016llx\n",
492 			(unsigned long long)
493 				c->RegisterArray.Type5SysRegs.MAIR_EL1);
494 		VERBOSE("  MIDR_EL1   = 0x%016llx\n",
495 			(unsigned long long)
496 				c->RegisterArray.Type5SysRegs.MIDR_EL1);
497 		VERBOSE("  MPIDR_EL1  = 0x%016llx\n",
498 			(unsigned long long)
499 				c->RegisterArray.Type5SysRegs.MPIDR_EL1);
500 		VERBOSE("  SCTLR_EL1  = 0x%016llx\n",
501 			(unsigned long long)
502 				c->RegisterArray.Type5SysRegs.SCTLR_EL1);
503 		VERBOSE("  SP_EL0     = 0x%016llx\n",
504 			(unsigned long long)
505 				c->RegisterArray.Type5SysRegs.SP_EL0);
506 		VERBOSE("  SP_EL1     = 0x%016llx\n",
507 			(unsigned long long)
508 				c->RegisterArray.Type5SysRegs.SP_EL1);
509 		VERBOSE("  TCR_EL1    = 0x%016llx\n",
510 			(unsigned long long)
511 				c->RegisterArray.Type5SysRegs.TCR_EL1);
512 		VERBOSE("  TPIDR_EL0  = 0x%016llx\n",
513 			(unsigned long long)
514 				c->RegisterArray.Type5SysRegs.TPIDR_EL0);
515 		VERBOSE("  TPIDR_EL1  = 0x%016llx\n",
516 			(unsigned long long)
517 				c->RegisterArray.Type5SysRegs.TPIDR_EL1);
518 		VERBOSE("  TPIDRRO_EL0= 0x%016llx\n",
519 			(unsigned long long)
520 				c->RegisterArray.Type5SysRegs.TPIDRRO_EL0);
521 		VERBOSE("  TTBR0_EL1  = 0x%016llx\n",
522 			(unsigned long long)
523 				c->RegisterArray.Type5SysRegs.TTBR0_EL1);
524 		VERBOSE("  TTBR1_EL1  = 0x%016llx\n",
525 			(unsigned long long)
526 				c->RegisterArray.Type5SysRegs.TTBR1_EL1);
527 		break;
528 
529 	default:
530 		VERBOSE("  Unknown context type %u\n",
531 			c->Hdr.RegisterContextType);
532 		break;
533 	}
534 }
535 
536 static void
print_contexts(const struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA * sec)537 print_contexts(const struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *sec)
538 {
539 	for (unsigned int i = 0; i < sec->CpuInfo.ContextInfoNum; i++)
540 		print_context_block(&sec->CpuContextInfo[i], i);
541 }
542 
543 /* Dump the CPER buffer contents */
print_cper(const void * buf)544 void print_cper(const void *buf)
545 {
546 	if (!buf) {
547 		WARN("%s : null buffer\n", __func__);
548 		return;
549 	}
550 
551 	const struct ACPI_GENERIC_ERROR_STATUS_BLOCK_HEADER *esb = buf;
552 	const struct ACPI_GENERIC_ERROR_DATA_ENTRY_HEADER *de =
553 		(const void *)(esb + 1);
554 	const struct EFI_ARM_PROCESSOR_ERROR_RECORD_DATA *sec =
555 		(const void *)(de + 1);
556 	const struct EFI_ARM_PROCESSOR_ERROR_INFORMATION *ei =
557 		&sec->CpuErrInfo[0];
558 
559 	VERBOSE("\n========== CPER DUMP ==========\n");
560 
561 	print_esb_header(esb);
562 	print_data_entry_header(de);
563 	print_cpu_section_header(sec);
564 	print_error_info(ei);
565 	print_contexts(sec);
566 
567 	VERBOSE("========== END OF CPER DUMP ==========\n\n");
568 }
569