Skip to content

Commit 2f74f09

Browse files
Tyler Baicarwildea01
authored andcommitted
efi: parse ARM processor error
Add support for ARM Common Platform Error Record (CPER). UEFI 2.6 specification adds support for ARM specific processor error information to be reported as part of the CPER records. This provides more detail on for processor error logs. Signed-off-by: Tyler Baicar <[email protected]> CC: Jonathan (Zhixiong) Zhang <[email protected]> Reviewed-by: James Morse <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 8a94471 commit 2f74f09

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

drivers/firmware/efi/cper.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,15 @@ void cper_print_bits(const char *pfx, unsigned int bits,
110110
static const char * const proc_type_strs[] = {
111111
"IA32/X64",
112112
"IA64",
113+
"ARM",
113114
};
114115

115116
static const char * const proc_isa_strs[] = {
116117
"IA32",
117118
"IA64",
118119
"X64",
120+
"ARM A32/T32",
121+
"ARM A64",
119122
};
120123

121124
static const char * const proc_error_type_strs[] = {
@@ -184,6 +187,122 @@ static void cper_print_proc_generic(const char *pfx,
184187
printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
185188
}
186189

190+
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
191+
static const char * const arm_reg_ctx_strs[] = {
192+
"AArch32 general purpose registers",
193+
"AArch32 EL1 context registers",
194+
"AArch32 EL2 context registers",
195+
"AArch32 secure context registers",
196+
"AArch64 general purpose registers",
197+
"AArch64 EL1 context registers",
198+
"AArch64 EL2 context registers",
199+
"AArch64 EL3 context registers",
200+
"Misc. system register structure",
201+
};
202+
203+
static void cper_print_proc_arm(const char *pfx,
204+
const struct cper_sec_proc_arm *proc)
205+
{
206+
int i, len, max_ctx_type;
207+
struct cper_arm_err_info *err_info;
208+
struct cper_arm_ctx_info *ctx_info;
209+
char newpfx[64];
210+
211+
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
212+
213+
len = proc->section_length - (sizeof(*proc) +
214+
proc->err_info_num * (sizeof(*err_info)));
215+
if (len < 0) {
216+
printk("%ssection length: %d\n", pfx, proc->section_length);
217+
printk("%ssection length is too small\n", pfx);
218+
printk("%sfirmware-generated error record is incorrect\n", pfx);
219+
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
220+
return;
221+
}
222+
223+
if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
224+
printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
225+
pfx, proc->mpidr);
226+
227+
if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
228+
printk("%serror affinity level: %d\n", pfx,
229+
proc->affinity_level);
230+
231+
if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
232+
printk("%srunning state: 0x%x\n", pfx, proc->running_state);
233+
printk("%sPower State Coordination Interface state: %d\n",
234+
pfx, proc->psci_state);
235+
}
236+
237+
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
238+
239+
err_info = (struct cper_arm_err_info *)(proc + 1);
240+
for (i = 0; i < proc->err_info_num; i++) {
241+
printk("%sError info structure %d:\n", pfx, i);
242+
243+
printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
244+
245+
if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
246+
if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
247+
printk("%sfirst error captured\n", newpfx);
248+
if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
249+
printk("%slast error captured\n", newpfx);
250+
if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
251+
printk("%spropagated error captured\n",
252+
newpfx);
253+
if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
254+
printk("%soverflow occurred, error info is incomplete\n",
255+
newpfx);
256+
}
257+
258+
printk("%serror_type: %d, %s\n", newpfx, err_info->type,
259+
err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
260+
proc_error_type_strs[err_info->type] : "unknown");
261+
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
262+
printk("%serror_info: 0x%016llx\n", newpfx,
263+
err_info->error_info);
264+
if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
265+
printk("%svirtual fault address: 0x%016llx\n",
266+
newpfx, err_info->virt_fault_addr);
267+
if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
268+
printk("%sphysical fault address: 0x%016llx\n",
269+
newpfx, err_info->physical_fault_addr);
270+
err_info += 1;
271+
}
272+
273+
ctx_info = (struct cper_arm_ctx_info *)err_info;
274+
max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
275+
for (i = 0; i < proc->context_info_num; i++) {
276+
int size = sizeof(*ctx_info) + ctx_info->size;
277+
278+
printk("%sContext info structure %d:\n", pfx, i);
279+
if (len < size) {
280+
printk("%ssection length is too small\n", newpfx);
281+
printk("%sfirmware-generated error record is incorrect\n", pfx);
282+
return;
283+
}
284+
if (ctx_info->type > max_ctx_type) {
285+
printk("%sInvalid context type: %d (max: %d)\n",
286+
newpfx, ctx_info->type, max_ctx_type);
287+
return;
288+
}
289+
printk("%sregister context type: %s\n", newpfx,
290+
arm_reg_ctx_strs[ctx_info->type]);
291+
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
292+
(ctx_info + 1), ctx_info->size, 0);
293+
len -= size;
294+
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
295+
}
296+
297+
if (len > 0) {
298+
printk("%sVendor specific error info has %u bytes:\n", pfx,
299+
len);
300+
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
301+
len, true);
302+
}
303+
}
304+
#endif
305+
187306
static const char * const mem_err_type_strs[] = {
188307
"unknown",
189308
"no error",
@@ -456,6 +575,16 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
456575
cper_print_pcie(newpfx, pcie, gdata);
457576
else
458577
goto err_section_too_small;
578+
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
579+
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
580+
struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
581+
582+
printk("%ssection_type: ARM processor error\n", newpfx);
583+
if (gdata->error_data_length >= sizeof(*arm_err))
584+
cper_print_proc_arm(newpfx, arm_err);
585+
else
586+
goto err_section_too_small;
587+
#endif
459588
} else
460589
printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
461590

include/linux/cper.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ enum {
180180
#define CPER_SEC_PROC_IPF \
181181
UUID_LE(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00, \
182182
0x80, 0xC7, 0x3C, 0x88, 0x81)
183+
/* Processor Specific: ARM */
184+
#define CPER_SEC_PROC_ARM \
185+
UUID_LE(0xE19E3D16, 0xBC11, 0x11E4, 0x9C, 0xAA, 0xC2, 0x05, \
186+
0x1D, 0x5D, 0x46, 0xB0)
183187
/* Platform Memory */
184188
#define CPER_SEC_PLATFORM_MEM \
185189
UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83, \
@@ -255,6 +259,22 @@ enum {
255259

256260
#define CPER_PCIE_SLOT_SHIFT 3
257261

262+
#define CPER_ARM_VALID_MPIDR BIT(0)
263+
#define CPER_ARM_VALID_AFFINITY_LEVEL BIT(1)
264+
#define CPER_ARM_VALID_RUNNING_STATE BIT(2)
265+
#define CPER_ARM_VALID_VENDOR_INFO BIT(3)
266+
267+
#define CPER_ARM_INFO_VALID_MULTI_ERR BIT(0)
268+
#define CPER_ARM_INFO_VALID_FLAGS BIT(1)
269+
#define CPER_ARM_INFO_VALID_ERR_INFO BIT(2)
270+
#define CPER_ARM_INFO_VALID_VIRT_ADDR BIT(3)
271+
#define CPER_ARM_INFO_VALID_PHYSICAL_ADDR BIT(4)
272+
273+
#define CPER_ARM_INFO_FLAGS_FIRST BIT(0)
274+
#define CPER_ARM_INFO_FLAGS_LAST BIT(1)
275+
#define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2)
276+
#define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3)
277+
258278
/*
259279
* All tables and structs must be byte-packed to match CPER
260280
* specification, since the tables are provided by the system BIOS
@@ -340,6 +360,40 @@ struct cper_ia_proc_ctx {
340360
__u64 mm_reg_addr;
341361
};
342362

363+
/* ARM Processor Error Section */
364+
struct cper_sec_proc_arm {
365+
__u32 validation_bits;
366+
__u16 err_info_num; /* Number of Processor Error Info */
367+
__u16 context_info_num; /* Number of Processor Context Info Records*/
368+
__u32 section_length;
369+
__u8 affinity_level;
370+
__u8 reserved[3]; /* must be zero */
371+
__u64 mpidr;
372+
__u64 midr;
373+
__u32 running_state; /* Bit 0 set - Processor running. PSCI = 0 */
374+
__u32 psci_state;
375+
};
376+
377+
/* ARM Processor Error Information Structure */
378+
struct cper_arm_err_info {
379+
__u8 version;
380+
__u8 length;
381+
__u16 validation_bits;
382+
__u8 type;
383+
__u16 multiple_error;
384+
__u8 flags;
385+
__u64 error_info;
386+
__u64 virt_fault_addr;
387+
__u64 physical_fault_addr;
388+
};
389+
390+
/* ARM Processor Context Information Structure */
391+
struct cper_arm_ctx_info {
392+
__u16 version;
393+
__u16 type;
394+
__u32 size;
395+
};
396+
343397
/* Old Memory Error Section UEFI 2.1, 2.2 */
344398
struct cper_sec_mem_err_old {
345399
__u64 validation_bits;

0 commit comments

Comments
 (0)