]>
Commit | Line | Data |
---|---|---|
0c530ab8 | 1 | /* |
316670eb | 2 | * Copyright (c) 2007-2011 Apple Inc. All rights reserved. |
0c530ab8 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
2d21ac55 | 29 | #include <kern/kalloc.h> |
593a1d5f | 30 | #include <mach/mach_time.h> |
0c530ab8 A |
31 | #include <i386/cpu_data.h> |
32 | #include <i386/cpuid.h> | |
593a1d5f A |
33 | #include <i386/cpu_topology.h> |
34 | #include <i386/cpu_threads.h> | |
35 | #include <i386/machine_cpu.h> | |
0c530ab8 A |
36 | #include <i386/machine_check.h> |
37 | #include <i386/proc_reg.h> | |
38 | ||
316670eb A |
39 | /* |
40 | * At the time of the machine-check exception, all hardware-threads panic. | |
41 | * Each thread saves the state of its MCA registers to its per-cpu data area. | |
42 | * | |
43 | * State reporting is serialized so one thread dumps all valid state for all | |
44 | * threads to the panic log. This may entail spinning waiting for other | |
45 | * threads to complete saving state to memory. A timeout applies to this wait | |
46 | * -- in particular, a 3-strikes timeout may prevent a thread from taking | |
47 | * part is the affair. | |
48 | */ | |
49 | ||
0c530ab8 A |
50 | #define IF(bool,str) ((bool) ? (str) : "") |
51 | ||
52 | static boolean_t mca_initialized = FALSE; | |
53 | static boolean_t mca_MCE_present = FALSE; | |
54 | static boolean_t mca_MCA_present = FALSE; | |
2d21ac55 | 55 | static uint32_t mca_family = 0; |
0c530ab8 A |
56 | static unsigned int mca_error_bank_count = 0; |
57 | static boolean_t mca_control_MSR_present = FALSE; | |
58 | static boolean_t mca_threshold_status_present = FALSE; | |
6d2010ae | 59 | static boolean_t mca_sw_error_recovery_present = FALSE; |
0c530ab8 A |
60 | static boolean_t mca_extended_MSRs_present = FALSE; |
61 | static unsigned int mca_extended_MSRs_count = 0; | |
c910b4d9 | 62 | static boolean_t mca_cmci_present = FALSE; |
0c530ab8 | 63 | static ia32_mcg_cap_t ia32_mcg_cap; |
2d21ac55 A |
64 | decl_simple_lock_data(static, mca_lock); |
65 | ||
66 | typedef struct { | |
67 | ia32_mci_ctl_t mca_mci_ctl; | |
68 | ia32_mci_status_t mca_mci_status; | |
69 | ia32_mci_misc_t mca_mci_misc; | |
70 | ia32_mci_addr_t mca_mci_addr; | |
71 | } mca_mci_bank_t; | |
72 | ||
73 | typedef struct mca_state { | |
316670eb A |
74 | boolean_t mca_is_saved; |
75 | boolean_t mca_is_valid; /* some state is valid */ | |
2d21ac55 A |
76 | ia32_mcg_ctl_t mca_mcg_ctl; |
77 | ia32_mcg_status_t mca_mcg_status; | |
78 | mca_mci_bank_t mca_error_bank[0]; | |
79 | } mca_state_t; | |
0c530ab8 | 80 | |
593a1d5f A |
81 | typedef enum { |
82 | CLEAR, | |
83 | DUMPING, | |
84 | DUMPED | |
85 | } mca_dump_state_t; | |
86 | static volatile mca_dump_state_t mca_dump_state = CLEAR; | |
87 | ||
0c530ab8 A |
88 | static void |
89 | mca_get_availability(void) | |
90 | { | |
91 | uint64_t features = cpuid_info()->cpuid_features; | |
92 | uint32_t family = cpuid_info()->cpuid_family; | |
93 | ||
94 | mca_MCE_present = (features & CPUID_FEATURE_MCE) != 0; | |
95 | mca_MCA_present = (features & CPUID_FEATURE_MCA) != 0; | |
2d21ac55 | 96 | mca_family = family; |
0c530ab8 A |
97 | |
98 | /* | |
99 | * If MCA, the number of banks etc is reported by the IA32_MCG_CAP MSR. | |
100 | */ | |
101 | if (mca_MCA_present) { | |
102 | ia32_mcg_cap.u64 = rdmsr64(IA32_MCG_CAP); | |
103 | mca_error_bank_count = ia32_mcg_cap.bits.count; | |
104 | mca_control_MSR_present = ia32_mcg_cap.bits.mcg_ctl_p; | |
105 | mca_threshold_status_present = ia32_mcg_cap.bits.mcg_tes_p; | |
6d2010ae | 106 | mca_sw_error_recovery_present = ia32_mcg_cap.bits.mcg_ser_p; |
c910b4d9 | 107 | mca_cmci_present = ia32_mcg_cap.bits.mcg_ext_corr_err_p; |
0c530ab8 A |
108 | if (family == 0x0F) { |
109 | mca_extended_MSRs_present = ia32_mcg_cap.bits.mcg_ext_p; | |
110 | mca_extended_MSRs_count = ia32_mcg_cap.bits.mcg_ext_cnt; | |
111 | } | |
112 | } | |
113 | } | |
114 | ||
115 | void | |
116 | mca_cpu_init(void) | |
117 | { | |
118 | unsigned int i; | |
119 | ||
120 | /* | |
121 | * The first (boot) processor is responsible for discovering the | |
122 | * machine check architecture present on this machine. | |
123 | */ | |
124 | if (!mca_initialized) { | |
125 | mca_get_availability(); | |
126 | mca_initialized = TRUE; | |
2d21ac55 | 127 | simple_lock_init(&mca_lock, 0); |
0c530ab8 A |
128 | } |
129 | ||
130 | if (mca_MCA_present) { | |
131 | ||
132 | /* Enable all MCA features */ | |
133 | if (mca_control_MSR_present) | |
134 | wrmsr64(IA32_MCG_CTL, IA32_MCG_CTL_ENABLE); | |
135 | ||
2d21ac55 | 136 | switch (mca_family) { |
0c530ab8 A |
137 | case 0x06: |
138 | /* Enable all but mc0 */ | |
139 | for (i = 1; i < mca_error_bank_count; i++) | |
140 | wrmsr64(IA32_MCi_CTL(i),0xFFFFFFFFFFFFFFFFULL); | |
141 | ||
142 | /* Clear all errors */ | |
143 | for (i = 0; i < mca_error_bank_count; i++) | |
144 | wrmsr64(IA32_MCi_STATUS(i), 0ULL); | |
145 | break; | |
146 | case 0x0F: | |
147 | /* Enable all banks */ | |
148 | for (i = 0; i < mca_error_bank_count; i++) | |
149 | wrmsr64(IA32_MCi_CTL(i),0xFFFFFFFFFFFFFFFFULL); | |
150 | ||
151 | /* Clear all errors */ | |
152 | for (i = 0; i < mca_error_bank_count; i++) | |
153 | wrmsr64(IA32_MCi_STATUS(i), 0ULL); | |
154 | break; | |
155 | } | |
156 | } | |
157 | ||
158 | /* Enable machine check exception handling if available */ | |
159 | if (mca_MCE_present) { | |
160 | set_cr4(get_cr4()|CR4_MCE); | |
161 | } | |
162 | } | |
163 | ||
c910b4d9 A |
164 | boolean_t |
165 | mca_is_cmci_present(void) | |
166 | { | |
167 | if (!mca_initialized) | |
168 | mca_cpu_init(); | |
169 | return mca_cmci_present; | |
170 | } | |
171 | ||
2d21ac55 A |
172 | void |
173 | mca_cpu_alloc(cpu_data_t *cdp) | |
174 | { | |
175 | vm_size_t mca_state_size; | |
176 | ||
177 | /* | |
178 | * Allocate space for an array of error banks. | |
179 | */ | |
180 | mca_state_size = sizeof(mca_state_t) + | |
181 | sizeof(mca_mci_bank_t) * mca_error_bank_count; | |
182 | cdp->cpu_mca_state = kalloc(mca_state_size); | |
183 | if (cdp->cpu_mca_state == NULL) { | |
184 | printf("mca_cpu_alloc() failed for cpu %d\n", cdp->cpu_number); | |
185 | return; | |
186 | } | |
187 | bzero((void *) cdp->cpu_mca_state, mca_state_size); | |
188 | ||
189 | /* | |
190 | * If the boot processor is yet have its allocation made, | |
191 | * do this now. | |
192 | */ | |
193 | if (cpu_datap(master_cpu)->cpu_mca_state == NULL) | |
194 | mca_cpu_alloc(cpu_datap(master_cpu)); | |
195 | } | |
196 | ||
197 | static void | |
593a1d5f | 198 | mca_save_state(mca_state_t *mca_state) |
2d21ac55 | 199 | { |
2d21ac55 A |
200 | mca_mci_bank_t *bank; |
201 | unsigned int i; | |
202 | ||
203 | assert(!ml_get_interrupts_enabled() || get_preemption_level() > 0); | |
204 | ||
2d21ac55 A |
205 | if (mca_state == NULL) |
206 | return; | |
207 | ||
208 | mca_state->mca_mcg_ctl = mca_control_MSR_present ? | |
209 | rdmsr64(IA32_MCG_CTL) : 0ULL; | |
210 | mca_state->mca_mcg_status.u64 = rdmsr64(IA32_MCG_STATUS); | |
211 | ||
212 | bank = (mca_mci_bank_t *) &mca_state->mca_error_bank[0]; | |
213 | for (i = 0; i < mca_error_bank_count; i++, bank++) { | |
214 | bank->mca_mci_ctl = rdmsr64(IA32_MCi_CTL(i)); | |
215 | bank->mca_mci_status.u64 = rdmsr64(IA32_MCi_STATUS(i)); | |
216 | if (!bank->mca_mci_status.bits.val) | |
217 | continue; | |
218 | bank->mca_mci_misc = (bank->mca_mci_status.bits.miscv)? | |
219 | rdmsr64(IA32_MCi_MISC(i)) : 0ULL; | |
220 | bank->mca_mci_addr = (bank->mca_mci_status.bits.addrv)? | |
221 | rdmsr64(IA32_MCi_ADDR(i)) : 0ULL; | |
316670eb | 222 | mca_state->mca_is_valid = TRUE; |
2d21ac55 | 223 | } |
c910b4d9 A |
224 | |
225 | /* | |
226 | * If we're the first thread with MCA state, point our package to it | |
227 | * and don't care about races | |
228 | */ | |
229 | if (x86_package()->mca_state == NULL) | |
316670eb A |
230 | x86_package()->mca_state = mca_state; |
231 | ||
232 | mca_state->mca_is_saved = TRUE; | |
2d21ac55 A |
233 | } |
234 | ||
235 | void | |
236 | mca_check_save(void) | |
237 | { | |
593a1d5f A |
238 | if (mca_dump_state > CLEAR) |
239 | mca_save_state(current_cpu_datap()->cpu_mca_state); | |
2d21ac55 A |
240 | } |
241 | ||
0c530ab8 A |
242 | static void mca_dump_64bit_state(void) |
243 | { | |
244 | kdb_printf("Extended Machine Check State:\n"); | |
245 | kdb_printf(" IA32_MCG_RAX: 0x%016qx\n", rdmsr64(IA32_MCG_RAX)); | |
246 | kdb_printf(" IA32_MCG_RBX: 0x%016qx\n", rdmsr64(IA32_MCG_RBX)); | |
247 | kdb_printf(" IA32_MCG_RCX: 0x%016qx\n", rdmsr64(IA32_MCG_RCX)); | |
248 | kdb_printf(" IA32_MCG_RDX: 0x%016qx\n", rdmsr64(IA32_MCG_RDX)); | |
249 | kdb_printf(" IA32_MCG_RSI: 0x%016qx\n", rdmsr64(IA32_MCG_RSI)); | |
250 | kdb_printf(" IA32_MCG_RDI: 0x%016qx\n", rdmsr64(IA32_MCG_RDI)); | |
251 | kdb_printf(" IA32_MCG_RBP: 0x%016qx\n", rdmsr64(IA32_MCG_RBP)); | |
252 | kdb_printf(" IA32_MCG_RSP: 0x%016qx\n", rdmsr64(IA32_MCG_RSP)); | |
253 | kdb_printf(" IA32_MCG_RFLAGS: 0x%016qx\n", rdmsr64(IA32_MCG_RFLAGS)); | |
254 | kdb_printf(" IA32_MCG_RIP: 0x%016qx\n", rdmsr64(IA32_MCG_RIP)); | |
255 | kdb_printf(" IA32_MCG_MISC: 0x%016qx\n", rdmsr64(IA32_MCG_MISC)); | |
256 | kdb_printf(" IA32_MCG_R8: 0x%016qx\n", rdmsr64(IA32_MCG_R8)); | |
257 | kdb_printf(" IA32_MCG_R9: 0x%016qx\n", rdmsr64(IA32_MCG_R9)); | |
258 | kdb_printf(" IA32_MCG_R10: 0x%016qx\n", rdmsr64(IA32_MCG_R10)); | |
259 | kdb_printf(" IA32_MCG_R11: 0x%016qx\n", rdmsr64(IA32_MCG_R11)); | |
260 | kdb_printf(" IA32_MCG_R12: 0x%016qx\n", rdmsr64(IA32_MCG_R12)); | |
261 | kdb_printf(" IA32_MCG_R13: 0x%016qx\n", rdmsr64(IA32_MCG_R13)); | |
262 | kdb_printf(" IA32_MCG_R14: 0x%016qx\n", rdmsr64(IA32_MCG_R14)); | |
263 | kdb_printf(" IA32_MCG_R15: 0x%016qx\n", rdmsr64(IA32_MCG_R15)); | |
264 | } | |
265 | ||
266 | static uint32_t rdmsr32(uint32_t msr) | |
267 | { | |
268 | return (uint32_t) rdmsr64(msr); | |
269 | } | |
270 | ||
271 | static void mca_dump_32bit_state(void) | |
272 | { | |
273 | kdb_printf("Extended Machine Check State:\n"); | |
274 | kdb_printf(" IA32_MCG_EAX: 0x%08x\n", rdmsr32(IA32_MCG_EAX)); | |
275 | kdb_printf(" IA32_MCG_EBX: 0x%08x\n", rdmsr32(IA32_MCG_EBX)); | |
276 | kdb_printf(" IA32_MCG_ECX: 0x%08x\n", rdmsr32(IA32_MCG_ECX)); | |
277 | kdb_printf(" IA32_MCG_EDX: 0x%08x\n", rdmsr32(IA32_MCG_EDX)); | |
278 | kdb_printf(" IA32_MCG_ESI: 0x%08x\n", rdmsr32(IA32_MCG_ESI)); | |
279 | kdb_printf(" IA32_MCG_EDI: 0x%08x\n", rdmsr32(IA32_MCG_EDI)); | |
280 | kdb_printf(" IA32_MCG_EBP: 0x%08x\n", rdmsr32(IA32_MCG_EBP)); | |
281 | kdb_printf(" IA32_MCG_ESP: 0x%08x\n", rdmsr32(IA32_MCG_ESP)); | |
282 | kdb_printf(" IA32_MCG_EFLAGS: 0x%08x\n", rdmsr32(IA32_MCG_EFLAGS)); | |
283 | kdb_printf(" IA32_MCG_EIP: 0x%08x\n", rdmsr32(IA32_MCG_EIP)); | |
284 | kdb_printf(" IA32_MCG_MISC: 0x%08x\n", rdmsr32(IA32_MCG_MISC)); | |
285 | } | |
286 | ||
cf7d32b8 A |
287 | static void |
288 | mca_report_cpu_info(void) | |
289 | { | |
cf7d32b8 A |
290 | i386_cpu_info_t *infop = cpuid_info(); |
291 | ||
593a1d5f | 292 | kdb_printf(" family: %d model: %d stepping: %d microcode: %d\n", |
cf7d32b8 A |
293 | infop->cpuid_family, |
294 | infop->cpuid_model, | |
295 | infop->cpuid_stepping, | |
6d2010ae | 296 | infop->cpuid_microcode_version); |
593a1d5f | 297 | kdb_printf(" %s\n", infop->cpuid_brand_string); |
cf7d32b8 A |
298 | } |
299 | ||
c910b4d9 | 300 | static const char *mc8_memory_operation[] = { |
6d2010ae A |
301 | [MC8_MMM_GENERIC] = "generic", |
302 | [MC8_MMM_READ] = "read", | |
303 | [MC8_MMM_WRITE] = "write", | |
304 | [MC8_MMM_ADDRESS_COMMAND] = "address/command", | |
305 | [MC8_MMM_RESERVED] = "reserved" | |
c910b4d9 A |
306 | }; |
307 | ||
308 | static void | |
309 | mca_dump_bank_mc8(mca_state_t *state, int i) | |
310 | { | |
311 | mca_mci_bank_t *bank; | |
312 | ia32_mci_status_t status; | |
313 | struct ia32_mc8_specific mc8; | |
314 | int mmm; | |
315 | ||
316 | bank = &state->mca_error_bank[i]; | |
317 | status = bank->mca_mci_status; | |
318 | mc8 = status.bits_mc8; | |
319 | mmm = MIN(mc8.memory_operation, MC8_MMM_RESERVED); | |
320 | ||
321 | kdb_printf( | |
322 | " IA32_MC%d_STATUS(0x%x): 0x%016qx %svalid\n", | |
323 | i, IA32_MCi_STATUS(i), status.u64, IF(!status.bits.val, "in")); | |
324 | if (!status.bits.val) | |
325 | return; | |
326 | ||
327 | kdb_printf( | |
328 | " Channel number: %d%s\n" | |
329 | " Memory Operation: %s\n" | |
6d2010ae | 330 | " Machine-specific error: %s%s%s%s%s%s%s%s%s\n" |
c910b4d9 A |
331 | " COR_ERR_CNT: %d\n", |
332 | mc8.channel_number, | |
333 | IF(mc8.channel_number == 15, " (unknown)"), | |
334 | mc8_memory_operation[mmm], | |
6d2010ae A |
335 | IF(mc8.read_ecc, "Read ECC "), |
336 | IF(mc8.ecc_on_a_scrub, "ECC on scrub "), | |
337 | IF(mc8.write_parity, "Write parity "), | |
338 | IF(mc8.redundant_memory, "Redundant memory "), | |
339 | IF(mc8.sparing, "Sparing/Resilvering "), | |
340 | IF(mc8.access_out_of_range, "Access out of Range "), | |
341 | IF(mc8.rtid_out_of_range, "RTID out of Range "), | |
342 | IF(mc8.address_parity, "Address Parity "), | |
343 | IF(mc8.byte_enable_parity, "Byte Enable Parity "), | |
c910b4d9 A |
344 | mc8.cor_err_cnt); |
345 | kdb_printf( | |
346 | " Status bits:\n%s%s%s%s%s%s", | |
347 | IF(status.bits.pcc, " Processor context corrupt\n"), | |
348 | IF(status.bits.addrv, " ADDR register valid\n"), | |
349 | IF(status.bits.miscv, " MISC register valid\n"), | |
350 | IF(status.bits.en, " Error enabled\n"), | |
351 | IF(status.bits.uc, " Uncorrected error\n"), | |
352 | IF(status.bits.over, " Error overflow\n")); | |
353 | if (status.bits.addrv) | |
354 | kdb_printf( | |
355 | " IA32_MC%d_ADDR(0x%x): 0x%016qx\n", | |
356 | i, IA32_MCi_ADDR(i), bank->mca_mci_addr); | |
357 | if (status.bits.miscv) { | |
358 | ia32_mc8_misc_t mc8_misc; | |
359 | ||
360 | mc8_misc.u64 = bank->mca_mci_misc; | |
361 | kdb_printf( | |
362 | " IA32_MC%d_MISC(0x%x): 0x%016qx\n" | |
6d2010ae | 363 | " RTID: %d\n" |
c910b4d9 A |
364 | " DIMM: %d\n" |
365 | " Channel: %d\n" | |
366 | " Syndrome: 0x%x\n", | |
367 | i, IA32_MCi_MISC(i), mc8_misc.u64, | |
6d2010ae | 368 | mc8_misc.bits.rtid, |
c910b4d9 A |
369 | mc8_misc.bits.dimm, |
370 | mc8_misc.bits.channel, | |
371 | (int) mc8_misc.bits.syndrome); | |
372 | } | |
373 | } | |
374 | ||
0c530ab8 | 375 | static const char *mca_threshold_status[] = { |
6d2010ae | 376 | [THRESHOLD_STATUS_NO_TRACKING] = "No tracking", |
316670eb A |
377 | [THRESHOLD_STATUS_GREEN] = "Green", |
378 | [THRESHOLD_STATUS_YELLOW] = "Yellow", | |
379 | [THRESHOLD_STATUS_RESERVED] = "Reserved" | |
0c530ab8 A |
380 | }; |
381 | ||
382 | static void | |
593a1d5f | 383 | mca_dump_bank(mca_state_t *state, int i) |
0c530ab8 | 384 | { |
593a1d5f | 385 | mca_mci_bank_t *bank; |
0c530ab8 A |
386 | ia32_mci_status_t status; |
387 | ||
593a1d5f A |
388 | bank = &state->mca_error_bank[i]; |
389 | status = bank->mca_mci_status; | |
390 | kdb_printf( | |
391 | " IA32_MC%d_STATUS(0x%x): 0x%016qx %svalid\n", | |
392 | i, IA32_MCi_STATUS(i), status.u64, IF(!status.bits.val, "in")); | |
393 | if (!status.bits.val) | |
394 | return; | |
395 | ||
396 | kdb_printf( | |
397 | " MCA error code: 0x%04x\n", | |
398 | status.bits.mca_error); | |
399 | kdb_printf( | |
400 | " Model specific error code: 0x%04x\n", | |
401 | status.bits.model_specific_error); | |
402 | if (!mca_threshold_status_present) { | |
0c530ab8 | 403 | kdb_printf( |
593a1d5f A |
404 | " Other information: 0x%08x\n", |
405 | status.bits.other_information); | |
406 | } else { | |
407 | int threshold = status.bits_tes_p.threshold; | |
0c530ab8 | 408 | kdb_printf( |
593a1d5f A |
409 | " Other information: 0x%08x\n" |
410 | " Threshold-based status: %s\n", | |
411 | status.bits_tes_p.other_information, | |
412 | (status.bits_tes_p.uc == 0) ? | |
413 | mca_threshold_status[threshold] : | |
414 | "Undefined"); | |
415 | } | |
6d2010ae A |
416 | if (mca_threshold_status_present && |
417 | mca_sw_error_recovery_present) { | |
418 | kdb_printf( | |
419 | " Software Error Recovery:\n%s%s", | |
420 | IF(status.bits_tes_p.ar, " Recovery action reqd\n"), | |
421 | IF(status.bits_tes_p.s, " Signaling UCR error\n")); | |
422 | } | |
593a1d5f A |
423 | kdb_printf( |
424 | " Status bits:\n%s%s%s%s%s%s", | |
425 | IF(status.bits.pcc, " Processor context corrupt\n"), | |
426 | IF(status.bits.addrv, " ADDR register valid\n"), | |
427 | IF(status.bits.miscv, " MISC register valid\n"), | |
428 | IF(status.bits.en, " Error enabled\n"), | |
429 | IF(status.bits.uc, " Uncorrected error\n"), | |
430 | IF(status.bits.over, " Error overflow\n")); | |
431 | if (status.bits.addrv) | |
0c530ab8 | 432 | kdb_printf( |
593a1d5f A |
433 | " IA32_MC%d_ADDR(0x%x): 0x%016qx\n", |
434 | i, IA32_MCi_ADDR(i), bank->mca_mci_addr); | |
435 | if (status.bits.miscv) | |
0c530ab8 | 436 | kdb_printf( |
593a1d5f A |
437 | " IA32_MC%d_MISC(0x%x): 0x%016qx\n", |
438 | i, IA32_MCi_MISC(i), bank->mca_mci_misc); | |
439 | } | |
440 | ||
441 | static void | |
316670eb | 442 | mca_cpu_dump_error_banks(mca_state_t *state) |
593a1d5f A |
443 | { |
444 | unsigned int i; | |
445 | ||
316670eb A |
446 | if (!state->mca_is_valid) |
447 | return; | |
448 | ||
593a1d5f A |
449 | kdb_printf("MCA error-reporting registers:\n"); |
450 | for (i = 0; i < mca_error_bank_count; i++ ) { | |
316670eb | 451 | if (i == 8 && state == x86_package()->mca_state) { |
c910b4d9 A |
452 | /* |
453 | * Fatal Memory Error | |
454 | */ | |
455 | ||
316670eb | 456 | /* Dump MC8 for this package */ |
c910b4d9 A |
457 | kdb_printf(" Package %d logged:\n", |
458 | x86_package()->ppkg_num); | |
459 | mca_dump_bank_mc8(state, 8); | |
c910b4d9 A |
460 | continue; |
461 | } | |
593a1d5f | 462 | mca_dump_bank(state, i); |
0c530ab8 A |
463 | } |
464 | } | |
465 | ||
466 | void | |
467 | mca_dump(void) | |
468 | { | |
316670eb A |
469 | mca_state_t *mca_state = current_cpu_datap()->cpu_mca_state; |
470 | uint64_t deadline; | |
471 | unsigned int i = 0; | |
0c530ab8 | 472 | |
593a1d5f A |
473 | /* |
474 | * Capture local MCA registers to per-cpu data. | |
475 | */ | |
476 | mca_save_state(mca_state); | |
2d21ac55 | 477 | |
4a3eedf9 | 478 | /* |
316670eb | 479 | * Serialize: the first caller controls dumping MCA registers, |
593a1d5f | 480 | * other threads spin meantime. |
4a3eedf9 | 481 | */ |
2d21ac55 | 482 | simple_lock(&mca_lock); |
593a1d5f | 483 | if (mca_dump_state > CLEAR) { |
4a3eedf9 | 484 | simple_unlock(&mca_lock); |
593a1d5f A |
485 | while (mca_dump_state == DUMPING) |
486 | cpu_pause(); | |
4a3eedf9 A |
487 | return; |
488 | } | |
593a1d5f A |
489 | mca_dump_state = DUMPING; |
490 | simple_unlock(&mca_lock); | |
2d21ac55 | 491 | |
316670eb A |
492 | /* |
493 | * Wait for all other hardware threads to save their state. | |
494 | * Or timeout. | |
495 | */ | |
496 | deadline = mach_absolute_time() + LockTimeOut; | |
497 | while (mach_absolute_time() < deadline && i < real_ncpus) { | |
498 | if (!cpu_datap(i)->cpu_mca_state->mca_is_saved) { | |
499 | cpu_pause(); | |
500 | continue; | |
501 | } | |
502 | i += 1; | |
503 | } | |
504 | ||
0c530ab8 A |
505 | /* |
506 | * Report machine-check capabilities: | |
507 | */ | |
508 | kdb_printf( | |
316670eb | 509 | "Machine-check capabilities 0x%016qx:\n", ia32_mcg_cap.u64); |
cf7d32b8 A |
510 | |
511 | mca_report_cpu_info(); | |
512 | ||
0c530ab8 | 513 | kdb_printf( |
593a1d5f | 514 | " %d error-reporting banks\n%s%s%s", mca_error_bank_count, |
0c530ab8 A |
515 | IF(mca_control_MSR_present, |
516 | " control MSR present\n"), | |
517 | IF(mca_threshold_status_present, | |
593a1d5f | 518 | " threshold-based error status present\n"), |
c910b4d9 A |
519 | IF(mca_cmci_present, |
520 | " extended corrected memory error handling present\n")); | |
0c530ab8 A |
521 | if (mca_extended_MSRs_present) |
522 | kdb_printf( | |
523 | " %d extended MSRs present\n", mca_extended_MSRs_count); | |
524 | ||
525 | /* | |
316670eb | 526 | * Dump all processor state: |
0c530ab8 | 527 | */ |
316670eb A |
528 | for (i = 0; i < real_ncpus; i++) { |
529 | mca_state_t *mcsp = cpu_datap(i)->cpu_mca_state; | |
530 | ia32_mcg_status_t status; | |
531 | ||
532 | kdb_printf("Processor %d: ", i); | |
533 | if (mcsp == NULL || | |
534 | mcsp->mca_is_saved == FALSE || | |
535 | mcsp->mca_mcg_status.u64 == 0) { | |
536 | kdb_printf("no machine-check status reported\n"); | |
537 | continue; | |
538 | } | |
539 | if (!mcsp->mca_is_valid) { | |
540 | kdb_printf("no valid machine-check state\n"); | |
541 | continue; | |
542 | } | |
543 | status = mcsp->mca_mcg_status; | |
544 | kdb_printf( | |
545 | "machine-check status 0x%016qx:\n%s%s%s", status.u64, | |
546 | IF(status.bits.ripv, " restart IP valid\n"), | |
547 | IF(status.bits.eipv, " error IP valid\n"), | |
548 | IF(status.bits.mcip, " machine-check in progress\n")); | |
0c530ab8 | 549 | |
316670eb A |
550 | mca_cpu_dump_error_banks(mcsp); |
551 | } | |
0c530ab8 A |
552 | |
553 | /* | |
554 | * Dump any extended machine state: | |
555 | */ | |
556 | if (mca_extended_MSRs_present) { | |
557 | if (cpu_mode_is64bit()) | |
558 | mca_dump_64bit_state(); | |
559 | else | |
560 | mca_dump_32bit_state(); | |
561 | } | |
2d21ac55 | 562 | |
593a1d5f A |
563 | /* Update state to release any other threads. */ |
564 | mca_dump_state = DUMPED; | |
0c530ab8 | 565 | } |
316670eb A |
566 | |
567 | ||
568 | extern void mca_exception_panic(void); | |
569 | extern void mtrr_lapic_cached(void); | |
570 | void mca_exception_panic(void) | |
571 | { | |
572 | #if DEBUG | |
573 | mtrr_lapic_cached(); | |
574 | #else | |
575 | kprintf("mca_exception_panic() requires DEBUG build\n"); | |
576 | #endif | |
577 | } |