2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <cpu/x86/msr.h>
16 #include <arch/acpi.h>
18 #include <soc/northbridge.h>
19 #include <console/console.h>
20 #include <arch/bert_storage.h>
32 static inline size_t mca_report_size_reqd(void)
36 size
= sizeof(acpi_generic_error_status_t
);
38 size
+= sizeof(acpi_hest_generic_data_v300_t
);
39 size
+= sizeof(cper_proc_generic_error_section_t
);
41 size
+= sizeof(acpi_hest_generic_data_v300_t
);
42 size
+= sizeof(cper_ia32x64_proc_error_section_t
);
45 size
+= cper_ia32x64_check_sz();
47 /* Context of MCG_CAP, MCG_STAT, MCG_CTL */
48 size
+= cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR
, 3);
50 /* Context of MCi_CTL, MCi_STATUS, MCi_ADDR, MCi_MISC */
51 size
+= cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR
, 4);
53 /* Context of CTL_MASK */
54 size
+= cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR
, 1);
59 static enum cper_x86_check_type
error_to_chktype(struct mca_bank
*mci
)
61 int error
= mca_err_type(mci
->sts
);
63 if (error
== MCA_ERRTYPE_BUS
)
64 return X86_PROCESSOR_BUS_CHK
;
65 if (error
== MCA_ERRTYPE_INT
)
66 return X86_PROCESSOR_MS_CHK
;
67 if (error
== MCA_ERRTYPE_MEM
)
68 return X86_PROCESSOR_CACHE_CHK
;
69 if (error
== MCA_ERRTYPE_TLB
)
70 return X86_PROCESSOR_TLB_CHK
;
72 return X86_PROCESSOR_MS_CHK
; /* unrecognized */
75 /* Fill additional information in the Generic Processor Error Section. */
76 static void fill_generic_section(cper_proc_generic_error_section_t
*sec
,
79 int type
= mca_err_type(mci
->sts
);
81 if (type
== MCA_ERRTYPE_BUS
) /* try to map MCA errors to CPER types */
82 sec
->error_type
= GENPROC_ERRTYPE_BUS
;
83 else if (type
== MCA_ERRTYPE_INT
)
84 sec
->error_type
= GENPROC_ERRTYPE_UARCH
;
85 else if (type
== MCA_ERRTYPE_MEM
)
86 sec
->error_type
= GENPROC_ERRTYPE_CACHE
;
87 else if (type
== MCA_ERRTYPE_TLB
)
88 sec
->error_type
= GENPROC_ERRTYPE_TLB
;
90 sec
->error_type
= GENPROC_ERRTYPE_UNKNOWN
;
91 sec
->validation
|= GENPROC_VALID_PROC_ERR_TYPE
;
94 /* Convert an error reported by an MCA bank into BERT information to be reported
95 * by the OS. The ACPI driver doesn't recognize/parse the IA32/X64 structure,
96 * which is the best method to report MSR context. As a result, add two
97 * structures: A "processor generic error" that is parsed, and an IA32/X64 one
98 * to capture complete information.
100 static void build_bert_mca_error(struct mca_bank
*mci
)
102 acpi_generic_error_status_t
*status
;
103 acpi_hest_generic_data_v300_t
*gen_entry
;
104 acpi_hest_generic_data_v300_t
*x86_entry
;
105 cper_proc_generic_error_section_t
*gen_sec
;
106 cper_ia32x64_proc_error_section_t
*x86_sec
;
107 cper_ia32x64_proc_error_info_t
*chk
;
108 cper_ia32x64_context_t
*ctx
;
110 if (mca_report_size_reqd() > bert_storage_remaining())
113 status
= bert_new_event(&CPER_SEC_PROC_GENERIC_GUID
);
117 gen_entry
= acpi_hest_generic_data3(status
);
118 gen_sec
= section_of_acpientry(gen_sec
, gen_entry
);
120 fill_generic_section(gen_sec
, mci
);
122 x86_entry
= bert_append_ia32x64(status
);
123 x86_sec
= section_of_acpientry(x86_sec
, x86_entry
);
125 chk
= new_cper_ia32x64_check(status
, x86_sec
, error_to_chktype(mci
));
129 ctx
= cper_new_ia32x64_context_msr(status
, x86_sec
, IA32_MCG_CAP
, 3);
132 ctx
= cper_new_ia32x64_context_msr(status
, x86_sec
,
133 IA32_MC0_CTL
+ (mci
->bank
* 4), 4);
136 ctx
= cper_new_ia32x64_context_msr(status
, x86_sec
,
137 MC0_CTL_MASK
+ mci
->bank
, 1);
144 /* We're here because of a hardware error, don't break something else */
145 printk(BIOS_ERR
, "Error: Not enough room in BERT region for Machine Check error\n");
148 static const char *const mca_bank_name
[] = {
150 "Instruction fetch unit",
155 "Floating point unit"
158 /* Check the Legacy Machine Check Architecture registers */
166 cap
= rdmsr(IA32_MCG_CAP
);
167 num_banks
= cap
.lo
& MCA_BANKS_MASK
;
169 if (is_warm_reset()) {
170 for (i
= 0 ; i
< num_banks
; i
++) {
171 mci
.sts
= rdmsr(IA32_MC0_STATUS
+ (i
* 4));
172 if (mci
.sts
.hi
|| mci
.sts
.lo
) {
173 int core
= cpuid_ebx(1) >> 24;
175 printk(BIOS_WARNING
, "#MC Error: core %d, bank %d %s\n",
176 core
, i
, mca_bank_name
[i
]);
178 printk(BIOS_WARNING
, " MC%d_STATUS = %08x_%08x\n",
179 i
, mci
.sts
.hi
, mci
.sts
.lo
);
180 mci
.addr
= rdmsr(MC0_ADDR
+ (i
* 4));
181 printk(BIOS_WARNING
, " MC%d_ADDR = %08x_%08x\n",
182 i
, mci
.addr
.hi
, mci
.addr
.lo
);
183 mci
.misc
= rdmsr(MC0_MISC
+ (i
* 4));
184 printk(BIOS_WARNING
, " MC%d_MISC = %08x_%08x\n",
185 i
, mci
.misc
.hi
, mci
.misc
.lo
);
186 mci
.ctl
= rdmsr(IA32_MC0_CTL
+ (i
* 4));
187 printk(BIOS_WARNING
, " MC%d_CTL = %08x_%08x\n",
188 i
, mci
.ctl
.hi
, mci
.ctl
.lo
);
189 mci
.cmask
= rdmsr(MC0_CTL_MASK
+ i
);
190 printk(BIOS_WARNING
, " MC%d_CTL_MASK = %08x_%08x\n",
191 i
, mci
.cmask
.hi
, mci
.cmask
.lo
);
194 if (CONFIG(ACPI_BERT
)
195 && mca_valid(mci
.sts
))
196 build_bert_mca_error(&mci
);
201 /* zero the machine check error status registers */
204 for (i
= 0 ; i
< num_banks
; i
++)
205 wrmsr(IA32_MC0_STATUS
+ (i
* 4), mci
.sts
);