MCE (Machine Check Exception)

x86 Machine Check Architecture(MCA)의 뱅크/레지스터(Register) 구조, MCE 심각도 분류(SRAR/SRAO/UCNA), 커널 처리 경로(Monarch 랑데부), CMCI 스톰, AMD SMCA, IIO(Integrated I/O) PCIe 에러 아키텍처(Completion Timeout, Poisoned TLP, Surprise Link Down, DMA/VT-d 에러), Uncore MCA 에러 종합(M2M/CHA/UPI/PCU/TOR/MDF), KVM 가상화 MCE 전파(VMEXIT, 가상 MCE 뱅크, HWPoison→게스트), APEI/GHES 펌웨어(Firmware) 연동, EDAC DIMM 디코드, memory_failure()/HWPoison 복구, GPU/가속기 연쇄 에러 분석(Xid↔IIO MCE 상관분석, AI/ML 클러스터 영향), ARM/RISC-V/POWER EEH 비교, DDR5 On-Die ECC, Row Hammer, MCE 디버깅 기법(perf/ftrace/eBPF), 로그 디코딩 실전과 운영 플레이북까지 다룹니다.

전제 조건: NMI, 인터럽트(Interrupt) 처리, 메모리 관리(Memory Management) 문서를 먼저 읽으세요. MCE는 NMI와 유사한 비마스킹 예외이며, 메모리 오류 복구는 메모리 서브시스템 이해가 필요합니다.
일상 비유: MCE는 자동차의 엔진 경고등(Check Engine Light)과 같습니다. 경미한 경고(CE)는 "다음 정비 때 확인"이지만, 치명적 경고(UC+PCC)는 "즉시 차를 세워라"입니다. 커널은 경고 수준에 따라 프로세스(Process)만 종료하거나, 시스템 전체를 멈추거나, 자동 복구를 시도합니다.

핵심 요약

  • Machine Check Exception — x86 벡터 18번 예외로, CPU/메모리/버스(Bus)의 하드웨어 오류를 보고합니다. CR4.MCE=1일 때만 활성화됩니다.
  • MCA 뱅크 — CPU 내부의 에러 감지 유닛(L1/L2/L3 캐시(Cache), 메모리 컨트롤러, 인터커넥트 등)이 각각 독립 레지스터 세트를 가집니다.
  • 심각도 3단계 — SRAR(즉시 복구 필요), SRAO(백그라운드 처리), UCNA(정보 전달만): 커널은 STATUS 비트로 자동 판별합니다.
  • Monarch 메커니즘 — MCE 발생 시 모든 CPU를 동기화하고, 한 CPU(Monarch)가 최종 의사결정(패닉/복구/무시)을 내립니다.
  • memory_failure() — HWPoison으로 물리 페이지(Page)를 오프라인 처리하고, 해당 메모리를 사용하던 프로세스에 SIGBUS를 전달합니다.

단계별 이해

  1. 1단계 — MCA 아키텍처 이해: MCE가 무엇이고, x86 예외 계층에서 어디에 위치하는지 파악합니다. (MCE 아키텍처 개요)
  2. 2단계 — 레지스터 구조: MCA 뱅크, MCi_STATUS 비트 필드, 에러 코드 체계를 이해합니다. (MCA 뱅크, STATUS 비트 필드, 에러 코드)
  3. 3단계 — 커널 처리 경로: 하드웨어 예외가 커널 핸들러(Handler)에 도달하고, Monarch가 선출되어 의사결정하는 과정을 추적합니다. (진입 경로, 처리 흐름, Monarch)
  4. 4단계 — 복구 메커니즘: memory_failure(), HWPoison, CMCI를 통한 오류 복구와 교정 인터럽트를 학습합니다. (HWPoison, CMCI)
  5. 5단계 — IIO와 Uncore: IIO(Integrated I/O)의 PCIe 에러 처리, Uncore 영역(M2M/CHA/UPI/TOR/MDF)의 에러 유형과 연쇄 패턴을 이해합니다. (IIO 아키텍처, Uncore 에러 종합)
  6. 6단계 — 가상화와 가속기: KVM 환경에서의 MCE 전파, GPU/가속기 연쇄 에러를 이해합니다. (KVM 가상화, GPU/가속기 에러)
  7. 7단계 — 플랫폼 통합: APEI/GHES, EDAC, AMD SMCA 등 다양한 플랫폼별 통합 경로를 이해합니다. (APEI/GHES, EDAC)
  8. 8단계 — 운영 실전: 로그 디코딩, 패턴 인식, 디버깅 기법(perf/eBPF), 테스트 주입, 플레이북을 통해 현장 대응 역량을 갖춥니다. (로그 디코딩, 디버깅 기법, 에러 패턴, 플레이북)

MCE 아키텍처 개요

Machine Check Exception(MCE)은 x86 아키텍처에서 벡터 18(#MC)로 정의된 abort 클래스 예외입니다. CPU 내부 또는 외부에서 발생하는 하드웨어 오류 — ECC 메모리 오류, 캐시 패리티 오류, 버스 타임아웃, TLB 오류 등 — 를 소프트웨어에 알려주는 유일한 표준 메커니즘입니다.

역사: Intel Pentium(P5)에서 Machine Check Architecture(MCA)가 처음 도입되었고, P6(Pentium Pro) 이후로 뱅크 기반 레지스터 모델이 표준화되었습니다. 현재 모든 x86-64 CPU는 MCA를 지원합니다.

예외 특성

속성의미
벡터 번호18 (#MC)IDT 엔트리 18
클래스Abort재시작(Reboot) 불가능할 수 있음
에러 코드없음정보는 MSR(MCA 뱅크)에 저장
ISTIST 3 (커널 6.x 기준)전용 스택에서 실행
활성화 조건CR4.MCE = 1부팅 시 커널이 설정
마스킹불가cli/sti로 차단 불가

MCE의 위치: x86 예외 계층

x86 예외/인터럽트 계층 Fault (재시작 가능) #DE (0) 나눗셈 오류 #PF (14) 페이지 폴트 #GP (13) 일반 보호 #NM (7) FPU 없음 Trap (다음 명령 실행) #DB (1) 디버그 #BP (3) 브레이크포인트 #OF (4) 오버플로 Abort (복구 불확실) #MC (18) MCE IST 3 전용 스택 CR4.MCE = 1 필수 #DF (8) 더블 폴트 Interrupt (비동기) #NMI (2) IST 1 IRQ 32~255 IPI (APIC) 하드웨어 오류 발생 MCA 뱅크 레지스터 MCi_STATUS 기록 #MC 벡터 18 IDT → IST3 UC = Uncorrected (교정 불가) | CE = Corrected Error (교정 완료) | PCC = Processor Context Corrupt UC+PCC → 시스템 패닉 | UC+!PCC → 프로세스 킬 가능 | CE → 로그 기록만

MCE는 동기(synchronous)비동기(asynchronous) 모두 가능합니다. 명령어 실행 중 발견된 메모리 오류(SRAR)는 동기적이고, 백그라운드 스크러빙이 발견한 오류(SRAO)는 비동기적입니다. 커널은 동기 MCE를 더 긴급하게 처리합니다.

/* arch/x86/kernel/cpu/mce/core.c — MCE 활성화 */
void mcheck_cpu_init(struct cpuinfo_x86 *c)
{
    /* CR4.MCE 비트 설정 — 이것이 없으면 MCE 시 triple fault → 리셋 */
    cr4_set_bits(X86_CR4_MCE);
    /* 각 MCA 뱅크의 CTL 레지스터를 0xFFFFFFFFFFFFFFFF로 설정 (모든 에러 활성화) */
    for (i = 0; i < num_banks; i++)
        wrmsrl(MSR_IA32_MCx_CTL(i), 0xFFFFFFFFFFFFFFFFULL);
}

MCA 뱅크와 레지스터

MCA(Machine Check Architecture)는 CPU 내부의 에러 감지 유닛을 뱅크(bank) 단위로 구성합니다. 각 뱅크는 특정 하드웨어 컴포넌트(L1 캐시, L2 캐시, 메모리 컨트롤러, QPI/UPI 등)에 매핑(Mapping)되며, 독립적인 레지스터 세트를 가집니다.

글로벌 레지스터

MSR주소역할
MCG_CAP0x179뱅크 수(Count), 확장 기능 플래그(MCG_EXT_P, MCG_SER_P, MCG_ELOG_P, MCG_LMCE_P)
MCG_STATUS0x17ARIPV(Restart IP Valid), EIPV(Error IP Valid), MCIP(MC In Progress), LMCE_S
MCG_CTL0x17BMCG_CTL_P=1일 때만 존재. 모든 뱅크의 글로벌 활성화/비활성화
MCG_EXT_CTL0x4D0LMCE_EN 비트 — Local MCE 활성화

뱅크별 레지스터 (i = 0..N-1)

MSR주소 공식역할
MCi_CTL0x400 + 4*i에러 유형별 활성화/비활성화 비트마스크
MCi_STATUS0x401 + 4*i에러 정보 — 가장 핵심적인 레지스터
MCi_ADDR0x402 + 4*i에러 발생 주소 (ADDRV=1일 때 유효)
MCi_MISC0x403 + 4*i추가 정보 — 주소 모드, LSB 등 (MISCV=1일 때 유효)
MCi_CTL20x280 + iCMCI 임계값 설정, CMCI_EN 비트
MCA 레지스터 파일 레이아웃 글로벌 MSR MCG_CAP (0x179) — 뱅크 수 MCG_STATUS (0x17A) MCG_CTL (0x17B) Bank 0 (예: L1 캐시) MC0_CTL (0x400) MC0_STATUS (0x401) ★ MC0_ADDR (0x402) MC0_MISC (0x403) Bank N-1 (예: IMC) MCn_CTL MCn_STATUS ★ MCn_ADDR MCn_MISC ... MCi_CTL2 (0x280 + i) — CMCI 제어 레지스터 CMCI_EN (bit 30) | CMCI Threshold (bits 14:0) MCG_CAP.Count 필드로 뱅크 수 결정 — 최근 Intel/AMD CPU는 20~32개 뱅크 보유
/* arch/x86/kernel/cpu/mce/core.c — 뱅크 스캔 */
static void __mcheck_cpu_mce_banks_init(void)
{
    int i;
    u64 cap;

    rdmsrl(MSR_IA32_MCG_CAP, cap);
    num_banks = cap & MCG_BANKCNT_MASK;   /* bits [7:0] */

    for (i = 0; i < num_banks; i++) {
        struct mce_bank *b = &mce_banks[i];
        b->ctl = ~(u64)0;   /* 모든 에러 유형 활성화 */
        wrmsrl(MSR_IA32_MCx_CTL(i), b->ctl);
    }
}
뱅크 매핑 확인: cat /sys/devices/system/machinecheck/machinecheck0/bank*로 각 뱅크의 CTL 값을 확인하고, mcelog --client 또는 rasdaemon으로 뱅크별 에러 발생 이력을 추적할 수 있습니다.

IA32_MCi_STATUS 비트 필드 상세

MCi_STATUS는 MCA의 핵심 레지스터로, 64비트 전체가 에러 정보를 담고 있습니다. 커널의 MCE 핸들러는 이 레지스터의 비트 조합으로 에러의 종류, 심각도, 복구 가능성을 판단합니다.

IA32_MCi_STATUS 64비트 비트맵 63 VAL 62 OVER 61 UC 60 EN 59 MISCV 58 ADDRV 57 PCC 56 S 55 AR 54:32 Other / Reserved 31:16 Model Specific 15:0 MCA Error Code VAL = MCi_STATUS 유효 | OVER = 이전 에러 덮어씌움 | UC = 교정 불가 EN = 에러 보고 활성 | MISCV = MISC 레지스터 유효 | ADDRV = ADDR 레지스터 유효 PCC = 프로세서 컨텍스트 손상 | S = Signaling (MCG_SER_P 필요) | AR = Action Required 심각도 결정 규칙 UC=1, S=1, AR=1 → SRAR | UC=1, S=1, AR=0 → SRAO | UC=1, S=0 → UCNA | UC=0 → CE PCC=1이면 → 항상 패닉 (프로세서 상태 복구 불가)
비트이름의미1일 때 동작
63VALSTATUS 유효성이 레지스터에 유효한 에러 정보가 있음
62OVER오버플로이전 에러를 읽기 전에 새 에러 발생 — 정보 손실 가능
61UCUncorrected하드웨어가 자동 교정하지 못한 에러
60ENError EnabledMCi_CTL에서 이 에러 유형이 활성화된 상태
59MISCVMISC ValidMCi_MISC 레지스터에 추가 정보 있음
58ADDRVAddress ValidMCi_ADDR에 에러 주소가 유효
57PCCProcessor Context CorruptCPU 내부 상태 손상 — 안전한 실행 계속 불가
56SSignaling (SER_P)소프트웨어 복구 가능성 표시 (MCG_SER_P 필요)
55ARAction Required즉시 조치 필요 (S=1이어야 의미 있음)
15:0MCA Error Code표준 에러 코드에러 유형 분류 (Simple/Compound)

MCA 에러 코드 분류

MCi_STATUS의 하위 16비트(bits 15:0)는 MCA 에러 코드로, Intel SDM에서 정의한 표준 포맷을 따릅니다. 크게 Simple Error Code와 Compound Error Code로 나뉩니다.

Simple Error Code (단순 에러 코드)

코드이름설명
0x0000No Error에러 없음
0x0001Unclassified분류 불가 에러
0x0002Microcode ROM Parity마이크로코드 ROM 패리티 에러
0x0003External외부 소스 에러
0x0004FRCFRC(Functional Redundancy Check) 에러
0x0005Internal Parity내부 패리티 에러
0x0400Internal Timer내부 타이머(Timer) 에러

Compound Error Code (복합 에러 코드)

복합 에러 코드는 000F 0FTT LLLL 형식의 비트 패턴으로 인코딩됩니다.

필드비트의미
LLLL (Level)3:00000Level 0
0001Level 1
0010Level 2
0011Generic / Level 3
0100~1111예약
TT (Transaction)5:400Instruction
01Data
10Generic
11예약
RRRR (Request)11:80000Generic Error (ERR)
0001Generic Read (RD)
0010Generic Write (WR)
0011Data Read (DRD)
0100Data Write (DWR)
CCCC (Channel)Variesmemory hierarchy캐시/메모리 계층 에러
bus/interconnect버스/인터커넥트 에러
timeout타임아웃 에러
자주 보이는 에러 코드:
  • 0x0011 — L1 캐시 데이터 읽기 에러
  • 0x0019 — L1 캐시 명령어 프리페치 에러
  • 0x00C0 — L2 캐시 에러
  • 0x0150 — 메모리 컨트롤러 에러 (DIMM ECC)
  • 0x0800 — 버스/인터커넥트 에러
/* arch/x86/kernel/cpu/mce/severity.c — 에러 코드 디코딩 */
#define MCESEV(s, m, c...) { .sev = MCE_##s##_SEVERITY, .msg = m, ##c }

static struct severity {
    u64 mask;
    u64 result;
    unsigned char sev;
    unsigned char mcgmask;
    unsigned char mcgres;
    char *msg;
} severities[] = {
    MCESEV(NO, "Invalid",
        SER, BITCLR(MCI_STATUS_VAL)),
    MCESEV(NO, "Not enabled",
        SER, BITCLR(MCI_STATUS_EN)),
    MCESEV(PANIC, "Processor context corrupt",
        BITSET(MCI_STATUS_PCC)),
    /* ... */
};

메모리 관련 에러 코드 상세

메모리 컨트롤러에서 발생하는 에러는 가장 흔한 MCE 원인입니다. 다음은 Intel/AMD 메모리 컨트롤러 뱅크에서 자주 보이는 에러 코드 패턴입니다.

STATUS 하위 16비트에러 분류일반적 원인
0x0001Unclassified분류 불가 내부 에러
0x0010Generic TLB ErrorTLB 패리티/ECC 에러
0x0011L1 Data TLB ReadL1 DTLB 읽기 에러
0x0012L2 Data TLB ReadL2 DTLB 읽기 에러
0x0100Generic Cache L0L0 마이크로-op 캐시 에러 (AMD)
0x0110L1 Cache GenericL1 캐시 일반 에러
0x0111L1 Cache Data ReadL1D 읽기 에러
0x0120L2 Cache GenericL2 캐시 일반 에러
0x0150Memory ControllerDRAM ECC 에러 (가장 흔함)
0x0151Memory ReadDRAM 읽기 ECC 에러
0x0152Memory WriteDRAM 쓰기 에러
0x0800Bus/InterconnectQPI/UPI 링크 에러
0x0C0FL3 Cache GenericLLC 에러
Compound Error Code 16비트 레이아웃 (000F RRRR PP TT LLLL) 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Reserved 000F (항상 0) RRRR (Request) ERR/RD/WR/DRD/DWR/IRD/... PP SRC/RES/OBS/GEN TT (Transaction) I / D / GEN LLLL (Level) L0 / L1 / L2 / LG 디코딩 예제: 0x0134 0x0134 = 0000 0001 0011 0100 → Reserved=0000 RRRR=0001 (RD: Generic Read) PP=00 (SRC) TT=11 (GEN) LLLL=0100 → L2 = "L2 캐시 Generic Read 에러"
에러 코드 디코딩 유틸리티: mcelog --asciiedac-util이 자동으로 에러 코드를 해석해줍니다. 수동 해석이 필요하면 Intel SDM Vol. 3B, Chapter 16 "Machine-Check Architecture"를 참조하세요.

MCE 심각도 분류

커널 함수 mce_severity()는 MCi_STATUS 비트를 분석하여 에러의 심각도를 결정합니다. Intel의 Software Developer's Manual에서 정의한 4가지 등급과 커널의 내부 분류가 있습니다.

Intel MCA Recovery 분류

분류UCSARPCC의미커널 동작
SRAR1110 Software Recoverable Action Required — 즉시 복구 필요 memory_failure() 호출, 프로세스에 SIGBUS
SRAO1100 Software Recoverable Action Optional — 백그라운드 처리 memory_failure() 오프라인, 워크큐에서 처리
UCNA1000 Uncorrected No Action — 정보만 전달 로그 기록, CMCI로 전달
CE0--- Corrected Error — 하드웨어가 자동 교정 로그 기록, CMCI/폴링(Polling)으로 수집
PCC=11--1 Processor Context Corrupt 무조건 패닉 (tolerant=3 제외)
MCE 심각도 결정 트리 MCi_STATUS 읽기 VAL = 1? No → 무시 UC = 1? CE (로그만) No PCC = 1? Yes PANIC Yes S = 1? No UCNA (로그) No AR = 1? Yes SRAR (즉시 복구) Yes SRAO (비동기 복구) No SRAR: 데이터 소비 중 에러 → memory_failure() + SIGBUS | SRAO: 스크러빙 에러 → 페이지 오프라인 UCNA: UC지만 컨텍스트 무관 → CMCI로 보고 | CE: 교정됨 → 통계 기록 (EDAC)
/* arch/x86/kernel/cpu/mce/severity.c */
static int mce_severity_intel(struct mce *m, struct pt_regs *regs,
                               char **msg, bool is_excp)
{
    /* severities[] 테이블을 순회하며 mask/result 매칭 */
    for (struct severity *s = severities;; s++) {
        if ((m->status & s->mask) != s->result)
            continue;
        if ((m->mcgstatus & s->mcgmask) != s->mcgres)
            continue;
        *msg = s->msg;
        return s->sev;
    }
}

커널 MCE 진입 경로

MCE가 발생하면 CPU는 IDT의 벡터 18 핸들러로 점프합니다. 리눅스 커널 6.x에서의 진입 경로는 어셈블리(Assembly) 엔트리 포인트에서 시작하여 C 핸들러까지 이어집니다.

MCE 하드웨어 → 커널 핸들러 흐름 HW 에러 감지 MCA 뱅크 기록 CPU #MC 생성 벡터 18, IST 3 asm_exc_machine_check SAVE_ALL, IST 스택 exc_machine_check nmi_enter() 호출 do_machine_check 핵심 로직 IST 3 스택 전환 상세 1. CPU가 TSS.IST3 포인터를 로드 → 전용 스택으로 RSP 전환 2. 이전 SS/RSP/RFLAGS/CS/RIP를 IST 스택에 푸시 → 커널 모드 진입 CR4.MCE = 0이면? MCE가 pending 상태에서 CR4.MCE=0이면 → #MC가 아닌 shutdown → triple fault → CPU 리셋 따라서 커널은 부팅 초기에 반드시 CR4.MCE=1을 설정합니다 (mcheck_cpu_init).
/* arch/x86/kernel/cpu/mce/core.c */
DEFINE_IDTENTRY_MCE(exc_machine_check)
{
    /* MCE 핸들러는 NMI-like 컨텍스트에서 실행 */
    if (user_mode(regs))
        nmi_enter();

    do_machine_check(regs);

    if (user_mode(regs))
        nmi_exit();
}

/* IST 3 설정: arch/x86/kernel/idt.c */
static const __initconst struct idt_data def_idts[] = {
    /* ... */
    ISTG(X86_TRAP_MC, asm_exc_machine_check, IST_INDEX_MCE),  /* IST 3 */
};
제약사항: MCE 핸들러 내에서는 printk()도 안전하지 않을 수 있습니다. CPU 상태가 손상되었을 수 있으므로, 최소한의 작업(MSR 읽기, 구조체(Struct) 기록)만 수행하고, 상세 처리는 뒤로 미룹니다.

do_machine_check() 처리 흐름

do_machine_check()는 MCE의 핵심 처리 함수입니다. 멀티 CPU 환경에서 여러 코어가 동시에 MCE를 받을 수 있으므로, Monarch 랑데부 프로토콜로 동기화한 뒤 한 CPU가 최종 결정을 내립니다.

do_machine_check() 멀티 CPU 흐름 CPU 0 CPU 1 CPU N Phase 1: mce_start() — Monarch 선출 atomic_inc(&mce_callin) → 첫 번째 CPU가 Monarch mce_callin 배리어 (타임아웃 대기) 뱅크 스캔 severity 뱅크 스캔 severity 뱅크 스캔 severity Phase 2: 각 CPU가 자기 뱅크 스캔 machine_check_poll() / 뱅크별 STATUS 읽기 mce_end() 배리어 Monarch (CPU 0): mce_reign() worst severity 수집 → 최종 판정 Phase 3: mce_reign() — 최종 의사결정 PANIC → mce_panic() SRAR → memory_failure() + kill_me_now/later mce_log() → Notifier Chain → 유저스페이스 /dev/mcelog, perf, rasdaemon Phase 4: 결과 전파 x86_mce_decoder_chain 순회 → EDAC/mcelog 통지 MCi_STATUS = 0 쓰기 (에러 ACK) Phase 5: 에러 클리어 후 정상 실행 재개 MCG_STATUS.MCIP=0 → 다음 MCE 수신 가능
/* arch/x86/kernel/cpu/mce/core.c — 핵심 흐름 */
noinstr void do_machine_check(struct pt_regs *regs)
{
    int worst = MCE_NO_SEVERITY;
    int order, no_way_out;

    /* Phase 1: Monarch 선출 및 랑데부 */
    order = mce_start(&no_way_out);

    /* Phase 2: 자신의 MCA 뱅크 스캔 */
    for (i = 0; i < num_banks; i++) {
        rdmsrl(MSR_IA32_MCx_STATUS(i), m.status);
        if (!(m.status & MCI_STATUS_VAL))
            continue;
        severity = mce_severity(&m, regs, &msg, true);
        if (severity > worst)
            worst = severity;
        mce_log(&m);  /* 링 버퍼에 기록 */
    }

    /* Phase 3: Monarch가 최종 결정 */
    if (order == 1)  /* Monarch */
        mce_reign();   /* worst severity 수집 → panic/recover */

    /* Phase 4: 랑데부 완료 */
    mce_end(order);

    /* Phase 5: 에러 클리어 */
    for (i = 0; i < num_banks; i++)
        wrmsrl(MSR_IA32_MCx_STATUS(i), 0);
}

Monarch 메커니즘

MCE는 일반적으로 모든 CPU에 동시에 브로드캐스트됩니다(LMCE 제외). 여러 CPU가 동시에 핸들러를 실행하면 의사결정이 분산되어 일관성을 잃을 수 있으므로, Monarch(군주) 프로토콜로 하나의 CPU가 최종 결정권을 갖습니다.

Monarch 선출 규칙

  1. mce_start()에서 atomic_inc_return(&mce_callin)을 호출
  2. 리턴 값이 1인 CPU가 Monarch (가장 먼저 도착한 CPU)
  3. 나머지 CPU(Subject)는 Monarch의 결정을 대기
  4. Monarch는 모든 Subject가 mce_callin에 도달하거나 타임아웃까지 대기

tolerant 레벨

/sys/devices/system/machinecheck/machinecheck0/tolerant 설정으로 MCE 대응 수준을 조절합니다.

레벨동작용도
0모든 MCE에서 즉시 패닉안전 최우선 환경 (의료/항공)
1 (기본값)PCC가 아니면 복구 시도, PCC → 패닉일반 서버/데스크톱
2RIPV가 없어도 복구 시도고가용성 서버
3MCE를 최대한 무시 (디버그용)테스트/개발 전용
tolerant=3 주의: 프로덕션에서 절대 사용하지 마세요. PCC=1인 MCE도 무시하면 데이터 손상이 발생할 수 있습니다. 이 설정은 MCE 주입 테스트 시에만 사용합니다.

mce_panic()의 결정 시점

/* arch/x86/kernel/cpu/mce/core.c */
static void mce_reign(void)
{
    int global_worst = MCE_NO_SEVERITY;

    /* 모든 CPU의 worst severity 수집 */
    for_each_possible_cpu(cpu) {
        int severity = per_cpu(mce_worst_severity, cpu);
        if (severity > global_worst)
            global_worst = severity;
    }

    if (global_worst >= MCE_PANIC_SEVERITY) {
        mce_panic("Fatal machine check", &m, msg);
        /* 여기서 리턴하지 않음 */
    }
    /* PANIC이 아니면 복구 경로로 진행 */
}

Monarch 타임아웃

Monarch는 Subject CPU의 도착을 monarch_timeout(기본 ~500us, CPU마다 조정)까지 대기합니다. 타임아웃이 발생하면 Monarch는 도착한 CPU 정보만으로 결정을 내립니다. 이는 MCE 자체가 일부 CPU를 무응답 상태로 만들었을 수 있기 때문입니다.

MCG_STATUS.MCIP 비트

MCG_STATUS의 MCIP(Machine Check In Progress) 비트는 MCE 핸들러가 실행 중임을 나타냅니다. 이 비트가 1인 상태에서 새로운 MCE가 발생하면 CPU는 shutdown 상태에 들어갑니다(triple fault). 따라서 커널은 MCE 핸들러 완료 시 반드시 MCG_STATUS.MCIP = 0으로 클리어해야 합니다.

/* MCE 핸들러 완료 시 MCIP 클리어 */
static void mce_wrmsrl(u32 msr, u64 v)
{
    if (msr == MSR_IA32_MCG_STATUS) {
        v &= ~MCG_STATUS_MCIP;  /* MCIP 클리어 → 다음 MCE 수신 가능 */
    }
    wrmsrl(msr, v);
}

Monarch와 가상화(Virtualization)

KVM 가상화 환경에서 MCE가 발생하면, 하이퍼바이저(Hypervisor)가 먼저 MCE를 가로챕니다(VMEXIT). 호스트 커널의 Monarch가 에러를 분석한 후, 게스트에 영향이 있으면 게스트에 가상 MCE를 주입합니다. LMCE 지원 시 게스트 vCPU에만 MCE를 전달하여 다른 vCPU의 VMEXIT를 방지합니다.

Monarch 상태 머신

Monarch 프로토콜은 명확한 상태 전이를 통해 진행됩니다. 모든 CPU가 MCE를 수신하면 mce_start()에서 동기화 배리어를 형성하고, Monarch CPU(가장 낮은 번호)가 최종 결정을 내립니다.

Monarch 프로토콜 상태 머신 IDLE MCE_RECEIVED #MC mce_start() CALLIN_BARRIER timeout or all arrived BANK_SCAN mce_end() CALLOUT_BARRIER Monarch: mce_reign() DECISION PANIC RECOVER LOG Monarch CPU = 가장 낮은 번호 CPU 최종 결정권 보유 Subject CPUs 배리어에서 대기
/* arch/x86/kernel/cpu/mce/core.c — mce_start() 내부 로직 */
static int mce_start(int *no_way_out)
{
    int order;
    int cpus = num_online_cpus();
    u64 timeout = (u64)mca_cfg.monarch_timeout * NSEC_PER_USEC;

    if (!timeout)
        return -1;  /* Monarch 비활성화 → 독립 처리 */

    /* 1단계: CALLIN — 모든 CPU가 도착을 알림 */
    atomic_add(*no_way_out, &global_nwo);
    order = atomic_inc_return(&mce_callin);  /* 도착 순서 기록 */

    /* 2단계: CALLIN 배리어 — 모든 CPU 도착 대기 */
    mce_barrier_enter(&mce_callin_barrier, timeout);

    /* order == 1인 CPU가 Monarch (첫 번째 도착) */
    if (order == 1) {
        /* Monarch: 글로벌 상태 초기화 */
        atomic_set(&global_nwo, 0);
        atomic_set(&mce_executing, 0);
    }

    /* 타임아웃 처리: 일부 CPU 미도착 시 도착한 CPU만으로 진행 */
    if (atomic_read(&mce_callin) != cpus) {
        mce_timed_out(&timeout,
            "Not all CPUs arrived at MCE rendezvous\n");
    }

    return order;
}

Monarch 결정 매트릭스

Monarch CPU는 mce_reign()에서 수집된 모든 MCE 정보를 종합하여 global_worst 심각도와 시스템 설정에 따라 최종 조치를 결정합니다.

global_worst 심각도 RIPV 비트 tolerant 레벨 최종 조치
MCE_PANIC_SEVERITY 무관 0, 1, 2 PANICmce_panic() 호출, 시스템 즉시 정지
MCE_PANIC_SEVERITY 무관 3 LOG — tolerant=3이면 패닉 억제, 로그만 기록
MCE_AR_SEVERITY 1 (유효) 0, 1 RECOVERmemory_failure()로 페이지 오프라인, 프로세스에 SIGBUS
MCE_AR_SEVERITY 0 (무효) 0 PANIC — 복귀 지점 없음, 복구 불가
MCE_AR_SEVERITY 0 (무효) 1, 2 RECOVER — 최선 노력(best-effort) 복구 시도
MCE_UC_SEVERITY 1 0, 1, 2 RECOVER — 비동기 UCE, 페이지 오프라인 후 계속
MCE_UC_SEVERITY 0 0 PANIC — 복귀 불가 + 엄격 모드
MCE_DEFERRED_SEVERITY 무관 무관 LOG — 지연(Latency) 처리, 나중에 소프트웨어 접근 시 처리
MCE_KEEP_SEVERITY 무관 무관 LOG — 정보성 기록, 조치 불필요
MCE_NO_SEVERITY 무관 무관 무시 — 오류 아님 (spurious MCE)
tolerant 레벨 설명: /sys/devices/system/machinecheck/machinecheck0/tolerant 값에 따라 0 = 최대한 엄격(패닉 우선), 1 = 기본값(복구 가능하면 시도), 2 = 관대(패닉 회피 노력), 3 = 패닉 완전 억제(디버깅(Debugging) 전용)로 동작합니다.

MCE와 CPU 핫플러그(Hotplug)

CPU 핫플러그 도중 MCE가 발생하면 특수한 상황이 발생합니다. 오프라인 상태이거나 핫플러그 진행 중인 CPU는 Monarch 랑데부에서 제외되어야 합니다.

커널은 다음과 같은 메커니즘으로 이 문제를 처리합니다:

/* arch/x86/kernel/cpu/mce/core.c — CPU 핫플러그 콜백 */
static int mce_cpu_online(unsigned int cpu)
{
    struct timer_list *t = this_cpu_ptr(&mce_timer);

    mce_device_create(cpu);       /* sysfs 노드 생성 */
    mce_threshold_create_device(cpu);
    mce_reenable_cpu();           /* MCE 뱅크 재활성화 */
    mce_start_timer(t);          /* 폴링 타이머 시작 */
    return 0;
}

static int mce_cpu_dead(unsigned int cpu)
{
    mce_threshold_remove_device(cpu);
    mce_device_remove(cpu);       /* sysfs 노드 제거 */
    return 0;
    /* 이후 이 CPU는 #MC를 수신하지 않음 → Monarch 랑데부 제외 */
}

MCE Notifier Chain과 복구

MCE 처리 파이프라인 MCA 뱅크 스캔 MCi_STATUS 읽기 mce_log() 링 버퍼 기록 x86_mce_decoder_chain blocking_notifier_call_chain 복구 동작 memory_failure() → HWPoison kill_me_now/later → SIGBUS /dev/mcelog (레거시 인터페이스) perf_event (PERF_TYPE_HW_CACHE) trace_mce_record (ftrace tracepoint) EDAC (DIMM 위치 디코드) SRAR 복구 경로 상세 MCE in #PF context → memory_failure(pfn, MF_ACTION_REQUIRED) → 페이지 unmmap → SIGBUS(BUS_MCEERR_AR) → 프로세스 종료

Notifier Chain 등록 우선순위(Priority)

우선순위등록자역할
MCE_PRIO_FIRSTmce_default_notifierdmesg 출력 (기본 디코더)
MCE_PRIO_MCELOGdev_mcelog/dev/mcelog 인터페이스
MCE_PRIO_EDACEDAC 드라이버DIMM 위치 디코딩
MCE_PRIO_NFITNVDIMM/NFITNVDIMM ARS
MCE_PRIO_CECCorrected Error CollectorCE 누적 추적

kill_me_now vs kill_me_later

SRAR 에러에서 커널은 두 가지 킬 전략을 사용합니다.

/* memory_failure_queue() — 비동기 처리 큐 */
void memory_failure_queue(unsigned long pfn, int flags)
{
    struct memory_failure_entry entry = {
        .pfn = pfn,
        .flags = flags,
    };
    kfifo_put(&mf_cpu->fifo, entry);
    schedule_work_on(smp_processor_id(), &mf_cpu->work);
}

MCE 링 버퍼(Ring Buffer) 구조

커널은 MCE 이벤트를 순환(circular) 링 버퍼에 기록합니다. 이 버퍼(Buffer)는 프로듀서-컨슈머 모델로 동작하며, NMI 컨텍스트에서도 안전하게 쓸 수 있도록 설계되어 있습니다.

MCE 링 버퍼 (struct mce_log) mce_log.entry[MCE_LOG_LEN=32] [0] [1] [2] ... [next] ... [31] next (write) 오버플로우 시 MCE_OVERFLOW 비트 설정, 최신 덮어쓰기 Producer do_machine_check() → mce_log() NMI 컨텍스트 /dev/mcelog read() 레거시 유저스페이스 trace_mce_record ftrace/perf 이벤트 mce_decoder_chain EDAC 등 디코더 Consumers 기록 흐름 1. mce_log(): entry[next] = mce → wmb() → next++ (atomic) 2. next >= MCE_LOG_LEN → overflow 비트 설정, next를 0으로 랩어라운드 3. mce_notify_irq() → wake_up_interruptible() → /dev/mcelog 폴 대기 해제

MCE 이벤트 필터링

perf를 사용하면 MCE 이벤트를 실시간(Real-time)으로 캡처하고 디코딩할 수 있습니다. mce:mce_record 트레이스포인트는 모든 MCE 로깅 경로에서 호출됩니다.

# MCE 트레이스 이벤트 캡처
$ perf record -e mce:mce_record -a --overwrite # 시스템 전체 기록

# 기록된 MCE 이벤트 디코딩
$ perf script
  mcelog  3421 [002] 1842.553291: mce:mce_record: \
    CPU: 2, MCGc: 0x0, MCGi: 0xf10, \
    Bank: 9, MCi: 0xbd80000000100134, \
    Addr: 0x3a7f8c000, MISC: 0x8c, severity: CE

# 특정 뱅크만 필터링 (Bank 9 = Memory Controller)
$ perf record -e mce:mce_record --filter 'bank == 9' -a

# ftrace로 직접 캡처 (perf 없이)
$ echo 1 > /sys/kernel/debug/tracing/events/mce/mce_record/enable
$ cat /sys/kernel/debug/tracing/trace_pipe

rasdaemon은 이러한 트레이스 이벤트를 SQLite DB에 저장하여 장기간 CE 추적과 페이지별 오류 통계를 제공합니다. 레거시 mcelog 데몬은 /dev/mcelog에서 직접 읽는 방식이며, 최신 커널에서는 rasdaemon 사용이 권장됩니다.

# rasdaemon으로 MCE 이력 조회
$ ras-mc-ctl --errors
# Label  CE count  UE count  Last error
# DIMM0  47        0         2026-03-15 14:23:01 Bank 9 CE
# DIMM1  0         0         —
# DIMM2  3         1         2026-03-14 09:11:44 Bank 9 UCE

# 페이지별 CE 누적 카운트 (메모리 교체 판단 기준)
$ ras-mc-ctl --error-count
# mc0: csrow0: ch0: 47 CEs, ch1: 0 CEs

# SQLite DB 직접 쿼리
$ sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
    "SELECT timestamp, err_type, mc_location FROM mce_record \
     WHERE mcgstatus LIKE '%MCIP%' ORDER BY id DESC LIMIT 10;"

memory_failure()와 HWPoison

memory_failure()는 물리 메모리(Physical Memory) 페이지의 하드웨어 오류를 처리하는 핵심 함수입니다. 커널은 해당 페이지를 HWPoison으로 마킹하고, 페이지 유형에 따라 적절한 복구 조치를 수행합니다.

HWPoison 처리 흐름 MCE 발생 memory_failure(pfn) SetPageHWPoison 페이지 유형 판별 page_action[] Clean Page Cache truncate/invalidate Dirty Page Cache 데이터 손실 가능 Anonymous Page SIGBUS 전송 Huge Page split → 개별 처리 커널 페이지 복구 불가 → panic 페이지 오프라인 (buddy allocator에서 제거) Early Kill vs Late Kill 정책 vm.memory_failure_early_kill = 1 → 매핑한 모든 프로세스 즉시 SIGBUS vm.memory_failure_early_kill = 0 → 접근 시점에 SIGBUS (Late Kill) soft_offline_page() — CE 예방 오프라인 CE가 누적되는 페이지를 선제적으로 오프라인 내용을 새 페이지로 마이그레이션 → 기존 페이지 격리
/* mm/memory-failure.c — 핵심 함수 */
int memory_failure(unsigned long pfn, int flags)
{
    struct page *p = pfn_to_page(pfn);

    /* 1. HWPoison 마킹 */
    SetPageHWPoison(p);

    /* 2. 페이지 잠금 및 참조 획득 */
    shake_page(p);  /* LRU에서 제거 시도 */

    /* 3. 페이지 유형에 따른 처리 */
    if (PageHuge(p))
        return memory_failure_hugetlb(pfn, p, flags);

    if (!PageLRU(p))
        return identify_page_state(pfn, p, flags);  /* 커널 페이지 등 */

    /* 4. 프로세스에 SIGBUS 전송 */
    collect_procs(p, &tokill);  /* 매핑한 프로세스 목록 */
    kill_procs(&tokill, flags & MF_ACTION_REQUIRED, pfn, flags);

    /* 5. 페이지 오프라인 */
    page_action(ps, p, pfn);
    return 0;
}
HWPoison 확인: /proc/kpageflags의 bit 19(HWPOISON)로 특정 페이지의 HWPoison 상태를 확인할 수 있습니다. page-types -l -b hwpoison 도구도 유용합니다.

page_action[] 타입별 처리 상세

memory_failure()는 오류 페이지의 유형을 판별한 뒤 page_action[] 배열에서 해당 타입의 핸들러를 호출합니다. 커널 소스(mm/memory-failure.c)의 error_states[] 배열이 이 매핑을 정의하며, 각 페이지 상태에 따라 복구 가능 여부와 처리 방식이 크게 달라집니다.

타입 (enum)대상 페이지핸들러 함수동작결과
me_kernel 커널이 직접 사용 중인 페이지 (slab, page table 등) me_kernel() 복구 불가 — 즉시 panic() 또는 프로세스 kill MF_FAILED
me_unknown 유형 판별 불가 페이지 me_unknown() 보수적 처리: 오프라인 시도, 실패 시 무시 MF_IGNORED / MF_FAILED
me_pagecache_clean 깨끗한 페이지 캐시 (디스크와 동기화됨) me_pagecache_clean() truncate_error_page()로 페이지 무효화(Invalidation) — 다음 접근 시 디스크에서 재로드 MF_RECOVERED
me_pagecache_dirty 더티 페이지 캐시 (아직 디스크에 미기록) me_pagecache_dirty() 매핑 프로세스에 SIGBUS, 페이지 무효화 — 데이터 손실 가능 MF_RECOVERED (일부 데이터 유실)
me_swapcache_clean 스왑(Swap) 캐시 (스왑 영역(Swap Area)과 동기화됨) me_swapcache_clean() 스왑 슬롯 해제, 페이지 삭제 — 스왑에서 재로드 가능 MF_RECOVERED
me_swapcache_dirty 더티 스왑 캐시 (수정 후 미기록) me_swapcache_dirty() 스왑 슬롯 무효화, 매핑 프로세스에 SIGBUS — 복구 불가능한 데이터 MF_DELAYED (접근 시 kill)
me_huge_page Huge page (2 MB / 1 GB) me_huge_page() split_huge_page() 호출 → 4 KB 서브페이지로 분리 후 해당 페이지만 재처리 재귀 호출
me_free buddy allocator의 프리 페이지 me_free() dissolve_free_huge_page() + buddy에서 영구 제거 — 프로세스 영향 없음 MF_RECOVERED
/* mm/memory-failure.c — error_states[] 배열 (커널 6.x 기준 간략화) */
static struct page_state error_states[] = {
    { 0,              0,         "free buddy",      me_free       },
    { slab,           slab,       "kernel slab",     me_kernel     },
    { head,           head,       "huge page",       me_huge_page  },
    { sc|dirty,       sc|dirty,   "swapcache dirty", me_swapcache_dirty },
    { sc,             sc,         "swapcache clean", me_swapcache_clean },
    { mlock|dirty,    dirty,      "dirty mlocked",   me_pagecache_dirty },
    { mlock,          mlock,      "clean mlocked",   me_pagecache_clean },
    { lru|dirty,      dirty,      "dirty LRU",       me_pagecache_dirty },
    { lru,            lru,        "clean LRU",       me_pagecache_clean },
    { 0,              0,         "unknown page",    me_unknown    },
};
처리 우선순위: error_states[] 배열은 위에서 아래로 순서대로 검사됩니다. 첫 번째 매칭되는 엔트리의 핸들러가 호출되므로, 커널 슬랩 페이지는 항상 LRU 페이지보다 먼저 검사되어 적절한 처리(panic 또는 slab 격리(Isolation))를 보장합니다.

ECC 유형과 MCE 관계

서버 메모리에서 사용되는 ECC(Error Correcting Code) 수준에 따라 MCE의 CE(Corrected Error)와 UC(Uncorrected Error) 발생 패턴이 달라집니다. ECC가 강력할수록 더 많은 비트 오류를 CE로 교정하여 UC 발생을 줄입니다.

ECC 계층 구조와 MCE 이벤트 매핑 On-die ECC (DDR5 내장) DRAM 칩 내부에서 단일 비트 오류 교정 호스트에 투명 — MCE 미생성 특징 DDR5 필수 기능, 128b 데이터에 8b ECC DRAM 내부 수정 → 메모리 컨트롤러 도달 전 해결 SECDED (Single Error Correct, Double Detect) 1비트 오류 → CE (교정), 2비트 오류 → UC (감지만) 가장 일반적인 서버 ECC (ECC DIMM) 1비트 → CE MCE CMCI / 폴링으로 수집 2비트 → UC MCE memory_failure() 호출 Chipkill / AMD SSDD DRAM 칩 1개 전체 장애도 교정 가능 심볼 기반 Reed-Solomon — x4/x8 칩에서 동작 단일 칩 장애 → CE (전체 교정) 2개 칩 동시 장애 → UC (SECDED 대비 UC 빈도 대폭 감소) AMD의 경우 MCi_SYND에 신드롬 비트 기록 Intel ADDDC Adaptive Double DRAM Device Correction 장애 칩을 스페어 영역으로 리맵핑하여 2칩 교정 2칩 장애까지 CE로 교정 Sapphire Rapids+에서 지원, iMC가 자동 뱅크 스페어링 수행 ADDDC 이벤트는 MCA Bank 13-20 (M2M/iMC)에서 보고 ECC 강도 증가 → CE 교정 범위 확대 → UC MCE 발생률 감소 → 시스템 가용성 향상
ECC 레벨 확인: edac-util -s 또는 /sys/devices/system/edac/mc/mc*/에서 메모리 컨트롤러의 ECC 모드를 확인할 수 있습니다. edac_mode 파일에 S4ECD4ED(Chipkill), S8ECD8ED, SECDED 등이 표시됩니다.

MCi_MISC 비트 필드 상세

MCi_MISC 레지스터는 오류 주소의 해석 방법과 복구 가능 주소의 정밀도를 알려줍니다. 특히 UCR(Uncorrected Recoverable) 에러에서 memory_failure()에 전달할 물리 주소(Physical Address)의 유효 범위를 결정하는 데 핵심적인 역할을 합니다.

비트 범위필드 이름설명
[63:57] 예약 미사용 (0)
[56] Overflow (OVF) 추가 에러 정보 오버플로 여부
[55:44] 모델 의존 CPU 모델별 추가 정보 (ECC 신드롬, 칩 번호 등)
[43:40] 예약 미사용 (0)
[39:32] 모델 의존 CPU별 추가 에러 정보
[8:6] Address Mode MCi_ADDR의 주소 해석 방식:
  • 000 — 세그먼트 오프셋(Offset)
  • 001 — 리니어 주소 (가상)
  • 010물리 주소 (가장 일반적)
  • 011 — 메모리 주소 오프셋 (Generics)
  • 111 — 제네릭 (아키텍처별)
[5:0] Recoverable Addr LSB 주소의 유효 최하위 비트 위치. 예: 값이 12이면 4 KB(페이지) 단위 정밀도, 값이 6이면 64 B(캐시라인) 단위 정밀도
/* arch/x86/kernel/cpu/mce/severity.c — MISC 비트 해석 */
#define MCI_MISC_ADDR_LSB(m)    ((m) & 0x3f)        /* bits [5:0]  */
#define MCI_MISC_ADDR_MODE(m)   (((m) >> 6) & 7)  /* bits [8:6]  */
#define MCI_MISC_ADDR_PHYS      2                    /* 물리 주소 모드 */

/* UCR 에러에서 PFN 추출 시 LSB를 확인 */
if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
    return;  /* 물리 주소가 아니면 memory_failure 호출 불가 */

int lsb = MCI_MISC_ADDR_LSB(m->misc);
if (lsb > PAGE_SHIFT)
    lsb = PAGE_SHIFT;  /* 페이지 단위로 클램프 */

MCi_ADDR 주소 해석

MCi_ADDR 레지스터에 기록된 주소는 MCi_MISC의 Address Mode에 따라 해석 방법이 다릅니다. 대부분의 메모리 에러에서는 물리 주소 모드(010)가 사용되며, 커널은 이 주소에서 PFN(Page Frame Number)을 추출하여 memory_failure()에 전달합니다.

단계연산설명
1. Address Mode 확인 MCi_MISC[8:6] == 010 물리 주소 모드인지 검증 — 다른 모드면 PFN 추출 불가
2. LSB 마스킹 addr &= ~((1UL << lsb) - 1) MCi_MISC[5:0]이 가리키는 LSB 이하 비트를 0으로 클리어
3. PFN 추출 pfn = addr >> PAGE_SHIFT 물리 주소를 12비트 시프트하여 페이지 프레임(Page Frame) 번호 산출
4. memory_failure 호출 memory_failure(pfn, flags) 해당 PFN의 페이지를 HWPoison으로 마킹하고 복구 처리
5. DIMM 매핑 (EDAC) edac_mc_handle_error() 물리 주소 → DIMM 슬롯/채널/랭크/뱅크/로우 매핑 (address decoder)
/* arch/x86/kernel/cpu/mce/core.c — MCi_ADDR에서 PFN 추출 */
static void mce_log_and_process(struct mce *m)
{
    unsigned long pfn;
    int lsb;

    /* 물리 주소 모드가 아니면 복구 불가 */
    if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
        return;

    /* 유효 비트 하한 */
    lsb = MCI_MISC_ADDR_LSB(m->misc);
    if (lsb > PAGE_SHIFT)
        lsb = PAGE_SHIFT;

    /* PFN 추출: 하위 비트 마스크 후 페이지 시프트 */
    pfn = (m->addr >> PAGE_SHIFT) &
          (((1UL << (46 - PAGE_SHIFT)) - 1));

    /* memory_failure 호출 (MF_ACTION_REQUIRED는 SRAR 에러에서 설정) */
    memory_failure(pfn, m->mcgstatus & MCG_STATUS_RIPV ?
                   MF_ACTION_REQUIRED : 0);
}

/* EDAC에서 물리 주소 → DIMM 위치 디코딩 (drivers/edac/skx_common.c) */
static int skx_decode_addr(u64 addr, struct decoded_addr *res)
{
    /* System Address → Socket → iMC → Channel → DIMM → Rank → Bank → Row/Col */
    res->socket  = skx_sad_decode(addr);
    res->imc     = skx_tad_decode(addr);
    res->channel = skx_channel_decode(addr);
    res->dimm    = skx_dimm_decode(addr);
    return 0;
}
EDAC DIMM 매핑: /sys/devices/system/edac/mc/mc*/dimm*/dimm_label에서 DIMM 물리 슬롯 이름을 확인하고, edac-util -l로 전체 매핑을 조회합니다. mcelog --dmi는 DMI/SMBIOS 테이블을 사용하여 주소를 DIMM 슬롯으로 변환합니다.

CMCI (Corrected MCE Interrupt)

CMCI(Corrected Machine Check Error Interrupt)는 교정된 에러(CE)를 효율적으로 수집하는 메커니즘입니다. 전통적인 MCE 폴링은 주기적으로 MSR을 읽어야 했지만, CMCI는 CE가 임계값에 도달하면 인터럽트를 발생시켜 즉시 알려줍니다.

CMCI 라이프사이클과 스톰 처리 정상 모드: CMCI 인터럽트 CE 발생 카운터 증가 임계값 도달 → CMCI IRQ MCi_CTL2.CMCI_EN=1, Threshold=N 스톰 모드: 폴링 전환 CMCI 폭주 cmci_storm _begin() 폴링 모드 전환 CMCI_EN=0 → timer로 주기적 폴링 스톰 복구: cmci_storm_end() 폴링 주기 동안 CE 빈도 감소 → CMCI 재활성화 (CMCI_EN=1) t=0: CE 시작 CMCI 인터럽트 스톰 감지 → 폴링 CE 감소 → CMCI 복구

CMCI vs 폴링 비교

특성CMCI폴링
지연 시간즉시 (인터럽트)check_interval 주기 (기본 5분)
CPU 오버헤드(Overhead)낮음 (이벤트 기반)주기적 MSR 읽기
스톰 대응자동 폴링 전환해당 없음
지원 CPUIntel Xeon 5500+ / AMD Zen+모든 MCA 지원 CPU
/* arch/x86/kernel/cpu/mce/intel.c */
static void cmci_storm_begin(int bank)
{
    __clear_bit(bank, this_cpu_ptr(mce_poll_banks));
    cmci_toggle_interrupt_mode(false);  /* CMCI_EN = 0 */
    /* 폴링 타이머 활성화 */
    mce_timer_kick(CMCI_STORM_INTERVAL);
}

static void cmci_storm_end(int bank)
{
    cmci_toggle_interrupt_mode(true);   /* CMCI_EN = 1 복원 */
    mce_timer_kick(CMCI_POLL_INTERVAL);
}

CMCI 임계값 설정

MCi_CTL2 레지스터의 bits [14:0]이 CMCI 임계값을 결정합니다. CE가 이 값에 도달하면 CMCI 인터럽트가 발생합니다. 커널은 기본적으로 임계값을 1로 설정하여 첫 번째 CE부터 즉시 인터럽트를 받습니다.

/* arch/x86/kernel/cpu/mce/intel.c — CMCI 임계값 설정 */
static void cmci_set_threshold(int bank, int thresh)
{
    u64 val;

    rdmsrl(MSR_IA32_MCx_CTL2(bank), val);
    val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK;
    val |= (u64)thresh & MCI_CTL2_CMCI_THRESHOLD_MASK;
    val |= MCI_CTL2_CMCI_EN;    /* bit 30: CMCI 활성화 */
    wrmsrl(MSR_IA32_MCx_CTL2(bank), val);
}

Corrected Error Collector (CEC)

Intel CPU에서 커널은 CEC(Corrected Error Collector)를 사용하여 CE가 반복되는 물리 페이지를 추적합니다. 동일 페이지에서 CE가 임계값을 초과하면 soft_offline_page()를 호출하여 예방적으로 오프라인합니다.

/* arch/x86/kernel/cpu/mce/intel.c — CEC */
static int cec_add_elem(u64 pfn)
{
    /* pfn을 decay table에 삽입 */
    /* 동일 pfn의 카운트가 action_threshold 초과 시: */
    if (count >= action_threshold) {
        /* 페이지 예방 오프라인 */
        soft_offline_page(pfn_to_page(pfn), MF_SOFT_OFFLINE);
        return 1;
    }
    return 0;
}
CEC decay: CEC는 시간이 지나면 카운터를 감쇠(decay)시킵니다. 일시적 CE(cosmic ray 등)는 자연스럽게 사라지고, 지속적인 CE만 임계값을 초과하여 오프라인됩니다. /sys/kernel/debug/cec/decay_interval로 감쇠 주기를 조정할 수 있습니다.

AMD Scalable MCA (SMCA)

AMD는 Zen 아키텍처부터 Scalable MCA(SMCA)를 도입하여 기존 MCA의 한계를 극복했습니다. SMCA는 뱅크별로 하드웨어 유닛을 동적으로 식별할 수 있어, 마이크로아키텍처 변경에 유연하게 대응합니다.

SMCA vs 기존 MCA

특성기존 MCA (Intel/레거시 AMD)AMD SMCA
뱅크 식별모델별 고정 매핑 (매뉴얼 참조)IPID 레지스터로 동적 식별
에러 코드표준 MCA 코드확장 코드 + SYND (Syndrome)
추가 레지스터CTL/STATUS/ADDR/MISC+ IPID, SYND, DESTAT, DEADDR
인스턴스뱅크 번호 = 유닛HWID/MCATYPE으로 유닛+인스턴스

SMCA 추가 레지스터

레지스터MSR 오프셋내용
MCi_IPID+5Hardware ID(HWID) + MCA Type → 유닛 식별
MCi_SYND+6Syndrome — ECC 신드롬, 에러 비트 위치
MCi_DESTAT+8Deferred Error Status
MCi_DEADDR+9Deferred Error Address
/* arch/x86/kernel/cpu/mce/amd.c — SMCA 뱅크 타입 결정 */
enum smca_bank_types smca_get_bank_type(unsigned int cpu, unsigned int bank)
{
    struct smca_bank *b;

    if (bank >= MAX_NR_BANKS)
        return N_SMCA_BANK_TYPES;

    b = &smca_banks[bank];
    if (!b->hwid)
        return N_SMCA_BANK_TYPES;

    return b->hwid->bank_type;  /* SMCA_LS, SMCA_IF, SMCA_L2, SMCA_DE, ... */
}

/* SMCA 하드웨어 유닛 목록 */
static const struct smca_hwid smca_hwid_mcatypes[] = {
    { SMCA_LS,      HWID_MCATYPE(0xB0, 0x0) },  /* Load Store */
    { SMCA_LS_V2,   HWID_MCATYPE(0xB0, 0x10) }, /* Load Store V2 */
    { SMCA_IF,      HWID_MCATYPE(0xB1, 0x0) },  /* Instruction Fetch */
    { SMCA_L2_CACHE, HWID_MCATYPE(0xB2, 0x0) }, /* L2 Cache */
    { SMCA_DE,      HWID_MCATYPE(0xB3, 0x0) },  /* Decode Unit */
    { SMCA_EX,      HWID_MCATYPE(0xB6, 0x0) },  /* Execution Unit */
    { SMCA_FP,      HWID_MCATYPE(0xB7, 0x0) },  /* Floating Point */
    { SMCA_UMC,     HWID_MCATYPE(0x96, 0x0) },  /* Unified Memory Controller */
    /* ... */
};
SMCA 디코딩: rasdaemon은 SMCA의 IPID를 자동으로 디코딩하여 "Load Store Unit" 같은 사람이 읽을 수 있는 이름을 출력합니다. 커널 로그에서는 Scalable MCA: ... IPID: ... 형태로 출력됩니다.
AMD SMCA vs Intel MCA 뱅크 구조 비교 Intel 전통 MCA (고정 뱅크 매핑) Bank 0: IFU Bank 1: DCU Bank 2: DTLB Bank 3: MLC Bank 4: PCU Bank 5-8: UPI/IIO Bank 9-12: M2M Bank 13-20: iMC 문제: 뱅크 번호가 CPU 모델마다 다름 매뉴얼 참조 없이는 Bank 5가 무엇인지 알 수 없음 레지스터 (뱅크당 4개) MCi_CTL MCi_STATUS MCi_ADDR MCi_MISC AMD SMCA (동적 IPID 기반) MCi_IPID 레지스터 HWID (하드웨어 유닛 식별) + MCATYPE (에러 타입) 뱅크 번호 고정 불필요, 런타임 식별 HWID: 0xB0 → LS Unit HWID: 0x96 → UMC HWID: 0xB2 → L2 Cache HWID: 0x2E → NBIO 장점: CPU 세대 불문 동일 코드로 디코딩 IPID만 읽으면 어떤 하드웨어 유닛인지 즉시 판별 레지스터 (뱅크당 8개) CTL STATUS ADDR MISC IPID SYND DESTAT DEADDR 식별: CPU 모델별 매뉴얼 참조 Bank N = ??? (Skylake와 Ice Lake가 다름) 식별: IPID.HWID + IPID.MCATYPE Zen 1 ~ Zen 5 모두 동일 방식으로 디코딩

Intel CPU 뱅크 매핑 (Skylake-SP 이후)

Intel 전통 MCA에서는 뱅크 번호가 CPU 마이크로아키텍처마다 다르게 매핑됩니다. 아래는 Skylake-SP(Xeon Scalable) 이후 서버 CPU의 일반적인 뱅크 할당입니다. Ice Lake-SP, Sapphire Rapids에서는 일부 뱅크가 추가/변경될 수 있습니다.

뱅크 번호유닛설명일반적인 에러
Bank 0IFU (Instruction Fetch Unit)명령어 페치 파이프라인(Pipeline)I-Cache 패리티, uop 캐시 에러
Bank 1DCU (Data Cache Unit)L1 데이터 캐시D-Cache ECC, 로드/스토어 에러
Bank 2DTLB데이터 TLBTLB 패리티 에러
Bank 3MLC (Mid-Level Cache)L2 캐시L2 ECC CE/UC
Bank 4PCU (Power Control Unit)전력 관리 유닛전압/클럭 관련 내부 에러
Bank 5-6Intel UPI소켓(Socket) 간 인터커넥트링크 CRC, 프로토콜 에러
Bank 7-8IIO (Integrated I/O)PCIe 루트 포트, CBDMAPCIe CE/UC, DMA 에러
Bank 9-12M2M (Mesh to Memory)메시 → 메모리 인터페이스주소 디코드 에러, patrol scrub CE
Bank 13-20iMC (integrated Memory Controller)메모리 채널 컨트롤러DRAM ECC CE/UC — 가장 빈번
Bank 21-24CHA (Caching Home Agent)LLC 슬라이스 + 디렉토리LLC ECC, 스누프 프로토콜 에러
참고: 뱅크 번호는 코어당 뱅크(0-4)와 uncore 뱅크(5+)로 나뉩니다. 코어당 뱅크는 각 논리 CPU에서 독립적으로 보고되고, uncore 뱅크는 소켓 내 특정 CPU에만 라우팅(Routing)됩니다. mcelog--dmi 옵션이나 커널 로그의 CPU N Bank M에서 확인할 수 있습니다.

AMD Zen SMCA 뱅크 타입 전체 목록

SMCA에서는 MCi_IPID 레지스터의 HWID(bits [43:32])와 MCATYPE(bits [63:48])으로 하드웨어 유닛을 식별합니다. 아래는 커널 소스(arch/x86/kernel/cpu/mce/amd.c)에 정의된 전체 SMCA 뱅크 타입입니다.

enum 이름HWIDMCATYPE유닛 설명주요 에러
SMCA_LS0xB00x0Load Store Unit로드/스토어 데이터 에러
SMCA_LS_V20xB00x10Load Store Unit V2 (Zen 3+)확장 LS 에러 코드
SMCA_IF0xB10x0Instruction FetchI-Cache, ITB(ITLB) 에러
SMCA_L2_CACHE0xB20x0L2 CacheL2 ECC CE/UC
SMCA_DE0xB30x0Decode Unituop 캐시, 디코더 에러
SMCA_RESERVED0xB40x0예약미사용
SMCA_EX0xB60x0Execution Unit정수/분기 실행 에러
SMCA_FP0xB70x0Floating PointFPU, SIMD 연산 에러
SMCA_L3_CACHE0xB80x0L3 CacheL3 ECC CE/UC, 태그 에러
SMCA_CS0x2B0x0Coherent Slave (xGMI/IF)인터커넥트 프로토콜 에러
SMCA_CS_V20x2B0x2Coherent Slave V2 (Zen 3+)확장 IF 에러
SMCA_PIE0x2E0x0Power, Interrupts, etc.APIC, 전력 관리 에러
SMCA_UMC0x960x0Unified Memory ControllerDRAM ECC CE/UC — 가장 빈번
SMCA_UMC_V20x960x10UMC V2 (Zen 4+ DDR5)DDR5 ECC, On-die ECC 이벤트
SMCA_PB0x050x0Parameter Block퓨즈/파라미터 에러
SMCA_PSP0xFF0x0Platform Security ProcessorPSP 펌웨어 에러
SMCA_PSP_V20xFF0x1PSP V2확장 PSP 에러
SMCA_SMU0x010x0System Management UnitSMU 펌웨어 에러
SMCA_SMU_V20x010x10SMU V2확장 SMU 에러
SMCA_MP50x010x2Microprocessor 5 UnitMP5 내부 에러
SMCA_MPDMA0x010x3MPDMADMA 엔진 에러
SMCA_NBIO0x2E0x1Northbridge I/O UnitPCIe, IOMMU 에러
SMCA_PCIE0x2E0x2PCIe Root PortPCIe AER CE/UC
SMCA_PCIE_V20x2E0x3PCIe V2 (Zen 4+)확장 PCIe 에러
SMCA_XGMI_PCS0x500x0xGMI PCS (Physical Coding)소켓 간 링크 물리 계층 에러
SMCA_NBIF0x2E0x4NB-IF (Northbridge Interface)데이터 패브릭 인터페이스 에러
SMCA_SHUB0x800x0System Hub사우스브릿지 연결 에러
SMCA_SATA0xA80x0SATA ControllerSATA PHY/프로토콜 에러
SMCA_USB0xAA0x0USB ControllerUSB 내부 에러
SMCA_GMI_PCS0x500x1GMI PCS (Global Memory Interconnect)다이 간 링크 에러
SMCA_XGMI_PHY0x590x0xGMI PHYxGMI 물리 계층 트레이닝 에러
SMCA_WAFL_PHY0x590x1WAFL PHYWAFL 링크 에러
SMCA_GMI_PHY0x590x2GMI PHYGMI 물리 계층 에러
SMCA 인스턴스 식별: 동일 HWID+MCATYPE을 가진 뱅크가 여러 개 존재할 수 있습니다 (예: UMC가 채널 수만큼). MCi_IPID의 bits [31:0]인 InstanceId로 같은 타입의 서로 다른 인스턴스를 구별합니다. rasdaemon 로그에서 instance: N으로 확인됩니다.

Deferred Error (SMCA 고유)

AMD SMCA는 Deferred Error라는 고유한 에러 유형을 지원합니다. Deferred Error는 즉각적인 데이터 손상을 일으키지는 않지만, 나중에 소비되면 문제가 될 수 있는 "잠재적 오류"입니다. 주로 배경 패트롤 스크러빙(background patrol scrubbing)에서 발견된 에러를 보고하는 데 사용됩니다.

레지스터MSR설명
MCi_DESTAT MCi_BASE + 8 Deferred Error Status — MCi_STATUS와 동일한 형식이지만, 지연된(deferred) 에러 전용. MCi_STATUS에 새 에러가 기록되어도 DESTAT의 내용은 보존됨
MCi_DEADDR MCi_BASE + 9 Deferred Error Address — 지연 에러가 발생한 물리 주소. memory_failure()에 전달하여 해당 페이지를 오프라인할 수 있음

일반적인 UC(Uncorrected) 에러와 Deferred Error의 핵심적인 차이점은 다음과 같습니다:

특성UC Error (일반)Deferred Error
발생 시점 데이터가 실제 소비될 때 (load, execution) 패트롤 스크러빙 등 백그라운드 검사에서 발견
즉각 영향 프로세스 kill 또는 panic (SRAR/SRAO) 즉각적 영향 없음 — 아직 소비되지 않은 데이터
STATUS 기록 MCi_STATUS.UC=1, MCi_STATUS.Deferred=0 MCi_STATUS.Deferred=1 (bit 32)
별도 레지스터 없음 (MCi_STATUS/ADDR 사용) MCi_DESTAT / MCi_DEADDR 전용 레지스터
커널 처리 memory_failure(pfn, MF_ACTION_REQUIRED) memory_failure(pfn, 0) — 선제적 오프라인
복구 전략 Late Kill / Early Kill 정책 적용 페이지 마이그레이션 후 오프라인 (데이터 보존 가능)
/* arch/x86/kernel/cpu/mce/amd.c — Deferred Error 처리 */
static void amd_deferred_error_interrupt(void)
{
    unsigned int bank;

    for (bank = 0; bank < this_cpu_read(mce_num_banks); bank++) {
        u64 status, addr;

        rdmsrl(MSR_AMD64_SMCA_MCx_DESTAT(bank), status);
        if (!(status & MCI_STATUS_VAL))
            continue;

        if (!(status & MCI_STATUS_DEFERRED))  /* bit 32: Deferred 플래그 */
            continue;

        rdmsrl(MSR_AMD64_SMCA_MCx_DEADDR(bank), addr);

        /* 지연 에러 주소로 선제적 memory_failure 호출 */
        if (addr) {
            unsigned long pfn = addr >> PAGE_SHIFT;
            memory_failure(pfn, 0);  /* MF_ACTION_REQUIRED 미설정 */
        }

        /* DESTAT 클리어 */
        wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(bank), 0);
    }
}

/* Deferred Error는 APIC LVT에 별도 벡터(DEFERRED_ERROR_VECTOR)로 전달됨 */
/* AMD 특유: 패트롤 스크러빙이 CE로 교정 불가한 오류를 발견하면       */
/* 즉시 UC를 발생시키지 않고 DESTAT에 기록 → 소프트웨어가 선제 대응 가능 */
패트롤 스크러빙과 Deferred Error: AMD EPYC 서버에서 UMC(Unified Memory Controller)의 패트롤 스크러빙은 주기적으로 DRAM 전체를 읽어 ECC 검사를 수행합니다. 교정 불가능한 에러가 발견되면 즉시 UC MCE를 발생시키는 대신 Deferred Error로 기록하여, 커널이 해당 페이지를 안전하게 마이그레이션한 뒤 오프라인할 수 있는 시간적 여유를 줍니다. 이는 Intel의 patrol scrub UC(Bank 9-12 M2M)와 대비되는 AMD의 고유한 장점입니다.

IIO (Integrated I/O) MCA 아키텍처

Intel 서버 CPU(Xeon Scalable 이후)에서 IIO(Integrated I/O)는 CPU 다이에 통합된 I/O 서브시스템으로, PCIe 루트 포트, DMI(Direct Media Interface), CBDMA/IOAT(Crystal Beach DMA), VT-d(Intel Virtualization Technology for Directed I/O) 엔진 등을 포함합니다. IIO는 CPU 내부에서 I/O 장치와 메시 인터커넥트 사이를 연결하는 핵심 컴포넌트이며, 전용 MCA 뱅크(일반적으로 Bank 5~8)를 통해 I/O 관련 하드웨어 에러를 보고합니다.

왜 IIO가 중요한가: 현대 데이터센터 워크로드에서 GPU, NVMe SSD, 고속 NIC, FPGA 등 PCIe 장치 사용이 급증하면서, IIO MCA 뱅크에서 보고되는 에러가 iMC(메모리) 에러 다음으로 흔해졌습니다. AI/ML 학습 클러스터에서 GPU 통신 장애, NVMe 어레이에서 디스크 탈락, 네트워크 카드 장애 등의 근본 원인이 IIO MCE인 경우가 많습니다.

IIO 내부 구조

각 IIO 스택(Stack)은 독립적인 PCIe 루트 컴플렉스를 제공합니다. Intel Xeon Scalable 플랫폼에서 소켓당 최대 6개의 IIO 스택이 존재하며, 각 스택은 PCIe 루트 포트, DMA 엔진, IOMMU를 포함합니다.

Intel IIO (Integrated I/O) 아키텍처 Mesh Interconnect (UPI/CHA/IMC) CPU 내부 메시 네트워크 IIO 서브시스템 (MCA Bank 5~8) IIO Stack 0 DMI 3.0/4.0 → PCH (사우스브릿지) SATA, USB, LPC, SPI IIO Stack 1 PCIe Root Port x16/x8/x4 분할 GPU, NIC IIO Stack 2 PCIe Root Port x16/x8/x4 분할 NVMe, FPGA IIO Stack 3 PCIe Root Port + CBDMA/IOAT DMA 엔진, DSA (SPR+) Stack 4~5 추가 PCIe (CPU 모델별 가변) IDI (In-Die Interconnect) IIO 스택 내부 컴포넌트 PCIe Root Port ITC (Ingress) OTC (Egress) IRP (IIO RP) VT-d (IOMMU) CBDMA/DSA Coherence I/F PCIe 디바이스 (에러 소스) GPU NVMe SSD NIC (100G+) FPGA CXL 장치 HBA/RAID SmartNIC/DPU ITC = Ingress Transaction Controller | OTC = Outgress Transaction Controller IRP = IIO Root Port controller | DSA = Data Streaming Accelerator (SPR+) | CBDMA = Crystal Beach DMA IDI = In-Die Interconnect: IIO 스택과 메시 인터커넥트 사이의 내부 연결

IIO MCA 뱅크 구조

IIO에서 보고되는 에러는 일반적으로 Bank 5~8에 매핑됩니다(CPU 모델에 따라 다름). 각 뱅크는 특정 IIO 스택에 대응합니다. IIO 뱅크의 MCi_STATUS 에러 코드는 표준 MCA 복합 에러 코드 외에 Intel 모델 고유 에러 코드(MSCOD)도 포함합니다.

뱅크IIO 스택일반적 장치보고 에러 유형
Bank 5IIO Stack 0 (DMI)PCH 연결 장치(SATA, USB, 온보드 LAN)DMI 링크 에러, PCH 통신 타임아웃
Bank 6IIO Stack 1PCIe Slot 1~2 (GPU, NIC)PCIe CE/UC, Completion Timeout, Poisoned TLP
Bank 7IIO Stack 2PCIe Slot 3~4 (NVMe, FPGA)PCIe CE/UC, ECRC Error, Unexpected Completion
Bank 8IIO Stack 3 (CBDMA)DMA 엔진, DSA, 추가 PCIeDMA 에러, IOAT 채널 에러, PCIe 에러
뱅크 번호 주의: IIO 뱅크 번호는 CPU 모델에 따라 다릅니다. Skylake-SP에서 Bank 5~8이 IIO이지만, Ice Lake-SP에서는 Bank 5~10, Sapphire Rapids에서는 IIO 스택이 더 세분화될 수 있습니다. 정확한 매핑은 Intel SDM 또는 해당 CPU의 MCA Error Code Reference를 확인하세요.

IIO MCi_STATUS 에러 코드 해석

IIO 뱅크의 MCi_STATUS 레지스터에서 에러 코드(bits 15:0)는 표준 MCA 형식을 따르지만, MSCOD(Model-Specific Error Code, bits 31:16)에 IIO 고유의 상세 정보가 인코딩됩니다. PCIe 에러의 경우 MSCOD 필드에서 PCIe AER 에러 유형을 구분할 수 있습니다.

MSCOD (bits 31:16)에러 유형설명일반적 원인
0x0000Completion TimeoutPCIe 요청에 대한 응답 타임아웃장치 응답 불가, 링크 다운, FLR 중 접근
0x0001Receiver OverflowIIO 수신 버퍼 오버플로(Buffer Overflow)과부하, 흐름 제어(Flow Control) 실패
0x0002Poisoned TLP독성 데이터(Poison bit) TLP 수신업스트림 장치 메모리 에러, ECC 실패
0x0003Unsupported Request지원하지 않는 PCIe 요청드라이버 버그, BAR 매핑 오류
0x0004ECRC ErrorEnd-to-End CRC 검증 실패PCIe 라이저/케이블 불량, 신호 무결성(Integrity)
0x0005Uncorrectable InternalIIO 내부 패리티/로직 에러CPU 하드웨어 결함, 마이크로코드 버그
0x0006Malformed TLP형식 오류 TLP 수신장치 하드웨어 결함, 링크 트레이닝 불완전
0x0007Flow Control Protocol흐름 제어 프로토콜 위반장치 또는 스위치 펌웨어 버그
0x0008Surprise Link Down예기치 않은 PCIe 링크 다운물리적 분리, 전원 불안정, 열 문제
0x0010Correctable InternalIIO 내부 교정 가능 에러일시적 패리티, 재시도로 복구
0x0020Header Log Overflow에러 헤더 로그 오버플로에러 폭주
0x0080Advisory Non-Fatal권고 비치명적 에러Poisoned TLP가 Advisory로 재분류
0x0200DMA Channel ErrorCBDMA/IOAT/DSA 채널 에러DMA 디스크립터 오류, 주소 변환(Address Translation) 실패
0x0400VT-d FaultIOMMU 주소 변환 실패DMAR 테이블 오류, 잘못된 DMA 주소

IIO MCi_MISC 레지스터 해석

IIO 뱅크에서 MCi_MISC(MISCV=1일 때)에는 에러와 관련된 PCIe 장치의 Bus/Device/Function(BDF) 정보가 인코딩됩니다. 이를 통해 에러를 발생시킨 특정 PCIe 장치를 정확히 식별할 수 있습니다.

비트 범위필드설명
bits 7:0Function NumberPCIe 장치 Function 번호 (0~7)
bits 12:8Device NumberPCIe 장치 Device 번호 (0~31)
bits 20:13Bus NumberPCIe 장치 Bus 번호 (0~255)
bits 23:21Segment GroupPCIe Segment Group (다중 세그먼트 시)
bits 31:24Root Port에러를 감지한 루트 포트 번호
/* IIO MCA MISC에서 BDF 추출 예시 (커널 내부) */
static void decode_iio_mce(struct mce *m)
{
    u8  func = m->misc & 0xFF;
    u8  dev  = (m->misc >> 8) & 0x1F;
    u16 bus  = (m->misc >> 13) & 0xFF;

    pr_emerg("IIO MCE: PCIe BDF %02x:%02x.%x MSCOD=0x%04x\n",
             bus, dev, func,
             (u16)(m->status >> 16) & 0xFFFF);
}

PCIe AER vs IIO MCA: 에러 보고 이중 경로

동일한 PCIe 에러가 두 가지 경로로 보고될 수 있습니다: PCIe AER(Advanced Error Reporting)와 IIO MCA 뱅크입니다. 이 두 경로는 독립적이며, 에러 발생 시 둘 다 트리거될 수 있습니다.

PCIe 에러 이중 보고 경로: AER vs IIO MCA PCIe 장치 에러 발생 Completion Timeout / Poisoned TLP / ... 경로 1: PCIe AER PCIe Config Space AER Capability AER Root Error Status MSI/MSI-X → aer_irq() pci_channel_io_frozen 드라이버 err_handler 호출 경로 2: IIO MCA Bank CPU 내부 MCA 뱅크 레지스터 MCi_STATUS (MSCOD + MCA code) #MC 벡터 18 (또는 CMCI) do_machine_check() severity 판단 → 패닉/복구/로그 동일 에러, 두 가지 보고 경로 AER: 소프트웨어 복구(드라이버 리셋) 중심 MCA: 하드웨어 무결성(패닉/오프라인) 중심
특성PCIe AERIIO MCA
트리거PCIe Config Space AER CapabilityCPU 내부 IIO 로직
인터럽트MSI/MSI-X (일반 인터럽트)#MC (벡터 18) 또는 CMCI
에러 정보AER 레지스터 (Header Log 포함)MCi_STATUS/ADDR/MISC (BDF 인코딩)
CE 처리AER Correctable → 로그만CMCI 또는 폴링으로 수집
UC 처리AER Fatal → PCIe 링크 리셋, 드라이버 복구MCE Severity 판단 → 패닉 가능
Firmware-FirstGHES가 AER을 가로챌 수 있음Firmware-First 시 GHES/BERT 경유
커널 핸들러aer_irq()pcie_do_recovery()do_machine_check() → severity
장점장치 식별 정확, 드라이버 복구 프레임워크CPU 레벨 무결성 보장, 데이터 오염 방지
Firmware-First 환경에서의 IIO: GHES(Generic Hardware Error Source) 기반 Firmware-First 모드에서는 PCIe 에러를 펌웨어(BMC/BIOS)가 먼저 수집하고, CPER(Common Platform Error Record) 형식으로 OS에 전달합니다. 이 경우 IIO MCA 뱅크에는 에러가 기록되지 않을 수 있으며, 대신 GHES 경로를 통해 ghes_proc()memory_failure() 또는 aer_recover_work_func()로 처리됩니다. APEI/GHES 통합 섹션을 참고하세요.

IIO 에러 시나리오별 분석

시나리오 1: PCIe Completion Timeout (CTO)

가장 흔한 IIO 에러입니다. CPU가 PCIe 장치에 요청을 보냈으나, 설정된 시간(기본 50ms~3.2초) 내에 응답을 받지 못한 경우입니다.

항목내용
MCA 코드MSCOD=0x0000, MCA 에러 코드=0x0e0b 범위
dmesg 시그니처Hardware Error ... IIO MCA Bank ... Completion Timeout
AER 대응pcieport ... AER: Uncorrectable (Non-Fatal) error received
흔한 원인
  • 장치 FLR(Function Level Reset) 중 호스트 접근
  • GPU/NIC 펌웨어 행(hang) 또는 내부 리셋
  • NVMe SSD 내부 GC(Garbage Collection) 중 과도한 지연
  • PCIe 링크 불안정 (열 문제, 물리적 접촉 불량)
  • BIOS/UEFI의 CTO 값이 워크로드에 비해 너무 짧음
  • 가상화 환경에서 VFIO passthrough 장치의 게스트 드라이버 문제
조치
  1. lspci -vvv에서 DevCtl2의 CTO 값 확인
  2. 장치 펌웨어 업데이트 확인
  3. PCIe 링크 상태 확인: lspci -vvv | grep -i "lnksta"
  4. 물리적 재장착 (라이저, 케이블 포함)
  5. CTO 값 조정: setpci -s BDF CAP_EXP+28.w=0x0025 (CTO 1~3.2초)

시나리오 2: Poisoned TLP 수신

PCIe 장치가 "독성(Poisoned)" 데이터를 포함한 TLP를 전송한 경우입니다. 이는 상류 장치의 메모리(예: GPU VRAM)에서 ECC 에러가 발생했음을 의미합니다.

항목내용
MCA 코드MSCOD=0x0002
의미장치가 DMA 읽기에서 에러 데이터를 CPU에 전달 (EP bit set in TLP header)
영향
  • CPU가 이 데이터를 소비하면 SRAR(UC+S+AR) → 프로세스 SIGBUS 또는 패닉
  • 데이터가 메모리에 기록되면 해당 cacheline이 poison 상태 → 추후 접근 시 MCE
  • IIO는 Poison을 전파(propagate)할 수도, 차단(contain)할 수도 있음 (BIOS 설정)
GPU 컨텍스트GPU VRAM ECC UC → Poisoned Completion → IIO MCE. NVIDIA GPU는 Xid 에러(Xid 48: DBE 에러)와 동시에 발생할 수 있음
NVMe 컨텍스트NVMe 컨트롤러 내부 DRAM 에러 → Poisoned DMA Read Completion → IIO MCE → I/O 에러
조치
  1. 장치 에러 로그 확인: GPU → nvidia-smi -q -d ERRORS, NVMe → nvme smart-log
  2. 장치 자체 ECC 상태 확인
  3. BIOS에서 Poison 전파 정책 확인 (Viral Mode Enable/Disable)
  4. 장치 교체 검토

시나리오 3: Surprise Link Down

항목내용
MCA 코드MSCOD=0x0008
dmesg 시그니처pcieport ... link down + IIO MCA 에러
원인
  • 물리적 분리: 카드 탈거, 라이저 접촉 불량, 케이블 단선
  • 전원 문제: GPU 보조 전원 미연결, 전원 공급 불안정
  • 열 문제: 과열로 인한 장치 자체 보호 셧다운
  • 장치 내부 리셋: 펌웨어 리셋, watchdog 타임아웃
  • PCIe 신호 무결성: 고속(Gen4/5) 링크에서의 BER(Bit Error Rate) 초과
핫플러그 vs 에러핫플러그 지원 슬롯에서의 의도적 제거는 Surprise Link Down을 정상 이벤트로 처리. 비핫플러그 슬롯에서 발생하면 에러로 취급
조치
  1. 물리적 연결 상태 확인 (카드 재장착, 라이저 케이블 점검)
  2. 전원 공급 확인 (GPU 보조 전원, 전원 공급 장치 용량)
  3. 장치 온도 이력 확인
  4. BIOS에서 PCIe 링크 속도 다운그레이드 시도 (Gen5 → Gen4)
  5. 다른 슬롯에서 재현 테스트

시나리오 4: DMA/IOAT 엔진 에러 (CBDMA/DSA)

항목내용
MCA 코드MSCOD=0x0200 범위
영향 범위IOAT(I/O Acceleration Technology) DMA 채널, DSA(Data Streaming Accelerator)
원인
  • DMA 디스크립터의 소스/목적지 주소 오류 (드라이버 버그)
  • IOMMU 주소 변환 실패 (VT-d 설정 불일치)
  • DMA 채널 하드웨어 결함
  • DSA 디바이스 설정 오류 (idxd 드라이버)
커널 IOAT 관련커널의 ioatdma 드라이버가 네트워크 DMA offload, dmaengine 프레임워크에서 사용. 에러 시 채널 리셋 후 재시도
DSA 관련SPR+ CPU의 DSA(Data Streaming Accelerator)는 idxd 드라이버로 관리. 메모리 복사/비교/CRC 가속. 에러 시 work queue 리셋

시나리오 5: VT-d (IOMMU) 변환 실패

항목내용
MCA 코드MSCOD=0x0400 범위
dmesg 시그니처DMAR: DRHD: handling fault status reg ... reason 06
원인
  • VFIO passthrough 장치의 IOVA 매핑 오류
  • DMA 리맵 테이블 설정 불일치
  • 장치가 IOMMU 페이지 테이블(Page Table)에 없는 주소로 DMA 시도
  • ACS(Access Control Services) 설정 문제로 인한 장치 그룹 격리 실패
가상화 영향KVM/QEMU VFIO passthrough 환경에서 게스트가 잘못된 DMA 주소를 프로그래밍하면 VT-d fault → IIO MCA 에러 → 게스트 강제 종료 가능

IIO 데이터 경로와 에러 감지 지점

IIO 스택 내부에서 PCIe 트랜잭션(Transaction)은 여러 단계를 거치며, 각 단계마다 독립적인 에러 감지 로직이 있습니다. 에러가 어느 단계에서 감지되었는지에 따라 MSCOD와 복구 가능성이 달라집니다.

IIO 스택 내부 데이터 경로와 에러 감지 지점 Mesh IDI 포트 코히런스 요청 IRP IIO Root Port Controller 에러 ①: 주소 디코드 에러 ②: CTO 감지 ITC Ingress Transaction Ctrl 에러 ③: Poison 수신 에러 ④: 오버플로 OTC Egress Transaction Ctrl 에러 ⑤: 패리티 에러 ⑥: 크레딧 PCIe Core Transaction Layer Data Link Layer Physical Layer 에러 ⑦: ECRC 에러 ⑧: Malformed TLP 에러 ⑨: Link Down 에러 ⑩: DLLP CRC VT-d (IOMMU) 에러 ⑪: DMA Remap Fault PCIe 장치 GPU/NVMe/NIC 내부 ECC, DMA Inbound Outbound Inbound: 장치→CPU (DMA Read Completion, MSI) | Outbound: CPU→장치 (MMIO Write, Config Access) ①~⑪: 에러 감지 지점 — 각 단계에서 독립적으로 에러를 MCi_STATUS에 기록
에러 지점컴포넌트감지 에러MSCOD심각도
IRP 주소 디코드잘못된 BAR/MMIO 주소 접근0x0003UC (Unsupported Request)
IRP CTO 타이머Completion Timeout0x0000UC Non-Fatal 또는 Fatal
ITC IngressPoisoned TLP 수신0x0002UC — Poison 전파 여부에 따라 변동
ITC 버퍼수신 버퍼 오버플로0x0001UC (데이터 손실)
OTC 패리티Egress 경로 내부 패리티0x0005UC Internal
OTC 크레딧흐름 제어 크레딧 에러0x0007UC (링크 교착 가능)
PCIe TLECRC 검증 실패0x0004UC (데이터 무결성)
PCIe TLMalformed TLP0x0006UC Fatal
PCIe PLSurprise Link Down0x0008UC Fatal
PCIe DLLDLLP CRC / Replay Timeout0x0010 (CE)CE (자동 재전송(Retransmission))
VT-dDMA 주소 변환 실패0x0400UC (DMA Remap Fault)

IIO Poison 전파 모델과 Viral Mode

PCIe 장치에서 Poisoned TLP를 수신한 IIO는 두 가지 전략 중 하나를 선택합니다: Containment(격리) 또는 Propagation(전파). 이 동작은 BIOS의 Viral Mode 설정과 IIO 내부 로직에 의해 결정됩니다.

IIO Poison 전파 모델: Containment vs Propagation Poison 발생 GPU VRAM ECC UC IIO ITC 수신 EP bit = 1 (Poisoned) Viral Mode? BIOS 설정 확인 Containment (격리) — Viral Disabled IIO가 Poison 소비 MCi_STATUS에 기록 CMCI/MCE 발생 장점: Poison이 메모리로 전파 안됨 피해 범위 제한적 단점: 원본 데이터 손실 Propagation (전파) — Viral Enabled Poison 메모리에 저장 cacheline poison 마킹 소비 시 SRAR MCE 장점: 정확한 소비자 식별 가능 memory_failure() 활용 단점: 시간차 MCE, 추적 어려움 Disabled Enabled
BIOS 설정동작권장 환경MCE 관점
Viral Mode Disabled (기본) IIO가 Poison을 즉시 소비하고 MCE/CMCI 발생 일반 서버, HPC IIO 뱅크에서 즉시 에러 보고. 피해 범위 명확
Viral Mode Enabled Poison을 메모리까지 전파, 실제 소비 시점에 SRAR MCE 미션 크리티컬 (정확한 소비자 식별 필요) 시간차 MCE. memory_failure()로 해당 페이지만 오프라인
Viral + MCA Recovery Poison 전파 + 소비 시 프로세스만 킬 (패닉 회피) 클라우드, 가상화 (VM 격리) 가장 정교한 복구. CPU의 MCG_CAP.MCG_SER_P=1 필요

IIO와 PCIe 스위치/팬아웃 토폴로지(Topology)

GPU 클러스터, NVMe JBOF, 스토리지 어레이에서는 PCIe 스위치(예: Broadcom PEX, Microchip Switchtec)를 통해 여러 장치를 하나의 IIO 스택에 연결합니다. 스위치를 경유한 에러는 디버깅이 더 복잡합니다.

토폴로지IIO 관점에러 진단 특징
직결 (Direct Attach) IIO Root Port → 장치 (1:1) MCi_MISC BDF가 정확히 에러 장치를 가리킴
PCIe 스위치 경유 IIO Root Port → 스위치 → 장치 (1:N) MCi_MISC BDF가 스위치 Downstream Port를 가리킴. 실제 에러 장치는 스위치의 AER 로그에서 확인해야 함
다단 스위치 (Cascaded Switch) IIO → Switch → Switch → 장치 BDF가 최상위 스위치를 가리킴. 하위 스위치의 포트별 AER 확인 필요
NTB (Non-Transparent Bridge) IIO → NTB → 원격 호스트 NTB 뒤의 에러는 NTB 자체 에러로 보고됨. 원격 호스트 로그 확인 필수
GPU NVLink/NVSwitch IIO → GPU (NVLink는 별도 경로) GPU 간 P2P(NVLink)는 IIO 무관. GPU↔CPU는 IIO 경유. GPU PCIe BAR 접근 시 IIO 에러 가능
CXL over IIO IIO → CXL 장치 (PCIe 물리 계층 공유) CXL.io 에러는 IIO MCA로, CXL.mem 에러는 GHES/CPER로 보고
# PCIe 스위치 뒤 장치 에러 추적 워크플로

# 1. IIO MCE에서 BDF 식별 → 스위치 Downstream Port일 수 있음
$ lspci -s <BDF>
# 출력 예: 85:00.0 PCI bridge: Broadcom PEX 8747 (rev ca)

# 2. 스위치 하위 장치 나열
$ lspci -tv -s <BDF>

# 3. 스위치 자체 AER 상태 확인
$ cat /sys/bus/pci/devices/0000:<BDF>/aer_dev_nonfatal

# 4. 스위치 하위 포트별 AER 확인
for dev in $(lspci -D | grep "PCI bridge" | awk '{print $1}'); do
  echo "--- $dev ---"
  cat /sys/bus/pci/devices/$dev/aer_dev_nonfatal 2>/dev/null
done

# 5. Switchtec 관리 도구 (Microchip 스위치)
$ switchtec status /dev/switchtec0
$ switchtec log-dump /dev/switchtec0

추가 IIO 에러 시나리오

시나리오 6: PCIe Replay Timer Timeout (DLLP CE)

항목내용
MSCOD0x0010 (Correctable Internal — DLLP 계층)
의미Data Link Layer의 ACK/NAK 프로토콜에서 재전송 타임아웃. TLP가 성공적으로 전달되지 못해 재전송됨
CE/UCCE — 자동 재전송으로 복구. 반복 시 링크 품질 저하 경고
원인
  • PCIe 신호 무결성 저하 (BER 증가)
  • 케이블/라이저 품질 문제 (Gen4/5에서 특히 민감)
  • 전자기 간섭 (EMI)
  • PCIe 리타이머(Retimer) 설정 부적절
모니터링lspci -vvvCESta:에서 RxErr+, Replay+ 확인. 카운터가 지속 증가하면 물리 계층 점검 필요
Gen5 특이사항PCIe 5.0(32 GT/s)에서는 시그널(Signal) 마진이 매우 좁아 리타이머(Retimer) 없이 장거리 연결 시 Replay CE가 빈번할 수 있음

시나리오 7: MMIO 트랜잭션 에러 (CPU→장치 방향)

항목내용
경로CPU 코어 → Mesh → IIO OTC → PCIe Core → 장치 BAR 영역
에러 유형
  • Unsupported Request (UR): 잘못된 BAR 주소에 MMIO 접근 → MSCOD=0x0003
  • Completer Abort (CA): 장치가 요청을 거부 → 장치 드라이버(Device Driver) 버그
  • MMIO Timeout: 장치 BAR 영역 접근에 응답 없음 → CTO로 보고
특이사항MMIO 에러는 CPU가 동기적으로 접근하는 경우(드라이버의 readl(), writel())에 발생. DMA(장치→메모리)와 달리 에러 시점이 명확
커널 보호pci_enable_pcie_error_reporting()으로 드라이버가 AER을 활성화. MMIO 에러 발생 시 pcie_do_recovery()로 장치 리셋 시도

시나리오 8: PCIe AtomicOp / Extended Tag 에러

항목내용
에러 유형AtomicOp Egress Blocked, Extended Tag Mismatch
배경PCIe AtomicOp은 GPU/FPGA가 호스트 메모리에 원자적 연산(Atomic Operation)을 수행할 때 사용. Extended Tag(10-bit)는 Gen4+에서 미해결 트랜잭션 수를 확대
원인
  • IIO의 AtomicOp Routing 설정 미비 (BIOS에서 비활성화)
  • PCIe 스위치가 AtomicOp를 지원하지 않아 차단
  • Extended Tag 불일치 (한쪽은 10-bit, 다른 쪽은 8-bit)
GPU 관련NVIDIA GPU의 PCIe P2P 또는 GPUDirect RDMA에서 AtomicOp 사용. IIO에서 차단되면 GPU 드라이버 초기화 실패 또는 성능 저하
조치BIOS에서 PCIe AtomicOp Egress Enable 활성화. setpci로 Device Control 2 레지스터의 AtomicOp 비트 확인

시나리오 9: DMI (Stack 0) 에러

항목내용
IIO 스택Stack 0 — DMI(Direct Media Interface)로 PCH에 연결
에러 유형
  • DMI Link CRC Error: CPU↔PCH 링크 CRC 실패 → 재전송 (CE)
  • DMI Timeout: PCH 응답 없음 → SATA/USB/LAN 접근 실패
  • DMI Protocol Error: DMI 프로토콜 위반 → 시스템 행 가능
영향DMI는 PCH의 유일한 상류 링크이므로, DMI 에러 시 PCH 하위 모든 장치(SATA, USB, 온보드 LAN, BMC)에 영향. 심한 경우 서버 관리 불가
원인메인보드 PCB 결함, CPU/PCH 간 라우팅 문제, PCH 하드웨어 결함
조치메인보드 교체 검토. DMI CE가 지속되면 CPU 또는 PCH 교체

시나리오 10: 가상화 환경 VFIO Passthrough IIO 에러

항목내용
환경KVM/QEMU + VFIO passthrough (GPU/NIC/NVMe를 VM에 직접 할당)
에러 유형
  • VT-d Fault → IIO MCA: 게스트가 잘못된 DMA 주소 프로그래밍
  • CTO from Guest: 게스트 드라이버가 FLR 중 장치 접근
  • Guest-triggered Link Reset: 게스트의 SBR/FLR이 호스트 IIO에 영향
  • MSI Remap Error: Interrupt Remapping 테이블 불일치
격리VFIO는 IOMMU(VT-d)로 게스트의 DMA를 격리하지만, PCIe 레벨 에러(CTO, Link Down)는 IIO에서 감지되어 호스트에 MCE를 발생시킴. 이로 인해 하나의 게스트 문제가 호스트 전체에 영향을 줄 수 있음
완화
  • vfio-pcierror_handler를 통한 AER 복구
  • QEMU의 x-pci-vendor-id 등으로 게스트의 장치 리셋 제어
  • ACS(Access Control Services) 활성화로 장치 간 격리 강화
  • LMCE 활성화로 IIO MCE의 영향을 해당 CPU로 제한

Intel 세대별 IIO 변천사

CPU 세대코드네임PCIe 지원IIO 특징주요 변경
Xeon Scalable 1stSkylake-SP (SKX)PCIe 3.0, 48레인 IIO Stack 0~5, Bank 5~8 IIO MCA 최초 표준화, CBDMA 8채널
Xeon Scalable 2ndCascade Lake (CLX)PCIe 3.0, 48레인 SKX와 동일 마이크로코드 개선 (IIO CE 필터링)
Xeon Scalable 3rdIce Lake-SP (ICX)PCIe 4.0, 64레인 IIO 스택 확장, Bank 5~10 PCIe Gen4 → 대역폭(Bandwidth) 2배, 링크 에러 감지 강화
Xeon Scalable 4thSapphire Rapids (SPR)PCIe 5.0, 80레인 IIO 재설계, DSA/IAA/QAT 통합 DSA(Data Streaming Accelerator), IAA(In-Memory Analytics Accelerator) 추가. CXL 1.1 Type 3 지원. MDF(Mesh Data Fabric) MCA 뱅크 신설
Xeon Scalable 5thEmerald Rapids (EMR)PCIe 5.0, 80레인 SPR 기반 개선 마이크로코드 IIO 에러 핸들링 개선, LMCE IIO 지원 확대
Xeon 6Granite Rapids (GNR)PCIe 5.0, 96레인 IIO 확장, CXL 2.0 CXL 2.0 Type 1/2/3, 더 많은 IIO 스택, MCA 뱅크 확장
PCIe Gen4/5와 IIO 에러: PCIe 세대가 올라갈수록 신호 무결성 요구사항이 엄격해집니다. Gen4(16 GT/s)와 Gen5(32 GT/s)에서는 시그널 마진이 줄어들어, 케이블 품질, 라이저 카드 품질, 커넥터 접촉 상태가 이전 세대보다 훨씬 중요합니다. Gen5 환경에서 IIO CE가 증가하면 물리 계층(PHY) 리트레이닝 빈도 증가를 의미하며, lspci -vvvLnkSta:에서 링크 속도와 폭 다운그레이드 여부를 확인해야 합니다.

IIO 에러 디버깅 워크플로

# 1. IIO MCA 뱅크 에러 확인
$ dmesg | grep -i "iio\|bank [5-8]\|mce.*bank"

# 2. PCIe AER 에러 동시 확인
$ dmesg | grep -i "aer\|pcieport"

# 3. 에러 발생 장치 BDF 식별 (MCA MISC에서 디코딩)
$ mcelog --client | grep -i "iio\|misc"

# 4. 해당 BDF의 장치 정보 확인
$ lspci -vvvs <BDF>

# 5. PCIe 링크 상태 확인
$ lspci -vvvs <BDF> | grep -i "lnksta\|lnkcap\|devsta\|devctl"

# 6. AER 에러 카운터 확인
$ cat /sys/bus/pci/devices/0000:<BDF>/aer_dev_correctable
$ cat /sys/bus/pci/devices/0000:<BDF>/aer_dev_fatal
$ cat /sys/bus/pci/devices/0000:<BDF>/aer_dev_nonfatal

# 7. 장치별 세부 진단
# GPU:
$ nvidia-smi -q -d ERRORS,TEMPERATURE,POWER
# NVMe:
$ nvme smart-log /dev/nvmeN
$ nvme error-log /dev/nvmeN
# NIC:
$ ethtool -S <interface> | grep -i "error\|drop\|crc"

# 8. PCIe topology와 NUMA 매핑 확인
$ lspci -tv
$ lstopo --of txt

Uncore MCA 에러 종합 분석

IIO 외에도 CPU의 Uncore 영역에는 여러 MCA 에러 소스가 존재합니다. Uncore는 CPU 코어 외부에 있지만 CPU 다이 내부에 통합된 공유 자원 — LLC(Last Level Cache), 메모리 컨트롤러, 메시 인터커넥트, 전력 관리 유닛 등 — 을 포함합니다. 데이터센터에서 발생하는 MCE의 상당 부분이 이 Uncore 영역에서 옵니다.

Intel 서버 CPU Uncore MCA 뱅크 토폴로지 코어 영역 (Core MCA: Bank 0~4) IFU (B0) DCU (B1) DTLB (B2) MLC (B3) PCU (B4) 메시 인터커넥트 (CHA/LLC: Bank 21~24+) CHA 0 LLC Slice 0 CHA 1 LLC Slice 1 ... CHA N LLC Slice N Snoop Filter 코히런스 디렉토리 TOR 트랜잭션 큐 UPI (Bank 5~6) UPI Link 0 UPI Link 1 IIO (Bank 7~8) PCIe, DMI, DMA M2M (Bank 9~12) 메시 ↔ 메모리 I/F iMC (Bank 13~20) DRAM 채널 DRAM DIMM (DDR4/DDR5) ECC CE/UC → iMC → M2M → CHA → 코어/IIO SPR+ 추가 (Bank 확장) MDF HBM MC CXL DP IAA/QAT M2M = Mesh to Memory | CHA = Caching Home Agent | TOR = Table of Requests MDF = Mesh Data Fabric (SPR+) | HBM MC = High Bandwidth Memory Controller (SPR HBM SKU) CXL DP = CXL Downstream Port | IAA = In-Memory Analytics Accelerator | QAT = QuickAssist Technology 에러 흐름: DRAM → iMC(ECC) → M2M(주소 변환) → CHA(코히런스) → 코어/IIO(소비)

M2M (Mesh to Memory) 에러

M2M은 CPU 내부 메시 인터커넥트와 iMC(메모리 컨트롤러) 사이의 중개 역할을 합니다. 메모리 요청의 주소 디코딩, 인터리빙, 미러링, 스페어링 결정을 담당합니다. Bank 9~12(SKX 기준)에 매핑됩니다.

에러 유형MSCOD설명일반적 원인
Patrol Scrub UC0x0010패트롤 스크러빙이 교정 불가 에러 발견DIMM 열화, ECC 2비트+ 오류
Patrol Scrub CE0x0010 (UC=0)패트롤 스크러빙이 교정 가능 에러 발견단일 비트 에러 (정상 동작)
Demand Read UC0x0001데이터 읽기 중 교정 불가 에러DRAM 셀 고장, Row Hammer
Full Mirror Failover0x0020미러 채널로 페일오버 발생기본 채널 DIMM 장애
Partial Mirror0x0021부분 미러 영역 에러미러 영역 DIMM 열화
Sparing Failover0x0030스페어 랭크로 전환 완료CE 임계값 초과 → 자동 스페어링
ADDDC Failover0x0040ADDDC(Adaptive Double DRAM Device Correction) 활성화단일 DRAM 디바이스 장애 교정
Address Parity0x0100메모리 주소 버스 패리티 에러하드웨어 결함 (메모리 버스)
Patrol Scrub과 M2M: Patrol Scrubbing에서 발견된 메모리 에러는 iMC가 아닌 M2M 뱅크에서 보고됩니다. 이는 scrub이 M2M 레벨에서 스케줄링되기 때문입니다. 따라서 "Bank 9~12 에러"를 보면 메모리 에러(Patrol Scrub 발견)일 가능성이 높습니다. iMC 뱅크(Bank 13~20)는 주로 Demand(실제 데이터 접근) 에러를 보고합니다.

CHA (Caching Home Agent) / LLC 에러

CHA는 LLC(Last Level Cache) 슬라이스와 코히런스 디렉토리를 관리합니다. Bank 21~24+(코어 수에 따라 가변)에 매핑됩니다.

에러 유형설명영향
LLC ECC CELLC 데이터 ECC 교정 가능 에러자동 교정, 로그만 기록
LLC ECC UCLLC 데이터 ECC 교정 불가 에러데이터 손상 가능 → PCC=1이면 패닉
LLC Tag ParityLLC 태그 패리티 에러캐시라인 무효화 후 재페치 (교정 가능 시)
Snoop Filter Error코히런스 디렉토리 에러멀티소켓에서 데이터 불일치 가능
TOR TimeoutTable of Requests 엔트리 타임아웃미처리 요청 → 시스템 행/패닉
SF/LLC Way Error특정 LLC Way 접근 실패캐시 용량 감소 (해당 Way 비활성화)

TOR (Table of Requests) 타임아웃

TOR 타임아웃은 CHA의 트랜잭션 큐에서 요청이 완료되지 못하고 타임아웃된 경우입니다. 이는 매우 심각한 상황으로, 거의 항상 시스템 패닉을 유발합니다.

항목내용
dmesg 시그니처mce: CPU N: Machine Check: ... Bank CHA ... TOR Timeout
일반적 원인
  • 메모리 접근 장애: DIMM 하드 페일 → 메모리 읽기/쓰기가 무한 대기
  • PCIe 장치 무응답: DMA 요청이 응답 없이 TOR에 체류 → IIO CTO와 연관
  • UPI 링크 문제: 원격 소켓 메모리 접근이 UPI 링크 장애로 중단
  • 코히런스 데드락: 복잡한 스누프 프로토콜 시나리오에서 교착 (매우 드뭄)
  • 마이크로코드 버그: 특정 조건에서 TOR 엔트리가 해제되지 않음
MCi_MISC 정보타임아웃된 요청의 주소, 요청 유형(Read/Write/Snoop), 대상 유닛 정보
조치
  1. BERT/BIOS 에러 로그에서 선행 에러 확인 (TOR timeout은 보통 2차 에러)
  2. 동시에 발생한 다른 MCA 뱅크 에러 확인 (IIO? M2M? UPI?)
  3. 마이크로코드 최신 버전 적용
  4. 메모리/PCIe 장치 하드웨어 점검

UPI (Ultra Path Interconnect) 링크 에러

UPI는 멀티소켓 시스템에서 CPU 간 통신을 담당합니다. Bank 5~6(SKX 기준)에 매핑됩니다. 원격 메모리 접근(NUMA), 코히런스 프로토콜, 인터럽트 라우팅에 사용됩니다.

에러 유형설명영향원인
CRC Error (CE)링크 CRC 검사 실패 (교정됨)자동 재전송, 성능 약간 저하일시적 신호 간섭, 커넥터 열화
CRC Error (UC)링크 CRC 교정 불가링크 다운, 원격 소켓 격리하드웨어 결함, 심한 전기적 잡음
L0p/L1 Entry Error전력 절약 모드 진입 실패전력 효율 저하링크 트레이닝 문제
Protocol ErrorUPI 프로토콜 위반시스템 패닉 (PCC=1 가능)마이크로코드/하드웨어 결함
Phy Init Error물리 계층 초기화 실패링크 비활성소켓/보드 하드웨어 문제
UPI CE 증가 시: UPI CE(CRC Error)가 짧은 시간에 급증하면 링크 하드웨어 열화를 의미합니다. 멀티소켓 서버에서 UPI 링크 장애 시 원격 소켓의 메모리에 접근할 수 없게 되어 해당 NUMA 노드의 모든 프로세스가 영향을 받습니다. UPI CE가 지속되면 CPU 또는 메인보드 교체를 검토해야 합니다.

PCU (Power Control Unit) 에러

PCU는 CPU 전력 관리, 주파수 제어(P-state, C-state), 온도 모니터링을 담당합니다. Bank 4에 매핑됩니다. PCU 에러는 전력/열 관련 문제를 나타냅니다.

에러 유형설명원인
Internal Firmware ErrorPCU 마이크로컨트롤러 펌웨어 에러마이크로코드 버그, 전력 시퀀싱 문제
VR (Voltage Regulator) Error전압 조정기 통신 에러VRM 하드웨어 결함, 전원 공급 불안정
MCA TimeoutPCU 내부 타이머 만료전력 상태 전환 중 교착
Core/Mesh Ratio Error주파수 비율 설정 실패오버클럭 또는 불안정한 전력 공급

MDF (Mesh Data Fabric) — SPR 이후

Sapphire Rapids부터 도입된 MDF(Mesh Data Fabric)는 기존 CHA/메시의 데이터 패브릭을 별도 MCA 뱅크로 분리한 것입니다. 메시 내부의 데이터 전송 경로에서 발생하는 에러를 보고합니다.

에러 유형설명영향
Data Fabric Parity메시 내부 데이터 전송 패리티 에러CE: 자동 교정, UC: 패닉 가능
Credit Overflow/Underflow크레딧 기반 흐름 제어 에러메시 교착 가능
Routing Error메시 라우팅 테이블(Routing Table) 에러패킷(Packet) 오배달 → 데이터 손상

Intel Cascade Lake 아키텍처 기준 MCA 뱅크 상세

Cascade Lake-SP(CLX)는 Xeon Scalable 2세대로, Skylake-SP(SKX)의 MCA 아키텍처를 기반으로 하되 RAS 기능이 크게 강화된 세대입니다. 현재도 데이터센터에서 널리 운용되고 있어, MCE 분석의 기준 아키텍처로 적합합니다. 이후 세대(ICX, SPR, EMR, GNR)와의 차이를 이해하는 데도 Cascade Lake를 기준으로 삼으면 효과적입니다.

Intel Cascade Lake-SP (CLX) MCA 뱅크 매핑과 Uncore 토폴로지 코어 MCA 뱅크 (논리 CPU당 독립) Bank 0: IFU 명령어 페치 유닛 Bank 1: DCU L1 데이터 캐시 Bank 2: DTLB 데이터 TLB Bank 3: MLC L2 캐시 (Mid-Level) Bank 4: PCU 전력 제어 유닛 Uncore MCA 뱅크 (소켓 공유, 특정 CPU에 라우팅) Bank 5~6: UPI 소켓 간 인터커넥트 UPI 0: Bank 5 UPI 1: Bank 6 Bank 7~8: IIO PCIe, DMI, CBDMA, VT-d Stack 0(DMI): Bank 7 Stack 1~5(PCIe): Bank 7~8 Bank 9~12: M2M Mesh↔Memory I/F 패트롤 스크럽 보고 미러링/스페어링 제어 Bank 13~20: iMC 메모리 채널 (6ch) Demand ECC CE/UC ADDDC 관리 Bank 21~48: CHA (코어 수에 비례) LLC 슬라이스 + 코히런스 디렉토리 + Snoop Filter CHA 0: Bank 21 | CHA 1: Bank 22 | ... | CHA N: Bank 21+N TOR (Table of Requests) 타임아웃 감지 CLX 고유 RAS 기능 (SKX 대비 신규) ADDDC Adaptive Double DRAM 2LM (Optane PMem) Memory Mode MCA Mirror Failover 강화 Partial Mirror 지원 IIO CE 필터링 마이크로코드 개선 DDR4 DIMM (6채널, DIMM당 최대 2DPC) RDIMM / LRDIMM / Optane PMem (CLX) CLX 뱅크 총 수: 최대 48개 (28코어 기준) — Bank 0~4(코어×28) + Bank 5~8(Uncore) + Bank 9~20(M2M/iMC) + Bank 21~48(CHA) ADDDC: 단일 DRAM 디바이스 전체 장애를 교정하는 Adaptive ECC (CLX에서 최초 도입, x4 DIMM 필요) 2LM: Optane Persistent Memory를 메모리 모드로 사용 시 DRAM이 캐시, Optane이 주 메모리 — 별도 MCA 이벤트 발생 Partial Mirror: 전체가 아닌 일부 주소 영역만 미러링 (OS 부트 영역 등) — CLX에서 도입

Cascade Lake 고유 RAS 기능과 MCA 영향

기능SKX (1세대)CLX (2세대) 변경MCA 관점 영향
ADDDC 미지원 Adaptive Double DRAM Device Correction 도입 M2M 뱅크(Bank 9~12)에서 ADDDC Failover 이벤트(MSCOD=0x0040) 보고. ADDDC 활성화 시 단일 DRAM 칩 고장을 교정 → CE로 보고 (UC 방지)
Optane PMem (2LM) 미지원 Memory Mode: DRAM이 캐시, Optane이 주 메모리 iMC 뱅크에서 Optane 미디어 에러 보고. 2LM 캐시 미스 시 Optane 접근 → 추가 지연. Optane UC 에러 시 DRAM 캐시에 있으면 복구 가능, 없으면 UC MCE
Partial Mirror Full Mirror만 주소 범위 지정 미러링 지원 M2M 뱅크에서 Partial Mirror Failover(MSCOD=0x0021) 보고. 미러 영역 외 에러는 일반 UC 처리
IIO CE 필터링 모든 IIO CE 보고 마이크로코드 개선으로 일부 IIO CE 자동 필터링 IIO CMCI 빈도 감소. spurious CE에 의한 CMCI 스톰 완화
LMCE 확대 제한적 더 많은 에러 유형에 LMCE 적용 iMC UC(Demand Read) 시 LMCE로 해당 코어만 MCE 수신 → Monarch 오버헤드 감소
Corrected Error Collector 기본 CE 누적 임계값 기반 사전 경고 강화 CE 누적이 임계값 초과 시 soft_offline_page() 자동 호출. /sys/devices/system/machinecheck/machinecheck0/ce_count에서 확인
CLX vs ICX vs SPR MCA 뱅크 차이:
  • Cascade Lake(CLX): 최대 ~48개 뱅크. 기준 아키텍처. UPI 2개, IIO 6스택, 6채널 DDR4
  • Ice Lake-SP(ICX): ~60개 뱅크. PCIe Gen4, 8채널 DDR4. IIO 뱅크 확장(Bank 5~10). CHA 뱅크 수 증가(40코어 → Bank 21~60)
  • Sapphire Rapids(SPR): ~80개+ 뱅크. PCIe Gen5, 8채널 DDR5, CXL 1.1. MDF 뱅크 신설(Mesh Data Fabric), HBM MC 뱅크(HBM SKU), DSA/IAA/QAT 가속기 뱅크. M2M → IMC(Integrated Memory Controller)로 재편
  • Granite Rapids(GNR): ~100개+ 뱅크. CXL 2.0, 12채널 DDR5(MRDIMM). 더 많은 IIO 스택, CXL DP(Downstream Port) 전용 뱅크 추가

Cascade Lake ADDDC 동작 상세

ADDDC(Adaptive Double DRAM Device Correction)는 CLX에서 도입된 핵심 RAS 기능으로, DIMM 내 단일 DRAM 칩(x4)의 완전 장애까지 교정할 수 있습니다. 기존 SDDC(Single Device Data Correction)의 확장입니다.

단계상태MCA 이벤트커널 동작
1. 정상 ADDDC 대기 (Standby) 없음 정상 동작, patrol scrub 활성
2. CE 누적 SDDC로 교정 중 iMC CE (Bank 13~20), EDAC 카운터 증가 rasdaemon 기록, 모니터링
3. CE 임계값 초과 ADDDC Region 활성화 M2M ADDDC Failover (MSCOD=0x0040) EDAC: "ADDDC engaged". 해당 Rank에서 추가 ECC 비트 할당
4. ADDDC 활성 중 2개 DRAM 디바이스 에러까지 교정 CE로 계속 보고 (UC 방지) DIMM 교체 권고. ADDDC 소진 시 UC 위험
5. ADDDC 소진 3번째 디바이스 장애 iMC UC → M2M UC → 패닉 가능 DIMM 교체 필수
# ADDDC 상태 확인 (EDAC sysfs)
$ cat /sys/devices/system/edac/mc/mc0/dimm0/dimm_edac_mode
# 출력 예: "x4 SDDC" 또는 "x4 ADDDC"

# ADDDC Failover 이벤트 확인
$ dmesg | grep -i "adddc\|failover"
$ ras-mc-ctl --errors | grep -i "adddc"

# Cascade Lake에서 ADDDC 활성화 여부 (BIOS 설정)
# BIOS → Advanced → Memory Configuration → ADDDC Sparing: Enabled

Uncore 에러 간 연쇄(Cascade) 패턴

Uncore 에러는 종종 연쇄적으로 발생합니다. 하나의 근본 원인(root cause)이 여러 MCA 뱅크에서 동시다발적으로 에러를 보고하게 만듭니다. 연쇄 패턴을 이해하면 근본 원인을 더 빠르게 식별할 수 있습니다. 아래는 Cascade Lake 아키텍처를 기준으로 한 에러 전파 경로입니다.

에러 연쇄(Cascade) 전파 경로 — CLX 기준 근본 원인 DIMM 장애 PCIe 장치 행 UPI 링크 다운 GPU VRAM UC 과열 Optane UC (2LM) 1차 에러 (MCA 뱅크) iMC UC (Bank 13~20) IIO CTO (Bank 7~8) UPI UC (Bank 5~6) IIO Poison (Bank 7~8) PCU (Bank 4) iMC Optane (Bank 13~20) 2차 연쇄 에러 M2M UC (Bank 9~12) → CHA TOR Timeout CHA TOR Timeout → 3rd party MCE CHA TOR Timeout (원격 메모리 미응답) 코어 SRAR (소비 시) 또는 메모리 Poison 코어 에러 (극단적) 또는 주파수 강제 저하 M2M UC (DRAM 캐시 미스) → CHA TOR Timeout 최종 결과 PANIC PANIC / 장치 격리 NUMA 격리 SIGBUS / 패닉 스로틀링 PANIC 실선 화살표: 확정적 에러 전파 | 점선: 상황에 따른 전파 (조건부) TOR Timeout은 거의 항상 2차 에러 — 근본 원인은 좌측 열에서 탐색 CLX 기준: ADDDC가 활성화되어 있으면 DIMM 장애의 일부가 CE로 흡수되어 연쇄 발생을 지연시킴

연쇄 에러 근본 원인 분석 체크리스트

여러 MCA 뱅크에서 동시에 에러가 보고되면, 다음 절차로 근본 원인을 식별합니다.

  1. 타임스탬프 정렬: dmesg -T 또는 rasdaemon DB에서 에러를 시간 순서로 정렬. 가장 이른 타임스탬프의 에러가 root cause 후보
  2. OVER 비트 확인: MCi_STATUS.OVER=1인 뱅크는 정보 손실이 있으므로, 해당 뱅크가 실제 1차 에러 소스였을 가능성 높음
  3. 뱅크 간 우선순위:
    • iMC(Bank 13~20) UC가 있으면 → DIMM이 근본 원인일 가능성 최우선
    • IIO(Bank 7~8) CTO가 있으면 → PCIe 장치가 근본 원인
    • UPI(Bank 5~6) UC가 있으면 → 소켓 간 링크 문제
    • CHA TOR Timeout만 있으면 → 2차 에러, 다른 뱅크에서 근본 원인 탐색
  4. BERT 확인: 패닉 후 재부팅 시 dmesg | grep BERT로 이전 부팅의 에러 정보 수집. BERT에 1차 에러가 남아 있을 수 있음
  5. BMC/IPMI SEL: ipmitool sel list에서 OS 레벨 로그와 교차 확인. 펌웨어가 OS보다 먼저 에러를 감지한 경우 있음
  6. 동일 소켓/채널 집중: 에러가 특정 소켓, 특정 메모리 채널, 특정 PCIe 슬롯에 집중되면 해당 하드웨어 교체 고려
# 연쇄 에러 분석 스크립트 예시
# 모든 MCA 뱅크 에러를 타임스탬프순으로 정렬

$ dmesg -T | grep -i "mce\|hardware error\|machine check" | sort

# rasdaemon DB에서 최근 1시간 에러를 뱅크별로 그룹화
$ sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
  "SELECT bank, error_type, COUNT(*), MIN(timestamp), MAX(timestamp)
   FROM mce_record
   WHERE timestamp > strftime('%s','now','-1 hour')
   GROUP BY bank ORDER BY MIN(timestamp);"

# BERT (Boot Error Record) 확인 — 패닉 후 재부팅 시
$ dmesg | grep -A 20 "BERT"

# IPMI SEL 로그와 교차 확인
$ ipmitool sel list | tail -20
연쇄 에러 분석 핵심 원칙:
  • TOR Timeout은 결과지 원인이 아닙니다. TOR Timeout만 보이면 다른 뱅크(iMC, IIO, UPI)에서 근본 원인을 반드시 찾아야 합니다.
  • M2M 에러는 경유지입니다. M2M은 메시와 메모리 사이의 중개 역할이므로, M2M UC는 iMC 에러의 전파이거나 patrol scrub 발견일 수 있습니다.
  • IIO Poison은 시간차가 있습니다. Viral Mode Enabled 시 Poison이 메모리에 저장된 후 나중에 SRAR로 나타나므로, IIO MCE와 코어 SRAR MCE 사이에 시간 차이가 있을 수 있습니다.
  • CLX의 ADDDC는 연쇄를 지연시킵니다. ADDDC가 활성화되면 단일 DRAM 칩 장애를 CE로 교정하여 UC MCE 발생을 지연시키지만, ADDDC가 소진되면 갑자기 UC 연쇄가 시작될 수 있습니다.

LMCE (Local MCE)

전통적으로 MCE는 모든 논리 프로세서에 브로드캐스트됩니다. LMCE(Local Machine Check Exception)는 특정 CPU에만 영향을 미치는 에러를 해당 CPU에만 전달하여 불필요한 Monarch 랑데부를 피합니다.

LMCE 활성화 조건

  1. MCG_CAP.MCG_LMCE_P = 1 — CPU가 LMCE를 지원
  2. MCG_EXT_CTL.LMCE_EN = 1 — 소프트웨어가 LMCE를 활성화
  3. IA32_FEATURE_CONTROL.LMCE_ON = 1 — 펌웨어가 LMCE를 허용

LMCE의 이점

시나리오기존 MCELMCE
64코어 서버에서 1개 코어 CE 64개 코어 모두 MCE 핸들러 진입, 랑데부 1개 코어만 핸들러 실행
멀티소켓에서 로컬 캐시 에러 전체 소켓 동기화 → 성능 영향 큼 해당 소켓의 해당 코어만 처리
가상화 환경 모든 vCPU에 VMEXIT 발생 에러 발생 vCPU만 VMEXIT
/* arch/x86/kernel/cpu/mce/core.c */
static void mce_intel_feature_init(struct cpuinfo_x86 *c)
{
    u64 cap, feat;

    rdmsrl(MSR_IA32_MCG_CAP, cap);
    if (cap & MCG_LMCE_P) {
        rdmsrl(MSR_IA32_FEAT_CTL, feat);
        if (feat & FEAT_CTL_LMCE_ENABLED) {
            rdmsrl(MSR_IA32_MCG_EXT_CTL, cap);
            cap |= MCG_EXT_CTL_LMCE_EN;
            wrmsrl(MSR_IA32_MCG_EXT_CTL, cap);
        }
    }
}

/* LMCE 발생 여부 확인 */
static bool mce_is_lmce(struct mce *m)
{
    return m->mcgstatus & MCG_STATUS_LMCES;
}
LMCE 확인: dmesg | grep LMCE로 부팅 시 LMCE 활성화 여부를 확인할 수 있습니다. 또는 rdmsr 0x4D0으로 MCG_EXT_CTL 레지스터를 직접 읽어볼 수 있습니다.
브로드캐스트 MCE vs LMCE 비교 브로드캐스트 MCE — 모든 CPU가 #MC 수신, Monarch 랑데부 진입 HW 에러 L2 캐시 CE #MC CPU 0 CPU 1 CPU 2 CPU 3 CPU 4 CPU 5 CPU 6 CPU 7 Monarch 랑데부 (8 CPU 전체 동기화) mce_start() → mce_end() — 모든 코어 stall ~500 µs 전체 정지 8 CPU × 500 µs = 4000 CPU·µs LMCE — 에러 발생 CPU만 #MC 수신, 나머지 정상 실행 계속 HW 에러 L2 캐시 CE #MC (local only) CPU 0 정상 실행 CPU 1 정상 실행 CPU 2 정상 실행 CPU 3 #MC 처리 CPU 4 정상 실행 CPU 5 정상 실행 CPU 6 정상 실행 CPU 7 정상 로컬 처리 (랑데부 없음) mce_log() → recover/kill ~500 µs × 1 CPU만 7 CPU 정상 운영 → 87.5% 절감 브로드캐스트 MCE 총 영향: 8 CPU × ~500 µs = ~4,000 CPU·µs 낭비 LMCE 총 영향: 1 CPU × ~500 µs = ~500 CPU·µs (87.5% 절감)

LMCE 지원 CPU 목록

프로세서마이크로아키텍처LMCE 지원비고
Intel Xeon E5 v4 Broadwell-EP (2016) 최초 지원 MCG_CAP.MCG_LMCE_P 비트 최초 도입
Intel Xeon Scalable 1세대 Skylake-SP (2017) 완전 지원 서버 플랫폼 기본 활성화
Intel Xeon Scalable 3세대 Ice Lake-SP (2021) 향상된 지원 LMCE + Enhanced MCA 통합
Intel Xeon Scalable 4세대 Sapphire Rapids (2023) 향상된 지원 In-Band ECC + LMCE 연동 개선
Intel Core 6세대+ Skylake 클라이언트+ 지원 (BIOS 의존) IA32_FEATURE_CONTROL 설정 필요
AMD EPYC/Ryzen Zen 1~5 N/A SMCA(Scalable MCA)로 다른 접근: MCA_STATUS에 에러 소스 CPU 기록, 별도 LMCE 불필요

LMCE 판별 로직 상세

do_machine_check()에서 LMCE 여부에 따라 Monarch 랑데부를 건너뛰는 핵심 분기 로직입니다. MCG_STATUS의 LMCES(bit 3) 비트가 설정되어 있으면 해당 MCE는 로컬 전용이므로 다른 CPU와 동기화할 필요가 없습니다.

/* arch/x86/kernel/cpu/mce/core.c — do_machine_check() 내부 LMCE 분기 */
noinstr void do_machine_check(struct pt_regs *regs)
{
    struct mce m;
    int worst = 0, order, no_way_out = 0;
    bool lmce = false;

    /* 1단계: MCG_STATUS 읽기 */
    m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);

    /* 2단계: LMCE 여부 판별 — MCG_STATUS.LMCES (bit 3) */
    lmce = m.mcgstatus & MCG_STATUS_LMCES;

    /* 3단계: MCA 뱅크 순회 — 에러 정보 수집 */
    for (i = 0; i < this_cpu_read(mce_num_banks); i++) {
        m.status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS));
        if (!(m.status & MCI_STATUS_VAL))
            continue;
        /* severity 평가, worst 갱신 */
        worst = mce_severity(&m, regs, ...);
    }

    /* 4단계: LMCE면 랑데부 건너뛰기 */
    if (!lmce) {
        /* 브로드캐스트 MCE — Monarch 랑데부 진입 */
        order = mce_start(&no_way_out);
        /* ... 모든 CPU 동기화 후 Monarch 판정 ... */
        mce_end(order);
    } else {
        /* LMCE — 이 CPU만 로컬 처리 */
        /* 랑데부 불필요, 바로 에러 처리 진행 */
    }

    /* 5단계: 에러 로깅 및 액션 */
    mce_log(&m);

    if (worst >= MCE_PANIC_SEVERITY && !lmce)
        mce_panic("Fatal MCE", &m, msg);
    else if (worst >= MCE_AR_SEVERITY)
        kill_me_maybe(cb);  /* 프로세스 kill 또는 페이지 오프라인 */
}
LMCE의 한계: 멀티비트 Uncorrectable 에러, 공유 리소스(L3/LLC 캐시, UPI/QPI 인터커넥트, 메모리 컨트롤러) 에러, 또는 시스템 전체에 영향을 미칠 수 있는 에러는 LMCE 대상이 아니며 여전히 브로드캐스트 MCE로 처리됩니다. 펌웨어(BIOS/UEFI)가 IA32_FEATURE_CONTROL.LMCE_ON을 설정하지 않으면 CPU가 LMCE를 지원하더라도 비활성화 상태로 남습니다.

MCE와 KVM 가상화

물리 서버에서 하드웨어 메모리 오류가 발생하면, 호스트 커널의 MCE 핸들러가 먼저 처리합니다. 해당 오류가 게스트 VM에 할당된 메모리 영역에 영향을 미치는 경우, KVM 하이퍼바이저는 게스트에도 MCE를 주입하여 게스트 OS가 적절히 대응할 수 있도록 합니다.

호스트→게스트 MCE 전파 흐름

호스트 커널 영역 게스트 VM 영역 하드웨어 오류 #MC Exception VMEXIT EXIT_REASON_MCE 호스트 MCE 핸들러 do_machine_check() 게스트 메모리? 호스트 자체 처리 완료 kvm_mce_broadcast() HWPoison 마킹 KVM MCE 주입 kvm_inject_mce() 게스트 MCE 핸들러 Guest #MC 페이지 오프라인 프로세스 종료/복구 가상 MCE 뱅크 MCi_STATUS/ADDR/MISC QEMU 사용자 공간 KVM_X86_SET_MCE 아니오

VMEXIT와 #MC 인터셉트

Intel VT-x 및 AMD-V는 게스트 실행 중 #MC 예외가 발생하면 무조건 VMEXIT를 수행합니다. 호스트가 반드시 먼저 제어권을 확보하는 구조입니다.

항목Intel VT-xAMD-V (SVM)
VMEXIT 사유EXIT_REASON_MCE_DURING_VMENTRY (41)SVM_EXIT_MC (0x052)
인터셉트 설정VMCS Exception Bitmap bit 18VMCB Intercept[INTERCEPT_MC]
비활성화 가능 여부불가 (항상 인터셉트)불가 (항상 인터셉트)
호스트 핸들러handle_machine_check()svm_handle_mce()

KVM_X86_SET_MCE ioctl을 통한 게스트 MCE 주입

/* include/uapi/linux/kvm.h — MCE 주입 구조체 */
struct kvm_x86_mce {
    __u64 status;      /* MCi_STATUS 값 */
    __u64 addr;        /* MCi_ADDR 값 */
    __u64 misc;        /* MCi_MISC 값 */
    __u64 mcg_status;  /* MCG_STATUS 값 */
    __u8  bank;        /* MCA 뱅크 번호 */
    __u8  pad1[7];
    __u64 pad2[3];
};

/* QEMU에서의 MCE 주입 예시 */
struct kvm_x86_mce mce = {
    .status    = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
               | MCI_STATUS_ADDRV | 0x0136,  /* SRAR: Data Load */
    .addr      = guest_phys_addr,
    .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV,
    .bank      = 1,
};
ioctl(vcpu_fd, KVM_X86_SET_MCE, &mce);

HWPoison과 게스트 메모리 영향

호스트가 물리 페이지를 HWPoison으로 마킹하면, KVM은 GPA↔HPA 매핑을 추적하여 해당 게스트에 MCE를 주입합니다. 동시에 EPT/NPT 테이블에서 매핑을 제거합니다.

단계처리 주체동작
1. 오류 감지호스트 MCE 핸들러MCA 뱅크 읽기, 오류 분류
2. 페이지 격리호스트 메모리 관리HWPoison 플래그 설정, 페이지 오프라인
3. QEMU 알림SIGBUSQEMU 프로세스에 BUS_MCEERR_AO 시그널 전달
4. MCE 주입QEMU → KVMGPA 계산 후 KVM_X86_SET_MCE ioctl 호출
5. EPT/NPT 언맵KVM MMU오염 페이지의 2차 매핑 제거
6. 게스트 처리게스트 커널게스트 내부 memory_failure() 실행
/* arch/x86/kvm/x86.c — MCE 브로드캐스트 및 주입 (개념 코드) */
void kvm_mce_broadcast(struct kvm *kvm, unsigned long pfn)
{
    struct kvm_vcpu *vcpu;
    gfn_t gfn = kvm_pfn_to_gfn(pfn);

    kvm_for_each_vcpu(i, vcpu, kvm) {
        struct kvm_x86_mce mce = {
            .status = MCI_STATUS_VAL | MCI_STATUS_UC | 0x0136,
            .addr   = gfn << PAGE_SHIFT,
            .bank   = 1,
        };
        /* LMCE 지원 시 오류 소유 vCPU에만 주입 */
        if (kvm_vcpu_supports_lmce(vcpu) && kvm_vcpu_owns_gfn(vcpu, gfn)) {
            mce.mcg_status |= MCG_STATUS_LMCE_S;
            kvm_inject_mce(vcpu, &mce);
            break;
        }
        kvm_inject_mce(vcpu, &mce); /* LMCE 미지원: 브로드캐스트 */
    }
}

라이브 마이그레이션과 MCE/HWPoison

시나리오처리 방식위험도
HWPoison 페이지 존재 (게스트 미접근)해당 페이지 스킵, 대상에서 제로 페이지 매핑중간
HWPoison 페이지 존재 (게스트 이미 통보됨)페이지 스킵, 가상 MCE 뱅크 상태 전송중간
마이그레이션 중 UCE 발생마이그레이션 중단 또는 페이지 격리 후 계속높음
vCPU MCE 뱅크 상태 전송KVM_GET_MSRS / KVM_SET_MSRS로 직렬화낮음
실무 참고: QEMU는 -cpu host,+mce,+mca,+lmce로 게스트에 MCE 기능을 노출합니다. +lmce를 추가하면 로컬 MCE도 지원하여 가상화 오버헤드를 줄입니다.

APEI/GHES 통합

APEI(ACPI Platform Error Interface)는 플랫폼 펌웨어와 OS 간의 표준 에러 보고 인터페이스입니다. 서버 플랫폼에서는 펌웨어가 먼저 에러를 수집하고(Firmware-First), GHES(Generic Hardware Error Source)를 통해 OS에 전달하는 방식이 일반적입니다.

Firmware-First vs OS-First MCE 처리 Firmware-First (서버 표준) HW 에러 발생 SMI → 펌웨어 에러 수집/로깅 GHES 통지 SCI/NMI/GPIO ghes_proc() CPER 파싱 → 커널 통지 memory_failure() OS-First (데스크톱/워크스테이션) HW 에러 발생 #MC 벡터 18 직접 CPU 예외 do_machine_check MCA 뱅크 직접 읽기 Monarch → 판정 severity → action memory_failure()

APEI 테이블 구성요소

ACPI 테이블역할
HEST (Hardware Error Source Table)하드웨어 에러 소스 목록과 각 소스의 통지 방법 정의
BERT (Boot Error Record Table)이전 부팅에서 발생한 치명적 에러를 다음 부팅에서 읽기
ERST (Error Record Serialization Table)에러 레코드를 비휘발성 저장소에 영속 저장
EINJ (Error Injection Table)테스트용 에러 주입 인터페이스

CPER (Common Platform Error Record)

GHES가 전달하는 에러 데이터는 CPER 포맷을 따릅니다. 각 에러 레코드에는 하나 이상의 Section이 포함되며, 섹션 타입별로 메모리 에러, PCIe 에러, 프로세서 에러 등을 구분합니다.

/* drivers/acpi/apei/ghes.c — GHES 처리 */
static int ghes_proc(struct ghes *ghes)
{
    struct acpi_hest_generic_status *estatus;

    estatus = ghes->estatus;
    ghes_copy_tofrom_phys(estatus, ghes->buffer_paddr, ...);

    /* CPER 섹션 순회 */
    apei_estatus_for_each_section(estatus, gdata) {
        guid_t *sec_type = (guid_t *)gdata->section_type;

        if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
            /* 메모리 에러 → memory_failure() */
            ghes_handle_memory_failure(gdata, sev);
        } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
            /* PCIe 에러 */
            ghes_handle_aer(gdata);
        }
    }
}

GHES 통지 방법

GHES는 에러를 OS에 알리는 여러 통지 메커니즘을 지원합니다. 통지 방법은 HEST 테이블에 정의되며, 에러 심각도에 따라 다른 경로를 사용합니다.

통지 유형사용 시나리오커널 핸들러
SCI (System Control Interrupt)CE, 비긴급 에러ACPI SCI → ghes_proc()
NMIUC, 긴급 에러NMI 핸들러 → ghes_proc()
GPIO/IRQ플랫폼 고유 인터럽트IRQ 핸들러 → ghes_proc()
Polled폴링 기반 수집타이머 → ghes_proc()
SEA (ARM)동기 외부 중단do_sea() → ghes_notify_sea()
SEI (ARM)비동기 에러do_serror() → ghes_notify_sei()

BERT (Boot Error Record Table)

이전 부팅에서 치명적 에러로 시스템이 리셋된 경우, 펌웨어는 에러 정보를 BERT 영역에 저장합니다. 다음 부팅 시 커널이 BERT를 읽어 이전 에러를 dmesg에 출력합니다.

# BERT 데이터 확인
$ dmesg | grep BERT
[    0.123456] BERT: Error records from previous boot:
[    0.123457] [Firmware Error]: Hardware error from APEI Generic Hardware Error Source: 0
[    0.123458] severity: fatal

# BERT ACPI 테이블 덤프 (디버그)
$ sudo cat /sys/firmware/acpi/tables/BERT | hexdump -C | head

ERST (Error Record Serialization Table)

ERST는 에러 레코드를 비휘발성 저장소(플래시, NVRAM)에 영속적으로 저장하는 인터페이스입니다. 커널은 /sys/firmware/acpi/tables/ERST를 통해 에러 레코드를 쓰고 읽을 수 있습니다. 이는 crash dump와 함께 사후 분석에 활용됩니다.

ACPI 참고: APEI의 상세한 ACPI 구조와 테이블 파싱 방법은 ACPI 서브시스템 페이지를 참조하세요.
GHES 에러 처리 내부 흐름 HEST 파싱 (부팅) acpi_hest_init() GHES 엔트리 등록 ghes_probe() x N개 에러소스 통지 핸들러 설치 SCI/NMI/SEA/IRQ 등록 런타임: 에러 발생 시 처리 흐름 HW 에러 발생 메모리/PCIe/CPU 통지 수신 SCI / NMI / SEA ghes_proc() 에러 소스별 핸들러 estatus 읽기 (물리 주소) ghes_copy_tofrom_phys() CPER 섹션 순회 apei_estatus_for_each_section(estatus, gdata) CPER_SEC_PLATFORM_MEM ghes_handle_memory_failure() memory_failure(pfn) / soft offline CPER_SEC_PCIE ghes_handle_aer() AER 에러 주입, pci_channel_io_frozen CPER_SEC_PROC_ARM ghes_handle_arm() ARM 프로세서 에러 디코드 페이지 오프라인 / 프로세스 kill hwpoison 마킹, 핫 리무브 PCIe 디바이스 복구 / 리셋 드라이버 error_detected() 콜백 트레이스 이벤트 / 로깅 arm_event, hw_error tracepoint guid_equal(sec_type, ...) 공통: trace_mc_event() → rasdaemon / mcelog 수집

CPER 메모리 에러 섹션 구조

GHES가 전달하는 메모리 에러는 UEFI 표준의 CPER Memory Error Section (CPER_SEC_PLATFORM_MEM) 포맷을 따릅니다. 각 필드에는 Validation Bits가 있어 해당 필드가 유효한지를 나타냅니다.

필드크기Validation Bit설명
Validation Bits 8 바이트 이후 각 필드의 유효 여부를 나타내는 비트맵(Bitmap)
Error Status 8 바이트 Bit 0 UEFI 에러 상태 코드 (에러 유형: 내부/버스/메모리 등)
Physical Address 8 바이트 Bit 1 에러가 발생한 물리 주소 — memory_failure(pfn) 호출에 사용
Physical Address Mask 8 바이트 Bit 2 유효 비트 범위 (어느 범위까지 영향받는지)
Node 2 바이트 Bit 3 NUMA 노드 번호
Card 2 바이트 Bit 4 메모리 카드/라이저 번호
Module 2 바이트 Bit 5 DIMM 모듈 번호
Bank 2 바이트 Bit 6 DRAM 뱅크 번호
Device 2 바이트 Bit 7 DRAM 디바이스 (칩) 번호
Row 2 바이트 Bit 8 에러 발생 행 주소
Column 2 바이트 Bit 9 에러 발생 열 주소
Bit Position 2 바이트 Bit 10 에러 발생 비트 위치 (싱글비트 CE 시)
Error Type 1 바이트 Bit 14 0=Unknown, 2=Multi-bit, 3=Single-symbol Chipkill, 8=Scrub CE 등
Module Handle (SMBIOS) 2 바이트 Bit 11 SMBIOS Type 17 핸들 — DIMM 식별 (dmidecode 연동)
/* drivers/acpi/apei/ghes.c — CPER 메모리 섹션 처리 */
static void ghes_handle_memory_failure(
    struct acpi_hest_generic_data *gdata, int sev)
{
    struct cper_sec_mem_err *mem_err;
    unsigned long pfn;

    mem_err = acpi_hest_get_payload(gdata);

    /* Validation Bits 확인: 물리 주소 유효한지 */
    if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
        return;

    /* Physical Address to PFN 변환 */
    pfn = mem_err->physical_addr >> PAGE_SHIFT;

    /* Physical Address Mask 적용 (유효 범위 계산) */
    if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
        pfn &= ~(mem_err->physical_addr_mask >> PAGE_SHIFT);

    /* severity에 따라 분기 */
    if (sev == GHES_SEV_RECOVERABLE) {
        /* Action Required: 즉시 memory_failure() */
        memory_failure_queue(pfn, MF_ACTION_REQUIRED);
    } else {
        /* Corrected: soft offline (예방적 페이지 격리) */
        memory_failure_queue(pfn, 0);
    }

    /* 트레이스 이벤트 발생 — rasdaemon/mcelog 수집용 */
    trace_mc_event(err_type, ...,
        mem_err->node, mem_err->card, mem_err->module,
        mem_err->bank, mem_err->device,
        mem_err->row, mem_err->column, ...);
}

GHES 에러 심각도 매핑

GHES의 에러 심각도(CPER Error Severity)는 커널 내부의 MCE severity 수준으로 매핑됩니다. 이 매핑은 에러 처리 액션(패닉, 프로세스 kill, 로깅 등)을 결정합니다.

GHES SeverityCPER 값커널 매핑처리 액션
Fatal CPER_SEV_FATAL (0) MCE_PANIC_SEVERITY 즉시 커널 패닉(Kernel Panic) — 복구 불가, 시스템 정지
Recoverable CPER_SEV_RECOVERABLE (1) MCE_AR_SEVERITY memory_failure() → 페이지 오프라인, 프로세스 SIGBUS kill
Corrected CPER_SEV_CORRECTED (2) MCE_KEEP_SEVERITY 로깅 + 임계치 기반 soft offline (예방적 격리)
Informational CPER_SEV_INFORMATIONAL (3) MCE_NO_SEVERITY 로깅만 — 통계 수집, 추세 분석용
심각도 확인 명령: dmesg | grep "Hardware error"로 GHES가 보고한 에러의 심각도를 확인할 수 있습니다. severity: fatal이면 시스템이 이미 패닉 상태이므로 crash dump에서 확인해야 합니다. rasdaemon --record를 실행하면 CE/UCE 이벤트를 SQLite DB에 기록하여 시계열 추세를 분석할 수 있습니다.

Firmware-First vs OS-First 선택 기준

에러 처리의 주체를 펌웨어(Firmware-First)와 OS(OS-First) 중 어디로 설정할지는 플랫폼 유형과 운영 환경에 따라 달라집니다. 다음 표는 실무 기준의 선택 가이드입니다.

플랫폼 유형권장 방식에러 경로근거
서버 (UEFI + BMC/IPMI) Firmware-First HW → SMI → 펌웨어 → GHES(SCI/NMI) → OS 펌웨어가 SEL에 기록, BMC 원격 알림, DIMM 위치 식별 가능
데스크톱/워크스테이션 OS-First HW → #MC → do_machine_check() 직접 대부분 HEST 없음. OS가 MCA 뱅크를 직접 읽는 것이 유일한 경로
VM 게스트 하이퍼바이저 위임 HW → 호스트 MCE → 하이퍼바이저 → 가상 MCE 주입 게스트는 MCA 뱅크 접근 불가. KVM은 kvm_mce_broadcast()로 가상 MCE 주입
ARM 서버 Firmware-First (SDEI/SEA) HW → EL3 펌웨어 → GHES(SEA/SDEI) → OS ARM APEI 지원. RAS 확장(ARMv8.2+) 필요
임베디드/IoT 플랫폼 고유 플랫폼별 인터럽트 / GPIO / 폴링 ACPI/UEFI 없는 환경. DT 기반 에러 핸들러 또는 SoC 고유 드라이버
클라우드 인스턴스 CSP 위임 HW → CSP 펌웨어 → 라이브 마이그레이션 또는 가상 MCE AWS/GCP/Azure가 HW 에러 관리. 게스트에 필터링된 에러만 전달
Firmware-First의 주의점: SMI(System Management Interrupt) 기반 Firmware-First는 에러 처리 중 OS가 수백 µs~수 ms 동안 완전히 정지합니다(SMI black hole). 실시간성이 중요한 워크로드에서는 이 지연이 문제가 될 수 있습니다. 커널 부팅 파라미터 mce=no_cmci와 BIOS에서 Firmware-First 비활성화를 함께 설정하면 OS-First로 전환할 수 있지만, DIMM 위치 식별 등 펌웨어 기능을 잃게 됩니다.

EDAC 서브시스템 연동

EDAC(Error Detection And Correction)은 ECC 메모리 에러를 추적하고 물리적 DIMM 위치까지 디코딩하는 리눅스 커널 서브시스템입니다. MCE 또는 GHES로부터 에러 통지를 받아 어떤 DIMM의 어떤 행/열에서 에러가 발생했는지 알려줍니다.

EDAC 아키텍처: MCE → DIMM 위치 디코드 MCE GHES/APEI mce_decoder_chain notifier 콜백 EDAC Core edac_mc_handle_error() mem_ctl_info 관리 ce_count / ue_count 플랫폼 드라이버 i10nm_edac / skx_edac amd64_edac / ghes_edac 주소 → 소켓/채널/DIMM/행/열 sysfs 출력: /sys/devices/system/edac/mc/ mc0/csrow0/ch0_ce_count = 42 → 소켓 0, DIMM A1, CE 42회 mc0/dimm0/dimm_label = "CPU_SrcID#0_MC#0_Chan#0_DIMM#0" mc0/ce_count = 42 | mc0/ue_count = 0

주요 EDAC 드라이버

드라이버플랫폼모듈명
i10nm_edacIntel Ice Lake / Sapphire Rapidsi10nm_edac
skx_edacIntel Skylake-SP / Cascade Lakeskx_edac
sb_edacIntel Sandy/Ivy Bridgesb_edac
amd64_edacAMD K8/Fam10h~Zen4amd64_edac
ghes_edacGHES 기반 (모든 UEFI 서버)ghes_edac
/* drivers/edac/edac_mc.c */
void edac_mc_handle_error(
    const enum hw_event_mc_err_type type,
    struct mem_ctl_info *mci,
    const u16 error_count,
    const unsigned long page_frame_number,
    const unsigned long offset_in_page,
    const unsigned long syndrome,
    const int top_layer,      /* 채널 */
    const int mid_layer,      /* DIMM */
    const int low_layer,      /* 행/열 */
    const char *msg,
    const char *other_detail)
{
    /* EDAC 에러 카운터 증가 + tracepoint + sysfs 업데이트 */
    trace_mc_event(type, msg, label, error_count, ...);
    edac_inc_ce_error(mci, enable_per_layer_report, pos);
}
EDAC 상태 확인: edac-util -s (요약), edac-util -r (DIMM별 상세), ras-mc-ctl --summary (rasdaemon 연동 요약).

EDAC sysfs 인터페이스 상세

EDAC은 /sys/devices/system/edac/ 아래에 계층적 sysfs 인터페이스를 제공합니다. 메모리 컨트롤러(mc), 칩셋 검증(pci), 에러 카운터 등을 확인할 수 있습니다.

# EDAC 메모리 컨트롤러 계층
/sys/devices/system/edac/mc/
├── mc0/                          # 메모리 컨트롤러 0
│   ├── ce_count                  # 총 CE 횟수
│   ├── ue_count                  # 총 UE 횟수
│   ├── ce_noinfo_count           # 위치 정보 없는 CE
│   ├── ue_noinfo_count           # 위치 정보 없는 UE
│   ├── seconds_since_reset       # 카운터 리셋 후 경과 시간
│   ├── mc_name                   # 드라이버 이름 (예: "skx_edac")
│   ├── size_mb                   # 총 메모리 크기
│   ├── dimm0/                    # DIMM 0
│   │   ├── dimm_ce_count         # 이 DIMM의 CE 횟수
│   │   ├── dimm_dev_type         # DDR4, DDR5 등
│   │   ├── dimm_edac_mode        # SECDED, Chipkill 등
│   │   ├── dimm_label            # DIMM 물리 위치 레이블
│   │   ├── dimm_location         # 채널/슬롯/랭크
│   │   └── dimm_mem_type         # Registered, Unbuffered
│   └── csrow0/                   # 칩-셀렉트 행 0
│       ├── ch0_ce_count          # 채널 0의 CE
│       └── ch1_ce_count          # 채널 1의 CE
DIMM 레이블 설정: echo "DIMM_A1" > /sys/devices/system/edac/mc/mc0/dimm0/dimm_label로 물리 슬롯 이름을 설정하면 에러 메시지에 해당 레이블이 포함되어 DIMM 식별이 쉬워집니다. ras-mc-ctl --register-labels를 사용하면 DMI/SMBIOS에서 자동 설정합니다.
EDAC 물리 주소 → DIMM 디코딩 과정 Physical Address 0x3A7F_C400_0080 Step 1 Socket Decode (Address Interleaving) Step 2 Channel Decode (Channel Hash) Step 3 DIMM/Rank Select (Rank Interleave) Step 4: Row / Column / Bank Decode DRAM 주소 비트 매핑 (open/close page) 디코딩 결과 Socket 0, Channel 1, DIMM 0, Rank 1 Row 0x1A3F, Col 0x040, Bank 3, BankGroup 1 Intel ADXL SKX/ICX/SPR 펌웨어 제공 디코드 테이블 adxl_decode() → 소켓/채널/DIMM skx_edac, i10nm_edac 사용 ACPI DSM 기반 decode table 런타임 재매핑 반영 AMD UMC Zen/Zen2/Zen3/Zen4 UMC 레지스터 직접 읽기 amd64_edac → umc_normaddr_to_sysaddr() Data Fabric interleave 해석 NPS(NUMA Per Socket) 모드 반영 CS/Bank/Row/Col 비트 매핑 GHES (CPER) 모든 UEFI 서버 펌웨어가 사전 디코드 CPER Memory Section ghes_edac → CPER 파싱 Node/Card/Module/Bank/Row/Col Physical Address Mask 포함

EDAC 주소 디코딩 알고리즘

MCE/GHES로부터 전달받은 물리 주소를 실제 DIMM 위치로 변환하는 과정은 플랫폼마다 다릅니다. 주소 인터리빙, 채널 해싱, 랭크 인터리빙 등 메모리 컨트롤러 설정에 따라 동일한 물리 주소라도 다른 DIMM에 매핑될 수 있습니다.

디코딩 방식플랫폼디코드 소스정확도특징
Intel ADXL SKX / ICX / SPR ACPI DSM 디코드 테이블 매우 높음 런타임 메모리 재매핑(sparing, mirroring failover) 자동 반영
AMD UMC 레지스터 Zen ~ Zen4+ UMC PCI config space 높음 Data Fabric interleave 비트 해석, NPS 모드 반영
GHES/CPER 모든 UEFI 서버 펌웨어 사전 디코드 높음 (펌웨어 의존) Physical Address Mask로 에러 범위 표시 가능
레거시 (sb_edac 등) Sandy/Ivy Bridge PCI SAD/TAD 레지스터 중간 수동 레지스터 파싱, 일부 인터리빙 모드 미지원
/* Intel ADXL 기반 디코딩 — drivers/edac/skx_common.c */
static int skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_mem)
{
    struct skx_dev *d;
    int i, len = 0;

    /* ADXL 라이브러리에 물리 주소 전달 → 디코드 테이블 참조 */
    if (adxl_decode(res->addr, adxl_values)) {
        edac_dbg(0, "Failed to decode addr 0x%llx\n", res->addr);
        return -EINVAL;
    }

    /* 디코드 결과에서 소켓/IMC/채널/DIMM/랭크 추출 */
    res->socket  = (int)adxl_values[adxl_component_indices[INDEX_SOCKET]];
    res->imc     = (int)adxl_values[adxl_component_indices[INDEX_MEMCTRL]];
    res->channel = (int)adxl_values[adxl_component_indices[INDEX_CHANNEL]];
    res->dimm    = (int)adxl_values[adxl_component_indices[INDEX_DIMM]];
    res->rank    = (int)adxl_values[adxl_component_indices[INDEX_RANK]];

    /* mem_ctl_info에서 해당 컨트롤러/DIMM 구조체 검색 */
    if (skx_adxl_get_mci(res))
        return -ENODEV;

    return 0;
}

/* AMD UMC 기반 디코딩 — drivers/edac/amd64_edac.c */
static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid,
                                     u8 umc, u64 *sys_addr)
{
    /* UMC 정규화 주소 → 시스템 물리 주소 변환 */
    /* Data Fabric interleave 비트, NPS 모드, CS base/mask 참조 */
    get_df_interleave(nid, umc, &intlv_num_chan, &intlv_addr_sel);
    /* ... */
}
ADXL vs 레거시 디코딩: Intel Skylake-SP 이전 세대(Sandy Bridge, Haswell)는 SAD/TAD PCI 레지스터를 드라이버가 직접 파싱했습니다. SKX 이후로는 펌웨어가 제공하는 ADXL(Address Decode Library) 테이블을 사용하여 메모리 스페어링/미러링 전환 후에도 정확한 디코딩이 가능합니다. AMD Zen 아키텍처에서는 UMC(Unified Memory Controller) 레지스터를 통해 Data Fabric의 인터리빙 방식까지 반영한 디코딩을 수행합니다.

EDAC과 rasdaemon 연동

rasdaemon은 커널 EDAC 서브시스템이 발생시키는 ras:mc_event tracepoint를 구독하여 메모리 에러를 SQLite 데이터베이스에 기록합니다. 이를 통해 장기적인 DIMM 건강 추이 분석과 사전 교체 판단이 가능합니다.

데이터 흐름 단계구성 요소설명
1. 에러 감지 HW → MCE/GHES ECC 에러 발생 → MCA bank 또는 GHES CPER 기록
2. EDAC 처리 edac_mc_handle_error() 물리 주소 → DIMM 위치 디코딩, ce_count/ue_count 증가
3. Tracepoint 발행 trace_mc_event() ras:mc_event tracepoint로 에러 정보 브로드캐스트
4. rasdaemon 수집 rasdaemon → tracefs /sys/kernel/tracing/events/ras/mc_event 구독
5. DB 기록 SQLite /var/lib/rasdaemon/ras-mc_event.db에 영구 저장
# rasdaemon 설치 및 서비스 시작
$ sudo apt install rasdaemon          # Debian/Ubuntu
$ sudo dnf install rasdaemon          # RHEL/Fedora
$ sudo systemctl enable --now rasdaemon

# rasdaemon이 trace event를 수신하는지 확인
$ sudo cat /sys/kernel/tracing/events/ras/mc_event/enable
1

# SQLite DB 위치 확인
$ ls -la /var/lib/rasdaemon/ras-mc_event.db

DIMM 건강 분석 SQL 쿼리: rasdaemon의 SQLite DB를 직접 쿼리하면 EDAC sysfs보다 훨씬 풍부한 시계열 분석이 가능합니다.

-- 최근 7일간 DIMM별 CE 추이
SELECT
    date(timestamp, 'unixepoch') AS day,
    mc, top_layer AS channel, mid_layer AS dimm,
    COUNT(*) AS ce_count
FROM mc_event
WHERE err_type = 'Corrected'
  AND timestamp > strftime('%s', 'now', '-7 days')
GROUP BY day, mc, channel, dimm
ORDER BY day, ce_count DESC;

-- 에러가 가장 많은 상위 5개 DIMM
SELECT
    mc, top_layer AS channel, mid_layer AS dimm,
    SUM(CASE WHEN err_type = 'Corrected' THEN error_count ELSE 0 END) AS total_ce,
    SUM(CASE WHEN err_type = 'Uncorrected' THEN error_count ELSE 0 END) AS total_ue,
    MIN(datetime(timestamp, 'unixepoch')) AS first_error,
    MAX(datetime(timestamp, 'unixepoch')) AS last_error
FROM mc_event
GROUP BY mc, channel, dimm
ORDER BY total_ce + total_ue * 1000 DESC
LIMIT 5;

-- CE → UE 에스컬레이션 탐지: CE 급증 후 UE 발생한 DIMM
SELECT ue.mc, ue.top_layer AS channel, ue.mid_layer AS dimm,
    ce_before.ce_count AS ce_before_ue,
    datetime(ue.timestamp, 'unixepoch') AS ue_time
FROM mc_event ue
JOIN (
    SELECT mc, top_layer, mid_layer, COUNT(*) AS ce_count,
           MAX(timestamp) AS last_ce
    FROM mc_event
    WHERE err_type = 'Corrected'
    GROUP BY mc, top_layer, mid_layer
) ce_before ON ue.mc = ce_before.mc
    AND ue.top_layer = ce_before.top_layer
    AND ue.mid_layer = ce_before.mid_layer
WHERE ue.err_type = 'Uncorrected'
    AND ce_before.ce_count > 10
ORDER BY ce_before.ce_count DESC;
자동화 팁: 위 쿼리들을 cron 스크립트에 통합하여 매일 DIMM 건강 리포트를 생성하면, CE가 급증하는 DIMM을 UE(복구 불가 에러)가 발생하기 전에 사전 교체할 수 있습니다. CE 24시간 누적 100회 이상이면 교체 후보로 분류하는 것이 일반적인 기준입니다.

RAS 유저스페이스 도구

MCE 이벤트를 수집, 디코딩, 분석하는 유저스페이스 도구입니다. mcelog은 레거시이고, 현재는 rasdaemon이 표준입니다.

도구 비교

도구상태데이터 소스저장특징
mcelog레거시 (deprecated)/dev/mcelog로그 파일 독립 데몬, 간단한 디코딩. 최신 커널에서 /dev/mcelog 제거 추세
rasdaemon현재 표준perf tracepointSQLite DB 다양한 에러 소스 통합(MCE/EDAC/GHES/AER/CXL), 구조화 로깅
ras-mc-ctlrasdaemon 포함rasdaemon DB- EDAC 요약, 에러 카운트, DIMM 레이블 관리
edac-util활성sysfs EDAC- EDAC sysfs 인터페이스의 사용자 친화적 래퍼

rasdaemon 설정 및 사용

# 설치 (RHEL/CentOS)
$ sudo yum install rasdaemon

# 서비스 시작
$ sudo systemctl enable --now rasdaemon

# 에러 요약 조회
$ sudo ras-mc-ctl --summary
Memory controller events summary:
        Corrected on DIMM Label(s): CPU_SrcID#0_MC#0_Chan#0_DIMM#0 location: 0:0:0:-1 errors: 42
        No Uncorrected errors.

# SQLite DB 직접 조회
$ sudo sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
  "SELECT timestamp, err_type, mc, top_layer, mid_layer, msg FROM mc_event ORDER BY id DESC LIMIT 10;"

# MCE 이벤트 조회
$ sudo ras-mc-ctl --errors
$ sudo sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
  "SELECT timestamp, mcgstatus, status, addr, bank FROM mce_record ORDER BY id DESC LIMIT 5;"
systemd 통합: systemd-journald도 MCE 이벤트를 journalctl -k -g "mce:"로 필터링할 수 있지만, 구조화된 분석에는 rasdaemon의 SQLite DB가 훨씬 효과적입니다.

rasdaemon 아키텍처

rasdaemon은 커널의 perf_event tracepoint를 구독하여 에러 이벤트를 수집합니다. ras:mc_event, ras:aer_event, ras:mce_record, ras:cxl_poison 등의 tracepoint를 모니터링하며, 수집된 데이터를 SQLite 데이터베이스에 저장합니다.

# rasdaemon이 구독하는 tracepoint 확인
$ sudo ls /sys/kernel/debug/tracing/events/ras/
aer_event      cxl_general_media  cxl_poison       mc_event
arm_event      cxl_memory_module  extlog_mem_event mce_record
cxl_dram       cxl_overflow       non_standard_event

# 실시간 트레이스 확인 (디버그 용)
$ sudo cat /sys/kernel/debug/tracing/events/ras/mc_event/enable
1
$ sudo cat /sys/kernel/debug/tracing/trace_pipe | grep mc_event

rasdaemon vs mcelog 마이그레이션

기존 mcelog 사용 환경에서 rasdaemon으로 전환할 때 주의할 점:

# mcelog → rasdaemon 전환
$ sudo systemctl stop mcelog
$ sudo systemctl disable mcelog
$ sudo systemctl enable --now rasdaemon

# 이전 mcelog 데이터는 수동 마이그레이션 필요
# rasdaemon은 tracepoint 기반이므로 /dev/mcelog 비사용
rasdaemon 주요 명령어 요약:
  • ras-mc-ctl --summary — 전체 에러 요약
  • ras-mc-ctl --errors — 에러 목록 상세
  • ras-mc-ctl --mainboard — 메인보드 정보
  • ras-mc-ctl --layout — DIMM 레이아웃
  • ras-mc-ctl --status — EDAC 드라이버 상태

CXL 메모리 에러와 MCE

CXL(Compute Express Link) 메모리 장치는 기존 DRAM과는 다른 에러 보고 경로를 사용합니다. CXL 프로토콜 에러는 PCIe AER 또는 GHES를 통해 보고되며, 궁극적으로 memory_failure()로 이어집니다.

CXL 에러 경로

에러 유형보고 경로커널 처리
CXL.mem 프로토콜 에러 GHES → CPER CXL 섹션 cxl_cper_handle_prot_err()
CXL 미디어 에러 (UC) GHES → CPER Memory → MCE notifier memory_failure() → HWPoison
CXL 미디어 에러 (CE) CXL 이벤트 로그 / GHES EDAC/rasdaemon 통계
CXL Poison List CXL mailbox 명령 cxl_mem_get_poison() → 선제 오프라인
/* drivers/cxl/core/mbox.c — Poison List 조회 */
int cxl_mem_get_poison(struct cxl_memdev *cxlmd,
                       u64 offset, u64 len,
                       struct cxl_region *cxlr)
{
    struct cxl_mbox_poison_out *po;
    int rc;

    rc = cxl_internal_send_cmd(mds, &mbox_cmd);
    if (rc)
        return rc;

    /* Poison 리스트 엔트리 순회 */
    for (i = 0; i < le16_to_cpu(po->count); i++) {
        trace_cxl_poison(cxlmd, cxlr, &po->record[i],
                         po->flags, po->overflow_ts, CXL_POISON_TRACE_LIST);
    }
    return 0;
}
CXL 관련 문서: CXL 메모리 아키텍처의 상세한 내용은 CXL 메모리 페이지를 참고하세요. MCE 관점에서 CXL은 "또 다른 에러 소스"이며, 최종적으로 memory_failure() 경로에 합류합니다.

GPU/가속기 MCE 연쇄 에러 분석

현대 데이터센터와 AI/ML 학습 클러스터에서 GPU 및 하드웨어 가속기에서 발생하는 하드웨어 에러(ECC 오류, DMA 장애 등)는 PCIe AER을 거쳐 CPU의 IIO MCA 뱅크에 기록되고, 최종적으로 MCE로 전파됩니다. 이 연쇄 과정을 정확히 이해해야 장애 원인을 신속하게 격리할 수 있습니다.

GPU 에러 연쇄 전파 경로

GPU HBM/GDDR ECC 에러 발생 NVIDIA Xid Error Xid 48/63/94/95 PCIe AER Poisoned TLP / UR IIO MCA Bank IA32_MC(i)_STATUS MCE Handler do_machine_check() memory_failure() 페이지 오프라인 Device Reset FLR / 드라이버 복구 NVLink / CXL 인터커넥트 에러 VT-d / IOMMU DMA 폴트 ECC CE/UE AER 보고 MCA 기록 MCE 발생

Xid 에러 코드와 MCE 상관관계

Xid 코드설명MCE 전파 여부IIO MSCOD증상조치
Xid 48DBE (Double Bit Error)높음 (UE)0x0136학습 NaN, GPU 행(hang)GPU 교체, nvidia-smi -r
Xid 63Row remapping 실패중간0x0136ECC 에러 급증 후 remapping 실패GPU 교체 예약
Xid 79GPU 복구 실패높음0x0402GPU 응답 없음노드 재시작 필요
Xid 94Contained ECC 에러낮음 (CE)-정상 동작, CE 카운터 증가카운터 모니터링
Xid 95Uncontained ECC 에러높음 (UE)0x0136프로세스 강제 종료, 패닉 가능즉시 GPU 교체

GPU Xid와 MCE 뱅크/IIO 스택 상관분석

# GPU의 PCIe 위치 확인
$ lspci -d 10de: -vvs 41:00.0
41:00.0 3D controller: NVIDIA Corporation A100
    UESta:  0x00004000  # ← Completion Abort 비트

# MCE 로그에서 Bank 번호 → IIO 스택 역추적
# Bank 6 = IIO Stack 1 (Skylake-SP 기준)
mce: [Hardware Error]: CPU 24 Bank 6:
  STATUS 0xbc20000001000136
  # MSCOD=0x0136: Received Parity Error
  # UC=1, PCC=1 → 프로세서 컨텍스트 손상

# GPU ECC 상태 확인
$ nvidia-smi --query-gpu=ecc.errors.corrected.volatile.total,\
ecc.errors.uncorrected.volatile.total,retired_pages.count --format=csv

GPU 관련 MCE 패턴 종합표

패턴MSCOD증상근본 원인조치
GPU ECC UE0x0136학습 NaN, Xid 48/95HBM/GDDR 결함GPU 교체
Completion Timeout0x0402GPU 행, 디바이스 소실GPU 펌웨어/PCIe 링크PCIe 리트레이닝, FLR
Poisoned TLP0x0136DMA 읽기 실패호스트 메모리 UCEDIMM 교체
VT-d Translation Fault0x0010IOMMU 폴트드라이버/IOMMU 설정 오류iommu=pt, 드라이버 업데이트
NVLink Degradation0x0136Xid 74, 성능 저하NVLink 케이블/NVSwitch 결함케이블 교체

AI/ML 학습 클러스터 MCE 영향

/* 분산 학습 중 단일 GPU ECC UE 발생 시 타임라인 */
T+0ms    GPU 3의 HBM에서 DBE(Double Bit Error) 발생
T+0.1ms  NVIDIA 드라이버 Xid 48 기록
T+0.5ms  PCIe AER Uncorrectable Error 전파
T+1ms    IIO MCA Bank 7에 기록 → MCE 핸들러 호출
T+2ms    memory_failure() 호출 — 오염 페이지 오프라인
T+100ms  GPU CUDA 컨텍스트 무효화
T+200ms  PyTorch/NCCL: Rank 3 통신 실패 감지
T+30s    NCCL timeout → 전체 AllReduce 데드락
T+60s    모든 Rank 학습 중단 → 마지막 체크포인트로 롤백 필요

// 영향: 8-GPU 노드 1대의 GPU 1개 장애
//       → 전체 클러스터 학습 중단

클러스터 운영 권장사항

아키텍처별 하드웨어 에러 처리 비교

MCE는 x86 고유 개념이지만, ARM, RISC-V, POWER 등 모든 서버급 아키텍처에 유사한 하드웨어 에러 보고 메커니즘이 있습니다. 각 아키텍처의 에러 감지/보고/복구 설계를 비교하면 하드웨어 RAS(Reliability, Availability, Serviceability)의 본질적인 문제와 해결 패턴을 더 깊이 이해할 수 있습니다.

크로스 아키텍처 하드웨어 에러 처리 비교 x86 (MCE) 벡터 18 #MC MCA 뱅크 (MSR) CMCI (CE 인터럽트) Monarch 랑데부 do_machine_check() APEI/GHES (선택) ARM (RAS Extension) SEA (Synchronous External Abort) SEI (SError Interrupt) ERRn 레지스터 (RAS Ext v1) SDEI (Software Delegated) do_sea() / do_serror() GHES (주요 경로) RISC-V 표준화 진행중 플랫폼별 구현 SBI MPXY 에러 보고 (SiFive/T-Head 독자) 플랫폼 핸들러 GHES (UEFI 구현 시) 공통 경로: GHES → memory_failure() → HWPoison 아키텍처에 무관하게 페이지 오프라인/프로세스 킬 동일

ARM RAS Extension 상세

메커니즘유형특성
SEA (Synchronous External Abort)동기x86 SRAR과 유사. 데이터 소비 중 UC 에러. memory_failure(MF_ACTION_REQUIRED)
SEI/SError비동기x86 SRAO/UCNA와 유사. 비동기적 외부 에러. 복구 가능성은 ESR_ELx로 판단
SDEI (Software Delegated Exception Interface)펌웨어 위임Firmware-First 모델. EL3/Secure World에서 에러 수집 → GHES로 전달
ERRn 레지스터RAS Extension v1ERR<n>STATUS, ERR<n>ADDR, ERR<n>MISC0/1 — x86 MCA 뱅크와 구조적으로 유사
/* arch/arm64/mm/fault.c — SEA 처리 */
static int do_sea(unsigned long far, unsigned long esr,
                  struct pt_regs *regs)
{
    /* GHES SEA handler에 먼저 전달 */
    if (ghes_notify_sea() >= 0)
        return 0;  /* GHES가 처리 완료 */

    /* GHES가 처리하지 못하면 프로세스 킬 */
    arm64_notify_die("Synchronous External Abort", regs, esr);
    return 0;
}

ARM RAS Extension v1 레지스터

ARM RAS Extension v1은 x86 MCA 뱅크와 유사한 에러 레코드 레지스터를 정의합니다. 각 에러 노드(Error Record)는 ERRn 접두사를 가진 시스템 레지스터 세트로 구성됩니다.

레지스터역할x86 MCA 대응
ERRIDR_EL1에러 레코드 수 및 기능 확인MCG_CAP
ERRnSTATUS에러 상태 (V/UE/CE/OF 비트)MCi_STATUS
ERRnADDR에러 발생 물리 주소MCi_ADDR
ERRnMISC0/1추가 에러 정보MCi_MISC
ERRnCTLR에러 보고 활성화 제어MCi_CTL
ERRnFRFeature Register — 지원 기능해당 없음

RISC-V 하드웨어 에러 표준화 현황

RISC-V는 아직 하드웨어 에러 보고에 대한 공식 표준이 확립되지 않았습니다. 현재 진행 중인 표준화 작업과 벤더 독자 구현이 혼재합니다:

IBM POWER EEH (Enhanced Error Handling) 상세

IBM POWER 아키텍처는 PCI I/O 에러 처리를 위해 EEH(Enhanced Error Handling)를 제공합니다. x86의 AER과 유사한 역할이지만, 하이퍼바이저 계층을 통한 격리와 자동화된 단계적 복구에 초점을 맞춥니다.

EEH 동작 메커니즘

  1. 에러 감지: PHB(PCI Host Bridge)가 PCI/PCIe 버스 에러를 감지
  2. PE 격리: 에러 발생 PE(Partitionable Endpoint)를 즉시 I/O 격리(frozen) 상태로 전환. MMIO 읽기는 모두 0xFF 반환
  3. OPAL 통지: 하이퍼바이저가 OS에 EEH 이벤트 전달
  4. 단계적 복구: I/O 재시도 → 슬롯 리셋 → PHB 리셋 → 실패 시 PE 영구 비활성화 (최대 5회)
/* arch/powerpc/kernel/eeh_driver.c — EEH 복구 콜백 */
static int eeh_report_error(struct eeh_dev *edev, struct eeh_pe *pe)
{
    struct pci_driver *drv = eeh_pcid_get(edev->pdev);
    if (!drv || !drv->err_handler || !drv->err_handler->error_detected)
        return PCI_ERS_RESULT_NONE;
    /* 드라이버에 에러 통지 — 복구 가능 여부 응답 */
    return drv->err_handler->error_detected(edev->pdev, edev->state);
}

POWER vs x86 vs ARM 에러 처리 비교

비교 항목IBM POWERx86 (Intel/AMD)ARM (Neoverse)
에러 예외Machine Check (벡터 0x200)#MC (벡터 18)SEA / SError
에러 레지스터SRR1, DSISR, OPAL 에러 로그MCA 뱅크 (MCi_STATUS/ADDR/MISC)ERRn 레지스터 (RAS Extension)
PCIe I/O 에러EEH (PHB 기반 PE 격리)AER + IIO MCASMMU + AER + GHES
에러 격리 단위PE (Partitionable Endpoint)PCIe 장치/기능 단위SMMU Stream ID 기반
복구 메커니즘EEH 단계적 복구 (최대 5회)AER 드라이버 콜백 + memory_failure()GHES → memory_failure()
펌웨어 역할OPAL/skiboot (필수, 에러 수집/필터링)APEI/GHES (선택적)SDEI → GHES (주요 경로)
Poison/SUESUE (Special Uncorrectable Error)Viral Mode / Data PoisoningPoison 비트 (CMN-700)
CPU 동기화Hypervisor 위임 (FWNMI)Monarch 랑데부코어별 독립 처리
메모리 에러 복구memory_failure() + HWPoison (OPAL 경유)memory_failure() + HWPoisonmemory_failure() + HWPoison (GHES 경유)
가상화 환경FWNMI — 하이퍼바이저가 게스트에 에러 주입LMCE + vMCE (KVM)SDEI → 게스트 GHES
POWER의 설계 철학: IBM POWER는 하이퍼바이저(OPAL/PowerVM)를 에러 처리의 중심에 놓습니다. x86이 OS 커널(Monarch)에서 직접 판단하는 것과 달리, POWER는 펌웨어가 에러를 사전 필터링하고 복구 가능 여부를 판단한 후 OS에 전달합니다. EEH는 단순한 에러 보고를 넘어 자동화된 단계적 복구까지 포함하는 점이 x86 AER 대비 주요 차별점입니다.

ARM RAS Extension v1/v1.1

ARMv8.2-A에서 도입된 FEAT_RAS(RAS Extension v1)는 하드웨어 에러 감지와 보고를 표준화한 것으로, x86 MCA에 대응하는 ARM의 공식 RAS 프레임워크입니다. ARMv8.4-A에서 FEAT_RASv1p1(v1.1)으로 강화되었습니다.

ARM RAS Extension 에러 처리 경로 하드웨어 에러 소스 L1/L2 캐시 LLC (System Cache) 메모리 컨트롤러 인터커넥트 (CMN) PCIe/SMMU GIC/타이머 ERRn 레지스터 (RAS Extension v1) ERRnSTATUS ERRnADDR ERRnMISC0/1 ERRnCTLR/FR Memory-mapped 또는 System Register 접근 EL3 Firmware (Secure World) ATF/TF-A RAS SDEI 발생기 CPER 레코드 생성 Firmware-First: 펌웨어가 에러 수집 → GHES로 전달 동기: SEA (Data Abort) ESR_ELx.EC = 0x25 (External Abort) 데이터 소비 중 UC → 즉시 처리 비동기: SError (SEI) ESR_ELx.ISS.AET 필드로 분류 백그라운드 에러 → 지연 처리 SDEI → GHES 경유 EL3에서 EL1으로 위임된 예외 ghes_notify_sea() 호출 do_sea() → SIGBUS/kill do_serror() → panic 가능 ghes_proc() → CPER 파싱 memory_failure(pfn, flags) → HWPoison → 페이지 오프라인 / SIGBUS x86/ARM/RISC-V 공통 최종 경로 SEA = Synchronous External Abort | SError/SEI = System Error Interrupt | SDEI = Software Delegated Exception Interface

ARM FEAT_RAS vs FEAT_RASv1p1 차이

기능FEAT_RAS (v1, ARMv8.2)FEAT_RASv1p1 (v1.1, ARMv8.4)
에러 레코드ERRnSTATUS/ADDR/MISC0/1/CTLR/FR동일 + ERRnPFGF, ERRnPFGCTL (Fault Injection)
DoubleFault미지원FEAT_DoubleFault — 에러 핸들링 중 2번째 에러 시 EL3로 라우팅
에러 분류 세분화CE/UC 2단계CE/DE(Deferred)/UC/UEO(Uncorrected Error Overwritten) 4단계
Deferred Error기본 지원DE(Deferred Error) 전용 상태 비트 표준화, AMD SMCA Deferred와 유사
SError 분류AET 필드 (2비트)IESB(Implicit Error Synchronization Barrier) 추가 — 에러 동기화 강화
Fault Injection미지원ERRnPFG* 레지스터로 소프트웨어 에러 주입 가능 (x86 EINJ 대응)
Timestamp미지원ERRnTS 레지스터 — 에러 타임스탬프 기록 (Generic Timer 기반)

ARM Neoverse 플랫폼별 RAS 구현

ARM Neoverse는 서버/인프라용 CPU IP로, 세대별로 RAS 기능이 다릅니다. AWS Graviton, Ampere Altra, Microsoft Cobalt 등 클라우드 서버에 사용됩니다.

코어 IP사용 제품RAS 버전에러 노드 수주요 RAS 기능
Neoverse N1 Graviton2, Altra FEAT_RAS v1 코어당 ~10개 L1/L2 ECC, 캐시 라인(Cache Line) 무효화 복구, SEA/SError, GHES 연동
Neoverse V1 Graviton3 FEAT_RAS v1.1 코어당 ~14개 V1 추가: DoubleFault, Deferred Error 표준화, 256-bit SVE 에러 감지
Neoverse N2 Graviton4, Cobalt 100 FEAT_RAS v1.1 코어당 ~16개 N2 추가: MPAM RAS 통합, CMN-700 인터커넥트 에러 강화
Neoverse V2 Graviton4(고성능 변종) FEAT_RAS v1.1 코어당 ~18개 V2 추가: 128-bit SME 에러 감지, 향상된 에러 신드롬
Neoverse V3/N3 차세대 FEAT_RAS v2 (예정) 확장 FEAT_RASv2: 에러 카운터 표준화, 더 정교한 에러 분류

ARM CMN (Coherent Mesh Network) 에러

ARM 서버 SoC의 인터커넥트인 CMN-600/CMN-700은 x86의 Mesh/CHA에 대응합니다. CMN 에러는 별도의 에러 노드를 통해 보고되며, GHES 경로로 OS에 전달됩니다.

CMN 에러 유형x86 대응설명
SN(Slave Node) ECC ErrorCHA LLC ECCSystem Level Cache(SLC) ECC 에러
HN-F(Home Node Filter) ErrorCHA Snoop Filter코히런스 디렉토리 에러
XP(Cross Point) ErrorMesh Data Fabric메시 라우팅 노드 에러
RN-D(Request Node DMA) ErrorIIO DMADMA 에이전트 에러
SBSX(SB SLC Exclusive) ErrorM2M메모리 인터페이스 노드 에러

Intel vs AMD MCA 아키텍처 차이 종합

x86 내에서도 Intel과 AMD는 MCA 구현에 상당한 차이가 있습니다. 같은 "MCA"라도 뱅크 식별 방식, 에러 분류, 복구 메커니즘, 레지스터 확장이 다릅니다.

Intel vs AMD MCA 아키텍처 핵심 차이 Intel MCA 뱅크 식별: 고정 매핑 (CPU 모델별 매뉴얼 참조) 에러 코드: MCA 표준 + MSCOD (모델 고유) CE 인터럽트: CMCI (APIC LVT + MCi_CTL2) 로컬 MCE: LMCE (MCG_EXT_CTL.LMCE_EN) 복구: SRAR/SRAO/UCNA (MCG_CAP.MCG_SER_P) Uncore: IIO / M2M / CHA / UPI / PCU / MDF(SPR+) 메모리 RAS: ADDDC / Mirroring / Sparing / Patrol Scrub AMD SMCA (Zen+) 뱅크 식별: IPID 동적 (HWID + MCATYPE) 에러 코드: MCA 표준 + SYND (신드롬) + IPID CE 인터럽트: Threshold (APIC LVT) + CMCI 호환 Deferred Error: DESTAT/DEADDR 전용 레지스터 복구: Deferred + Poison 선제 오프라인 Uncore: NBIO / PCIE / CS / PIE / UMC / xGMI 메모리 RAS: ECC Poison / DRAM Post Package Repair SMCA 장점: 세대 불문 동일 코드로 디코딩 | Intel 장점: MSCOD로 더 세밀한 에러 분류, LMCE로 성능 최적화
비교 항목Intel (Xeon Scalable)AMD (EPYC, Zen)
뱅크 식별 고정 번호 (Bank 0=IFU, Bank 4=PCU 등). CPU 세대마다 번호-유닛 매핑이 변경됨. SDM/에러코드 레퍼런스 참조 필요 MCi_IPID 레지스터의 HWID+MCATYPE으로 런타임 식별. Zen 1~5 모두 동일 디코딩 코드 사용 가능
레지스터 수 뱅크당 5개 (CTL, STATUS, ADDR, MISC, CTL2) 뱅크당 최대 10개 (+IPID, SYND, DESTAT, DEADDR, CONFIG)
에러 분류 SRAR/SRAO/UCNA (STATUS 비트 조합으로 분류). MCG_CAP.MCG_SER_P=1이면 복구 가능 Deferred Error가 별도 유형으로 존재. SRAR/SRAO 외에 Deferred(잠재적 에러) 독립 처리
CE 보고 CMCI (MCi_CTL2.CMCI_EN, 임계값 기반). CMCI 스톰 시 자동 폴링 전환 Threshold Interrupt (APIC LVT). 뱅크별 CE 임계값 설정. CMCI 호환 모드도 지원
브로드캐스트 제어 LMCE (Local MCE) — 특정 에러를 해당 CPU에만 전달. 다른 CPU의 VMEXIT 방지 LMCE 미지원. 모든 UC MCE는 브로드캐스트. (Zen 5+에서 지원 가능성)
ECC 신드롬 MCi_MISC에 제한적 신드롬 정보 MCi_SYND 전용 레지스터에 상세 신드롬 (에러 비트 위치, ECC 패턴)
Deferred Error 없음 (patrol scrub UC → 즉시 MCE 또는 SRAO) DESTAT/DEADDR로 잠재 에러 기록 → 소프트웨어가 선제 오프라인 가능
I/O 에러 IIO 뱅크 (MSCOD로 PCIe 에러 세분화). AER과 이중 보고 NBIO/PCIE 뱅크 (SMCA IPID로 식별). PCIe AER은 별도
인터커넥트 UPI (Bank 5~6). 소켓 간 CRC/Protocol Error xGMI PCS/PHY, GMI PCS/PHY, WAFL. 다이 간/소켓 간 링크 별도 뱅크
메모리 컨트롤러 iMC(Bank 13~20) + M2M(Bank 9~12). ADDDC, Mirroring, Sparing UMC (SMCA_UMC). On-die ECC(DDR5), Post Package Repair(PPR)
보안 프로세서 해당 없음 (별도 MCA 뱅크 없음) PSP(Platform Security Processor) 뱅크 — PSP 펌웨어 에러 보고
Poison 전파 Viral Mode (BIOS 설정) — Containment/Propagation 선택 Data Poisoning 기본 지원 — Deferred Error로 선제 대응 가능
커널 소스 arch/x86/kernel/cpu/mce/intel.c, severity.c arch/x86/kernel/cpu/mce/amd.c, smca.c
운영 관점 핵심 차이:
  • 에러 로그 분석: Intel은 CPU N Bank M MSCOD=...를 모델별 매뉴얼로 해석. AMD는 Scalable MCA: IPID=... HWID=0xB0 → Load Store로 자동 식별
  • 메모리 에러 대응: Intel은 ADDDC+Patrol Scrub UC → MCE → memory_failure(). AMD는 Patrol Scrub → Deferred Error → 소프트웨어 선제 오프라인 (UC MCE 없이 페이지 격리 가능)
  • PCIe 에러: Intel IIO MSCOD로 CTO/Poison/LinkDown 세분화. AMD NBIO/PCIE SMCA는 IPID로 식별하지만 세부 에러 코드는 덜 세분화
  • 디버깅 도구: 둘 다 rasdaemon이 자동 디코딩. Intel은 mcelog도 사용 가능. AMD는 rasdaemon이 SMCA를 더 잘 지원

크로스 아키텍처 에러 처리 종합 비교

x86(Intel/AMD), ARM, RISC-V, POWER를 포괄하는 종합 비교표입니다. 서버 플랫폼을 설계하거나 다중 아키텍처 환경을 운영할 때 참고합니다.

비교 항목x86 Intelx86 AMDARM (Neoverse)RISC-VPOWER (IBM)
에러 예외 #MC (벡터 18) #MC (벡터 18) SEA / SError 플랫폼 종속 Machine Check (0x200)
에러 레지스터 MCA 뱅크 (MSR) SMCA 뱅크 (MSR + IPID) ERRn 레지스터 CSR (벤더 독자) SRR1 + DSISR
뱅크/노드 수 ~48~100개 ~32~64개 코어당 ~10~18개 미표준화 ~20~40개
CE 인터럽트 CMCI Threshold Int. Fault IRQ / GHES 플랫폼 종속 CE 핸들러
Firmware-First APEI/GHES (선택) APEI/GHES (선택) SDEI → GHES (주요 경로) SBI + GHES (개발 중) OPAL/skiboot (필수)
에러 동기화 Monarch 랑데부 Monarch 랑데부 코어별 독립 처리 미정의 Hypervisor 위임
메모리 복구 memory_failure() + HWPoison memory_failure() + HWPoison memory_failure() + HWPoison memory_failure() (GHES 경유 시) memory_failure() + HWPoison
Deferred Error 없음 DESTAT/DEADDR FEAT_RASv1p1 DE 없음 없음
에러 주입 EINJ (ACPI) EINJ (ACPI) ERRnPFG (v1.1) 벤더 종속 OPAL inject
Poison 전파 Viral Mode Data Poisoning Poison 비트 (CMN) 미정의 SUE (Special Uncorrectable Error)
PCIe 에러 IIO MCA + AER NBIO/PCIE SMCA + AER SMMU + AER + GHES AER + 플랫폼 EEH (Enhanced Error Handling)
메모리 ECC SDDC/ADDDC/Mirroring On-die ECC + PPR 플랫폼 종속 플랫폼 종속 Chipkill + 동적 Sparing
EDAC 드라이버 i10nm_edac, skx_edac amd64_edac 플랫폼별 (thunderx2, xgene 등) 없음/개발 중 pasemi_edac 등
유저스페이스 도구 rasdaemon, mcelog rasdaemon rasdaemon (GHES 경유) 없음/개발 중 opal-prd
성숙도 매우 높음 (20년+) 높음 (Zen 이후 ~8년) 중간 (서버 진출 ~6년) 낮음 (초기) 매우 높음 (30년+)

IBM POWER의 EEH (Enhanced Error Handling)

IBM POWER 아키텍처의 EEH는 PCIe 에러 처리에서 x86 AER/IIO MCA보다 진보된 모델입니다. x86에서는 PCIe UC 에러 시 장치가 사실상 죽지만, POWER EEH는 자동 복구 단계를 제공합니다.

EEH 복구 단계동작x86 대응
1. I/O Freeze에러 장치의 MMIO/DMA를 냉동 (데이터 오염 차단)AER pci_channel_io_frozen 유사
2. MMIO Detect냉동된 장치의 MMIO 읽기가 all-1s(0xFFFFFFFF) 반환 → 드라이버가 감지x86에서도 동일 패턴이지만 표준화되지 않음
3. Slot ResetPHB(PCI Host Bridge) 레벨 리셋 → 장치 재초기화AER pcie_do_recovery() 유사하지만 더 강력
4. Resume드라이버의 resume 콜백(Callback)으로 정상 동작 복귀AER mmio_enabled/resume 콜백
5. Full Reset위 단계 실패 시 PE(Partitionable Endpoint) 전체 리셋x86에는 대응 없음 (보통 재부팅)
아키텍처 선택 시사점:
  • 메모리 RAS 최우선: Intel ADDDC + Mirroring 또는 IBM POWER Chipkill + 동적 Sparing
  • PCIe 복구 최우선: IBM POWER EEH가 가장 성숙. x86은 AER+IIO MCA 조합으로 대응
  • Deferred Error (선제 대응): AMD SMCA 또는 ARM RAS v1.1이 Deferred Error를 네이티브 지원
  • 다중 아키텍처 운영: GHES/CPER 기반 통합 모니터링이 핵심. rasdaemon이 x86/ARM 모두 지원하므로 통합 대시보드 구축 가능
  • ARM 서버 주의: ARM은 Firmware-First(SDEI→GHES)가 주요 경로이므로, 펌웨어(TF-A/UEFI) 품질이 RAS 성능에 직접 영향. Intel/AMD의 OS-First 모델보다 펌웨어 의존도 높음

RISC-V 하드웨어 에러 표준화 현황

RISC-V는 아직 하드웨어 에러 보고에 대한 공식 표준이 확립되지 않았습니다. 현재 진행 중인 표준화 작업과 벤더 독자 구현이 혼재합니다:

수렴 방향: 장기적으로 ARM과 RISC-V 모두 GHES를 공통 에러 보고 프레임워크로 사용하는 방향으로 수렴하고 있습니다. 이는 유저스페이스 도구(rasdaemon 등)가 아키텍처에 무관하게 동작할 수 있게 합니다. RISC-V RAS 워킹 그룹은 ARM FEAT_RAS를 참고하여 ERRn 유사 레지스터 표준 제정을 검토 중입니다.

MCE 테스트 주입

MCE 처리 경로의 정확성을 검증하려면 하드웨어 에러를 시뮬레이션해야 합니다. 리눅스 커널은 여러 단계의 주입 메커니즘을 제공합니다.

주입 방법 비교

방법수준요구사항특징
mce-inject소프트웨어 MCE CONFIG_X86_MCE_INJECT=y 커널 내부에서 가짜 MCE 생성. MCA 뱅크를 실제로 쓰지 않음
EINJ펌웨어 레벨 CONFIG_ACPI_APEI_EINJ=y, BIOS 지원 ACPI EINJ 테이블로 실제 메모리 에러 주입. 가장 현실적
hwpoison-inject페이지 레벨 CONFIG_HWPOISON_INJECT=y debugfs에서 직접 PFN 지정하여 HWPoison 마킹

mce-inject 사용법

# mce-inject 모듈 로드
$ sudo modprobe mce-inject

# 주입 파일 작성 (SRAO 메모리 에러)
$ cat > /tmp/mce-test.txt <<EOF
CPU 0 BANK 9
STATUS 0xBD2000000000017A
ADDR 0x12345678
MISC 0x0000000000000086
MCGSTATUS 0x0
EOF

# 주입 실행
$ sudo sh -c "cat /tmp/mce-test.txt > /sys/kernel/debug/mce-inject/mce-inject"

# dmesg 확인
$ dmesg | tail -20

EINJ (Error Injection) 사용법

# EINJ 모듈 로드
$ sudo modprobe einj

# 지원되는 에러 유형 확인
$ cat /sys/kernel/debug/apei/einj/available_error_type
0x00000002    Memory Correctable
0x00000008    Memory Uncorrectable non-fatal
0x00000010    Memory Uncorrectable fatal

# CE 주입 (특정 물리 주소)
$ sudo sh -c "echo 0x2 > /sys/kernel/debug/apei/einj/error_type"
$ sudo sh -c "echo 0x100000000 > /sys/kernel/debug/apei/einj/param1"   # 물리 주소
$ sudo sh -c "echo 0xFFFFFFFFFFFFF000 > /sys/kernel/debug/apei/einj/param2"  # 마스크
$ sudo sh -c "echo 1 > /sys/kernel/debug/apei/einj/error_inject"

hwpoison-inject 사용법

# 특정 PFN에 HWPoison 주입
$ sudo sh -c "echo 0x12345 > /sys/kernel/debug/hwpoison/corrupt-pfn"

# soft offline (CE 예방)
$ sudo sh -c "echo 0x12345 > /sys/kernel/debug/hwpoison/soft-offline-pfn"

# HWPoison 해제
$ sudo sh -c "echo 0x12345 > /sys/kernel/debug/hwpoison/unpoison-pfn"
주의: EINJ로 UC fatal 에러를 주입하면 실제 시스템 패닉이 발생합니다. 반드시 테스트 환경에서만 사용하고, tolerant=3 설정으로 패닉을 방지하거나 VM 스냅샷을 준비하세요.

MCE 테스트 시나리오 매트릭스

시나리오주입 방법예상 결과검증 사항
CE 단일 발생 mce-inject (UC=0) dmesg CE 로그, EDAC 카운트 증가 rasdaemon DB에 기록 확인
CE 폭주 (CMCI 스톰) mce-inject 반복 CMCI → 폴링 전환 cmci_storm 감지 로그 확인
SRAR (데이터 소비) EINJ + 메모리 접근 SIGBUS, 프로세스 종료 HWPoison 페이지 확인
SRAO (백그라운드) mce-inject (UC=1,S=1,AR=0) 페이지 오프라인 buddy allocator 제외 확인
UC+PCC (패닉) mce-inject (UC=1,PCC=1) 시스템 패닉 BERT 또는 crash dump
HWPoison 복구 hwpoison-inject 페이지 오프라인, 매핑 제거 /proc/kpageflags 확인
soft offline hwpoison soft-offline 마이그레이션 후 페이지 격리 vmstat migration 카운트

가상 머신에서의 MCE 테스트

QEMU/KVM에서 MCE를 주입하여 게스트 커널의 MCE 핸들링을 테스트할 수 있습니다.

# QEMU 모니터에서 게스트에 MCE 주입
(qemu) mce 0 9 0xBD2000000000017A 0x12345678 0x86

# 파라미터: CPU BANK STATUS ADDR MISC
# CPU 0, Bank 9, STATUS = SRAO 메모리 에러

# KVM에서 ioctl로 프로그래밍 주입
# KVM_X86_SET_MCE ioctl → struct kvm_x86_mce

MCE 디버깅 기법 (perf/ftrace/eBPF)

MCE 이벤트는 하드웨어 오류의 핵심 진단 정보를 담고 있지만, 발생 빈도가 낮고 재현이 어려워 체계적인 디버깅 도구 활용이 필수적입니다. 리눅스 커널은 perf, ftrace, eBPF 등 다양한 트레이싱 프레임워크를 통해 MCE 이벤트를 실시간 모니터링하고 분석할 수 있는 인프라를 제공합니다.

Hardware Layer Kernel Layer Tracing Framework User Analysis CPU MCA Bank Memory ECC PCIe AER ACPI GHES do_machine_check() MCE Handler ras:mce_record Tracepoint EDAC Subsystem 메모리 오류 집계 /dev/mcelog Legacy 인터페이스 perf 이벤트 샘플링 ftrace 함수 추적 eBPF/bpftrace 커스텀 분석 sysfs machinecheck kdump 크래시 덤프 사용자 분석: mcelog / rasdaemon / crash / 커스텀 스크립트

perf를 이용한 MCE 이벤트 추적

# MCE 관련 트레이스포인트 확인
$ perf list 'ras:*'

# MCE 이벤트 실시간 기록
$ perf record -e ras:mce_record -a --overwrite -o mce_trace.data

# 기록된 MCE 이벤트 상세 출력
$ perf script -i mce_trace.data

# EDAC/AER 이벤트도 함께 추적
$ perf record -e ras:mce_record -e ras:mc_event -e ras:aer_event -a -o ras_all.data

ftrace를 이용한 MCE 핸들러 추적

# function_graph 트레이서로 MCE 핸들러 추적
$ cd /sys/kernel/debug/tracing
$ echo 0 > tracing_on
$ echo function_graph > current_tracer
$ echo do_machine_check > set_graph_function
$ echo 1 > tracing_on

# MCE 관련 함수만 필터링
$ echo do_machine_check > set_ftrace_filter
$ echo mce_severity >> set_ftrace_filter
$ echo mce_reign >> set_ftrace_filter

# 트레이스포인트 직접 활성화
$ echo 1 > events/ras/mce_record/enable

eBPF/bpftrace를 이용한 MCE 모니터링

# MCE 이벤트 발생 시 뱅크 번호와 상태 출력
$ bpftrace -e '
tracepoint:ras:mce_record {
    printf("MCE: cpu=%d bank=%d status=0x%llx addr=0x%llx\n",
           args->cpu, args->bank, args->status, args->addr);
}'

# MCE 뱅크별 발생 횟수 집계
$ bpftrace -e '
tracepoint:ras:mce_record {
    @mce_by_bank[args->bank] = count();
    @mce_by_cpu[args->cpu] = count();
}'

# 물리 주소 기반 반복 오류 감지
$ bpftrace -e '
tracepoint:ras:mce_record {
    @addr_count[args->addr] = count();
    if (@addr_count[args->addr] >= 3) {
        printf("WARNING: 반복 MCE at addr=0x%llx (count=%d)\n",
               args->addr, @addr_count[args->addr]);
    }
}'

# do_machine_check() 실행 시간 측정
$ bpftrace -e '
kprobe:do_machine_check { @start[tid] = nsecs; }
kretprobe:do_machine_check /@start[tid]/ {
    @mce_latency_us = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}'

크래시 덤프 분석 (kdump + crash)

치명적 MCE로 인한 커널 패닉 이후에는 kdump가 캡처한 메모리 덤프를 crash 유틸리티로 분석합니다.

# crash 유틸리티로 덤프 분석
$ crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/<timestamp>/vmcore

# crash 프롬프트에서 MCE 정보 조회
crash> log | grep -i "mce\|machine check"
crash> bt -a              # 모든 CPU 백트레이스
crash> struct mce mcelog.entry[0]
crash> px mcelog.entry[0].status
crash> px mcelog.entry[0].addr

MCE 이벤트 상관 분석

# 타임스탬프 기반 통합 분석
$ journalctl --since "2 hours ago" -k | \
  grep -iE "mce|edac|aer|ghes|hardware.error" | \
  sort -k1,3 | tee /tmp/hw_error_timeline.log

# rasdaemon DB에서 시간 범위 기반 교차 조회
$ sqlite3 /var/lib/rasdaemon/ras-mc_event.db "
  SELECT 'MCE' as type, timestamp, error_msg FROM mce_record
  WHERE timestamp > datetime('now', '-2 hours')
  UNION ALL
  SELECT 'MC' as type, timestamp, error_msg FROM mc_event
  WHERE timestamp > datetime('now', '-2 hours')
  UNION ALL
  SELECT 'AER' as type, timestamp, error_msg FROM aer_event
  WHERE timestamp > datetime('now', '-2 hours')
  ORDER BY timestamp;"
상관 분석 핵심: MCE의 ADDR 필드 물리 주소를 EDAC의 DIMM 위치(채널/슬롯/랭크)와 매핑하면, 특정 DIMM의 물리적 교체 여부를 판단할 수 있습니다. page-types -b hwpoison으로 오프라인 페이지도 확인하세요.

커널 설정 옵션

MCE/RAS 관련 커널 설정 옵션의 종합 목록입니다. 프로덕션 서버에서는 대부분 활성화하는 것이 권장됩니다.

설정기본값설명
CONFIG_X86_MCEy (x86에서)MCE 핸들러 핵심. 비활성화하면 MCE 시 triple fault
CONFIG_X86_MCE_INTELyIntel 전용 MCE 확장 (CMCI, LMCE, CEC 등)
CONFIG_X86_MCE_AMDyAMD 전용 MCE 확장 (SMCA, Threshold 인터럽트)
CONFIG_X86_MCE_THRESHOLDyAMD Threshold 카운터 인터럽트 지원
CONFIG_X86_MCE_INJECTmMCE 주입 모듈 (테스트용)
CONFIG_MEMORY_FAILUREymemory_failure() / HWPoison 지원
CONFIG_HWPOISON_INJECTmHWPoison 주입 debugfs 인터페이스
CONFIG_EDACyEDAC 서브시스템 핵심
CONFIG_EDAC_GHESyGHES 기반 EDAC 드라이버
CONFIG_EDAC_SKXmIntel Skylake-SP EDAC
CONFIG_EDAC_I10NMmIntel Ice Lake / SPR EDAC
CONFIG_EDAC_AMD64mAMD64 EDAC (Fam10h~Zen4)
CONFIG_ACPI_APEIyACPI Platform Error Interface
CONFIG_ACPI_APEI_GHESyGHES(Generic HW Error Source) 지원
CONFIG_ACPI_APEI_EINJmEINJ 에러 주입 지원
CONFIG_ACPI_APEI_ERST_DEBUGmERST 디버그 인터페이스
CONFIG_RAS_CECyCorrected Error Collector (Intel)
커널 설정 확인: zcat /proc/config.gz | grep -E "MCE|EDAC|APEI|MEMORY_FAILURE|HWPOISON" 또는 grep -r "MCE\|EDAC" /boot/config-$(uname -r)

MCE 로그 디코딩 실전

실제 MCE 로그를 단계별로 해석하는 실전 가이드입니다. dmesg에 출력되는 MCE 메시지의 각 필드가 무엇을 의미하는지 분석합니다.

MCE 로그 디코딩 흐름 1. dmesg 수집 mce: [HW Error] 2. STATUS 분석 비트 필드 분리 3. 에러 코드 하위 16비트 해석 4. ADDR 해석 물리 주소 → DIMM 5. 조치 교체/모니터 실제 dmesg 예제: [12345.678] mce: [Hardware Error]: Machine check events logged [12345.678] mce: [Hardware Error]: CPU 3: Machine Check: 0 Bank 9: be00000000800400 [12345.678] mce: [Hardware Error]: TSC 123456789abcdef ADDR 0000000012345000 MISC 0000000000000086 [12345.678] mce: [Hardware Error]: PROCESSOR 0:506e3 TIME 1234567890 SOCKET 0 APIC 6 microcode 2007006 STATUS 0xbe00000000800400: VAL=1, OVER=0, UC=1, EN=1, PCC=1 → PANIC 가능

STATUS 디코딩 단계별 안내

예시: STATUS = 0xBE00000000800400

# 64비트 이진 분해
0xBE00000000800400 =
  1  0  1  1  1  1  1  0  0000...  1000 0000 0000 0100 0000 0000
  63 62 61 60 59 58 57 56          [31:16]   [15:0] = 0x0400

# 상위 비트 해석
bit 63 (VAL)   = 1 → 유효한 에러
bit 62 (OVER)  = 0 → 오버플로 없음
bit 61 (UC)    = 1 → 교정 불가 (Uncorrected)
bit 60 (EN)    = 1 → 에러 보고 활성
bit 59 (MISCV) = 1 → MISC 레지스터 유효
bit 58 (ADDRV) = 1 → ADDR 레지스터 유효
bit 57 (PCC)   = 1 → 프로세서 컨텍스트 손상!
bit 56 (S)     = 0 → MCG_SER_P 미지원 또는 비활성

# 에러 코드 (bits 15:0) = 0x0400
0x0400 = 0000 0100 0000 0000
→ Internal Timer Error (Simple Error Code)

# 결론: UC + PCC → 프로세서 상태 복구 불가 → 시스템 패닉

유용한 디코딩 도구

# mcelog으로 디코딩 (레거시)
$ sudo mcelog --ascii --file /tmp/mce.log

# rasdaemon SQLite 쿼리
$ sudo sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
  "SELECT datetime(timestamp,'unixepoch'), bank, status, addr,
          CASE WHEN (status >> 61) & 1 THEN 'UC' ELSE 'CE' END as type
   FROM mce_record ORDER BY id DESC LIMIT 10;"

# edac-util로 DIMM 매핑 확인
$ edac-util -s
$ edac-util -r

CE (Corrected Error) 로그 예제

# EDAC CE 로그 예시
[54321.987] EDAC MC0: 1 CE memory read error on CPU_SrcID#0_MC#0_Chan#0_DIMM#0
            (channel:0 slot:0 page:0x1234 offset:0x0 grain:32 syndrome:0x0)
[54321.987] EDAC MC0: 1 CE ... area:DRAM err_code:0001:0091

# 해석:
# - MC0: 메모리 컨트롤러 0
# - 1 CE: Corrected Error 1회
# - Channel 0, Slot 0: 첫 번째 채널의 첫 번째 DIMM
# - page:0x1234: 물리 페이지 프레임 번호
# - grain:32: 에러 입도 (바이트)
# - err_code:0001:0091: 계층/에러 코드

SRAR (Action Required) 로그 예제

[98765.432] mce: [Hardware Error]: CPU 12 Bank 7: bd80000000100134
[98765.432] mce: [Hardware Error]: RIP !INEXACT! 33:<00007f1234567890>
[98765.432] mce: [Hardware Error]: TSC a1b2c3d4e5f67890 ADDR 0000000087654000
[98765.432] mce: [Hardware Error]: MISC 000000000000008c PPIN 1234567890abcdef
[98765.432] mce: [Hardware Error]: PROCESSOR 2:806f8 TIME 1710000000 SOCKET 1 APIC 24
[98765.432] Memory failure 0x87654: recovery action for dirty LRU page: Recovered

# STATUS 0xBD80000000100134 디코딩:
# bit 63 VAL=1, bit 61 UC=1, bit 60 EN=1
# bit 59 MISCV=1, bit 58 ADDRV=1
# bit 57 PCC=0 → 프로세서 컨텍스트 정상
# bit 56 S=1, bit 55 AR=1 → SRAR
# Error Code (bits 15:0) = 0x0134 → L3 캐시 데이터 읽기 에러
# 결과: memory_failure()로 페이지 복구 성공 ("Recovered")

자주 발생하는 MCE 패턴

데이터센터에서 흔히 관찰되는 MCE 패턴과 각각의 원인, 대응 방법을 정리합니다.

패턴 1: CE 누적 (DIMM 열화)

증상: 동일 DIMM에서 CE가 지속적으로 증가. 시간에 따라 빈도 증가.
항목내용
dmesg 시그니처EDAC MC0: 1 CE ... on DIMM0 (반복)
STATUS 특성UC=0, VAL=1 — CE (Corrected Error)
원인DIMM 셀 열화, 접촉 불량, 전압 마진 부족
조치1) DIMM 재장착 시도 2) CE 임계값 초과 시 교체 3) BIOS에서 스페어링 활성화
긴급도낮음 → 중간 (교체 계획 수립)

패턴 2: UC no PCC (복구 가능한 에러)

증상: 특정 프로세스가 SIGBUS로 종료됨. 시스템은 정상 운영.
항목내용
dmesg 시그니처mce: Uncorrected hardware memory error in user-access at ...
STATUS 특성UC=1, PCC=0, S=1, AR=1 → SRAR
원인메모리 비트 플립 (ECC 2비트 이상 오류)
조치1) 해당 페이지 HWPoison 자동 처리됨 2) 동일 DIMM 모니터링 3) 반복 시 DIMM 교체
긴급도중간 (서비스 재시작 필요할 수 있음)

패턴 3: UC + PCC (시스템 패닉)

증상: 시스템 즉시 패닉. "Fatal machine check" 메시지.
항목내용
dmesg 시그니처Kernel panic - not syncing: Fatal machine check on current CPU
STATUS 특성UC=1, PCC=1 — 프로세서 컨텍스트 손상
원인CPU 캐시 패리티, 마이크로코드 버그, 전력 불안정, 과열
조치1) BERT 데이터 확인 2) 마이크로코드 업데이트 3) CPU 교체 고려 4) 전력/냉각 점검
긴급도높음 (즉시 대응)

패턴 4: OVER + UC (에러 오버플로)

항목내용
dmesg 시그니처mce: Overflowed uncorrected error
STATUS 특성OVER=1, UC=1 — 이전 에러가 읽히기 전에 새 에러 발생
원인에러 폭주, 하드웨어 심각한 결함
조치즉시 하드웨어 점검. 정보 손실로 인해 root cause 분석 어려울 수 있음
긴급도매우 높음

패턴 5: Thermal MCE

항목내용
dmesg 시그니처CPU0: Temperature above threshold, cpu clock throttled
원인CPU 과열 — 쿨러 고장, 열 전도 패드 열화, 데이터센터 냉방 문제
조치1) 즉시 냉각 확인 2) 팬 RPM 점검 3) thermal paste 재도포 4) 부하 분산(Load Balancing)
참고Thermal Management 페이지 참조

패턴 6: 버스/인터커넥트 에러

항목내용
에러 코드0x0800 범위 (Bus/Interconnect Error)
원인QPI/UPI 링크 에러, PCIe 버스 에러, 물리적 커넥터 문제
조치1) PCIe 카드 재장착 2) 케이블 점검 3) BIOS에서 링크 속도 조정

패턴 7: IIO PCIe Completion Timeout

증상: 특정 PCIe 장치 응답 불가. AER 에러와 IIO MCA 에러 동시 발생.
항목내용
dmesg 시그니처mce: IIO Bank ... MSCOD=0x0000 Completion Timeout + pcieport ... AER: Uncorrectable error received
MCA 뱅크Bank 5~8 (IIO 스택, CPU 모델별 가변)
MSCOD0x0000 (Completion Timeout)
원인GPU/NVMe/NIC 행(hang), FLR 중 접근, PCIe 링크 불안정, 라이저 접촉 불량
조치1) lspci -vvvs <BDF>로 링크 상태 확인 2) 장치 펌웨어 업데이트 3) 물리적 재장착 4) CTO 값 조정
긴급도중간~높음 (장치 유형에 따라 서비스 영향 판단)

패턴 8: IIO Poisoned TLP (데이터 독성 전파)

증상: PCIe 장치에서 Poison 데이터 수신. 소비 프로세스 SIGBUS 또는 패닉 가능.
항목내용
dmesg 시그니처mce: IIO Bank ... MSCOD=0x0002 Poisoned TLP
MSCOD0x0002 (Poisoned TLP)
원인GPU VRAM ECC UC, NVMe 내부 DRAM 에러, 장치 메모리 결함
GPU 관련NVIDIA Xid 48/63 (DBE/Row Remapper Failure)과 동시 발생 가능
조치1) 장치 에러 로그 확인 2) 장치 ECC 상태 확인 3) BIOS Viral Mode 설정 확인 4) 장치 교체 검토
긴급도높음 (데이터 무결성 위협)

패턴 9: TOR (Table of Requests) 타임아웃

증상: 시스템 패닉. 다른 MCA 에러(IIO/M2M/UPI)와 동반 발생.
항목내용
dmesg 시그니처Kernel panic ... MCE: CHA Bank ... TOR Timeout
MCA 뱅크Bank 21~24+ (CHA/LLC)
원인DIMM 하드 페일 → 메모리 접근 불가, PCIe 장치 무응답 → DMA 체류, UPI 링크 다운 → 원격 메모리 접근 중단, 마이크로코드 버그
분석 핵심TOR Timeout은 거의 항상 2차 에러. 동시 발생한 다른 뱅크 에러(IIO/M2M/UPI)에서 근본 원인을 찾아야 함
조치1) BERT 데이터에서 선행 에러 확인 2) 동시 발생 MCA 뱅크 에러 전수 분석 3) 마이크로코드 업데이트 4) 메모리/장치 하드웨어 점검
긴급도매우 높음 (패닉 후 원인 분석 필수)

패턴 10: UPI 링크 에러 (멀티소켓)

항목내용
dmesg 시그니처mce: CPU N Bank 5 ... UPI CRC Error
MCA 뱅크Bank 5~6 (UPI)
CE 상황CRC 교정 가능 → 자동 재전송, 성능 약간 저하. CE 빈도 증가 시 링크 열화 경고
UC 상황링크 다운 → 원격 NUMA 노드 접근 불가 → 해당 노드 프로세스 대량 SIGBUS/패닉
원인소켓 간 인터커넥트 하드웨어 열화, 메인보드 UPI 트레이스 결함, 전기적 잡음
조치1) UPI CE 추세 모니터링 2) BIOS에서 UPI 링크 속도 다운그레이드 시도 3) CPU 또는 메인보드 교체 검토

패턴 11: M2M Patrol Scrub UC (사전 발견 메모리 에러)

항목내용
dmesg 시그니처mce: M2M Bank ... Patrol Scrub Error UC
MCA 뱅크Bank 9~12 (M2M)
의미Patrol Scrubbing이 배경에서 교정 불가 메모리 에러를 사전 발견
장점아직 소비되지 않은 데이터 → SRAO로 처리 가능 (memory_failure로 페이지 오프라인)
원인DIMM 열화, ECC 2비트+ 오류 (Demand 접근 전에 발견)
조치1) 해당 DIMM CE 이력 확인 2) HWPoison 페이지 확인 3) DIMM 교체 계획
긴급도중간 (사전 발견이므로 즉각적 서비스 영향은 제한적)

패턴 12: GPU/가속기 관련 IIO 연쇄 에러

증상: AI/ML 학습 작업 중 GPU 에러와 IIO MCE 동시 발생. 학습 작업 중단.
항목내용
에러 체인GPU VRAM ECC UC → Poisoned TLP → IIO MCE (MSCOD=0x0002) → 소비 코어 SRAR → SIGBUS
NVIDIA 시그니처dmesg에 NVRM: Xid ... 48(DBE), Xid ... 63(Row Remapper Failure) 등장
AMD GPU 시그니처dmesg에 amdgpu: ... ECC error
조치
  1. nvidia-smi -q -d ERRORS,ECC로 GPU ECC 상태 확인
  2. GPU Row Remapper 상태 확인 (remapped rows 수)
  3. GPU 온도 이력 확인 (nvidia-smi dmon)
  4. GPU 교체 (Row Remapper 소진 시)
  5. AI 학습 프레임워크의 체크포인트(Checkpoint) 복구 활용
긴급도높음 (학습 작업 중단, GPU 하드웨어 결함 확인 필요)

패턴 13: Row Hammer 유발 MCE

증상: 특정 DIMM에서 비정상적으로 높은 CE 빈도. 동일 뱅크(Bank) 내 인접 행(Row)에서 반복 발생. 간헐적으로 UCE(Uncorrectable Error)로 확대되어 SIGBUS 또는 패닉 발생.

Row Hammer는 DRAM의 물리적 특성을 이용한 현상으로, 특정 행을 반복 접근(Hammering)하면 인접 행(Victim Row)의 셀에서 전하 누출이 발생하여 비트 플립(Bit Flip)이 일어납니다. 이는 의도적 공격뿐 아니라 고부하 워크로드에서도 자연적으로 발생할 수 있습니다.

Row Hammer → MCE 발생 경로

  1. 반복 행 활성화: 공격자 또는 워크로드가 동일 DRAM 행을 수만~수십만 회 반복 접근 (clflush + 메모리 읽기 루프)
  2. 인접 행 비트 플립: Victim Row의 셀 커패시터(Capacitor) 전하가 누출되어 0→1 또는 1→0 전환
  3. ECC 감지: 메모리 컨트롤러의 ECC가 비트 오류를 감지 — 단일 비트 → CE, 다중 비트 → UCE → memory_failure() 호출
  4. MCE 생성: MCA 뱅크(메모리 컨트롤러)에 에러 기록, STATUS.VAL=1 설정

TRR (Target Row Refresh)과 한계

DDR4 이후 DRAM 제조사들은 TRR(Target Row Refresh)을 도입하여 Aggressor Row 감지 시 Victim Row를 사전 리프레시(Refresh)합니다. 그러나 TRRespass, Half-Double, Blacksmith 등 연구에서 TRR 우회 패턴이 발견되었으며, DDR5에서는 표준화된 RFM(Refresh Management) 명령으로 개선되었으나 공정 미세화에 따라 취약성은 증가 추세입니다.

항목내용
dmesg 시그니처EDAC MC0: 1 CE ... on DIMM0 (단시간 대량 반복) + mce: [Hardware Error]: ... ADDR: 동일 뱅크 내 인접 주소
STATUS 특성UC=0 (CE 단계) 또는 UC=1, PCC=0 (UCE 확대 시). 에러 코드 0x0150~0x0151 (메모리 컨트롤러)
원인DRAM Row Hammer — 워크로드 또는 의도적 공격에 의한 인접 행 비트 플립
구별 방법1) CE가 동일 DIMM의 인접 물리 행에 집중 2) 짧은 시간에 비정상적 CE 폭증 3) edac-util로 특정 랭크/뱅크 집중 확인
조치1) BIOS에서 TRR/pTRR 활성화 확인 2) DIMM 펌웨어 업데이트 3) ECC 모드 강화(Chipkill) 4) 반복 시 DIMM 교체 5) 보안 관점: CAP_SYS_RAWIO 제한 검토
긴급도중간~높음 (CE 단계: 모니터링, UCE 확대 시: 즉시 대응)

성능 영향과 튜닝

MCE 서브시스템은 정상 상태에서 거의 오버헤드가 없지만, 에러 발생 시나 폴링 설정에 따라 성능에 영향을 줄 수 있습니다. 대규모 서버 클러스터에서는 MCE 관련 설정이 전체 가용성에 영향을 미칠 수 있으므로 적절한 튜닝이 필요합니다.

MCE 관련 커널 부트 파라미터

파라미터설명기본값
mce=offMCE 핸들링 완전 비활성화 (위험)비활성
mce=dont_log_ceCE를 dmesg에 기록하지 않음비활성
mce=ignore_ceCE를 완전히 무시비활성
mce=no_cmciCMCI 비활성화 (폴링만 사용)비활성
mce=bootlog부팅 시 MCA 뱅크의 이전 에러 로깅활성
mce=recoverySRAR/SRAO 복구 경로 강제 활성화자동 감지
memory_corruption_check=1주기적 메모리 무결성 검사0

sysfs 튜닝 파라미터

파라미터경로기본값설명
check_interval /sys/devices/system/machinecheck/machinecheck0/check_interval 300 (5분) MCE 폴링 주기 (초). CMCI 비지원 CPU에서만 의미 있음
tolerant /sys/devices/system/machinecheck/machinecheck0/tolerant 1 MCE 대응 레벨 (0=항상 패닉, 1=기본, 2=관대, 3=무시)
monarch_timeout /sys/devices/system/machinecheck/machinecheck0/monarch_timeout CPU 종속 Monarch 랑데부 타임아웃 (us). 0이면 타임아웃 없음
dont_log_ce /sys/devices/system/machinecheck/machinecheck0/dont_log_ce 0 1이면 CE를 dmesg에 기록하지 않음 (CE 폭주 시 유용)
ignore_ce /sys/devices/system/machinecheck/machinecheck0/ignore_ce 0 1이면 CE를 완전히 무시 (CMCI도 비활성화)

ECC Patrol Scrubbing

메모리 스크러빙은 DRAM의 모든 위치를 주기적으로 읽어 CE를 사전에 발견하고 교정합니다. 스크럽 주기가 짧을수록 UC 에러(CE 누적 → 2비트 오류)를 예방하지만, 메모리 대역폭을 소비합니다.

설정위치권장값
Patrol ScrubBIOS/UEFI 설정Enabled (기본)
Scrub RateBIOS/UEFI 설정24시간 이내 전체 메모리 스캔
EDAC scrub ratesysfs (일부 드라이버)드라이버 종속
BIOS 설정 체크리스트:
  • Memory Patrol Scrub: Enabled
  • Memory ECC: Enabled (기본)
  • Memory RAS Mode: Independent (성능) 또는 Mirroring (가용성)
  • ADDDC (Adaptive Double DRAM Device Correction): Enabled (서버)
  • Corrected Error Threshold: 제조사 권장값

성능 영향 요약

상황성능 영향완화 방법
정상 (에러 없음)무시할 수 있음 (~0%)-
MCE 폴링 (CMCI 없음)매우 낮음 (5분마다 MSR 읽기)CMCI 지원 CPU 사용
CMCI 스톰중간 (인터럽트 폭주)자동 폴링 전환 (커널 기본 동작)
MCE 핸들링 (UC)높음 (모든 CPU 동기화)LMCE 활성화
memory_failure()해당 페이지 오프라인총 메모리 대비 무시 가능
Patrol Scrub낮음 (~1-3% 대역폭)비활성화 가능하나 비권장
MCE 모니터링 아키텍처 전체도 Hardware Layer CPU MCA Banks DIMM ECC CXL Memory PCIe AER Kernel Layer MCE Handler do_machine_check() GHES/APEI ghes_proc() EDAC Core edac_mc_handle_error() Tracepoint ras:mc_event, ras:aer_event sysfs: /sys/devices/system/edac/mc/ | /dev/mcelog Userspace rasdaemon tracefs 구독 SQLite DB ras-mc_event.db mcelog (레거시) /dev/mcelog edac-util sysfs 파싱 Monitoring Prometheus node_exporter (textfile) Grafana EDAC Dashboard Alertmanager Alerting PagerDuty Slack E-mail

Prometheus + Grafana 모니터링 구축

대규모 서버 환경에서는 rasdaemon의 SQLite DB를 Prometheus 메트릭으로 변환하여 Grafana 대시보드에서 실시간 모니터링하고, Alertmanager로 임계값 알림을 설정합니다. node_exporter의 textfile collector를 활용하면 별도 exporter 개발 없이 구현 가능합니다.

#!/bin/bash
# /usr/local/bin/edac-metrics.sh
# node_exporter textfile collector용 EDAC 메트릭 생성 스크립트
# cron: */5 * * * * /usr/local/bin/edac-metrics.sh

TEXTFILE_DIR="/var/lib/node_exporter/textfile_collector"
PROM_FILE="${TEXTFILE_DIR}/edac.prom"
TMP_FILE="${PROM_FILE}.tmp"
DB="/var/lib/rasdaemon/ras-mc_event.db"

mkdir -p "${TEXTFILE_DIR}"

{
  echo "# HELP edac_ce_total Total corrected errors per DIMM"
  echo "# TYPE edac_ce_total counter"

  # EDAC sysfs에서 직접 메트릭 수집
  for mc in /sys/devices/system/edac/mc/mc*; do
    [ -d "$mc" ] || continue
    mc_id=$(basename "$mc" | sed 's/mc//')
    for dimm in "${mc}"/dimm*; do
      [ -d "$dimm" ] || continue
      dimm_id=$(basename "$dimm" | sed 's/dimm//')
      label=$(cat "${dimm}/dimm_label" 2>/dev/null || echo "unknown")
      ce=$(cat "${dimm}/dimm_ce_count" 2>/dev/null || echo 0)
      ue=$(cat "${dimm}/dimm_ue_count" 2>/dev/null || echo 0)
      echo "edac_ce_total{mc=\"${mc_id}\",dimm=\"${dimm_id}\",label=\"${label}\"} ${ce}"
      echo "edac_ue_total{mc=\"${mc_id}\",dimm=\"${dimm_id}\",label=\"${label}\"} ${ue}"
    done
  done

  echo "# HELP edac_ue_total Total uncorrected errors per DIMM"
  echo "# TYPE edac_ue_total counter"

  # rasdaemon DB에서 최근 1시간 CE rate 계산
  echo "# HELP edac_ce_rate_1h CE count in last hour"
  echo "# TYPE edac_ce_rate_1h gauge"
  if [ -f "${DB}" ]; then
    sqlite3 "${DB}" "SELECT mc, top_layer, mid_layer, COUNT(*) FROM mc_event \
      WHERE err_type='Corrected' AND timestamp > strftime('%s','now','-1 hour') \
      GROUP BY mc, top_layer, mid_layer;" | while IFS='|' read mc ch dm cnt; do
      echo "edac_ce_rate_1h{mc=\"${mc}\",channel=\"${ch}\",dimm=\"${dm}\"} ${cnt}"
    done
  fi
} > "${TMP_FILE}"

mv "${TMP_FILE}" "${PROM_FILE}"
# node_exporter 실행 시 textfile collector 경로 지정
$ node_exporter --collector.textfile.directory=/var/lib/node_exporter/textfile_collector

# Prometheus에서 확인
$ curl -s http://localhost:9090/api/v1/query?query=edac_ce_total | jq .

# Alertmanager 규칙 예시 (prometheus.rules.yml)
# CE가 1시간에 50회 이상이면 경고, UE 발생 시 긴급
# Prometheus alerting rules — /etc/prometheus/rules/edac.rules.yml
groups:
  - name: edac_alerts
    rules:
      - alert: HighCorrectedErrorRate
        expr: increase(edac_ce_total[1h]) > 50
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "DIMM {{ $labels.label }} CE 급증 ({{ $value }}/h)"
          description: "MC {{ $labels.mc }} DIMM {{ $labels.dimm }}에서 1시간 내 {{ $value }}건의 CE 발생. DIMM 교체 검토 필요."

      - alert: UncorrectedError
        expr: increase(edac_ue_total[5m]) > 0
        labels:
          severity: critical
        annotations:
          summary: "DIMM {{ $labels.label }} UE 발생!"
          description: "MC {{ $labels.mc }} DIMM {{ $labels.dimm }}에서 복구 불가 에러. 즉시 DIMM 교체 필요."

      - alert: CEtoUEEscalation
        expr: increase(edac_ce_total[24h]) > 100 and increase(edac_ue_total[24h]) > 0
        labels:
          severity: critical
        annotations:
          summary: "CE→UE 에스컬레이션 감지: {{ $labels.label }}"
Grafana 대시보드 구성 권장:
  • 패널 1: 시간축 CE/UE 추이 그래프 (increase(edac_ce_total[1h]) by (label))
  • 패널 2: DIMM별 누적 에러 히트맵 (소켓×채널 행렬)
  • 패널 3: 서버별 EDAC 상태 테이블 (정상/주의/위험 색상 코딩)
  • 패널 4: 최근 24시간 UE 발생 서버 리스트 (즉시 대응 필요)

대규모 서버 클러스터 MCE 통계

Google, Meta(Facebook), Microsoft 등이 발표한 대규모 데이터센터 연구에서 DRAM 에러율과 DIMM 수명 패턴에 대한 실측 데이터를 확인할 수 있습니다. 이 데이터는 DIMM 교체 정책과 용량 계획에 중요한 근거가 됩니다.

연구 출처플릿 규모CE 발생 DIMM 비율UE 발생 DIMM 비율주요 발견
Google (2009) ~수십만 서버 연간 ~32% 서버에서 CE 연간 ~1.3% 서버에서 UE CE 있는 DIMM은 이후 CE 발생 확률 6~30배 증가
Meta/Facebook (2015) ~수백만 DIMM 연간 ~20% DIMM에서 CE 연간 ~0.03% DIMM에서 UE 온도 10도 상승 시 에러율 ~2배 증가
Microsoft Azure (2018) 수백만 서버 연간 ~9% 서버에서 CE - CE 패턴으로 72시간 내 UE 예측 가능 (논문 기반)

CE → UE 에스컬레이션 확률

CE 패턴24시간 내 UE 확률7일 내 UE 확률권장 조치
단일 CE (1회) < 0.1% ~0.5% 모니터링 유지
반복 CE (같은 주소, 10회+) ~2-5% ~8-15% 해당 페이지 soft offline, DIMM 교체 계획
CE 폭주 (24시간 100회+) ~10-20% ~25-40% 즉시 DIMM 교체, 워크로드 마이그레이션
다중 행/열 CE (여러 주소) ~15-30% ~35-50% 긴급 DIMM 교체, 행/열 패턴은 DRAM 셀 열화 표시

DIMM 수명 곡선 (Bathtub Curve)

운영 기간고장률 특성주요 원인운영 가이드
0~6개월 (초기 고장) 상대적으로 높음 (~2-3x 정상) 제조 결함, 솔더링 불량, 초기 전기적 스트레스 DOA 검사 강화, burn-in 테스트 수행
6개월~3년 (안정기) 최저 (기준 고장률) 랜덤 소프트 에러 (우주선, 알파입자) 정상 모니터링, patrol scrub 유지
3~5년+ (마모기) 점진적 증가 (~1.5-4x) DRAM 셀 열화, Row Hammer, 반복 스트레스 CE 임계값 강화, 사전 교체 프로그램 운영
용량 계획 시사점: Google 연구에 따르면, CE가 발생한 DIMM의 이후 CE 확률은 CE가 없던 DIMM 대비 6~30배 높습니다. 따라서 첫 CE 발생 후 모니터링을 강화하고, 반복 CE 발생 시 사전 교체하는 것이 TCO 관점에서 유리합니다. 대규모 클러스터에서는 연간 DIMM 재고를 총 DIMM 수의 2~5%로 유지하는 것이 일반적입니다.

MCE와 ECC 메모리 모드

서버 메모리 컨트롤러는 여러 ECC/RAS 모드를 지원하며, 가용성과 성능 사이의 트레이드오프에 따라 적절한 모드를 선택해야 합니다. BIOS/UEFI에서 설정하며, MCE/EDAC이 보고하는 에러 유형과 복구 능력에 직접 영향을 줍니다.

모드용량 영향대역폭 영향ECC 능력가용성적용 시나리오
Independent 100% 사용 가능 최대 대역폭 기본 SECDED (1비트 교정, 2비트 검출) 보통 HPC, 대용량 메모리 필요 환경, 일반 서버
Mirroring 50% (절반이 미러) 읽기: ~동일, 쓰기: ~동일 전체 채널 장애까지 복구 가능 최고 미션 크리티컬 DB, 금융, 의료 시스템
Lockstep 100% (채널 쌍 결합) 50% (2채널 → 1논리채널) x8 SDDC (단일 DRAM 칩 전체 오류 교정) 높음 Chipkill 필요 환경, 단일 칩 고장 허용
Sparing 1 Rank/DIMM 예비 전환 시 일시 저하 CE 임계값 초과 시 자동 전환 높음 장기 무중단 운영 서버, 교체 주기가 긴 환경
ADDDC ~100% (동적) 활성화 시 약간 저하 2x DRAM 디바이스 에러 교정 (Adaptive) 매우 높음 Intel SPR+, DDR5 서버, 최신 데이터센터
모드 선택 가이드:
  • 기본 권장: Independent + ADDDC Enabled (DDR5 서버). 용량 손실 없이 높은 RAS 제공
  • 최고 가용성: Mirroring + ADDDC. 미러 채널 내에서도 ADDDC로 이중 보호
  • HPC/대역폭: Independent + Patrol Scrub. 성능 최우선, CE 모니터링으로 보완
  • 레거시 DDR4: Lockstep (x4 DIMM) 또는 Rank Sparing. Chipkill 수준 보호
EDAC 드라이버는 현재 활성 모드를 dimm_edac_mode sysfs 항목으로 보고합니다.

DDR5 On-Die ECC와 MCE 변화

DDR5는 JEDEC 표준으로 On-Die ECC를 필수 기능으로 규정합니다. 각 DRAM 다이(Die) 내부에 ECC 엔진이 탑재되어, 데이터가 DRAM 칩 외부로 나가기 전에 단일 비트 오류를 자체 교정합니다. 이 변화는 호스트 측 MCE 패턴에 근본적인 영향을 미칩니다.

On-Die ECC 동작 원리

MCE 모니터링에 미치는 영향

핵심 문제: On-Die ECC가 단일 비트 오류를 내부에서 교정하므로, 호스트 측 CE 카운트가 DDR4 대비 크게 감소합니다. 이는 DIMM 건강 상태 악화를 CE 빈도 증가로 조기 감지하던 기존 RAS 전략의 효과를 약화시킵니다.

DDR5 시대의 대안적 건강 모니터링

  1. DDR5 ECS(Error Check and Scrub): JEDEC 표준의 인밴드(In-band) ECS 명령으로 DRAM 내부 오류 카운터 조회 가능. 호스트 메모리 컨트롤러가 주기적으로 ECS 수행
  2. 내부 에러 로깅: 일부 DDR5 DRAM은 MR(Mode Register)를 통해 On-Die ECC 교정 횟수를 노출. 하드웨어 벤더별 지원 수준 차이 있음
  3. CXL 메모리 건강 명령: CXL 연결 메모리의 경우 CXL 2.0+ Health Status 명령(Get Health Info)으로 미디어 에러율, 온도, 수명 정보를 직접 조회
  4. Intel PPR(Post Package Repair): Hard PPR은 결함 있는 DRAM 행을 영구적으로 스페어 행으로 대체. Soft PPR은 재부팅 전까지만 유효한 임시 수리
  5. Device-level Sparing: Intel Sapphire Rapids 이후, 결함 DRAM 디바이스를 투명하게 스페어 디바이스로 교체 (ADDDC 확장)

DDR4 ECC vs DDR5 On-Die ECC + Host ECC 비교

비교 항목DDR4 (Host ECC만)DDR5 (On-Die ECC + Host ECC)
1차 ECC없음 (호스트 ECC만)On-Die ECC (DRAM 내부 SECDED)
2차 ECCSECDED / Chipkill (호스트)SECDED / Chipkill (호스트)
단일 비트 오류호스트 CE MCE 생성On-Die에서 교정, CE MCE 미생성
2비트 오류 (같은 워드)호스트 UCE → memory_failure()On-Die ECC 미교정 → 호스트 ECC 감지, CE 또는 UCE
CE 기반 DIMM 건강 감시효과적 (CE 증가 = 열화 신호)제한적 (On-Die ECC가 CE를 마스킹)
대안 모니터링CE 카운터, EDAC sysfsECS, 내부 에러 로깅, CXL Health, PPR 이력
UCE 발생 패턴CE 점진적 증가 후 UCE 전환CE 경고 없이 갑작스런 UCE 가능
Patrol Scrub 효과잠재 CE 조기 발견에 효과적On-Die 교정으로 마스킹된 오류는 감지 불가, ECS 병행 필요
RAS 운영 전략CE 임계값 기반 사전 교체다층 모니터링 필요 (ECS + CE + CXL Health + PPR 이력 종합 판단)
운영 권장: DDR5 서버에서는 BIOS에서 ECS 주기적 실행을 활성화하고, rasdaemon의 DDR5 지원 버전(v0.8.0+)을 사용하여 ECS 이벤트와 CE를 함께 모니터링하세요. CE 카운트만으로 DIMM 교체를 판단하지 말고, ECS 결과와 PPR 이력을 종합적으로 평가해야 합니다.

MCE 운영 플레이북

MCE 운영 의사결정 트리 MCE 알림 수신 시스템 패닉 발생? Yes → 즉시 대응 1. BERT 데이터 수집 2. crash dump 분석 Yes UC (교정 불가)? No CE → 모니터링 1. DIMM별 CE 카운트 추적 2. 임계값 초과 시 DIMM 교체 계획 3. rasdaemon 알림 설정 No 프로세스 킬됨? Yes Yes → 서비스 복구 1. 영향받은 서비스 재시작 2. HWPoison 페이지 확인 3. 동일 DIMM 모니터링 강화 Yes No → 비동기 처리됨 SRAO: 페이지 오프라인 완료 UCNA: 정보 기록만 No 공통: rasdaemon 이력 확인 → DIMM CE 추세 분석 → 24시간 내 재발 여부 모니터링

CE 인시던트 대응 체크리스트

  1. 에러 수집: ras-mc-ctl --summary로 DIMM별 CE 카운트 확인
  2. 추세 분석: rasdaemon SQLite에서 시간대별 CE 빈도 쿼리
  3. DIMM 식별: EDAC sysfs에서 소켓/채널/DIMM 슬롯 위치 확인
  4. 임계값 판단: 24시간 내 CE > 100 → DIMM 교체 권장 (벤더 가이드 참조)
  5. 선제 조치: soft_offline_page()로 문제 페이지 사전 격리 고려

UC 인시던트 대응 체크리스트

  1. 서비스 영향 확인: SIGBUS로 종료된 프로세스 확인 (dmesg | grep -i sigbus)
  2. HWPoison 상태: page-types -l -b hwpoison으로 오프라인 페이지 수 확인
  3. 이전 CE 이력: 동일 DIMM에서 CE 누적이 있었는지 확인 (예측 가능했는지)
  4. DIMM 교체: UC 발생 DIMM은 교체 우선순위 최상위로 에스컬레이션
  5. 마이크로코드: 최신 마이크로코드 적용 여부 확인

패닉 후 복구 체크리스트

  1. BERT 확인: 재부팅 후 dmesg | grep BERT로 이전 에러 정보 수집
  2. crash dump: kdump/ERST로 저장된 vmcore 분석 (crash 유틸리티)
  3. BIOS 에러 로그: BMC/IPMI SEL 로그 확인 (ipmitool sel list)
  4. 하드웨어 점검: CPU/DIMM/보드 교체 결정
  5. 사후 보고서: 타임라인, root cause, 재발 방지 작성

모니터링 설정 권장사항

# rasdaemon + 알림 설정 예시

# 1. rasdaemon 서비스 활성화
$ sudo systemctl enable --now rasdaemon

# 2. CE 모니터링 스크립트 (cron에 등록)
$ cat /usr/local/bin/mce-monitor.sh
#!/bin/bash
CE_COUNT=$(sqlite3 /var/lib/rasdaemon/ras-mc_event.db \
  "SELECT COUNT(*) FROM mc_event WHERE err_type='Corrected' AND timestamp > strftime('%s','now','-1 hour');")
if [ "$CE_COUNT" -gt 10 ]; then
  echo "ALERT: $CE_COUNT CE errors in last hour" | mail -s "MCE Alert" ops@example.com
fi

# 3. journald 기반 실시간 감시
$ journalctl -k -f -g "mce:|EDAC|Hardware Error"

MCE는 하드웨어 에러 처리의 핵심 인프라로, 커널의 여러 서브시스템과 깊이 연관됩니다. 아래 문서들은 MCE의 다양한 측면을 이해하는 데 도움이 됩니다.

추가 참고 자료: