diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 13:42:39 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-30 13:42:39 -0500 |
commit | b8dbf73086085f1973d3ae66f709e78c077fed05 (patch) | |
tree | b6bfe33415352b93e01778b5cc5c41c271656e28 | |
parent | d772794637451c424729dd71690d7ac158523108 (diff) | |
parent | a5c03c31af2291f13689d11760c0b59fb70c9a5a (diff) |
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI updates from Ingo Molnar:
"The biggest change in this cycle was the addition of ARM CPER error
decoding when printing EFI errors into the kernel log.
There are also misc smaller updates: documentation update, cleanups
and an EFI memory map permissions quirk"
* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/efi: Clarify that reset attack mitigation needs appropriate userspace
efi: Parse ARM error information value
efi: Move ARM CPER code to new file
efi: Use PTR_ERR_OR_ZERO()
arm64/efi: Ignore EFI_MEMORY_XP attribute if RP and/or WP are set
efi/capsule-loader: Fix pr_err() string to end with newline
-rw-r--r-- | arch/arm64/kernel/efi.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/Kconfig | 10 | ||||
-rw-r--r-- | drivers/firmware/efi/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/capsule-loader.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/cper-arm.c | 356 | ||||
-rw-r--r-- | drivers/firmware/efi/cper.c | 122 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 2 | ||||
-rw-r--r-- | include/linux/cper.h | 48 |
8 files changed, 422 insertions, 123 deletions
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 82cd07592519..f85ac58d08a3 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c | |||
@@ -48,7 +48,9 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) | |||
48 | return pgprot_val(PAGE_KERNEL_ROX); | 48 | return pgprot_val(PAGE_KERNEL_ROX); |
49 | 49 | ||
50 | /* RW- */ | 50 | /* RW- */ |
51 | if (attr & EFI_MEMORY_XP || type != EFI_RUNTIME_SERVICES_CODE) | 51 | if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) == |
52 | EFI_MEMORY_XP) || | ||
53 | type != EFI_RUNTIME_SERVICES_CODE) | ||
52 | return pgprot_val(PAGE_KERNEL); | 54 | return pgprot_val(PAGE_KERNEL); |
53 | 55 | ||
54 | /* RWX */ | 56 | /* RWX */ |
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 2b4c39fdfa91..6047ed4e8a3d 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig | |||
@@ -159,13 +159,21 @@ config RESET_ATTACK_MITIGATION | |||
159 | using the TCG Platform Reset Attack Mitigation specification. This | 159 | using the TCG Platform Reset Attack Mitigation specification. This |
160 | protects against an attacker forcibly rebooting the system while it | 160 | protects against an attacker forcibly rebooting the system while it |
161 | still contains secrets in RAM, booting another OS and extracting the | 161 | still contains secrets in RAM, booting another OS and extracting the |
162 | secrets. | 162 | secrets. This should only be enabled when userland is configured to |
163 | clear the MemoryOverwriteRequest flag on clean shutdown after secrets | ||
164 | have been evicted, since otherwise it will trigger even on clean | ||
165 | reboots. | ||
163 | 166 | ||
164 | endmenu | 167 | endmenu |
165 | 168 | ||
166 | config UEFI_CPER | 169 | config UEFI_CPER |
167 | bool | 170 | bool |
168 | 171 | ||
172 | config UEFI_CPER_ARM | ||
173 | bool | ||
174 | depends on UEFI_CPER && ( ARM || ARM64 ) | ||
175 | default y | ||
176 | |||
169 | config EFI_DEV_PATH_PARSER | 177 | config EFI_DEV_PATH_PARSER |
170 | bool | 178 | bool |
171 | depends on ACPI | 179 | depends on ACPI |
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 269501dfba53..a3e73d6e8a43 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
@@ -30,3 +30,4 @@ arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o | |||
30 | obj-$(CONFIG_ARM) += $(arm-obj-y) | 30 | obj-$(CONFIG_ARM) += $(arm-obj-y) |
31 | obj-$(CONFIG_ARM64) += $(arm-obj-y) | 31 | obj-$(CONFIG_ARM64) += $(arm-obj-y) |
32 | obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o | 32 | obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o |
33 | obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o | ||
diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 055e2e8f985a..e456f4602df1 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c | |||
@@ -45,7 +45,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) | |||
45 | pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE; | 45 | pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE; |
46 | 46 | ||
47 | if (pages_needed == 0) { | 47 | if (pages_needed == 0) { |
48 | pr_err("invalid capsule size"); | 48 | pr_err("invalid capsule size\n"); |
49 | return -EINVAL; | 49 | return -EINVAL; |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c new file mode 100644 index 000000000000..698e5c8e0c8d --- /dev/null +++ b/drivers/firmware/efi/cper-arm.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * UEFI Common Platform Error Record (CPER) support | ||
3 | * | ||
4 | * Copyright (C) 2017, The Linux Foundation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/cper.h> | ||
24 | #include <linux/dmi.h> | ||
25 | #include <linux/acpi.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/aer.h> | ||
28 | #include <linux/printk.h> | ||
29 | #include <linux/bcd.h> | ||
30 | #include <acpi/ghes.h> | ||
31 | #include <ras/ras_event.h> | ||
32 | |||
33 | #define INDENT_SP " " | ||
34 | |||
35 | static const char * const arm_reg_ctx_strs[] = { | ||
36 | "AArch32 general purpose registers", | ||
37 | "AArch32 EL1 context registers", | ||
38 | "AArch32 EL2 context registers", | ||
39 | "AArch32 secure context registers", | ||
40 | "AArch64 general purpose registers", | ||
41 | "AArch64 EL1 context registers", | ||
42 | "AArch64 EL2 context registers", | ||
43 | "AArch64 EL3 context registers", | ||
44 | "Misc. system register structure", | ||
45 | }; | ||
46 | |||
47 | static const char * const arm_err_trans_type_strs[] = { | ||
48 | "Instruction", | ||
49 | "Data Access", | ||
50 | "Generic", | ||
51 | }; | ||
52 | |||
53 | static const char * const arm_bus_err_op_strs[] = { | ||
54 | "Generic error (type cannot be determined)", | ||
55 | "Generic read (type of instruction or data request cannot be determined)", | ||
56 | "Generic write (type of instruction of data request cannot be determined)", | ||
57 | "Data read", | ||
58 | "Data write", | ||
59 | "Instruction fetch", | ||
60 | "Prefetch", | ||
61 | }; | ||
62 | |||
63 | static const char * const arm_cache_err_op_strs[] = { | ||
64 | "Generic error (type cannot be determined)", | ||
65 | "Generic read (type of instruction or data request cannot be determined)", | ||
66 | "Generic write (type of instruction of data request cannot be determined)", | ||
67 | "Data read", | ||
68 | "Data write", | ||
69 | "Instruction fetch", | ||
70 | "Prefetch", | ||
71 | "Eviction", | ||
72 | "Snooping (processor initiated a cache snoop that resulted in an error)", | ||
73 | "Snooped (processor raised a cache error caused by another processor or device snooping its cache)", | ||
74 | "Management", | ||
75 | }; | ||
76 | |||
77 | static const char * const arm_tlb_err_op_strs[] = { | ||
78 | "Generic error (type cannot be determined)", | ||
79 | "Generic read (type of instruction or data request cannot be determined)", | ||
80 | "Generic write (type of instruction of data request cannot be determined)", | ||
81 | "Data read", | ||
82 | "Data write", | ||
83 | "Instruction fetch", | ||
84 | "Prefetch", | ||
85 | "Local management operation (processor initiated a TLB management operation that resulted in an error)", | ||
86 | "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)", | ||
87 | }; | ||
88 | |||
89 | static const char * const arm_bus_err_part_type_strs[] = { | ||
90 | "Local processor originated request", | ||
91 | "Local processor responded to request", | ||
92 | "Local processor observed", | ||
93 | "Generic", | ||
94 | }; | ||
95 | |||
96 | static const char * const arm_bus_err_addr_space_strs[] = { | ||
97 | "External Memory Access", | ||
98 | "Internal Memory Access", | ||
99 | "Unknown", | ||
100 | "Device Memory Access", | ||
101 | }; | ||
102 | |||
103 | static void cper_print_arm_err_info(const char *pfx, u32 type, | ||
104 | u64 error_info) | ||
105 | { | ||
106 | u8 trans_type, op_type, level, participation_type, address_space; | ||
107 | u16 mem_attributes; | ||
108 | bool proc_context_corrupt, corrected, precise_pc, restartable_pc; | ||
109 | bool time_out, access_mode; | ||
110 | |||
111 | /* If the type is unknown, bail. */ | ||
112 | if (type > CPER_ARM_MAX_TYPE) | ||
113 | return; | ||
114 | |||
115 | /* | ||
116 | * Vendor type errors have error information values that are vendor | ||
117 | * specific. | ||
118 | */ | ||
119 | if (type == CPER_ARM_VENDOR_ERROR) | ||
120 | return; | ||
121 | |||
122 | if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) { | ||
123 | trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT) | ||
124 | & CPER_ARM_ERR_TRANSACTION_MASK); | ||
125 | if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) { | ||
126 | printk("%stransaction type: %s\n", pfx, | ||
127 | arm_err_trans_type_strs[trans_type]); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) { | ||
132 | op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT) | ||
133 | & CPER_ARM_ERR_OPERATION_MASK); | ||
134 | switch (type) { | ||
135 | case CPER_ARM_CACHE_ERROR: | ||
136 | if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) { | ||
137 | printk("%soperation type: %s\n", pfx, | ||
138 | arm_cache_err_op_strs[op_type]); | ||
139 | } | ||
140 | break; | ||
141 | case CPER_ARM_TLB_ERROR: | ||
142 | if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) { | ||
143 | printk("%soperation type: %s\n", pfx, | ||
144 | arm_tlb_err_op_strs[op_type]); | ||
145 | } | ||
146 | break; | ||
147 | case CPER_ARM_BUS_ERROR: | ||
148 | if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) { | ||
149 | printk("%soperation type: %s\n", pfx, | ||
150 | arm_bus_err_op_strs[op_type]); | ||
151 | } | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | if (error_info & CPER_ARM_ERR_VALID_LEVEL) { | ||
157 | level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT) | ||
158 | & CPER_ARM_ERR_LEVEL_MASK); | ||
159 | switch (type) { | ||
160 | case CPER_ARM_CACHE_ERROR: | ||
161 | printk("%scache level: %d\n", pfx, level); | ||
162 | break; | ||
163 | case CPER_ARM_TLB_ERROR: | ||
164 | printk("%sTLB level: %d\n", pfx, level); | ||
165 | break; | ||
166 | case CPER_ARM_BUS_ERROR: | ||
167 | printk("%saffinity level at which the bus error occurred: %d\n", | ||
168 | pfx, level); | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) { | ||
174 | proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT) | ||
175 | & CPER_ARM_ERR_PC_CORRUPT_MASK); | ||
176 | if (proc_context_corrupt) | ||
177 | printk("%sprocessor context corrupted\n", pfx); | ||
178 | else | ||
179 | printk("%sprocessor context not corrupted\n", pfx); | ||
180 | } | ||
181 | |||
182 | if (error_info & CPER_ARM_ERR_VALID_CORRECTED) { | ||
183 | corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT) | ||
184 | & CPER_ARM_ERR_CORRECTED_MASK); | ||
185 | if (corrected) | ||
186 | printk("%sthe error has been corrected\n", pfx); | ||
187 | else | ||
188 | printk("%sthe error has not been corrected\n", pfx); | ||
189 | } | ||
190 | |||
191 | if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) { | ||
192 | precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT) | ||
193 | & CPER_ARM_ERR_PRECISE_PC_MASK); | ||
194 | if (precise_pc) | ||
195 | printk("%sPC is precise\n", pfx); | ||
196 | else | ||
197 | printk("%sPC is imprecise\n", pfx); | ||
198 | } | ||
199 | |||
200 | if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) { | ||
201 | restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT) | ||
202 | & CPER_ARM_ERR_RESTARTABLE_PC_MASK); | ||
203 | if (restartable_pc) | ||
204 | printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx); | ||
205 | } | ||
206 | |||
207 | /* The rest of the fields are specific to bus errors */ | ||
208 | if (type != CPER_ARM_BUS_ERROR) | ||
209 | return; | ||
210 | |||
211 | if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) { | ||
212 | participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT) | ||
213 | & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK); | ||
214 | if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) { | ||
215 | printk("%sparticipation type: %s\n", pfx, | ||
216 | arm_bus_err_part_type_strs[participation_type]); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) { | ||
221 | time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT) | ||
222 | & CPER_ARM_ERR_TIME_OUT_MASK); | ||
223 | if (time_out) | ||
224 | printk("%srequest timed out\n", pfx); | ||
225 | } | ||
226 | |||
227 | if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) { | ||
228 | address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT) | ||
229 | & CPER_ARM_ERR_ADDRESS_SPACE_MASK); | ||
230 | if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) { | ||
231 | printk("%saddress space: %s\n", pfx, | ||
232 | arm_bus_err_addr_space_strs[address_space]); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) { | ||
237 | mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT) | ||
238 | & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK); | ||
239 | printk("%smemory access attributes:0x%x\n", pfx, mem_attributes); | ||
240 | } | ||
241 | |||
242 | if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) { | ||
243 | access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT) | ||
244 | & CPER_ARM_ERR_ACCESS_MODE_MASK); | ||
245 | if (access_mode) | ||
246 | printk("%saccess mode: normal\n", pfx); | ||
247 | else | ||
248 | printk("%saccess mode: secure\n", pfx); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | void cper_print_proc_arm(const char *pfx, | ||
253 | const struct cper_sec_proc_arm *proc) | ||
254 | { | ||
255 | int i, len, max_ctx_type; | ||
256 | struct cper_arm_err_info *err_info; | ||
257 | struct cper_arm_ctx_info *ctx_info; | ||
258 | char newpfx[64], infopfx[64]; | ||
259 | |||
260 | printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); | ||
261 | |||
262 | len = proc->section_length - (sizeof(*proc) + | ||
263 | proc->err_info_num * (sizeof(*err_info))); | ||
264 | if (len < 0) { | ||
265 | printk("%ssection length: %d\n", pfx, proc->section_length); | ||
266 | printk("%ssection length is too small\n", pfx); | ||
267 | printk("%sfirmware-generated error record is incorrect\n", pfx); | ||
268 | printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | if (proc->validation_bits & CPER_ARM_VALID_MPIDR) | ||
273 | printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n", | ||
274 | pfx, proc->mpidr); | ||
275 | |||
276 | if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL) | ||
277 | printk("%serror affinity level: %d\n", pfx, | ||
278 | proc->affinity_level); | ||
279 | |||
280 | if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) { | ||
281 | printk("%srunning state: 0x%x\n", pfx, proc->running_state); | ||
282 | printk("%sPower State Coordination Interface state: %d\n", | ||
283 | pfx, proc->psci_state); | ||
284 | } | ||
285 | |||
286 | snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); | ||
287 | |||
288 | err_info = (struct cper_arm_err_info *)(proc + 1); | ||
289 | for (i = 0; i < proc->err_info_num; i++) { | ||
290 | printk("%sError info structure %d:\n", pfx, i); | ||
291 | |||
292 | printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1); | ||
293 | |||
294 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) { | ||
295 | if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST) | ||
296 | printk("%sfirst error captured\n", newpfx); | ||
297 | if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST) | ||
298 | printk("%slast error captured\n", newpfx); | ||
299 | if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED) | ||
300 | printk("%spropagated error captured\n", | ||
301 | newpfx); | ||
302 | if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW) | ||
303 | printk("%soverflow occurred, error info is incomplete\n", | ||
304 | newpfx); | ||
305 | } | ||
306 | |||
307 | printk("%serror_type: %d, %s\n", newpfx, err_info->type, | ||
308 | err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ? | ||
309 | cper_proc_error_type_strs[err_info->type] : "unknown"); | ||
310 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { | ||
311 | printk("%serror_info: 0x%016llx\n", newpfx, | ||
312 | err_info->error_info); | ||
313 | snprintf(infopfx, sizeof(infopfx), "%s%s", newpfx, INDENT_SP); | ||
314 | cper_print_arm_err_info(infopfx, err_info->type, | ||
315 | err_info->error_info); | ||
316 | } | ||
317 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR) | ||
318 | printk("%svirtual fault address: 0x%016llx\n", | ||
319 | newpfx, err_info->virt_fault_addr); | ||
320 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR) | ||
321 | printk("%sphysical fault address: 0x%016llx\n", | ||
322 | newpfx, err_info->physical_fault_addr); | ||
323 | err_info += 1; | ||
324 | } | ||
325 | |||
326 | ctx_info = (struct cper_arm_ctx_info *)err_info; | ||
327 | max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1; | ||
328 | for (i = 0; i < proc->context_info_num; i++) { | ||
329 | int size = sizeof(*ctx_info) + ctx_info->size; | ||
330 | |||
331 | printk("%sContext info structure %d:\n", pfx, i); | ||
332 | if (len < size) { | ||
333 | printk("%ssection length is too small\n", newpfx); | ||
334 | printk("%sfirmware-generated error record is incorrect\n", pfx); | ||
335 | return; | ||
336 | } | ||
337 | if (ctx_info->type > max_ctx_type) { | ||
338 | printk("%sInvalid context type: %d (max: %d)\n", | ||
339 | newpfx, ctx_info->type, max_ctx_type); | ||
340 | return; | ||
341 | } | ||
342 | printk("%sregister context type: %s\n", newpfx, | ||
343 | arm_reg_ctx_strs[ctx_info->type]); | ||
344 | print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, | ||
345 | (ctx_info + 1), ctx_info->size, 0); | ||
346 | len -= size; | ||
347 | ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size); | ||
348 | } | ||
349 | |||
350 | if (len > 0) { | ||
351 | printk("%sVendor specific error info has %u bytes:\n", pfx, | ||
352 | len); | ||
353 | print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info, | ||
354 | len, true); | ||
355 | } | ||
356 | } | ||
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index d2fcafcea07e..c165933ebf38 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c | |||
@@ -122,7 +122,7 @@ static const char * const proc_isa_strs[] = { | |||
122 | "ARM A64", | 122 | "ARM A64", |
123 | }; | 123 | }; |
124 | 124 | ||
125 | static const char * const proc_error_type_strs[] = { | 125 | const char * const cper_proc_error_type_strs[] = { |
126 | "cache error", | 126 | "cache error", |
127 | "TLB error", | 127 | "TLB error", |
128 | "bus error", | 128 | "bus error", |
@@ -157,8 +157,8 @@ static void cper_print_proc_generic(const char *pfx, | |||
157 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { | 157 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { |
158 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); | 158 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); |
159 | cper_print_bits(pfx, proc->proc_error_type, | 159 | cper_print_bits(pfx, proc->proc_error_type, |
160 | proc_error_type_strs, | 160 | cper_proc_error_type_strs, |
161 | ARRAY_SIZE(proc_error_type_strs)); | 161 | ARRAY_SIZE(cper_proc_error_type_strs)); |
162 | } | 162 | } |
163 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) | 163 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) |
164 | printk("%s""operation: %d, %s\n", pfx, proc->operation, | 164 | printk("%s""operation: %d, %s\n", pfx, proc->operation, |
@@ -188,122 +188,6 @@ static void cper_print_proc_generic(const char *pfx, | |||
188 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); | 188 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); |
189 | } | 189 | } |
190 | 190 | ||
191 | #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) | ||
192 | static const char * const arm_reg_ctx_strs[] = { | ||
193 | "AArch32 general purpose registers", | ||
194 | "AArch32 EL1 context registers", | ||
195 | "AArch32 EL2 context registers", | ||
196 | "AArch32 secure context registers", | ||
197 | "AArch64 general purpose registers", | ||
198 | "AArch64 EL1 context registers", | ||
199 | "AArch64 EL2 context registers", | ||
200 | "AArch64 EL3 context registers", | ||
201 | "Misc. system register structure", | ||
202 | }; | ||
203 | |||
204 | static void cper_print_proc_arm(const char *pfx, | ||
205 | const struct cper_sec_proc_arm *proc) | ||
206 | { | ||
207 | int i, len, max_ctx_type; | ||
208 | struct cper_arm_err_info *err_info; | ||
209 | struct cper_arm_ctx_info *ctx_info; | ||
210 | char newpfx[64]; | ||
211 | |||
212 | printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); | ||
213 | |||
214 | len = proc->section_length - (sizeof(*proc) + | ||
215 | proc->err_info_num * (sizeof(*err_info))); | ||
216 | if (len < 0) { | ||
217 | printk("%ssection length: %d\n", pfx, proc->section_length); | ||
218 | printk("%ssection length is too small\n", pfx); | ||
219 | printk("%sfirmware-generated error record is incorrect\n", pfx); | ||
220 | printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | if (proc->validation_bits & CPER_ARM_VALID_MPIDR) | ||
225 | printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n", | ||
226 | pfx, proc->mpidr); | ||
227 | |||
228 | if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL) | ||
229 | printk("%serror affinity level: %d\n", pfx, | ||
230 | proc->affinity_level); | ||
231 | |||
232 | if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) { | ||
233 | printk("%srunning state: 0x%x\n", pfx, proc->running_state); | ||
234 | printk("%sPower State Coordination Interface state: %d\n", | ||
235 | pfx, proc->psci_state); | ||
236 | } | ||
237 | |||
238 | snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); | ||
239 | |||
240 | err_info = (struct cper_arm_err_info *)(proc + 1); | ||
241 | for (i = 0; i < proc->err_info_num; i++) { | ||
242 | printk("%sError info structure %d:\n", pfx, i); | ||
243 | |||
244 | printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1); | ||
245 | |||
246 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) { | ||
247 | if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST) | ||
248 | printk("%sfirst error captured\n", newpfx); | ||
249 | if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST) | ||
250 | printk("%slast error captured\n", newpfx); | ||
251 | if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED) | ||
252 | printk("%spropagated error captured\n", | ||
253 | newpfx); | ||
254 | if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW) | ||
255 | printk("%soverflow occurred, error info is incomplete\n", | ||
256 | newpfx); | ||
257 | } | ||
258 | |||
259 | printk("%serror_type: %d, %s\n", newpfx, err_info->type, | ||
260 | err_info->type < ARRAY_SIZE(proc_error_type_strs) ? | ||
261 | proc_error_type_strs[err_info->type] : "unknown"); | ||
262 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) | ||
263 | printk("%serror_info: 0x%016llx\n", newpfx, | ||
264 | err_info->error_info); | ||
265 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR) | ||
266 | printk("%svirtual fault address: 0x%016llx\n", | ||
267 | newpfx, err_info->virt_fault_addr); | ||
268 | if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR) | ||
269 | printk("%sphysical fault address: 0x%016llx\n", | ||
270 | newpfx, err_info->physical_fault_addr); | ||
271 | err_info += 1; | ||
272 | } | ||
273 | |||
274 | ctx_info = (struct cper_arm_ctx_info *)err_info; | ||
275 | max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1; | ||
276 | for (i = 0; i < proc->context_info_num; i++) { | ||
277 | int size = sizeof(*ctx_info) + ctx_info->size; | ||
278 | |||
279 | printk("%sContext info structure %d:\n", pfx, i); | ||
280 | if (len < size) { | ||
281 | printk("%ssection length is too small\n", newpfx); | ||
282 | printk("%sfirmware-generated error record is incorrect\n", pfx); | ||
283 | return; | ||
284 | } | ||
285 | if (ctx_info->type > max_ctx_type) { | ||
286 | printk("%sInvalid context type: %d (max: %d)\n", | ||
287 | newpfx, ctx_info->type, max_ctx_type); | ||
288 | return; | ||
289 | } | ||
290 | printk("%sregister context type: %s\n", newpfx, | ||
291 | arm_reg_ctx_strs[ctx_info->type]); | ||
292 | print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, | ||
293 | (ctx_info + 1), ctx_info->size, 0); | ||
294 | len -= size; | ||
295 | ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size); | ||
296 | } | ||
297 | |||
298 | if (len > 0) { | ||
299 | printk("%sVendor specific error info has %u bytes:\n", pfx, | ||
300 | len); | ||
301 | print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info, | ||
302 | len, true); | ||
303 | } | ||
304 | } | ||
305 | #endif | ||
306 | |||
307 | static const char * const mem_err_type_strs[] = { | 191 | static const char * const mem_err_type_strs[] = { |
308 | "unknown", | 192 | "unknown", |
309 | "no error", | 193 | "no error", |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 557a47829d03..8ce70c2e73d5 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -608,7 +608,7 @@ static int __init efi_load_efivars(void) | |||
608 | return 0; | 608 | return 0; |
609 | 609 | ||
610 | pdev = platform_device_register_simple("efivars", 0, NULL, 0); | 610 | pdev = platform_device_register_simple("efivars", 0, NULL, 0); |
611 | return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; | 611 | return PTR_ERR_OR_ZERO(pdev); |
612 | } | 612 | } |
613 | device_initcall(efi_load_efivars); | 613 | device_initcall(efi_load_efivars); |
614 | #endif | 614 | #endif |
diff --git a/include/linux/cper.h b/include/linux/cper.h index 723e952fde0d..d14ef4e77c8a 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h | |||
@@ -275,6 +275,50 @@ enum { | |||
275 | #define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2) | 275 | #define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2) |
276 | #define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3) | 276 | #define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3) |
277 | 277 | ||
278 | #define CPER_ARM_CACHE_ERROR 0 | ||
279 | #define CPER_ARM_TLB_ERROR 1 | ||
280 | #define CPER_ARM_BUS_ERROR 2 | ||
281 | #define CPER_ARM_VENDOR_ERROR 3 | ||
282 | #define CPER_ARM_MAX_TYPE CPER_ARM_VENDOR_ERROR | ||
283 | |||
284 | #define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0) | ||
285 | #define CPER_ARM_ERR_VALID_OPERATION_TYPE BIT(1) | ||
286 | #define CPER_ARM_ERR_VALID_LEVEL BIT(2) | ||
287 | #define CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT BIT(3) | ||
288 | #define CPER_ARM_ERR_VALID_CORRECTED BIT(4) | ||
289 | #define CPER_ARM_ERR_VALID_PRECISE_PC BIT(5) | ||
290 | #define CPER_ARM_ERR_VALID_RESTARTABLE_PC BIT(6) | ||
291 | #define CPER_ARM_ERR_VALID_PARTICIPATION_TYPE BIT(7) | ||
292 | #define CPER_ARM_ERR_VALID_TIME_OUT BIT(8) | ||
293 | #define CPER_ARM_ERR_VALID_ADDRESS_SPACE BIT(9) | ||
294 | #define CPER_ARM_ERR_VALID_MEM_ATTRIBUTES BIT(10) | ||
295 | #define CPER_ARM_ERR_VALID_ACCESS_MODE BIT(11) | ||
296 | |||
297 | #define CPER_ARM_ERR_TRANSACTION_SHIFT 16 | ||
298 | #define CPER_ARM_ERR_TRANSACTION_MASK GENMASK(1,0) | ||
299 | #define CPER_ARM_ERR_OPERATION_SHIFT 18 | ||
300 | #define CPER_ARM_ERR_OPERATION_MASK GENMASK(3,0) | ||
301 | #define CPER_ARM_ERR_LEVEL_SHIFT 22 | ||
302 | #define CPER_ARM_ERR_LEVEL_MASK GENMASK(2,0) | ||
303 | #define CPER_ARM_ERR_PC_CORRUPT_SHIFT 25 | ||
304 | #define CPER_ARM_ERR_PC_CORRUPT_MASK GENMASK(0,0) | ||
305 | #define CPER_ARM_ERR_CORRECTED_SHIFT 26 | ||
306 | #define CPER_ARM_ERR_CORRECTED_MASK GENMASK(0,0) | ||
307 | #define CPER_ARM_ERR_PRECISE_PC_SHIFT 27 | ||
308 | #define CPER_ARM_ERR_PRECISE_PC_MASK GENMASK(0,0) | ||
309 | #define CPER_ARM_ERR_RESTARTABLE_PC_SHIFT 28 | ||
310 | #define CPER_ARM_ERR_RESTARTABLE_PC_MASK GENMASK(0,0) | ||
311 | #define CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT 29 | ||
312 | #define CPER_ARM_ERR_PARTICIPATION_TYPE_MASK GENMASK(1,0) | ||
313 | #define CPER_ARM_ERR_TIME_OUT_SHIFT 31 | ||
314 | #define CPER_ARM_ERR_TIME_OUT_MASK GENMASK(0,0) | ||
315 | #define CPER_ARM_ERR_ADDRESS_SPACE_SHIFT 32 | ||
316 | #define CPER_ARM_ERR_ADDRESS_SPACE_MASK GENMASK(1,0) | ||
317 | #define CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT 34 | ||
318 | #define CPER_ARM_ERR_MEM_ATTRIBUTES_MASK GENMASK(8,0) | ||
319 | #define CPER_ARM_ERR_ACCESS_MODE_SHIFT 43 | ||
320 | #define CPER_ARM_ERR_ACCESS_MODE_MASK GENMASK(0,0) | ||
321 | |||
278 | /* | 322 | /* |
279 | * All tables and structs must be byte-packed to match CPER | 323 | * All tables and structs must be byte-packed to match CPER |
280 | * specification, since the tables are provided by the system BIOS | 324 | * specification, since the tables are provided by the system BIOS |
@@ -494,6 +538,8 @@ struct cper_sec_pcie { | |||
494 | /* Reset to default packing */ | 538 | /* Reset to default packing */ |
495 | #pragma pack() | 539 | #pragma pack() |
496 | 540 | ||
541 | extern const char * const cper_proc_error_type_strs[4]; | ||
542 | |||
497 | u64 cper_next_record_id(void); | 543 | u64 cper_next_record_id(void); |
498 | const char *cper_severity_str(unsigned int); | 544 | const char *cper_severity_str(unsigned int); |
499 | const char *cper_mem_err_type_str(unsigned int); | 545 | const char *cper_mem_err_type_str(unsigned int); |
@@ -503,5 +549,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *, | |||
503 | struct cper_mem_err_compact *); | 549 | struct cper_mem_err_compact *); |
504 | const char *cper_mem_err_unpack(struct trace_seq *, | 550 | const char *cper_mem_err_unpack(struct trace_seq *, |
505 | struct cper_mem_err_compact *); | 551 | struct cper_mem_err_compact *); |
552 | void cper_print_proc_arm(const char *pfx, | ||
553 | const struct cper_sec_proc_arm *proc); | ||
506 | 554 | ||
507 | #endif | 555 | #endif |