]>
Commit | Line | Data |
---|---|---|
0c530ab8 A |
1 | /* |
2 | * Copyright (c) 2007 Apple Inc. All rights reserved. | |
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 | ||
29 | #include <i386/cpu_data.h> | |
30 | #include <i386/cpuid.h> | |
31 | #include <i386/machine_check.h> | |
32 | #include <i386/proc_reg.h> | |
33 | ||
34 | #define IF(bool,str) ((bool) ? (str) : "") | |
35 | ||
36 | static boolean_t mca_initialized = FALSE; | |
37 | static boolean_t mca_MCE_present = FALSE; | |
38 | static boolean_t mca_MCA_present = FALSE; | |
39 | static unsigned int mca_error_bank_count = 0; | |
40 | static boolean_t mca_control_MSR_present = FALSE; | |
41 | static boolean_t mca_threshold_status_present = FALSE; | |
42 | static boolean_t mca_extended_MSRs_present = FALSE; | |
43 | static unsigned int mca_extended_MSRs_count = 0; | |
44 | static ia32_mcg_cap_t ia32_mcg_cap; | |
45 | ||
46 | static void | |
47 | mca_get_availability(void) | |
48 | { | |
49 | uint64_t features = cpuid_info()->cpuid_features; | |
50 | uint32_t family = cpuid_info()->cpuid_family; | |
51 | ||
52 | mca_MCE_present = (features & CPUID_FEATURE_MCE) != 0; | |
53 | mca_MCA_present = (features & CPUID_FEATURE_MCA) != 0; | |
54 | ||
55 | /* | |
56 | * If MCA, the number of banks etc is reported by the IA32_MCG_CAP MSR. | |
57 | */ | |
58 | if (mca_MCA_present) { | |
59 | ia32_mcg_cap.u64 = rdmsr64(IA32_MCG_CAP); | |
60 | mca_error_bank_count = ia32_mcg_cap.bits.count; | |
61 | mca_control_MSR_present = ia32_mcg_cap.bits.mcg_ctl_p; | |
62 | mca_threshold_status_present = ia32_mcg_cap.bits.mcg_tes_p; | |
63 | if (family == 0x0F) { | |
64 | mca_extended_MSRs_present = ia32_mcg_cap.bits.mcg_ext_p; | |
65 | mca_extended_MSRs_count = ia32_mcg_cap.bits.mcg_ext_cnt; | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
70 | void | |
71 | mca_cpu_init(void) | |
72 | { | |
73 | unsigned int i; | |
74 | ||
75 | /* | |
76 | * The first (boot) processor is responsible for discovering the | |
77 | * machine check architecture present on this machine. | |
78 | */ | |
79 | if (!mca_initialized) { | |
80 | mca_get_availability(); | |
81 | mca_initialized = TRUE; | |
82 | } | |
83 | ||
84 | if (mca_MCA_present) { | |
85 | ||
86 | /* Enable all MCA features */ | |
87 | if (mca_control_MSR_present) | |
88 | wrmsr64(IA32_MCG_CTL, IA32_MCG_CTL_ENABLE); | |
89 | ||
90 | switch (cpuid_family()) { | |
91 | case 0x06: | |
92 | /* Enable all but mc0 */ | |
93 | for (i = 1; i < mca_error_bank_count; i++) | |
94 | wrmsr64(IA32_MCi_CTL(i),0xFFFFFFFFFFFFFFFFULL); | |
95 | ||
96 | /* Clear all errors */ | |
97 | for (i = 0; i < mca_error_bank_count; i++) | |
98 | wrmsr64(IA32_MCi_STATUS(i), 0ULL); | |
99 | break; | |
100 | case 0x0F: | |
101 | /* Enable all banks */ | |
102 | for (i = 0; i < mca_error_bank_count; i++) | |
103 | wrmsr64(IA32_MCi_CTL(i),0xFFFFFFFFFFFFFFFFULL); | |
104 | ||
105 | /* Clear all errors */ | |
106 | for (i = 0; i < mca_error_bank_count; i++) | |
107 | wrmsr64(IA32_MCi_STATUS(i), 0ULL); | |
108 | break; | |
109 | } | |
110 | } | |
111 | ||
112 | /* Enable machine check exception handling if available */ | |
113 | if (mca_MCE_present) { | |
114 | set_cr4(get_cr4()|CR4_MCE); | |
115 | } | |
116 | } | |
117 | ||
118 | static void mca_dump_64bit_state(void) | |
119 | { | |
120 | kdb_printf("Extended Machine Check State:\n"); | |
121 | kdb_printf(" IA32_MCG_RAX: 0x%016qx\n", rdmsr64(IA32_MCG_RAX)); | |
122 | kdb_printf(" IA32_MCG_RBX: 0x%016qx\n", rdmsr64(IA32_MCG_RBX)); | |
123 | kdb_printf(" IA32_MCG_RCX: 0x%016qx\n", rdmsr64(IA32_MCG_RCX)); | |
124 | kdb_printf(" IA32_MCG_RDX: 0x%016qx\n", rdmsr64(IA32_MCG_RDX)); | |
125 | kdb_printf(" IA32_MCG_RSI: 0x%016qx\n", rdmsr64(IA32_MCG_RSI)); | |
126 | kdb_printf(" IA32_MCG_RDI: 0x%016qx\n", rdmsr64(IA32_MCG_RDI)); | |
127 | kdb_printf(" IA32_MCG_RBP: 0x%016qx\n", rdmsr64(IA32_MCG_RBP)); | |
128 | kdb_printf(" IA32_MCG_RSP: 0x%016qx\n", rdmsr64(IA32_MCG_RSP)); | |
129 | kdb_printf(" IA32_MCG_RFLAGS: 0x%016qx\n", rdmsr64(IA32_MCG_RFLAGS)); | |
130 | kdb_printf(" IA32_MCG_RIP: 0x%016qx\n", rdmsr64(IA32_MCG_RIP)); | |
131 | kdb_printf(" IA32_MCG_MISC: 0x%016qx\n", rdmsr64(IA32_MCG_MISC)); | |
132 | kdb_printf(" IA32_MCG_R8: 0x%016qx\n", rdmsr64(IA32_MCG_R8)); | |
133 | kdb_printf(" IA32_MCG_R9: 0x%016qx\n", rdmsr64(IA32_MCG_R9)); | |
134 | kdb_printf(" IA32_MCG_R10: 0x%016qx\n", rdmsr64(IA32_MCG_R10)); | |
135 | kdb_printf(" IA32_MCG_R11: 0x%016qx\n", rdmsr64(IA32_MCG_R11)); | |
136 | kdb_printf(" IA32_MCG_R12: 0x%016qx\n", rdmsr64(IA32_MCG_R12)); | |
137 | kdb_printf(" IA32_MCG_R13: 0x%016qx\n", rdmsr64(IA32_MCG_R13)); | |
138 | kdb_printf(" IA32_MCG_R14: 0x%016qx\n", rdmsr64(IA32_MCG_R14)); | |
139 | kdb_printf(" IA32_MCG_R15: 0x%016qx\n", rdmsr64(IA32_MCG_R15)); | |
140 | } | |
141 | ||
142 | static uint32_t rdmsr32(uint32_t msr) | |
143 | { | |
144 | return (uint32_t) rdmsr64(msr); | |
145 | } | |
146 | ||
147 | static void mca_dump_32bit_state(void) | |
148 | { | |
149 | kdb_printf("Extended Machine Check State:\n"); | |
150 | kdb_printf(" IA32_MCG_EAX: 0x%08x\n", rdmsr32(IA32_MCG_EAX)); | |
151 | kdb_printf(" IA32_MCG_EBX: 0x%08x\n", rdmsr32(IA32_MCG_EBX)); | |
152 | kdb_printf(" IA32_MCG_ECX: 0x%08x\n", rdmsr32(IA32_MCG_ECX)); | |
153 | kdb_printf(" IA32_MCG_EDX: 0x%08x\n", rdmsr32(IA32_MCG_EDX)); | |
154 | kdb_printf(" IA32_MCG_ESI: 0x%08x\n", rdmsr32(IA32_MCG_ESI)); | |
155 | kdb_printf(" IA32_MCG_EDI: 0x%08x\n", rdmsr32(IA32_MCG_EDI)); | |
156 | kdb_printf(" IA32_MCG_EBP: 0x%08x\n", rdmsr32(IA32_MCG_EBP)); | |
157 | kdb_printf(" IA32_MCG_ESP: 0x%08x\n", rdmsr32(IA32_MCG_ESP)); | |
158 | kdb_printf(" IA32_MCG_EFLAGS: 0x%08x\n", rdmsr32(IA32_MCG_EFLAGS)); | |
159 | kdb_printf(" IA32_MCG_EIP: 0x%08x\n", rdmsr32(IA32_MCG_EIP)); | |
160 | kdb_printf(" IA32_MCG_MISC: 0x%08x\n", rdmsr32(IA32_MCG_MISC)); | |
161 | } | |
162 | ||
163 | static const char *mca_threshold_status[] = { | |
164 | [THRESHOLD_STATUS_NO_TRACKING] "No tracking", | |
165 | [THRESHOLD_STATUS_GREEN] "Green", | |
166 | [THRESHOLD_STATUS_YELLOW] "Yellow", | |
167 | [THRESHOLD_STATUS_RESERVED] "Reserved" | |
168 | }; | |
169 | ||
170 | static void | |
171 | mca_dump_error_banks(void) | |
172 | { | |
173 | unsigned int i; | |
174 | ia32_mci_status_t status; | |
175 | ||
176 | kdb_printf("MCA error-reporting registers:\n"); | |
177 | for (i = 0; i < mca_error_bank_count; i++ ) { | |
178 | status.u64 = rdmsr64(IA32_MCi_STATUS(i)); | |
179 | kdb_printf( | |
180 | " IA32_MC%d_STATUS(0x%x): 0x%016qx %svalid\n", | |
181 | i, IA32_MCi_STATUS(i), status.u64, | |
182 | IF(!status.bits.val, "in")); | |
183 | if (!status.bits.val) | |
184 | continue; | |
185 | kdb_printf( | |
186 | " MCA error code : 0x%04x\n", | |
187 | status.bits.mca_error); | |
188 | kdb_printf( | |
189 | " Model specific error code: 0x%04x\n", | |
190 | status.bits.model_specific_error); | |
191 | if (!mca_threshold_status_present) { | |
192 | kdb_printf( | |
193 | " Other information : 0x%08x\n", | |
194 | status.bits.other_information); | |
195 | } else { | |
196 | int threshold = status.bits_tes_p.threshold; | |
197 | kdb_printf( | |
198 | " Other information : 0x%08x\n" | |
199 | " Threshold-based status : %s\n", | |
200 | status.bits_tes_p.other_information, | |
201 | (status.bits_tes_p.uc == 0) ? | |
202 | mca_threshold_status[threshold] : | |
203 | "Undefined"); | |
204 | } | |
205 | kdb_printf( | |
206 | " Status bits:\n%s%s%s%s%s%s", | |
207 | IF(status.bits.pcc, " Processor context corrupt\n"), | |
208 | IF(status.bits.addrv, " ADDR register valid\n"), | |
209 | IF(status.bits.miscv, " MISC register valid\n"), | |
210 | IF(status.bits.en, " Error enabled\n"), | |
211 | IF(status.bits.uc, " Uncorrected error\n"), | |
212 | IF(status.bits.over, " Error overflow\n")); | |
213 | if (status.bits.addrv) | |
214 | kdb_printf( | |
215 | " IA32_MC%d_ADDR(0x%x): 0x%016qx\n", | |
216 | i, IA32_MCi_ADDR(i), rdmsr64(IA32_MCi_ADDR(i))); | |
217 | if (status.bits.miscv) | |
218 | kdb_printf( | |
219 | " IA32_MC%d_MISC(0x%x): 0x%016qx\n", | |
220 | i, IA32_MCi_MISC(i), rdmsr64(IA32_MCi_MISC(i))); | |
221 | } | |
222 | } | |
223 | ||
224 | void | |
225 | mca_dump(void) | |
226 | { | |
227 | ia32_mcg_status_t status; | |
228 | ||
229 | /* | |
230 | * Report machine-check capabilities: | |
231 | */ | |
232 | kdb_printf( | |
233 | "Machine-check capabilities 0x%016qx:\n", ia32_mcg_cap.u64); | |
234 | kdb_printf( | |
235 | " %d error-reporting banks\n%s%s", mca_error_bank_count, | |
236 | IF(mca_control_MSR_present, | |
237 | " control MSR present\n"), | |
238 | IF(mca_threshold_status_present, | |
239 | " threshold-based error status present\n")); | |
240 | if (mca_extended_MSRs_present) | |
241 | kdb_printf( | |
242 | " %d extended MSRs present\n", mca_extended_MSRs_count); | |
243 | ||
244 | /* | |
245 | * Report machine-check status: | |
246 | */ | |
247 | status.u64 = rdmsr64(IA32_MCG_STATUS); | |
248 | kdb_printf( | |
249 | "Machine-check status 0x%016qx\n%s%s%s", status.u64, | |
250 | IF(status.bits.ripv, " restart IP valid\n"), | |
251 | IF(status.bits.eipv, " error IP valid\n"), | |
252 | IF(status.bits.mcip, " machine-check in progress\n")); | |
253 | ||
254 | /* | |
255 | * Dump error-reporting registers: | |
256 | */ | |
257 | mca_dump_error_banks(); | |
258 | ||
259 | /* | |
260 | * Dump any extended machine state: | |
261 | */ | |
262 | if (mca_extended_MSRs_present) { | |
263 | if (cpu_mode_is64bit()) | |
264 | mca_dump_64bit_state(); | |
265 | else | |
266 | mca_dump_32bit_state(); | |
267 | } | |
268 | } |