]>
Commit | Line | Data |
---|---|---|
a17ae4c3 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 | 2 | /* |
f5daba1d | 3 | * Machine check handler |
1da177e4 | 4 | * |
a53c8fab | 5 | * Copyright IBM Corp. 2000, 2009 |
f5daba1d HC |
6 | * Author(s): Ingo Adlung <adlung@de.ibm.com>, |
7 | * Martin Schwidefsky <schwidefsky@de.ibm.com>, | |
8 | * Cornelia Huck <cornelia.huck@de.ibm.com>, | |
9 | * Heiko Carstens <heiko.carstens@de.ibm.com>, | |
1da177e4 LT |
10 | */ |
11 | ||
052ff461 | 12 | #include <linux/kernel_stat.h> |
1da177e4 | 13 | #include <linux/init.h> |
1da177e4 | 14 | #include <linux/errno.h> |
81f64b87 | 15 | #include <linux/hardirq.h> |
6c81511c | 16 | #include <linux/log2.h> |
00a8f886 | 17 | #include <linux/kprobes.h> |
6c81511c | 18 | #include <linux/slab.h> |
022e4fc0 | 19 | #include <linux/time.h> |
3f07c014 IM |
20 | #include <linux/module.h> |
21 | #include <linux/sched/signal.h> | |
22 | ||
3994a52b | 23 | #include <linux/export.h> |
1da177e4 | 24 | #include <asm/lowcore.h> |
f5daba1d | 25 | #include <asm/smp.h> |
fd5ada04 | 26 | #include <asm/stp.h> |
76d4e00a | 27 | #include <asm/cputime.h> |
f5daba1d HC |
28 | #include <asm/nmi.h> |
29 | #include <asm/crw.h> | |
80703617 | 30 | #include <asm/switch_to.h> |
cad49cfc | 31 | #include <asm/ctl_reg.h> |
c929500d | 32 | #include <asm/asm-offsets.h> |
da72ca4d | 33 | #include <linux/kvm_host.h> |
1da177e4 | 34 | |
77fa2245 | 35 | struct mcck_struct { |
36324963 HC |
36 | unsigned int kill_task : 1; |
37 | unsigned int channel_report : 1; | |
38 | unsigned int warning : 1; | |
29b0a825 | 39 | unsigned int stp_queue : 1; |
dc6e1555 | 40 | unsigned long mcck_code; |
77fa2245 HC |
41 | }; |
42 | ||
43 | static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); | |
6c81511c MS |
44 | static struct kmem_cache *mcesa_cache; |
45 | static unsigned long mcesa_origin_lc; | |
46 | ||
47 | static inline int nmi_needs_mcesa(void) | |
48 | { | |
49 | return MACHINE_HAS_VX || MACHINE_HAS_GS; | |
50 | } | |
51 | ||
52 | static inline unsigned long nmi_get_mcesa_size(void) | |
53 | { | |
54 | if (MACHINE_HAS_GS) | |
55 | return MCESA_MAX_SIZE; | |
56 | return MCESA_MIN_SIZE; | |
57 | } | |
58 | ||
59 | /* | |
60 | * The initial machine check extended save area for the boot CPU. | |
61 | * It will be replaced by nmi_init() with an allocated structure. | |
62 | * The structure is required for machine check happening early in | |
63 | * the boot process. | |
64 | */ | |
65 | static struct mcesa boot_mcesa __initdata __aligned(MCESA_MAX_SIZE); | |
66 | ||
67 | void __init nmi_alloc_boot_cpu(struct lowcore *lc) | |
68 | { | |
69 | if (!nmi_needs_mcesa()) | |
70 | return; | |
71 | lc->mcesad = (unsigned long) &boot_mcesa; | |
72 | if (MACHINE_HAS_GS) | |
73 | lc->mcesad |= ilog2(MCESA_MAX_SIZE); | |
74 | } | |
75 | ||
76 | static int __init nmi_init(void) | |
77 | { | |
78 | unsigned long origin, cr0, size; | |
79 | ||
80 | if (!nmi_needs_mcesa()) | |
81 | return 0; | |
82 | size = nmi_get_mcesa_size(); | |
83 | if (size > MCESA_MIN_SIZE) | |
84 | mcesa_origin_lc = ilog2(size); | |
85 | /* create slab cache for the machine-check-extended-save-areas */ | |
86 | mcesa_cache = kmem_cache_create("nmi_save_areas", size, size, 0, NULL); | |
87 | if (!mcesa_cache) | |
88 | panic("Couldn't create nmi save area cache"); | |
89 | origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL); | |
90 | if (!origin) | |
91 | panic("Couldn't allocate nmi save area"); | |
92 | /* The pointer is stored with mcesa_bits ORed in */ | |
93 | kmemleak_not_leak((void *) origin); | |
94 | __ctl_store(cr0, 0, 0); | |
95 | __ctl_clear_bit(0, 28); /* disable lowcore protection */ | |
96 | /* Replace boot_mcesa on the boot CPU */ | |
97 | S390_lowcore.mcesad = origin | mcesa_origin_lc; | |
98 | __ctl_load(cr0, 0, 0); | |
99 | return 0; | |
100 | } | |
101 | early_initcall(nmi_init); | |
102 | ||
103 | int nmi_alloc_per_cpu(struct lowcore *lc) | |
104 | { | |
105 | unsigned long origin; | |
106 | ||
107 | if (!nmi_needs_mcesa()) | |
108 | return 0; | |
109 | origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL); | |
110 | if (!origin) | |
111 | return -ENOMEM; | |
112 | /* The pointer is stored with mcesa_bits ORed in */ | |
113 | kmemleak_not_leak((void *) origin); | |
114 | lc->mcesad = origin | mcesa_origin_lc; | |
115 | return 0; | |
116 | } | |
117 | ||
118 | void nmi_free_per_cpu(struct lowcore *lc) | |
119 | { | |
120 | if (!nmi_needs_mcesa()) | |
121 | return; | |
122 | kmem_cache_free(mcesa_cache, (void *)(lc->mcesad & MCESA_ORIGIN_MASK)); | |
123 | } | |
77fa2245 | 124 | |
00a8f886 | 125 | static notrace void s390_handle_damage(void) |
f5daba1d | 126 | { |
00a8f886 | 127 | smp_emergency_stop(); |
f5daba1d HC |
128 | disabled_wait((unsigned long) __builtin_return_address(0)); |
129 | while (1); | |
130 | } | |
00a8f886 | 131 | NOKPROBE_SYMBOL(s390_handle_damage); |
f5daba1d | 132 | |
1da177e4 | 133 | /* |
77fa2245 HC |
134 | * Main machine check handler function. Will be called with interrupts enabled |
135 | * or disabled and machine checks enabled or disabled. | |
1da177e4 | 136 | */ |
f5daba1d | 137 | void s390_handle_mcck(void) |
1da177e4 | 138 | { |
77fa2245 HC |
139 | unsigned long flags; |
140 | struct mcck_struct mcck; | |
1da177e4 | 141 | |
77fa2245 HC |
142 | /* |
143 | * Disable machine checks and get the current state of accumulated | |
144 | * machine checks. Afterwards delete the old state and enable machine | |
145 | * checks again. | |
146 | */ | |
147 | local_irq_save(flags); | |
148 | local_mcck_disable(); | |
2cb4a182 SO |
149 | mcck = *this_cpu_ptr(&cpu_mcck); |
150 | memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck)); | |
d3a73acb | 151 | clear_cpu_flag(CIF_MCCK_PENDING); |
77fa2245 HC |
152 | local_mcck_enable(); |
153 | local_irq_restore(flags); | |
1da177e4 | 154 | |
77fa2245 | 155 | if (mcck.channel_report) |
f5daba1d | 156 | crw_handle_channel_report(); |
7b886416 HC |
157 | /* |
158 | * A warning may remain for a prolonged period on the bare iron. | |
159 | * (actually until the machine is powered off, or the problem is gone) | |
160 | * So we just stop listening for the WARNING MCH and avoid continuously | |
161 | * being interrupted. One caveat is however, that we must do this per | |
162 | * processor and cannot use the smp version of ctl_clear_bit(). | |
163 | * On VM we only get one interrupt per virtally presented machinecheck. | |
164 | * Though one suffices, we may get one interrupt per (virtual) cpu. | |
165 | */ | |
77fa2245 | 166 | if (mcck.warning) { /* WARNING pending ? */ |
1da177e4 | 167 | static int mchchk_wng_posted = 0; |
7b886416 HC |
168 | |
169 | /* Use single cpu clear, as we cannot handle smp here. */ | |
1da177e4 LT |
170 | __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ |
171 | if (xchg(&mchchk_wng_posted, 1) == 0) | |
9ec52099 | 172 | kill_cad_pid(SIGPWR, 1); |
1da177e4 | 173 | } |
29b0a825 HC |
174 | if (mcck.stp_queue) |
175 | stp_queue_work(); | |
77fa2245 HC |
176 | if (mcck.kill_task) { |
177 | local_irq_enable(); | |
178 | printk(KERN_EMERG "mcck: Terminating task because of machine " | |
dc6e1555 | 179 | "malfunction (code 0x%016lx).\n", mcck.mcck_code); |
77fa2245 HC |
180 | printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", |
181 | current->comm, current->pid); | |
182 | do_exit(SIGSEGV); | |
183 | } | |
184 | } | |
71cde587 | 185 | EXPORT_SYMBOL_GPL(s390_handle_mcck); |
77fa2245 HC |
186 | |
187 | /* | |
3037a52f | 188 | * returns 0 if all required registers are available |
77fa2245 HC |
189 | * returns 1 otherwise |
190 | */ | |
3037a52f | 191 | static int notrace s390_check_registers(union mci mci, int umode) |
77fa2245 | 192 | { |
ad3bc0ac | 193 | union ctlreg2 cr2; |
77fa2245 | 194 | int kill_task; |
77fa2245 HC |
195 | |
196 | kill_task = 0; | |
f5daba1d | 197 | |
dc6e1555 | 198 | if (!mci.gr) { |
77fa2245 HC |
199 | /* |
200 | * General purpose registers couldn't be restored and have | |
8f149ea6 | 201 | * unknown contents. Stop system or terminate process. |
77fa2245 | 202 | */ |
8f149ea6 MS |
203 | if (!umode) |
204 | s390_handle_damage(); | |
77fa2245 | 205 | kill_task = 1; |
f5daba1d | 206 | } |
3037a52f | 207 | /* Check control registers */ |
70e28aa0 HC |
208 | if (!mci.cr) { |
209 | /* | |
210 | * Control registers have unknown contents. | |
211 | * Can't recover and therefore stopping machine. | |
212 | */ | |
213 | s390_handle_damage(); | |
70e28aa0 | 214 | } |
dc6e1555 | 215 | if (!mci.fp) { |
77fa2245 | 216 | /* |
8f149ea6 MS |
217 | * Floating point registers can't be restored. If the |
218 | * kernel currently uses floating point registers the | |
219 | * system is stopped. If the process has its floating | |
220 | * pointer registers loaded it is terminated. | |
77fa2245 | 221 | */ |
8f149ea6 MS |
222 | if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7) |
223 | s390_handle_damage(); | |
224 | if (!test_cpu_flag(CIF_FPU)) | |
225 | kill_task = 1; | |
f5daba1d | 226 | } |
dc6e1555 | 227 | if (!mci.fc) { |
5a79859a HC |
228 | /* |
229 | * Floating point control register can't be restored. | |
8f149ea6 MS |
230 | * If the kernel currently uses the floating pointer |
231 | * registers and needs the FPC register the system is | |
232 | * stopped. If the process has its floating pointer | |
3037a52f | 233 | * registers loaded it is terminated. |
5a79859a | 234 | */ |
8f149ea6 MS |
235 | if (S390_lowcore.fpu_flags & KERNEL_FPC) |
236 | s390_handle_damage(); | |
8f149ea6 MS |
237 | if (!test_cpu_flag(CIF_FPU)) |
238 | kill_task = 1; | |
86fa7087 | 239 | } |
5a79859a | 240 | |
3037a52f | 241 | if (MACHINE_HAS_VX) { |
dc6e1555 | 242 | if (!mci.vr) { |
80703617 | 243 | /* |
8f149ea6 MS |
244 | * Vector registers can't be restored. If the kernel |
245 | * currently uses vector registers the system is | |
246 | * stopped. If the process has its vector registers | |
3037a52f | 247 | * loaded it is terminated. |
80703617 | 248 | */ |
8f149ea6 MS |
249 | if (S390_lowcore.fpu_flags & KERNEL_VXR) |
250 | s390_handle_damage(); | |
251 | if (!test_cpu_flag(CIF_FPU)) | |
252 | kill_task = 1; | |
80703617 | 253 | } |
80703617 | 254 | } |
3037a52f | 255 | /* Check if access registers are valid */ |
dc6e1555 | 256 | if (!mci.ar) { |
77fa2245 HC |
257 | /* |
258 | * Access registers have unknown contents. | |
259 | * Terminating task. | |
260 | */ | |
261 | kill_task = 1; | |
f5daba1d | 262 | } |
3037a52f | 263 | /* Check guarded storage registers */ |
ad3bc0ac MS |
264 | cr2.val = S390_lowcore.cregs_save_area[2]; |
265 | if (cr2.gse) { | |
3037a52f | 266 | if (!mci.gs) { |
916cda1a MS |
267 | /* |
268 | * Guarded storage register can't be restored and | |
269 | * the current processes uses guarded storage. | |
270 | * It has to be terminated. | |
271 | */ | |
272 | kill_task = 1; | |
3037a52f | 273 | } |
916cda1a | 274 | } |
77fa2245 | 275 | /* Check if old PSW is valid */ |
3037a52f | 276 | if (!mci.wp) { |
77fa2245 HC |
277 | /* |
278 | * Can't tell if we come from user or kernel mode | |
279 | * -> stopping machine. | |
280 | */ | |
3d68286a | 281 | s390_handle_damage(); |
3037a52f MS |
282 | } |
283 | /* Check for invalid kernel instruction address */ | |
284 | if (!mci.ia && !umode) { | |
285 | /* | |
286 | * The instruction address got lost while running | |
287 | * in the kernel -> stopping machine. | |
288 | */ | |
289 | s390_handle_damage(); | |
290 | } | |
77fa2245 | 291 | |
dc6e1555 | 292 | if (!mci.ms || !mci.pm || !mci.ia) |
77fa2245 HC |
293 | kill_task = 1; |
294 | ||
295 | return kill_task; | |
296 | } | |
3037a52f | 297 | NOKPROBE_SYMBOL(s390_check_registers); |
77fa2245 | 298 | |
da72ca4d QH |
299 | /* |
300 | * Backup the guest's machine check info to its description block | |
301 | */ | |
302 | static void notrace s390_backup_mcck_info(struct pt_regs *regs) | |
303 | { | |
304 | struct mcck_volatile_info *mcck_backup; | |
305 | struct sie_page *sie_page; | |
306 | ||
307 | /* r14 contains the sie block, which was set in sie64a */ | |
308 | struct kvm_s390_sie_block *sie_block = | |
309 | (struct kvm_s390_sie_block *) regs->gprs[14]; | |
310 | ||
311 | if (sie_block == NULL) | |
312 | /* Something's seriously wrong, stop system. */ | |
313 | s390_handle_damage(); | |
314 | ||
315 | sie_page = container_of(sie_block, struct sie_page, sie_block); | |
316 | mcck_backup = &sie_page->mcck_info; | |
317 | mcck_backup->mcic = S390_lowcore.mcck_interruption_code & | |
318 | ~(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE); | |
319 | mcck_backup->ext_damage_code = S390_lowcore.external_damage_code; | |
320 | mcck_backup->failing_storage_address | |
321 | = S390_lowcore.failing_storage_address; | |
322 | } | |
00a8f886 | 323 | NOKPROBE_SYMBOL(s390_backup_mcck_info); |
da72ca4d | 324 | |
b73d40c6 | 325 | #define MAX_IPD_COUNT 29 |
022e4fc0 | 326 | #define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ |
b73d40c6 | 327 | |
f5daba1d HC |
328 | #define ED_STP_ISLAND 6 /* External damage STP island check */ |
329 | #define ED_STP_SYNC 7 /* External damage STP sync check */ | |
f5daba1d | 330 | |
c929500d QH |
331 | #define MCCK_CODE_NO_GUEST (MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE) |
332 | ||
77fa2245 HC |
333 | /* |
334 | * machine check handler. | |
335 | */ | |
cc54c1e6 | 336 | void notrace s390_do_machine_check(struct pt_regs *regs) |
77fa2245 | 337 | { |
f5daba1d | 338 | static int ipd_count; |
b73d40c6 HC |
339 | static DEFINE_SPINLOCK(ipd_lock); |
340 | static unsigned long long last_ipd; | |
f5daba1d | 341 | struct mcck_struct *mcck; |
b73d40c6 | 342 | unsigned long long tmp; |
dc6e1555 | 343 | union mci mci; |
c929500d | 344 | unsigned long mcck_dam_code; |
77fa2245 | 345 | |
81f64b87 | 346 | nmi_enter(); |
420f42ec | 347 | inc_irq_stat(NMI_NMI); |
dc6e1555 | 348 | mci.val = S390_lowcore.mcck_interruption_code; |
eb7e7d76 | 349 | mcck = this_cpu_ptr(&cpu_mcck); |
77fa2245 | 350 | |
dc6e1555 | 351 | if (mci.sd) { |
77fa2245 | 352 | /* System damage -> stopping machine */ |
3d68286a | 353 | s390_handle_damage(); |
f5daba1d | 354 | } |
c929500d QH |
355 | |
356 | /* | |
357 | * Reinject the instruction processing damages' machine checks | |
358 | * including Delayed Access Exception into the guest | |
359 | * instead of damaging the host if they happen in the guest. | |
360 | */ | |
361 | if (mci.pd && !test_cpu_flag(CIF_MCCK_GUEST)) { | |
dc6e1555 | 362 | if (mci.b) { |
77fa2245 HC |
363 | /* Processing backup -> verify if we can survive this */ |
364 | u64 z_mcic, o_mcic, t_mcic; | |
77fa2245 HC |
365 | z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); |
366 | o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | | |
367 | 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | | |
368 | 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | | |
369 | 1ULL<<16); | |
dc6e1555 | 370 | t_mcic = mci.val; |
77fa2245 HC |
371 | |
372 | if (((t_mcic & z_mcic) != 0) || | |
373 | ((t_mcic & o_mcic) != o_mcic)) { | |
3d68286a | 374 | s390_handle_damage(); |
77fa2245 | 375 | } |
b73d40c6 HC |
376 | |
377 | /* | |
378 | * Nullifying exigent condition, therefore we might | |
379 | * retry this instruction. | |
380 | */ | |
b73d40c6 | 381 | spin_lock(&ipd_lock); |
1aae0560 | 382 | tmp = get_tod_clock(); |
b73d40c6 HC |
383 | if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) |
384 | ipd_count++; | |
385 | else | |
386 | ipd_count = 1; | |
b73d40c6 | 387 | last_ipd = tmp; |
b73d40c6 | 388 | if (ipd_count == MAX_IPD_COUNT) |
3d68286a | 389 | s390_handle_damage(); |
b73d40c6 | 390 | spin_unlock(&ipd_lock); |
f5daba1d | 391 | } else { |
77fa2245 | 392 | /* Processing damage -> stopping machine */ |
3d68286a | 393 | s390_handle_damage(); |
77fa2245 HC |
394 | } |
395 | } | |
3037a52f | 396 | if (s390_check_registers(mci, user_mode(regs))) { |
8f149ea6 MS |
397 | /* |
398 | * Couldn't restore all register contents for the | |
399 | * user space process -> mark task for termination. | |
400 | */ | |
401 | mcck->kill_task = 1; | |
402 | mcck->mcck_code = mci.val; | |
403 | set_cpu_flag(CIF_MCCK_PENDING); | |
77fa2245 | 404 | } |
da72ca4d QH |
405 | |
406 | /* | |
407 | * Backup the machine check's info if it happens when the guest | |
408 | * is running. | |
409 | */ | |
410 | if (test_cpu_flag(CIF_MCCK_GUEST)) | |
411 | s390_backup_mcck_info(regs); | |
412 | ||
dc6e1555 | 413 | if (mci.cd) { |
d54853ef | 414 | /* Timing facility damage */ |
3d68286a | 415 | s390_handle_damage(); |
d54853ef | 416 | } |
dc6e1555 | 417 | if (mci.ed && mci.ec) { |
d54853ef | 418 | /* External damage */ |
d2fec595 | 419 | if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC)) |
29b0a825 | 420 | mcck->stp_queue |= stp_sync_check(); |
d2fec595 | 421 | if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND)) |
29b0a825 | 422 | mcck->stp_queue |= stp_island_check(); |
fd5ada04 | 423 | if (mcck->stp_queue) |
29b0a825 | 424 | set_cpu_flag(CIF_MCCK_PENDING); |
d54853ef | 425 | } |
c929500d QH |
426 | |
427 | /* | |
428 | * Reinject storage related machine checks into the guest if they | |
429 | * happen when the guest is running. | |
430 | */ | |
431 | if (!test_cpu_flag(CIF_MCCK_GUEST)) { | |
432 | if (mci.se) | |
433 | /* Storage error uncorrected */ | |
434 | s390_handle_damage(); | |
435 | if (mci.ke) | |
436 | /* Storage key-error uncorrected */ | |
437 | s390_handle_damage(); | |
438 | if (mci.ds && mci.fa) | |
439 | /* Storage degradation */ | |
440 | s390_handle_damage(); | |
441 | } | |
dc6e1555 | 442 | if (mci.cp) { |
77fa2245 HC |
443 | /* Channel report word pending */ |
444 | mcck->channel_report = 1; | |
d3a73acb | 445 | set_cpu_flag(CIF_MCCK_PENDING); |
77fa2245 | 446 | } |
dc6e1555 | 447 | if (mci.w) { |
77fa2245 HC |
448 | /* Warning pending */ |
449 | mcck->warning = 1; | |
d3a73acb | 450 | set_cpu_flag(CIF_MCCK_PENDING); |
77fa2245 | 451 | } |
c929500d QH |
452 | |
453 | /* | |
454 | * If there are only Channel Report Pending and External Damage | |
455 | * machine checks, they will not be reinjected into the guest | |
456 | * because they refer to host conditions only. | |
457 | */ | |
458 | mcck_dam_code = (mci.val & MCIC_SUBCLASS_MASK); | |
459 | if (test_cpu_flag(CIF_MCCK_GUEST) && | |
460 | (mcck_dam_code & MCCK_CODE_NO_GUEST) != mcck_dam_code) { | |
461 | /* Set exit reason code for host's later handling */ | |
462 | *((long *)(regs->gprs[15] + __SF_SIE_REASON)) = -EINTR; | |
463 | } | |
464 | clear_cpu_flag(CIF_MCCK_GUEST); | |
81f64b87 | 465 | nmi_exit(); |
1da177e4 | 466 | } |
00a8f886 | 467 | NOKPROBE_SYMBOL(s390_do_machine_check); |
1da177e4 | 468 | |
f5daba1d | 469 | static int __init machine_check_init(void) |
1da177e4 | 470 | { |
d54853ef | 471 | ctl_set_bit(14, 25); /* enable external damage MCH */ |
f5daba1d | 472 | ctl_set_bit(14, 27); /* enable system recovery MCH */ |
1da177e4 | 473 | ctl_set_bit(14, 24); /* enable warning MCH */ |
1da177e4 LT |
474 | return 0; |
475 | } | |
24d05ff8 | 476 | early_initcall(machine_check_init); |