Machine Check Exception (MCE) 是CPU發現硬體錯誤時觸發的異常(exception),中斷号是18,異常的類型是abort:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CMhJGNxYTZyYTZ3ADNhJmMxETOwMWZ1ITO1MmZ2IWNm9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
導緻MCE的原因主要有:總線故障、記憶體ECC校驗錯、cache錯誤、TLB錯誤、内部時鐘錯誤,等等。不僅硬體故障會引起MCE,不恰當的BIOS配置、firmware bug、軟體bug也有可能引起MCE。
在 Linux 系統上,如果發生的MCE錯誤屬于可以自動糾正的類型,那麼系統保持繼續運作,MCE錯誤日志會記錄在一個ring buffer中(這個ring buffer通過裝置檔案/dev/mcelog來通路),用 mcelog(8) 指令可以讀取MCE日志,系統通常會通過cron任務或者mcelog.service把ring buffer中的MCE日志寫入/var/log/mcelog檔案中。如果發生的MCE錯誤屬于無法恢複的類型,那麼系統會panic,錯誤資訊會輸出在終端上和message buffer裡。
分析MCE需要參考Intel手冊第3卷,15章Machine-Check Architecture和16章Interpreting Machine-Check Error Codes。由于MCE在不同型号的CPU上有差異,解讀的方法也有不同,第16章是專門解釋在不同的CPU型号上如何解讀MCE錯誤碼。
每個CPU上有一組寄存器稱為 Machine-Check MSR (Model-Specific Register),用于Machine-Check的控制與記錄,分為全局寄存器和若幹Bank寄存器(CPU的硬體單元分成若幹組,每一組稱為一個Bank)。當發生MCE時,錯誤資訊記錄在全局狀态寄存器 MCG_STATUS MSR 和Bank寄存器 MCi_STATUS MSR 中,如下圖黃色框所示:
分析MCE的方法,就是根據Intel手冊解讀上述寄存器中記錄的錯誤資訊。Linux核心把MCE的資訊儲存在下面的結構體中:
/arch/x86/include/asm/mce.h :
0067 struct mce {
0068 __u64 status;
0069 __u64 misc;
0070 __u64 addr;
0071 __u64 mcgstatus;
0072 __u64 ip;
0073 __u64 tsc;
0074 __u64 time;
0075 __u8 cpuvendor;
0076 __u8 inject_flags;
0077 __u16 pad;
0078 __u32 cpuid;
0079 __u8 cs;
0080 __u8 bank;
0081 __u8 cpu;
0082 __u8 finished;
0083 __u32 extcpu;
0084 __u32 socketid;
0085 __u32 apicid;
0086 __u64 mcgcap;
0087 };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/arch/x86/include/asm/mce.h:
0067structmce{
0068__u64status;
0069__u64misc;
0070__u64addr;
0071__u64mcgstatus;
0072__u64ip;
0073__u64tsc;
0074__u64time;
0075__u8cpuvendor;
0076__u8inject_flags;
0077__u16pad;
0078__u32cpuid;
0079__u8cs;
0080__u8bank;
0081__u8cpu;
0082__u8finished;
0083__u32extcpu;
0084__u32socketid;
0085__u32apicid;
0086__u64mcgcap;
0087};
下面的MCE錯誤資訊截取自一台因MCE而crash的機器,我們以此為例來解讀一下MCE資訊。
注:産生以下資訊的核心函數是:
static void print_mce(struct mce *m)
源程式:arch/x86/kernel/cpu/mcheck/mce.c
如果需要的話,閱讀源程式可以了解輸出的資訊與原始資料的對應關系。
[Hardware Error]: CPU 3: Machine Check Exception: 4 Bank 5: be00000000800400
[Hardware Error]: TSC 128727f47a97 ADDR 3f628bd69349 MISC 1
[Hardware Error]: PROCESSOR 0:106a5 TIME 1450279905 SOCKET 1 APIC 14
[Hardware Error]: Machine check: Processor context corrupt
Kernel panic - not syncing: Fatal Machine check
1
2
3
4
5
[HardwareError]:CPU3:MachineCheckException:4Bank5:be00000000800400
[HardwareError]:TSC128727f47a97ADDR3f628bd69349MISC1
[HardwareError]:PROCESSOR0:106a5TIME1450279905SOCKET1APIC14
[HardwareError]:Machinecheck:Processorcontextcorrupt
Kernelpanic-notsyncing:FatalMachinecheck
其中CPU和Bank是MCE的接收者:
CPU 3 – 表示檢測到MCE錯誤的是3号CPU,對應struct mce的extcpu字段;
Bank 5 – 一組硬體單元稱為一個bank,每個bank對應一組machine-check寄存器;
MCE的錯誤代碼包括兩部分:
Machine Check Exception: 4 – 表示 IA32_MCG_STATUS MSR寄存器的狀态碼是4(含義見後文),對應 mcgstatus字段;
be00000000800400 – 表示 IA32_MCi_STATUS MSR寄存器中的錯誤碼(含義見後文),對應status字段。
Machine Check Excheption: 4 的含義
它來自全局狀态寄存器 IA32_MCG_STATUS MSR,(對應struct mce的 mcgstatus字段),隻用到三個bit,如下所示。4表示machine-check in progress。
Bit 0: Restart IP Valid. 表示程式的執行是否可以在被異常中斷的指令處重新開始。
Bit 1: Error IP Valid. 表示被中斷的指令是否與MCE錯誤直接相關。
Bit 2: Machine Check In Progress. 表示 machine check 正在進行中。
be00000000800400 的含義
它來自bank寄存器IA32_MCi_STATUS MSR,(對應struct mce的status字段)。
be00000000800400 的二進制位如下:
Bit 63: VAL. 表示本寄存器中包含有效的錯誤碼
Bit 61: UC. 表示是無法糾正的MCE
Bit 60: EN. 表示處于允許報告錯誤的狀态
Bit 59: MISCV. 表示MCi_MISC寄存器中含有對該錯誤的補充資訊
Bit 58: ADDRV. 表示MCi_ADDR寄存器含有發生錯誤的記憶體位址
Bit 57: PCC. 表示該CPU的上下文狀态已被該錯誤破壞,無法恢複軟體代碼的運作
Bits [16:31] 包含特定CPU型号相關的擴充錯誤碼. 本例中是0x0080.
Bits [0:15] 包含MCE錯誤碼,該錯誤碼是所有CPU型号通用的,分為兩類:simple error codes(簡單錯誤碼) 和 compound error codes(複合錯誤碼),本例中0x0400表示Internal timer error:
– Simple Error Codes:
0000 0000 0000 0000 – 沒有錯誤.
0000 0000 0000 0001 – Unclassified. 未分類的錯誤類型.
0000 0000 0000 0010 – ROM微碼校驗錯
0000 0000 0000 0011 – MCE是由于别的CPU的BINT# 引起的.
0000 0000 0000 0100 – Functional redundancy check (FRC) master/slave error.
0000 0000 0000 0101 – Internal parity error.
0000 0100 0000 0000 – Internal timer error.
0000 01xx xxxx xxxx – Internal unclassified error. 至少有一個x等于1
– Compound Error Codes:
000F 0000 0000 11LL – Generic cache hierarchy errors.
000F 0000 0001 TTLL – TLB errors.
000F 0000 1MMM CCCC – Memory controller errors (Intel-only).
000F 0001 RRRR TTLL – Memory errors in the cache hierarchy.
000F 1PPT RRRR IILL – Bus and interconnect errors.
下一步,由于Bits [16:31] 是非零值0x0080,包含的是特定CPU型号相關的擴充錯誤碼,我們要參考Intel手冊第三卷第16章。首先确定CPU型号,我們需要的是CPU faimily和model,從/proc/cpuinfo中可以找到:
# less /proc/cpuinfo
...
processor : 3
vendor_id : GenuineIntel
cpu family : 6
model : 26
model name : Intel(R) Xeon(R) CPU L5520 @ 2.27GHz
stepping : 5
cpu MHz : 2266.700
cache size : 8192 KB
physical id : 1
siblings : 8
core id : 2
cpu cores : 4
apicid : 20
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# less /proc/cpuinfo
...
processor:3
vendor_id:GenuineIntel
cpufamily:6
model:26
modelname:Intel(R)Xeon(R)[email protected]
stepping:5
cpuMHz:2266.700
cachesize:8192KB
physicalid:1
siblings:8
coreid:2
cpucores:4
apicid:20
...
根據cpu family/model,即06_1AH,找到Intel手冊中對應的章節,但是沒找到比對Internal timer error和0x0080的條目。是以隻能到此為止了。
總結我們的發現:
CPU 3 發現了無法糾正的MCE,是Internal timer error,被中斷的指令與MCE不相關,被中斷的程式指令不能恢複運作,CPU的上下文已被MCE破壞。
怎樣禁用MCE
可以在 /boot/grub/grub.conf 中加入以下内容:mce=off。
還有其它的MCE選項,比如禁用CMCI(Corrected Machine Check Interrupt),或者禁用MCE日志,等等,例如:
mce=off — Disable machine check
mce=no_cmci — Disable CMCI(Corrected Machine Check Interrupt)
參見文檔:Documentation/x86/x86_64/boot-options.txt
每個 CPU 都有一個sysfs接口:
/sys/devices/system/machinecheck/machinecheckN
注:(N = CPU number)
其中包含的可調參數參見:Documentation/x86/x86_64/machinecheck