Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/cper-arm.c
50771 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* UEFI Common Platform Error Record (CPER) support
4
*
5
* Copyright (C) 2017, The Linux Foundation. All rights reserved.
6
*/
7
8
#include <linux/kernel.h>
9
#include <linux/module.h>
10
#include <linux/time.h>
11
#include <linux/cper.h>
12
#include <linux/dmi.h>
13
#include <linux/acpi.h>
14
#include <linux/pci.h>
15
#include <linux/printk.h>
16
#include <linux/bcd.h>
17
#include <acpi/ghes.h>
18
#include <ras/ras_event.h>
19
20
static const char * const arm_reg_ctx_strs[] = {
21
"AArch32 general purpose registers",
22
"AArch32 EL1 context registers",
23
"AArch32 EL2 context registers",
24
"AArch32 secure context registers",
25
"AArch64 general purpose registers",
26
"AArch64 EL1 context registers",
27
"AArch64 EL2 context registers",
28
"AArch64 EL3 context registers",
29
"Misc. system register structure",
30
};
31
32
static const char * const arm_err_trans_type_strs[] = {
33
"Instruction",
34
"Data Access",
35
"Generic",
36
};
37
38
static const char * const arm_bus_err_op_strs[] = {
39
"Generic error (type cannot be determined)",
40
"Generic read (type of instruction or data request cannot be determined)",
41
"Generic write (type of instruction of data request cannot be determined)",
42
"Data read",
43
"Data write",
44
"Instruction fetch",
45
"Prefetch",
46
};
47
48
static const char * const arm_cache_err_op_strs[] = {
49
"Generic error (type cannot be determined)",
50
"Generic read (type of instruction or data request cannot be determined)",
51
"Generic write (type of instruction of data request cannot be determined)",
52
"Data read",
53
"Data write",
54
"Instruction fetch",
55
"Prefetch",
56
"Eviction",
57
"Snooping (processor initiated a cache snoop that resulted in an error)",
58
"Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
59
"Management",
60
};
61
62
static const char * const arm_tlb_err_op_strs[] = {
63
"Generic error (type cannot be determined)",
64
"Generic read (type of instruction or data request cannot be determined)",
65
"Generic write (type of instruction of data request cannot be determined)",
66
"Data read",
67
"Data write",
68
"Instruction fetch",
69
"Prefetch",
70
"Local management operation (processor initiated a TLB management operation that resulted in an error)",
71
"External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
72
};
73
74
static const char * const arm_bus_err_part_type_strs[] = {
75
"Local processor originated request",
76
"Local processor responded to request",
77
"Local processor observed",
78
"Generic",
79
};
80
81
static const char * const arm_bus_err_addr_space_strs[] = {
82
"External Memory Access",
83
"Internal Memory Access",
84
"Unknown",
85
"Device Memory Access",
86
};
87
88
static void cper_print_arm_err_info(const char *pfx, u32 type,
89
u64 error_info)
90
{
91
u8 trans_type, op_type, level, participation_type, address_space;
92
u16 mem_attributes;
93
bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
94
bool time_out, access_mode;
95
96
/*
97
* Vendor type errors have error information values that are vendor
98
* specific.
99
*/
100
if (type & CPER_ARM_VENDOR_ERROR)
101
return;
102
103
if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
104
trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
105
& CPER_ARM_ERR_TRANSACTION_MASK);
106
if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
107
printk("%stransaction type: %s\n", pfx,
108
arm_err_trans_type_strs[trans_type]);
109
}
110
}
111
112
if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
113
op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
114
& CPER_ARM_ERR_OPERATION_MASK);
115
if (type & CPER_ARM_CACHE_ERROR) {
116
if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
117
printk("%scache error, operation type: %s\n", pfx,
118
arm_cache_err_op_strs[op_type]);
119
}
120
}
121
if (type & CPER_ARM_TLB_ERROR) {
122
if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
123
printk("%sTLB error, operation type: %s\n", pfx,
124
arm_tlb_err_op_strs[op_type]);
125
}
126
}
127
if (type & CPER_ARM_BUS_ERROR) {
128
if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
129
printk("%sbus error, operation type: %s\n", pfx,
130
arm_bus_err_op_strs[op_type]);
131
}
132
}
133
}
134
135
if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
136
level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
137
& CPER_ARM_ERR_LEVEL_MASK);
138
if (type & CPER_ARM_CACHE_ERROR)
139
printk("%scache level: %d\n", pfx, level);
140
141
if (type & CPER_ARM_TLB_ERROR)
142
printk("%sTLB level: %d\n", pfx, level);
143
144
if (type & CPER_ARM_BUS_ERROR)
145
printk("%saffinity level at which the bus error occurred: %d\n",
146
pfx, level);
147
}
148
149
if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
150
proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
151
& CPER_ARM_ERR_PC_CORRUPT_MASK);
152
if (proc_context_corrupt)
153
printk("%sprocessor context corrupted\n", pfx);
154
else
155
printk("%sprocessor context not corrupted\n", pfx);
156
}
157
158
if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
159
corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
160
& CPER_ARM_ERR_CORRECTED_MASK);
161
if (corrected)
162
printk("%sthe error has been corrected\n", pfx);
163
else
164
printk("%sthe error has not been corrected\n", pfx);
165
}
166
167
if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
168
precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
169
& CPER_ARM_ERR_PRECISE_PC_MASK);
170
if (precise_pc)
171
printk("%sPC is precise\n", pfx);
172
else
173
printk("%sPC is imprecise\n", pfx);
174
}
175
176
if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
177
restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
178
& CPER_ARM_ERR_RESTARTABLE_PC_MASK);
179
if (restartable_pc)
180
printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
181
}
182
183
/* The rest of the fields are specific to bus errors */
184
if (type != CPER_ARM_BUS_ERROR)
185
return;
186
187
if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
188
participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
189
& CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
190
if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
191
printk("%sparticipation type: %s\n", pfx,
192
arm_bus_err_part_type_strs[participation_type]);
193
}
194
}
195
196
if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
197
time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
198
& CPER_ARM_ERR_TIME_OUT_MASK);
199
if (time_out)
200
printk("%srequest timed out\n", pfx);
201
}
202
203
if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
204
address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
205
& CPER_ARM_ERR_ADDRESS_SPACE_MASK);
206
if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
207
printk("%saddress space: %s\n", pfx,
208
arm_bus_err_addr_space_strs[address_space]);
209
}
210
}
211
212
if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
213
mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
214
& CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
215
printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
216
}
217
218
if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
219
access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
220
& CPER_ARM_ERR_ACCESS_MODE_MASK);
221
if (access_mode)
222
printk("%saccess mode: normal\n", pfx);
223
else
224
printk("%saccess mode: secure\n", pfx);
225
}
226
}
227
228
void cper_print_proc_arm(const char *pfx,
229
const struct cper_sec_proc_arm *proc,
230
u32 length)
231
{
232
int i, len, max_ctx_type;
233
struct cper_arm_err_info *err_info;
234
struct cper_arm_ctx_info *ctx_info;
235
char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
236
char error_type[120];
237
238
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
239
240
len = proc->section_length - (sizeof(*proc) +
241
proc->err_info_num * (sizeof(*err_info)));
242
243
if (len < 0 || proc->section_length > length) {
244
printk("%ssection length: %d, CPER size: %d\n",
245
pfx, proc->section_length, length);
246
printk("%ssection length is too %s\n", pfx,
247
(len < 0) ? "small" : "big");
248
printk("%sfirmware-generated error record is incorrect\n", pfx);
249
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
250
return;
251
}
252
253
if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
254
printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
255
pfx, proc->mpidr);
256
257
if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
258
printk("%serror affinity level: %d\n", pfx,
259
proc->affinity_level);
260
261
if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
262
printk("%srunning state: 0x%x\n", pfx, proc->running_state);
263
printk("%sPower State Coordination Interface state: %d\n",
264
pfx, proc->psci_state);
265
}
266
267
snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
268
269
err_info = (struct cper_arm_err_info *)(proc + 1);
270
for (i = 0; i < proc->err_info_num; i++) {
271
printk("%sError info structure %d:\n", pfx, i);
272
273
printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
274
275
if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
276
if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
277
printk("%sfirst error captured\n", newpfx);
278
if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
279
printk("%slast error captured\n", newpfx);
280
if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
281
printk("%spropagated error captured\n",
282
newpfx);
283
if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
284
printk("%soverflow occurred, error info is incomplete\n",
285
newpfx);
286
}
287
288
cper_bits_to_str(error_type, sizeof(error_type),
289
FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
290
cper_proc_error_type_strs,
291
ARRAY_SIZE(cper_proc_error_type_strs));
292
293
printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type,
294
error_type,
295
(err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
296
297
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
298
printk("%serror_info: 0x%016llx\n", newpfx,
299
err_info->error_info);
300
snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
301
cper_print_arm_err_info(infopfx, err_info->type,
302
err_info->error_info);
303
}
304
if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
305
printk("%svirtual fault address: 0x%016llx\n",
306
newpfx, err_info->virt_fault_addr);
307
if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
308
printk("%sphysical fault address: 0x%016llx\n",
309
newpfx, err_info->physical_fault_addr);
310
err_info += 1;
311
}
312
313
ctx_info = (struct cper_arm_ctx_info *)err_info;
314
max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
315
for (i = 0; i < proc->context_info_num; i++) {
316
int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
317
318
printk("%sContext info structure %d:\n", pfx, i);
319
if (len < size) {
320
printk("%ssection length is too small\n", newpfx);
321
printk("%sfirmware-generated error record is incorrect\n", pfx);
322
return;
323
}
324
if (ctx_info->type > max_ctx_type) {
325
printk("%sInvalid context type: %d (max: %d)\n",
326
newpfx, ctx_info->type, max_ctx_type);
327
return;
328
}
329
printk("%sregister context type: %s\n", newpfx,
330
arm_reg_ctx_strs[ctx_info->type]);
331
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
332
(ctx_info + 1), ctx_info->size, 0);
333
len -= size;
334
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
335
}
336
337
if (len > 0) {
338
printk("%sVendor specific error info has %u bytes:\n", pfx,
339
len);
340
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
341
len, true);
342
}
343
}
344
345