MSR 레지스터 (Model-Specific Register)

x86 MSR 종합 가이드: RDMSR/WRMSR 명령어, 시스템 제어/SYSCALL/APIC/PMU/전력/보안/가상화 MSR, MTRR/PAT, Linux 커널 MSR API, AMD 전용 MSR, Spectre 완화, KVM MSR 비트맵, msr-tools 디버깅.

관련 표준: Intel SDM Vol.4 (MSR 전체 목록), AMD APM Vol.2 (AMD MSR) — 모델 특화 레지스터의 비트 필드와 용도를 정의하는 프로세서 규격입니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.
전제 조건: 커널 아키텍처(x86 특권 레벨, Ring 0/3 개념)를 먼저 읽으세요. MSR은 x86 전용 개념이므로 x86 아키텍처 기초 지식이 필요합니다.
일상 비유: MSR은 CPU의 히든 설정 메뉴와 같습니다. 스마트폰에도 일반 설정 앱 외에 개발자 옵션이 숨어 있듯이, CPU에도 일반 레지스터(EAX 등) 외에 성능 튜닝, 전력 관리, 보안 설정을 위한 특수 레지스터가 수천 개 존재합니다. RDMSR/WRMSR 명령어로만 접근할 수 있으며, Ring 0(커널)에서만 사용 가능합니다.

핵심 요약

  • MSR — Model-Specific Register. CPU 동작 모드, 성능, 전력, 보안을 제어하는 특수 레지스터입니다.
  • RDMSR / WRMSR — MSR을 읽고 쓰는 특권 명령어. ECX에 MSR 번호를 지정합니다.
  • 주요 MSR — TSC(타임스탬프), EFER(Long Mode), APIC_BASE, MTRR(메모리 타입), PAT 등이 있습니다.
  • rdmsr / wrmsr 도구 — 사용자 공간에서 /dev/cpu/N/msr을 통해 MSR을 읽고 쓸 수 있습니다.

단계별 이해

  1. MSR 개념 잡기 — 일반 레지스터(범용, 세그먼트)와 달리 MSR은 번호(인덱스)로 식별되는 특수 목적 레지스터입니다.

    Intel SDM Vol.4에 수천 개의 MSR이 문서화되어 있습니다.

  2. 읽기 실습sudo rdmsr 0x10으로 TSC(Time Stamp Counter) 값을 읽어봅니다.

    msr-tools 패키지를 설치하고 modprobe msr로 MSR 드라이버를 로드합니다.

  3. 커널 API — 드라이버/커널 코드에서는 rdmsrl()/wrmsrl() 함수로 MSR에 접근합니다.

    잘못된 MSR 쓰기는 시스템 크래시를 유발할 수 있으므로 주의가 필요합니다.

MSR 개요

MSR(Model-Specific Register)은 x86 프로세서에 내장된 특수 레지스터 집합으로, CPU의 동작 모드 제어, 성능 모니터링, 전력 관리, 보안 완화 등 다양한 기능을 담당합니다. "Model-Specific"이라는 이름처럼 원래는 CPU 모델마다 다른 레지스터 세트를 가졌으나, 현재는 많은 MSR이 Intel/AMD 간에 공통으로(architectural) 정의되어 있습니다.

MSR의 역사와 발전

MSR 주소 공간

MSR은 32비트 주소 공간(0x00000000 ~ 0xFFFFFFFF)을 사용하며, 각 MSR은 64비트(EDX:EAX) 값을 가집니다. 주소 범위는 대략 다음과 같이 구분됩니다:

주소 범위용도예시
0x00000000 ~ 0x00001FFFArchitectural MSRIA32_TSC, IA32_APIC_BASE
0x00000100 ~ 0x000001FFFixed/PMC 영역IA32_MTRR*, PMC
0x00000174 ~ 0x00000176SYSENTER MSRIA32_SYSENTER_CS/ESP/EIP
0x00000186 ~ 0x0000018F성능 이벤트 선택IA32_PERFEVTSEL0~7
0x000001A0기능 제어IA32_MISC_ENABLE
0x00000300 ~ 0x000003FFFixed Counter / PMCIA32_FIXED_CTR0~2
0x00000400 ~ 0x00000477MC(Machine Check) 뱅크IA32_MCi_CTL/STATUS
0x00000480 ~ 0x0000049FVMX 기능 보고IA32_VMX_BASIC 등
0x00000800 ~ 0x000008FFx2APICICR, LVT 등
0xC0000000 ~ 0xC0001FFFAMD/Long mode MSRMSR_EFER, MSR_STAR, MSR_LSTAR
0xC0010000 ~ 0xC001FFFFAMD 전용HWCR, SYSCFG, NB_CFG

접근 권한

RDMSR/WRMSR 명령어는 Ring 0(커널 모드)에서만 실행 가능합니다. 유저 공간에서 실행하면 #GP(General Protection) 예외가 발생합니다. 다만 RDTSC, RDTSCP, RDPMC 등 일부 전용 명령어는 CR4 비트 설정에 따라 Ring 3에서도 실행할 수 있습니다.

팁: 유저 공간에서 MSR에 접근하려면 /dev/cpu/<n>/msr 장치 파일 또는 msr-tools 패키지의 rdmsr/wrmsr 유틸리티를 사용합니다. 단, CONFIG_X86_MSR=y로 커널이 빌드되어야 하며, CAP_SYS_RAWIO 권한이 필요합니다.

RDMSR / WRMSR 명령어

명령어 형식

명령어입력출력설명
RDMSRECX = MSR 주소EDX:EAX = 64비트 값MSR 읽기
WRMSRECX = MSR 주소, EDX:EAX = 값없음MSR 쓰기
RDTSC없음EDX:EAX = TSC 값IA32_TSC 전용 읽기
RDTSCP없음EDX:EAX = TSC, ECX = TSC_AUX직렬화된 TSC 읽기
RDPMCECX = PMC 인덱스EDX:EAX = 카운터 값PMC 전용 읽기

직렬화와 순서 보장

WRMSR직렬화(serializing) 명령어로 분류되어, 이전의 모든 명령어가 완료된 후에 실행됩니다. 반면 RDMSR은 직렬화 명령어가 아니므로, 정확한 순서 보장이 필요하면 앞에 LFENCE 또는 MFENCE를 배치해야 합니다.

; 직렬화된 MSR 읽기 패턴
lfence                ; 이전 명령어 완료 보장
mov  $0x10, %ecx    ; IA32_TSC = 0x10
rdmsr                 ; EDX:EAX = TSC 값
shl  $32, %rdx
or   %rax, %rdx      ; RDX = 64비트 TSC

CPUID를 통한 MSR 존재 확인

특정 MSR에 접근하기 전에 해당 기능의 존재 여부를 CPUID로 확인해야 합니다. 존재하지 않는 MSR에 접근하면 #GP(0) 예외가 발생합니다.

CPUID 리프비트확인 대상
CPUID.01H:EDXbit 5MSR 명령어 지원 (RDMSR/WRMSR)
CPUID.01H:EDXbit 4TSC 지원
CPUID.01H:ECXbit 15PDCM (IA32_PERF_CAPABILITIES)
CPUID.80000001H:EDXbit 20NX bit (IA32_EFER.NXE)
CPUID.80000001H:EDXbit 11SYSCALL/SYSRET
CPUID.07H:EBXbit 0FSGSBASE 명령어
CPUID.07H:EDXbit 26IA32_SPEC_CTRL / IBRS
CPUID.07H:EDXbit 29IA32_ARCH_CAPABILITIES

시스템 제어 MSR

IA32_EFER (0xC0000080) — Extended Feature Enable Register

Long Mode 활성화와 NX bit 제어를 담당하는 핵심 MSR입니다.

비트이름설명
0SCESYSCALL/SYSRET Enable
8LMELong Mode Enable (IA-32e 활성화)
10LMALong Mode Active (읽기 전용, CR0.PG로 활성화)
11NXENo-Execute Enable (W^X 보안)
12SVMESVM Enable (AMD-V 전용)
13LMSLELong Mode Segment Limit Enable (AMD)
14FFXSRFast FXSAVE/FXRSTOR (AMD)
15TCETranslation Cache Extension (AMD)
/* arch/x86/kernel/cpu/common.c — Long Mode 진입 시 EFER 설정 */
static void setup_efer(void)
{
    u64 efer;
    rdmsrl(MSR_EFER, efer);

    efer |= EFER_SCE;        /* SYSCALL enable */
    if (boot_cpu_has(X86_FEATURE_NX))
        efer |= EFER_NX;     /* NX bit enable */
    wrmsrl(MSR_EFER, efer);
}

IA32_MISC_ENABLE (0x1A0)

다양한 CPU 기능을 활성화/비활성화하는 범용 제어 레지스터입니다.

비트이름설명
0Fast-Strings EnableREP MOVSB/STOSB 최적화
7Performance Monitoring AvailablePMU 사용 가능 여부
11Branch Trace Storage UnavailableBTS 비활성화 (읽기 전용)
12PEBS UnavailablePEBS 비활성화 (읽기 전용)
16Enhanced SpeedStep EnableEIST/P-state 전환 활성화
18ENABLE_MONITOR_FSMMONITOR/MWAIT 활성화
22Limit CPUID MaxvalCPUID 리프 제한 (레거시 OS 호환)
23xTPR Message DisableTPR 메시지 비활성화
34XD Bit DisableNX bit 전역 비활성화

IA32_FEATURE_CONTROL (0x3A)

VMX(가상화) 활성화 및 BIOS 잠금을 제어합니다. BIOS/UEFI 펌웨어가 부팅 시 설정하며, Lock bit이 설정되면 재부팅 전까지 변경 불가합니다.

비트이름설명
0Lock1로 설정 시 이 MSR은 읽기 전용 (재부팅까지)
1Enable VMX in SMXTXT 환경에서 VMX 활성화
2Enable VMX outside SMX일반 환경에서 VMX 활성화
8~14SENTER Local Function EnablesTXT SENTER 리프 활성화
15SENTER Global EnableTXT SENTER 전역 활성화
17SGX Launch Control EnableSGX Launch Enclave 제어
18SGX Global EnableSGX 전역 활성화
/* arch/x86/kernel/cpu/feat_ctl.c — VMX 활성화 확인 */
void init_ia32_feat_ctl(struct cpuinfo_x86 *c)
{
    u64 msr;

    rdmsrl(MSR_IA32_FEAT_CTL, msr);
    if (msr & FEAT_CTL_LOCKED)
        return;  /* BIOS가 이미 잠금 */

    /* Lock 비트 없이 열려 있으면 직접 설정 */
    msr = FEAT_CTL_LOCKED;
    msr |= FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX;
    wrmsrl(MSR_IA32_FEAT_CTL, msr);
}

SYSCALL / SYSRET MSR

Long Mode에서 SYSCALL/SYSRET 명령어는 시스템 콜 진입/복귀를 위해 3개의 MSR을 사용합니다. 이 MSR들은 IA32_EFER.SCE=1일 때만 유효합니다.

MSR주소용도
MSR_STAR0xC0000081SYSCALL의 CS/SS 선택자 (비트 47:32 = kernel CS, 비트 63:48 = user CS)
MSR_LSTAR0xC0000082SYSCALL 진입점의 64비트 RIP (Long Mode)
MSR_CSTAR0xC0000083SYSCALL 진입점 RIP (Compatibility Mode, Linux 미사용)
MSR_SYSCALL_MASK0xC0000084SYSCALL 시 RFLAGS에 적용할 마스크 (마스크된 비트 = 0)
/* arch/x86/kernel/cpu/common.c — SYSCALL MSR 초기화 */
void syscall_init(void)
{
    wrmsr(MSR_STAR, 0,
          (__USER32_CS << 16) | __KERNEL_CS);  /* STAR 상위 32비트 */
    wrmsrl(MSR_LSTAR,
          (unsigned long)entry_SYSCALL_64);   /* 시스템 콜 진입점 */

#ifdef CONFIG_IA32_EMULATION
    wrmsrl(MSR_CSTAR,
          (unsigned long)entry_SYSCALL_compat);
#endif

    /* IF, TF, DF, AC 플래그 마스킹 — 인터럽트/디버그 비활성화 */
    wrmsrl(MSR_SYSCALL_MASK,
          X86_EFLAGS_TF | X86_EFLAGS_DF |
          X86_EFLAGS_IF | X86_EFLAGS_AC);
}
SYSCALL 동작: SYSCALL 실행 시 CPU는 (1) RCX에 리턴 주소(RIP) 저장, (2) R11에 RFLAGS 저장, (3) CS/SS를 STAR에서 로드, (4) RIP를 LSTAR에서 로드, (5) RFLAGS를 SYSCALL_MASK로 마스킹합니다. 스택 전환은 CPU가 하지 않으며, 커널이 직접 per-CPU 영역에서 RSP를 교체합니다.

세그먼트 Base MSR (FS/GS)

Long Mode에서 FS/GS 세그먼트의 base 주소는 GDT가 아닌 MSR로 관리됩니다. Linux 커널은 GS_BASE를 per-CPU 데이터 포인터로, FS_BASE를 유저 공간 TLS(Thread-Local Storage)로 사용합니다.

MSR주소용도
IA32_FS_BASE0xC0000100FS 세그먼트 base (유저: TLS/glibc)
IA32_GS_BASE0xC0000101GS 세그먼트 base (현재 활성 GS)
IA32_KERNEL_GS_BASE0xC0000102SWAPGS로 교환할 GS base (대기 값)

SWAPGS 메커니즘

SWAPGS는 IA32_GS_BASE와 IA32_KERNEL_GS_BASE를 원자적으로 교환합니다. 시스템 콜/인터럽트 진입 시 커널은 SWAPGS를 실행하여 per-CPU 포인터를 GS에 로드하고, 복귀 시 다시 SWAPGS로 유저의 GS를 복원합니다.

; entry_SYSCALL_64 진입부 (arch/x86/entry/entry_64.S)
SYM_CODE_START(entry_SYSCALL_64)
    swapgs                        ; GS = per-CPU base (커널용)
    mov  %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2)
    SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp  ; KPTI: 커널 페이지 테이블 전환
    mov  PER_CPU_VAR(cpu_current_top_of_stack), %rsp
    ; ... 레지스터 저장, 시스템 콜 디스패치

FSGSBASE 명령어 (Linux 5.3+)

FSGSBASE CPU 기능(CPUID.07H:EBX.FSGSBASE[bit 0])이 있으면, RDFSBASE/WRFSBASE/RDGSBASE/WRGSBASE 명령어로 WRMSR 없이 직접 FS/GS base를 읽고 쓸 수 있습니다. 이 명령어들은 비직렬화이며 매우 빠릅니다(~10 사이클 vs WRMSR ~100 사이클).

/* arch/x86/include/asm/fsgsbase.h */
static inline unsigned long rdgsbase(void)
{
    unsigned long gsbase;
    asm volatile("rdgsbase %0" : "=r"(gsbase) :: "memory");
    return gsbase;
}

static inline void wrgsbase(unsigned long gsbase)
{
    asm volatile("wrgsbase %0" :: "r"(gsbase) : "memory");
}
주의: CR4.FSGSBASE=1이어야 FSGSBASE 명령어가 Ring 3에서도 사용 가능합니다. Linux 5.3부터 기본 활성화되며, 그 전에는 WRMSR로만 FS/GS base를 변경했습니다. FSGSBASE 활성화 시 SWAPGS 대신 WRGSBASE를 사용할 수 있지만, Linux은 호환성을 위해 SWAPGS를 유지합니다.

APIC MSR

IA32_APIC_BASE (0x1B)

Local APIC의 기본 주소와 활성화 상태를 제어합니다.

비트이름설명
8BSPBootstrap Processor 플래그 (읽기 전용)
10EXTDx2APIC 모드 활성화
11ENAPIC 전역 활성화
12~35APIC BaseAPIC MMIO base 주소 (기본: 0xFEE00000)

x2APIC 모드 MSR (0x800~0x8FF)

x2APIC 모드에서는 MMIO 대신 MSR을 통해 APIC 레지스터에 접근합니다. 이는 MMIO보다 빠르고 32비트 APIC ID를 지원하여 256 CPU 이상의 시스템을 지원할 수 있습니다.

MSR 주소xAPIC MMIO 오프셋이름접근
0x8020x20APIC IDR
0x8030x30APIC VersionR
0x8080x80Task Priority (TPR)R/W
0x80B0xB0EOIW
0x80F0xF0Spurious Interrupt VectorR/W
0x8300x300+0x310ICR (64비트 통합)R/W
0x832~8380x320~380LVT (Timer, Thermal, PMI 등)R/W
0x83FSelf IPIW
/* arch/x86/kernel/apic/x2apic_cluster.c — x2APIC IPI 전송 */
static void x2apic_send_IPI(int cpu, int vector)
{
    u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);

    /* x2APIC ICR: MSR 0x830, 하위 32비트 = vector+flags, 상위 32비트 = dest */
    wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4),
          ((u64)dest << 32) | APIC_DM_FIXED | vector);
}
x2APIC 장점: (1) MSR 접근은 MMIO보다 빠름 (캐시 불가 메모리 접근 불필요), (2) ICR이 64비트 단일 레지스터로 통합되어 원자적 IPI 전송 가능, (3) 32비트 APIC ID로 최대 2^32개 논리 CPU 지원.

성능 모니터링 MSR (PMU)

Performance Monitoring Unit(PMU) MSR은 CPU 이벤트(캐시 미스, 분기 예측 실패, 명령어 은퇴 등)를 하드웨어 수준에서 카운팅합니다. perf 도구가 내부적으로 이 MSR들을 프로그래밍합니다.

Architectural PMU (버전 2+)

MSR주소설명
IA32_PERFEVTSELx0x186 + x이벤트 선택 레지스터 (이벤트/umask/usr/os/edge 등)
IA32_PMCx0x0C1 + x범용 성능 카운터 (48비트)
IA32_FIXED_CTR00x309Instruction Retired (고정 카운터)
IA32_FIXED_CTR10x30AUnhalted Core Cycles (고정 카운터)
IA32_FIXED_CTR20x30BUnhalted Reference Cycles (고정 카운터)
IA32_FIXED_CTR_CTRL0x38D고정 카운터 제어 (OS/USR/PMI 설정)
IA32_PERF_GLOBAL_CTRL0x38F전역 카운터 활성화 비트맵
IA32_PERF_GLOBAL_STATUS0x38E오버플로 상태 (PMI 인터럽트 원인)
IA32_PERF_GLOBAL_OVF_CTRL0x390오버플로 상태 클리어

IA32_PERFEVTSELx 비트 필드

비트 63                                                    0
┌────────┬───┬───┬───┬────┬───┬───┬───┬──────────┬──────────┐
│Reserved│INV│CNT│ANY│ EN │INT│ PC│ E │ UnitMask │  Event   │
│ 63:32  │ 23│22 │21 │ 22 │20 │19 │18 │  15:8    │  Select  │
│        │   │MASK    │    │   │   │   │  (umask) │   7:0    │
└────────┴───┴───┴───┴────┴───┴───┴───┴──────────┴──────────┘

EN (bit 22)  = 카운터 활성화
INT (bit 20) = 오버플로 시 PMI 인터럽트 발생
USR (bit 16) = Ring 3 이벤트 카운팅
OS  (bit 17) = Ring 0 이벤트 카운팅
/* L3 캐시 미스 이벤트 프로그래밍 예 */
#define PERFEVTSEL_EN      (1ULL << 22)
#define PERFEVTSEL_OS      (1ULL << 17)
#define PERFEVTSEL_USR     (1ULL << 16)

/* Event 0x2E, Umask 0x41 = LLC-misses (Skylake 기준) */
u64 evtsel = 0x2E | (0x41 << 8) |
            PERFEVTSEL_EN | PERFEVTSEL_OS | PERFEVTSEL_USR;
wrmsrl(MSR_P6_EVNTSEL0, evtsel);

/* 카운터 읽기 */
u64 count;
rdmsrl(MSR_P6_PERFCTR0, count);
pr_info("LLC misses: %llu\n", count);
팁: perf stat -e cache-misses,instructions,cycles ./program 명령은 내부적으로 이 PMU MSR들을 프로그래밍합니다. 커널 드라이버 arch/x86/events/intel/core.c가 MSR 접근을 추상화합니다.

전력/주파수 MSR

현대 x86 CPU는 MSR을 통해 동적 주파수/전압 조절(DVFS)을 제어합니다. Linux의 cpufreq 드라이버(intel_pstate, amd-pstate)가 이 MSR들을 직접 사용하여 CPU의 성능 수준을 조절합니다. 이 섹션에서는 P-State 제어, HWP(Hardware P-States), RAPL(전력 제한), C-State 레지던시, AMD CPPC 등 전력/주파수 관련 MSR 전체를 상세히 다룹니다.

핵심 용어:
  • P-State: Performance State — CPU 주파수/전압 조합. P0이 최고 성능, 숫자가 클수록 저전력.
  • C-State: CPU Idle State — C0(활성), C1(Halt), C3(Sleep), C6(Deep Sleep) 등. 깊을수록 절전.
  • FID: Frequency ID — 주파수 배수(ratio). Base Clock × FID = 실제 주파수.
  • VID: Voltage ID — 전압 식별자. FID와 함께 P-State를 정의.
  • DVFS: Dynamic Voltage and Frequency Scaling — 부하에 따라 주파수와 전압을 동적 조절.
  • EPP: Energy Performance Preference — HWP에서 성능 vs 절전 우선순위 (0=성능, 255=절전).
  • RAPL: Running Average Power Limit — 패키지/코어/DRAM의 전력 소비를 제한하고 측정.
레거시 P-State (EIST) HWP (Speed Shift) 공통 피드백 OS cpufreq governor IA32_PERF_CTL (0x199) CPU P-State 전환 IA32_PERF_STATUS (0x198) 전환 지연: ~10μs OS가 매번 결정 OS: HWP_REQUEST (0x774) Min/Max/Desired + EPP HW 자율 P-State 선택 (부하/온도/전력 종합 판단) HWP_STATUS (0x777) 전환 지연: ~1ms → ~30μs HW가 자율 결정 APERF/MPERF (0xE8/E7) 실제 주파수 측정 RAPL (0x610~0x619) 전력 소비 측정/제한 C-State 레지던시

MSR_PLATFORM_INFO (0xCE) — 플랫폼 주파수 정보

CPU의 기본 주파수 비율(ratio), 최소/최대 비율, TDP 관련 정보를 담고 있는 읽기 전용 MSR입니다. intel_pstate 드라이버가 초기화 시 가장 먼저 읽는 MSR입니다.

비트필드설명
15:8Maximum Non-Turbo Ratio기본 주파수 비율 (Base Frequency = BCLK × 이 값). 예: 0x22 = 34 → 3.4GHz (BCLK 100MHz)
23:16예약됨
28Programmable Ratio Limit for Turbo1이면 MSR_TURBO_RATIO_LIMIT 프로그래밍 가능
29Programmable TDP Limit for Turbo1이면 TDP 제한 변경 가능
30Programmable TJ Offset1이면 TjMax 오프셋 변경 가능
40:32Maximum Efficiency Ratio최소 효율 주파수 비율 (최저 P-State). 예: 0x04 = 400MHz
47:41예약됨
55:48Minimum Operating Ratio절대 최소 동작 비율 (C-State 진입 직전 최저 주파수)
/* drivers/cpufreq/intel_pstate.c — 플랫폼 정보에서 주파수 범위 결정 */
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
    u64 value;

    rdmsrl(MSR_PLATFORM_INFO, value);

    /* Base Frequency ratio (bits 15:8) */
    cpu->pstate.max_pstate = (value >> 8) & 0xFF;
    /* Minimum Efficiency ratio (bits 40:32) */
    cpu->pstate.min_pstate = (value >> 32) & 0xFF;
    /* 예: max_pstate=34 → 3.4GHz, min_pstate=4 → 400MHz (BCLK=100MHz) */

    rdmsrl(MSR_TURBO_RATIO_LIMIT, value);
    cpu->pstate.turbo_pstate = value & 0xFF;  /* 1코어 활성 시 최대 터보 비율 */

    pr_debug("cpu %d: min=%d base=%d turbo=%d\n",
             cpu->cpu, cpu->pstate.min_pstate,
             cpu->pstate.max_pstate, cpu->pstate.turbo_pstate);
}

IA32_PERF_CTL / IA32_PERF_STATUS — P-State 제어 (레거시 EIST)

Enhanced Intel SpeedStep Technology(EIST)에서 OS가 직접 목표 P-State를 설정하고, 현재 P-State를 읽는 데 사용하는 MSR 쌍입니다. HWP 활성화 시에도 레거시 호환을 위해 존재하지만, 실질적 제어는 HWP MSR이 담당합니다.

IA32_PERF_CTL (0x199) — 목표 P-State 설정

비트필드설명
7:0Target Ratio목표 주파수 비율 (BCLK × ratio = 목표 주파수)
15:8예약됨 (일부 모델에서 VID 인코딩)
16IDA/Turbo Disengage1이면 해당 코어의 터보 부스트 비활성화
31:17예약됨
32IDA/Turbo Disengage (64-bit)일부 모델에서 추가 터보 제어

IA32_PERF_STATUS (0x198) — 현재 P-State (읽기 전용)

비트필드설명
15:0Current Performance State Value현재 동작 중인 P-State 값 (ratio + VID 인코딩)
/* 레거시 P-State 전환 — acpi-cpufreq 드라이버 */
/* drivers/cpufreq/acpi-cpufreq.c */
static void do_drv_write(void *_cmd)
{
    struct drv_cmd *cmd = _cmd;

    /* MSR_IA32_PERF_CTL에 목표 비율 쓰기 */
    wrmsrl(MSR_IA32_PERF_CTL,
           cmd->val | (rdmsrl(MSR_IA32_PERF_CTL) & ~0xFFFFULL));
    /*
     * P-State 전환은 즉각적이지 않음:
     * - Intel: ~10μs (전압/주파수 안정화)
     * - 전환 중 IA32_PERF_STATUS 값이 점진적으로 변경
     * - IA32_MISC_ENABLE[16] (EIST Enable)이 1이어야 동작
     */
}
주의: IA32_MISC_ENABLE(0x1A0)의 비트 16(Enhanced SpeedStep Enable)이 0이면 EIST가 비활성화되어 IA32_PERF_CTL 쓰기가 무시됩니다. BIOS에서 SpeedStep을 활성화해야 합니다.

MSR_TURBO_RATIO_LIMIT (0x1AD) — 터보 부스트 비율 제한

활성 코어 수에 따른 최대 터보 부스트 비율을 정의합니다. 활성 코어가 적을수록 더 높은 주파수까지 부스트할 수 있습니다 (열/전력 여유분 활용).

비트필드설명
7:01C Max Turbo Ratio1코어 활성 시 최대 비율 (가장 높음)
15:82C Max Turbo Ratio2코어 활성 시 최대 비율
23:163C Max Turbo Ratio3코어 활성 시 최대 비율
31:244C Max Turbo Ratio4코어 활성 시 최대 비율
39:325C Max Turbo Ratio5코어 활성 시 최대 비율
47:406C Max Turbo Ratio6코어 활성 시 최대 비율
55:487C Max Turbo Ratio7코어 활성 시 최대 비율
63:568C Max Turbo Ratio8코어 활성 시 최대 비율
/* 터보 비율 파싱 — turbostat 도구 로직과 유사 */
static void dump_turbo_ratios(void)
{
    u64 turbo_limit;
    int i;

    rdmsrl(MSR_TURBO_RATIO_LIMIT, turbo_limit);
    for (i = 0; i < 8; i++) {
        u8 ratio = (turbo_limit >> (i * 8)) & 0xFF;
        pr_info("%dC turbo: %d (%d MHz)\n",
               i + 1, ratio, ratio * 100);
    }
    /*
     * 출력 예시 (i7-12700):
     * 1C turbo: 49 (4900 MHz)   ← 단일 코어 최대
     * 2C turbo: 49 (4900 MHz)
     * 3C turbo: 48 (4800 MHz)
     * 4C turbo: 47 (4700 MHz)
     * ...
     * 8C turbo: 46 (4600 MHz)   ← 전코어 터보
     */
}

/* 코어 수가 8 이상인 CPU는 추가 MSR 사용:
 * MSR_TURBO_RATIO_LIMIT1 (0x1AE): 코어 9~16
 * MSR_TURBO_RATIO_LIMIT2 (0x1AF): 코어 17~24
 * MSR_TURBO_RATIO_LIMIT3 (0x1AC): 그룹별 비율 (Atom 계열)
 */
실용 팁: turbostat 도구는 이 MSR을 읽어 코어 수별 최대 터보 주파수를 표시합니다: turbostat --show Core,CPU,Bzy_MHz,TSC_MHz,Busy%,PkgWatt

HWP (Hardware P-States) — Intel Speed Shift 심화

HWP는 Skylake(6세대) 이후 Intel CPU에서 지원하는 하드웨어 자율 P-State 관리 기술입니다. 기존 EIST에서는 OS가 매번 목표 P-State를 결정해야 했으나, HWP에서는 OS가 성능 범위와 선호도만 설정하면 CPU 하드웨어가 부하, 온도, 전력 상태를 종합적으로 판단하여 최적의 P-State를 자율 선택합니다. P-State 전환 응답 시간이 ~10ms에서 ~30μs로 대폭 개선됩니다.

IA32_PM_ENABLE (0x770) — HWP 활성화

비트필드설명
0HWP_ENABLE1로 설정하면 HWP 활성화. 비가역적: 한 번 활성화하면 재부팅 전까지 비활성화 불가.
63:1예약됨 (0으로 유지)
비가역적 MSR: IA32_PM_ENABLE에 1을 쓰면 HWP가 영구(재부팅까지) 활성화됩니다. 다시 0으로 되돌릴 수 없으므로, 커널 드라이버는 부팅 초기에 한 번만 설정합니다.

IA32_HWP_CAPABILITIES (0x771) — 하드웨어 성능 범위 (읽기 전용)

CPU가 보고하는 P-State 범위. OS는 이 범위 내에서 HWP_REQUEST를 설정해야 합니다.

비트필드설명
7:0Highest_Performance최대 성능 수준 (터보 포함). 예: 49 → 4.9GHz
15:8Guaranteed_Performance지속 보장 성능 수준 (Base Freq). 예: 34 → 3.4GHz
23:16Most_Efficient_Performance최고 에너지 효율 성능 수준. 예: 8 → 800MHz
31:24Lowest_Performance절대 최저 성능 수준. 예: 4 → 400MHz
/* IA32_HWP_CAPABILITIES 파싱 */
static void read_hwp_caps(struct cpudata *cpu)
{
    u64 cap;
    rdmsrl(MSR_IA32_HWP_CAPABILITIES, cap);

    cpu->hwp_cap.highest  = HWP_HIGHEST_PERF(cap);      /* bits 7:0   */
    cpu->hwp_cap.guaranteed = HWP_GUARANTEED_PERF(cap);  /* bits 15:8  */
    cpu->hwp_cap.efficient = HWP_MOSTEFFICIENT_PERF(cap); /* bits 23:16 */
    cpu->hwp_cap.lowest   = HWP_LOWEST_PERF(cap);       /* bits 31:24 */

    /*
     * 실제 예시 (Intel i9-13900K):
     *   Highest=49, Guaranteed=34, Efficient=8, Lowest=4
     *   → 4.9GHz 최대, 3.4GHz 보장, 800MHz 효율, 400MHz 최저
     */
}

IA32_HWP_REQUEST (0x774) — OS → HW 성능 요청 (코어별)

OS가 HWP에 전달하는 성능 힌트. 각 논리 코어별로 독립 설정 가능합니다.

비트필드설명
7:0Minimum_Performance허용 최저 성능. 이 이하로 내려가지 않음. 절전 vs 응답 지연 트레이드오프.
15:8Maximum_Performance허용 최대 성능. 이 이상 올라가지 않음. 전력/발열 제한에 활용.
23:16Desired_Performance목표 성능 힌트. 0이면 HW가 자율 결정 (자율 모드).
31:24Energy_Performance_PreferenceEPP 값 (0~255): 0=최대 성능, 128=균형, 255=최대 절전.
41:32Activity_Window부하 모니터링 창 크기 (10비트: 7비트 값 + 3비트 지수). 0이면 HW 기본값.
42Package_Control1이면 이 코어의 요청이 패키지 레벨에서 적용
59:43예약됨
63:60예약됨

EPP (Energy Performance Preference) 상세

EPP는 HWP에서 성능과 에너지 효율 사이의 균형점을 OS가 CPU에 전달하는 핵심 파라미터입니다. 값이 작을수록 성능 우선, 클수록 절전 우선입니다.

EPP 값Linux 정책sysfs 값동작 특성
0performanceperformance최대 터보 부스트, 전력 무제한. 고성능 서버/게이밍.
64balance_performancebalance_performance성능 우선이지만 약간의 절전 고려. 데스크톱 기본값.
128default/normaldefault성능과 절전 균형. 일반 워크로드.
192balance_powerbalance_power절전 우선이지만 합리적 성능 유지. 노트북 배터리 모드.
255powerpower최대 절전, 최저 주파수 유지. 극한 배터리 절약.
/* drivers/cpufreq/intel_pstate.c — HWP_REQUEST 설정 (전체 필드) */
static void intel_pstate_hwp_set(struct cpudata *cpu)
{
    u64 value, prev;
    s16 epp;

    rdmsrl_on_cpu(cpu->cpu, MSR_IA32_HWP_REQUEST, &prev);

    value  = HWP_MIN_PERF(cpu->pstate.min_pstate);      /* bits 7:0   */
    value |= HWP_MAX_PERF(cpu->pstate.max_pstate);      /* bits 15:8  */
    value |= HWP_DESIRED_PERF(0);                       /* bits 23:16 — 0 = 자율 모드 */
    epp = intel_pstate_get_epp(cpu);
    value |= HWP_ENERGY_PERF_PREFERENCE(epp);            /* bits 31:24 */

    if (value != prev) {
        wrmsrl_on_cpu(cpu->cpu, MSR_IA32_HWP_REQUEST, value);
        trace_cpu_frequency(cpu->pstate.max_pstate * cpu->pstate.scaling, cpu->cpu);
    }
}
sysfs에서 EPP 설정:
echo "balance_performance" > /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_available_preferences 로 사용 가능한 값 확인.

IA32_HWP_REQUEST_PKG (0x772) — 패키지 레벨 HWP 요청

패키지(소켓) 전체에 대한 HWP 요청을 설정합니다. 코어별 HWP_REQUEST에서 Package_Control 비트(42)가 0인 경우 이 MSR의 값이 기본 적용됩니다.

비트필드설명
7:0Minimum_Performance패키지 전체 최저 성능
15:8Maximum_Performance패키지 전체 최대 성능
23:16Desired_Performance패키지 전체 목표 성능
31:24Energy_Performance_Preference패키지 전체 EPP
41:32Activity_Window패키지 전체 활동 창

IA32_HWP_INTERRUPT (0x773) — HWP 변경 알림 인터럽트

비트필드설명
0EN_Guaranteed_Performance_ChangeGuaranteed Performance가 변경될 때 인터럽트 발생
1EN_Excursion_Minimum성능이 Minimum 이하로 떨어질 때 인터럽트 발생
2EN_Highest_Performance_ChangeHighest Performance가 변경될 때 인터럽트 발생

IA32_HWP_STATUS (0x777) — HWP 상태 피드백

비트필드설명
0Guaranteed_Performance_Change1이면 보장 성능 수준이 변경됨 (W1C: 1 쓰면 클리어)
2Excursion_To_Minimum1이면 성능이 요청 최소치 이하로 내려갔음 (W1C)
4Highest_Performance_Change1이면 최대 성능 수준이 변경됨 (W1C)
/* HWP 인터럽트 핸들러 — 보장 성능 변경 처리 */
void intel_pstate_irq_handler(void)
{
    u64 status;
    rdmsrl(MSR_IA32_HWP_STATUS, status);

    if (status & 0x1) {
        /* Guaranteed Performance 변경 — 열 스로틀링 등으로 발생 */
        u64 cap;
        rdmsrl(MSR_IA32_HWP_CAPABILITIES, cap);
        pr_info("HWP guaranteed perf changed to %llu\n",
               (cap >> 8) & 0xFF);
        /* 상태 비트 클리어 (W1C) */
        wrmsrl(MSR_IA32_HWP_STATUS, status);
    }
}

APERF / MPERF — 실제 주파수 측정

APERF와 MPERF는 CPU의 실제 동작 주파수와 활용률을 측정하는 핵심 카운터 쌍입니다. 두 카운터 모두 C0 상태(활성)에서만 증가하며, C-State(유휴)에서는 멈춥니다.

MSR주소동작
IA32_MPERF0xE7Maximum Performance 카운터. 최대 비터보 주파수(TSC rate)에 비례하여 증가. C0 상태에서만 증가.
IA32_APERF0xE8Actual Performance 카운터. 실제 동작 클럭에 비례하여 증가. 터보 부스트/스로틀링 반영.

APERF/MPERF를 이용한 핵심 계산

/*
 * 두 시점(t0, t1) 사이의 델타를 이용한 계산:
 *
 * 1) 실제 평균 주파수:
 *    actual_freq = base_freq × (ΔAPERF / ΔMPERF)
 *    - ΔAPERF > ΔMPERF → 터보 부스트 활성 (base_freq 초과)
 *    - ΔAPERF < ΔMPERF → 스로틀링 발생 (base_freq 미만)
 *    - ΔAPERF = ΔMPERF → 정확히 base_freq로 동작
 *
 * 2) C0 레지던시 (CPU 활용률):
 *    busy% = ΔMPERF / ΔTSC × 100
 *    - TSC는 항상 일정 비율로 증가 (invariant TSC)
 *    - MPERF는 C0에서만 증가
 *    → ΔMPERF/ΔTSC = C0 상태에서 보낸 시간 비율
 *
 * 3) 평균 주파수 (유휴 포함):
 *    avg_freq = TSC_freq × (ΔAPERF / ΔTSC)
 *    - 전체 시간 대비 실제 작업량 반영
 */

struct freq_sample {
    u64 aperf, mperf, tsc;
};

static void snapshot(struct freq_sample *s)
{
    unsigned long flags;
    local_irq_save(flags);
    rdmsrl(MSR_IA32_APERF, s->aperf);
    rdmsrl(MSR_IA32_MPERF, s->mperf);
    s->tsc = rdtsc_ordered();
    local_irq_restore(flags);
}

static void calc_freq(struct freq_sample *s0, struct freq_sample *s1)
{
    u64 da = s1->aperf - s0->aperf;
    u64 dm = s1->mperf - s0->mperf;
    u64 dt = s1->tsc   - s0->tsc;
    u64 base_khz = tsc_khz;  /* 커널 전역 변수 */

    pr_info("actual_freq = %llu MHz\n",
           div64_u64(base_khz * da, dm) / 1000);
    pr_info("C0 busy = %llu.%llu%%\n",
           dm * 100 / dt, (dm * 10000 / dt) % 100);
    pr_info("avg_freq (incl idle) = %llu MHz\n",
           div64_u64(base_khz * da, dt) / 1000);
}
turbostat와의 관계: turbostatBzy_MHz 컬럼은 base_freq × ΔAPERF/ΔMPERF를, Busy%ΔMPERF/ΔTSC × 100을 보여줍니다. Avg_MHzbase_freq × ΔAPERF/ΔTSC입니다.

RAPL (Running Average Power Limit) MSR

RAPL은 Intel Sandy Bridge 이후 도입된 전력 측정 및 제한 메커니즘으로, 패키지/코어/DRAM/GPU의 실시간 전력 소비를 모니터링하고, 전력 상한을 설정할 수 있습니다. 커널의 intel_rapl 드라이버와 powercap 프레임워크가 이 MSR들을 추상화합니다.

RAPL 도메인 (Power Domain)

도메인약칭측정/제한 대상주요 MSR 기반 주소
Package (PKG)PKGCPU 패키지 전체 (코어 + Uncore + GPU)0x610 ~ 0x614
Power Plane 0 (PP0)PP0CPU 코어 영역만0x638 ~ 0x63A
Power Plane 1 (PP1)PP1내장 GPU (클라이언트 CPU만)0x640 ~ 0x642
DRAMDRAM메모리 컨트롤러/DRAM (서버 CPU)0x618 ~ 0x61C
Platform (PSys)PSYS전체 시스템 (Skylake+, 노트북)0x64C ~ 0x650

MSR_RAPL_POWER_UNIT (0x606) — 전력 단위

RAPL MSR의 값을 물리 단위로 변환하기 위한 단위 정보입니다. 모든 RAPL 값 해석의 기준이 됩니다.

비트필드설명
3:0Power Units전력 단위 = 1/(2^n) 와트. 보통 n=3 → 0.125W
12:8Energy Status Units에너지 단위 = 1/(2^n) 줄. 보통 n=14 → ~61μJ
19:16Time Units시간 단위 = 1/(2^n) 초. 보통 n=10 → ~976μs
/* RAPL 단위 파싱 */
static void parse_rapl_units(void)
{
    u64 units;
    double power_unit, energy_unit, time_unit;

    rdmsrl(MSR_RAPL_POWER_UNIT, units);

    power_unit  = 1.0 / (1 << (units & 0xF));         /* 보통 0.125W  */
    energy_unit = 1.0 / (1 << ((units >> 8) & 0x1F));  /* 보통 ~61μJ   */
    time_unit   = 1.0 / (1 << ((units >> 16) & 0xF)); /* 보통 ~976μs  */

    /* 예: Power Unit=3 → 1/8=0.125W
     *     Energy Unit=14 → 1/16384 ≈ 61.04μJ
     *     Time Unit=10 → 1/1024 ≈ 976.6μs
     */
}

MSR_PKG_POWER_LIMIT (0x610) — 패키지 전력 제한

패키지 레벨의 전력 제한(PL1/PL2)을 설정합니다. PL1은 장기(sustained) TDP, PL2는 단기(burst) TDP입니다.

비트필드설명
14:0Power Limit 1 (PL1)장기 전력 제한 (Power Units 단위). 예: 600 × 0.125W = 75W TDP
15PL1 Enable1이면 PL1 활성화
16PL1 Clamping Limitation1이면 PL1 미만으로도 클램핑 허용 (더 공격적 제한)
23:17PL1 Time WindowPL1 시간 창 (Time Units 사용). 이 시간 동안의 평균 전력이 PL1 이하여야 함
46:32Power Limit 2 (PL2)단기 전력 제한. 보통 PL1의 1.25배. 예: 93.75W
47PL2 Enable1이면 PL2 활성화
48PL2 Clamping LimitationPL2 클램핑 허용
55:49PL2 Time WindowPL2 시간 창 (보통 ~28ms)
63Lock1이면 이 MSR 잠금 (재부팅까지 변경 불가). BIOS가 설정.
/* drivers/powercap/intel_rapl_msr.c — RAPL 전력 제한 설정 */
static int set_domain_power_limit(struct rapl_domain *rd,
                                  u64 power_limit_uw, int pl_id)
{
    u64 val, mask;
    int shift = (pl_id == 1) ? 0 : 32;

    rdmsrl(rd->msr_power_limit, val);

    /* 와트를 RAPL 단위로 변환 */
    u64 raw = div64_u64(power_limit_uw,
                        rd->rp->power_unit * 1000000ULL);
    mask = 0x7FFFULL << shift;
    val = (val & ~mask) | ((raw & 0x7FFF) << shift);
    val |= (1ULL << (15 + shift));  /* Enable bit */

    wrmsrl(rd->msr_power_limit, val);
    return 0;
}

MSR_PKG_ENERGY_STATUS (0x611) — 패키지 에너지 소비 (읽기 전용)

패키지의 누적 에너지 소비량입니다. 32비트 카운터로, 오버플로우됩니다.

비트필드설명
31:0Total Energy Consumed누적 에너지 (Energy Units 단위). 두 시점의 차이로 전력 계산.
/* 패키지 전력 측정 (두 시점 간 에너지 차이) */
static u64 measure_pkg_power_mw(unsigned int interval_ms)
{
    u64 e0, e1, units;
    u64 energy_unit;

    rdmsrl(MSR_RAPL_POWER_UNIT, units);
    energy_unit = 1000000ULL >> ((units >> 8) & 0x1F);  /* μJ 단위 */

    rdmsrl(MSR_PKG_ENERGY_STATUS, e0);
    msleep(interval_ms);
    rdmsrl(MSR_PKG_ENERGY_STATUS, e1);

    /* 32비트 오버플로우 처리 */
    u64 delta = (e1 - e0) & 0xFFFFFFFF;
    /* mW = (delta × energy_unit_μJ) / interval_ms */
    return div64_u64(delta * energy_unit, interval_ms);
}
/*
 * 오버플로우 주기 예시:
 *   Energy Unit=14 → 61μJ/count
 *   200W 소비 시: 2^32 × 61μJ / 200W ≈ 1311초 ≈ ~22분
 *   커널은 주기적으로 읽어 오버플로우를 추적해야 함
 */

RAPL 도메인별 MSR 주소 정리

용도PKGPP0 (Core)PP1 (GPU)DRAMPSys
Power Limit0x6100x6380x6400x6180x64C
Energy Status0x6110x6390x6410x6190x64D
Power Info0x6140x63A0x6420x61C
Perf Status0x63B0x61B
Policy0x63C0x642
sysfs에서 RAPL 접근:
/sys/class/powercap/intel-rapl:0/energy_uj — 패키지 누적 에너지 (μJ)
/sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw — PL1 (μW)
/sys/class/powercap/intel-rapl:0/constraint_1_power_limit_uw — PL2 (μW)
perf stat -e power/energy-pkg/도 동일한 MSR을 읽습니다.

C-State 관련 MSR

C-State MSR은 CPU 유휴 상태 제어와 각 C-State의 레지던시(체류 시간) 측정에 사용됩니다. cpuidle 드라이버(intel_idle)와 turbostat이 이 MSR들을 활용합니다.

MSR_PKG_CST_CONFIG_CONTROL (0xE2) — 패키지 C-State 제어

비트필드설명
3:0Package C-State Limit허용 최대 패키지 C-State. 0=C0, 1=C2, 2=C6, 3=C6N, 7=제한 없음 (모델별 상이)
10I/O MWAIT Redirection Enable1이면 I/O 명령어를 MWAIT C-State로 리다이렉션
15CFG Lock1이면 이 MSR 잠금 (재부팅까지 변경 불가). BIOS가 설정.
25C3 State Auto Demotion Enable1이면 C3 자동 디모션 활성화
26C1 State Auto Demotion Enable1이면 C1 자동 디모션 활성화
27Enable C3 Undemotion1이면 C3 언디모션 활성화
28Enable C1 Undemotion1이면 C1 언디모션 활성화
C-State 디모션/언디모션: CPU가 C6 진입을 요청해도 짧은 유휴 기간이 예상되면 자동으로 C3이나 C1으로 "디모션"하여 진입/복귀 지연을 줄입니다. 반대로 "언디모션"은 이전에 디모션된 코어를 다시 깊은 C-State로 올립니다.

C-State 레지던시 MSR (코어/패키지)

MSR주소범위설명
MSR_CORE_C1_RES0x660코어코어 C1 레지던시 카운터 (TSC 단위)
MSR_CORE_C3_RESIDENCY0x3FC코어코어 C3 레지던시 카운터
MSR_CORE_C6_RESIDENCY0x3FD코어코어 C6 레지던시 카운터
MSR_CORE_C7_RESIDENCY0x3FE코어코어 C7 레지던시 카운터
MSR_PKG_C2_RESIDENCY0x60D패키지패키지 C2 레지던시 카운터
MSR_PKG_C3_RESIDENCY0x3F8패키지패키지 C3 레지던시 카운터
MSR_PKG_C6_RESIDENCY0x3F9패키지패키지 C6 레지던시 카운터
MSR_PKG_C7_RESIDENCY0x3FA패키지패키지 C7 레지던시 카운터
MSR_PKG_C8_RESIDENCY0x630패키지패키지 C8 레지던시 (Haswell+)
MSR_PKG_C9_RESIDENCY0x631패키지패키지 C9 레지던시 (Haswell+)
MSR_PKG_C10_RESIDENCY0x632패키지패키지 C10 레지던시 (가장 깊은 유휴)
/* C-State 레지던시 비율 측정 */
static void measure_cstate_residency(unsigned int interval_ms)
{
    u64 tsc0, tsc1, c6_0, c6_1, c7_0, c7_1;

    tsc0 = rdtsc_ordered();
    rdmsrl(MSR_CORE_C6_RESIDENCY, c6_0);
    rdmsrl(MSR_CORE_C7_RESIDENCY, c7_0);

    msleep(interval_ms);

    tsc1 = rdtsc_ordered();
    rdmsrl(MSR_CORE_C6_RESIDENCY, c6_1);
    rdmsrl(MSR_CORE_C7_RESIDENCY, c7_1);

    u64 dt  = tsc1 - tsc0;
    u64 dc6 = c6_1 - c6_0;
    u64 dc7 = c7_1 - c7_0;

    pr_info("C6 residency: %llu.%02llu%%\n",
           dc6 * 100 / dt, (dc6 * 10000 / dt) % 100);
    pr_info("C7 residency: %llu.%02llu%%\n",
           dc7 * 100 / dt, (dc7 * 10000 / dt) % 100);
    /*
     * turbostat 출력과 대응:
     *   CPU%c1 = C1 residency %, CPU%c6 = C6 residency %
     *   Pkg%pc2 = Package C2 %, Pkg%pc6 = Package C6 %
     *   이상적인 유휴 서버: Pkg%pc6 > 90%
     */
}

IA32_ENERGY_PERF_BIAS (0x1B0) — 에너지 성능 편향

HWP의 EPP보다 이전에 도입된(Sandy Bridge+) 레거시 에너지 성능 힌트입니다. HWP가 활성화되지 않은 시스템에서 CPU의 자율적 전력 관리 결정에 힌트를 제공합니다.

비트필드설명
3:0Energy Policy Hint0=최대 성능, 7=균형, 15=최대 절전
63:4예약됨
Linux 상수의미
0ENERGY_PERF_BIAS_PERFORMANCE최대 성능 — 전력 무시
4ENERGY_PERF_BIAS_BALANCE_PERFORMANCE성능 우선 균형
6ENERGY_PERF_BIAS_NORMAL일반 (커널 기본값)
8ENERGY_PERF_BIAS_BALANCE_POWERSAVE절전 우선 균형
15ENERGY_PERF_BIAS_POWERSAVE최대 절전
EPB vs EPP: EPB(4비트, 0~15)는 레거시, EPP(8비트, 0~255)는 HWP에서 사용. HWP 활성화 시 EPP가 우선하며, EPB는 HWP가 아닌 하드웨어 결정(터보/C-State)에만 영향. /sys/devices/system/cpu/cpu0/power/energy_perf_bias로 설정 가능.

IA32_CLOCK_MODULATION (0x19A) — 클럭 변조 (레거시 스로틀링)

소프트웨어 제어 클럭 변조(Software Controlled Clock Modulation, aka duty cycling)를 설정합니다. 이는 가장 초기의 전력 관리 기법으로, CPU 클럭을 일정 비율로 on/off 하여 전력을 줄입니다. 현대 CPU에서는 DVFS가 훨씬 효율적이므로 거의 사용되지 않습니다.

비트필드설명
0Extended On-Demand Clock Modulation Enable1이면 fine-grained duty cycle 사용 (3:1 비트 포함 4비트)
3:1On-Demand Clock Modulation Duty Cycle듀티 사이클: 001=12.5%, 010=25%, ..., 111=87.5%
4On-Demand Clock Modulation Enable1이면 클럭 변조 활성화

AMD P-State MSR (CPPC)

AMD Zen 아키텍처 CPU는 ACPI CPPC(Collaborative Processor Performance Control) 프레임워크를 기반으로 P-State를 관리합니다. Linux의 amd-pstate 드라이버(5.17+)가 이 MSR들을 사용합니다.

MSR_AMD_CPPC_ENABLE (0xC00102B1) — CPPC 활성화

비트필드설명
0CPPC Enable1이면 CPPC(하드웨어 자율 P-State) 활성화

MSR_AMD_CPPC_CAP1 (0xC00102B0) — CPPC 성능 범위

비트필드설명
7:0Highest Performance최대 성능 수준 (부스트 포함)
15:8Nominal Performance공칭 성능 수준 (Base Frequency 상당)
23:16Lowest Nonlinear Performance에너지 효율이 급격히 떨어지기 시작하는 하한
31:24Lowest Performance절대 최저 성능 수준

MSR_AMD_CPPC_REQ (0xC00102B3) — CPPC 성능 요청

비트필드설명
7:0Maximum Performance허용 최대 성능
15:8Minimum Performance허용 최저 성능
23:16Desired Performance목표 성능 (0=자율)
31:24Energy Performance PreferenceEPP (0=성능, 255=절전) — Intel HWP EPP와 동일 의미

MSR_AMD_PSTATE_DEF (0xC0010064 ~ 0xC0010069) — P-State 정의

AMD CPU는 최대 8개의 하드웨어 P-State 정의를 MSR에 보관합니다 (P0~P7). 각 MSR은 FID(주파수), DID(분주비), VID(전압)를 인코딩합니다.

비트필드설명
7:0CpuFidCPU Frequency ID
13:8CpuDfsIdCPU DFS (Divider) ID
21:14CpuVidCPU Voltage ID
22IddDiv전류 분배기
29:23IddValue전류 값
63PstateEn1이면 이 P-State 유효
/* AMD P-State 주파수 계산 */
static u32 amd_pstate_freq_mhz(u64 pstate_def)
{
    u32 fid = pstate_def & 0xFF;
    u32 did = (pstate_def >> 8) & 0x3F;

    if (did == 0)
        return 0;  /* 0으로 나눗셈 방지 */
    /* Frequency (MHz) = 200 × FID / DID */
    return 200 * fid / did;
    /*
     * 예: Ryzen 9 7950X P0
     *   FID=0xB0 (176), DID=0x08 (8)
     *   Freq = 200 × 176 / 8 = 4400 MHz
     */
}

/* drivers/cpufreq/amd-pstate.c — CPPC 성능 요청 */
static void amd_pstate_update(struct amd_cpudata *cpudata,
                              u32 min_perf, u32 des_perf,
                              u32 max_perf, bool fast_switch)
{
    u64 value = READ_ONCE(cpudata->cppc_req_cached);

    value &= ~(AMD_CPPC_MIN_PERF_MASK | AMD_CPPC_DES_PERF_MASK |
               AMD_CPPC_MAX_PERF_MASK);
    value |= AMD_CPPC_MIN_PERF(min_perf);
    value |= AMD_CPPC_DES_PERF(des_perf);
    value |= AMD_CPPC_MAX_PERF(max_perf);

    if (fast_switch)
        wrmsrl(MSR_AMD_CPPC_REQ, value);
    else
        wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
}
amd-pstate 드라이버 모드:
amd-pstate=passive: OS governor가 목표 주파수 결정 → 드라이버가 CPPC MSR에 변환하여 전달.
amd-pstate=active: amd-pstate-epp 드라이버 사용, EPP 기반 하드웨어 자율 관리 (Intel HWP와 유사).
amd-pstate=guided: OS가 min/max만 설정, 그 범위 내에서 하드웨어가 자율 결정.

cpufreq 드라이버와 MSR 매핑

Linux 커널의 cpufreq 프레임워크는 MSR을 직접 노출하지 않고, sysfs를 통해 추상화합니다. 각 sysfs 파일이 어떤 MSR을 읽고 쓰는지 이해하면 디버깅에 유용합니다.

sysfs 경로Intel MSRAMD MSR설명
scaling_min_freqHWP_REQUEST[7:0]CPPC_REQ[15:8]최소 주파수 설정
scaling_max_freqHWP_REQUEST[15:8]CPPC_REQ[7:0]최대 주파수 설정
scaling_cur_freqAPERF/MPERF 계산APERF/MPERF 계산현재 실제 주파수
cpuinfo_min_freqPLATFORM_INFO[40:32]CPPC_CAP1[31:24]하드웨어 최소 주파수
cpuinfo_max_freqTURBO_RATIO_LIMIT[7:0]CPPC_CAP1[7:0]하드웨어 최대 주파수
base_frequencyPLATFORM_INFO[15:8]CPPC_CAP1[15:8]기본 주파수 (비터보)
energy_performance_preferenceHWP_REQUEST[31:24]CPPC_REQ[31:24]EPP 값
# 전력/주파수 관련 주요 확인 명령어

# 현재 주파수 정책 확인
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver      # intel_pstate 또는 amd-pstate
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor     # performance, powersave 등

# HWP/EPP 확인 (Intel)
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_available_preferences

# RAPL 전력 확인
cat /sys/class/powercap/intel-rapl:0/name                     # package-0
cat /sys/class/powercap/intel-rapl:0/energy_uj                # 누적 에너지 (μJ)
cat /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw  # PL1 (μW)

# turbostat으로 종합 확인
turbostat --show Core,CPU,Avg_MHz,Busy%,Bzy_MHz,TSC_MHz,PkgWatt,CorWatt,Pkg%pc2,Pkg%pc6

# MSR 직접 읽기 (msr-tools)
rdmsr -p 0 0xCE                # MSR_PLATFORM_INFO
rdmsr -p 0 0x1AD               # MSR_TURBO_RATIO_LIMIT
rdmsr -p 0 0x774 -f 31:24      # HWP_REQUEST의 EPP 필드만
rdmsr -p 0 0x611               # PKG_ENERGY_STATUS (RAPL)

열 관리 MSR

CPU 온도 모니터링과 열 스로틀링(thermal throttling) 제어를 위한 MSR입니다.

MSR주소설명
IA32_THERM_STATUS0x19C코어별 열 상태 및 온도 읽기
IA32_THERM_INTERRUPT0x19B열 인터럽트 임계값 설정
IA32_PACKAGE_THERM_STATUS0x1B1패키지 전체 열 상태
IA32_PACKAGE_THERM_INTERRUPT0x1B2패키지 열 인터럽트 설정
IA32_TEMPERATURE_TARGET0x1A2TjMax (최대 허용 온도, 읽기 전용)

온도 계산 방법

Intel CPU는 TjMax로부터의 거리(Digital Readout)를 보고합니다:

/* drivers/hwmon/coretemp.c — 코어 온도 읽기 */
static int get_core_temp(int cpu)
{
    u32 eax, edx;
    int tjmax, temp;

    /* TjMax 읽기 (보통 100°C) */
    rdmsr_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
    tjmax = (eax >> 16) & 0xFF;

    /* 현재 온도 = TjMax - Digital Readout */
    rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, &edx);
    if (eax & 0x80000000) {  /* Reading Valid 비트 */
        temp = tjmax - ((eax >> 16) & 0x7F);
        return temp;  /* 섭씨 온도 */
    }
    return -1;
}
참고: /sys/class/hwmon/hwmon*/temp*_input으로 유저 공간에서 읽을 수 있으며, 값은 밀리도(m°C) 단위입니다 (예: 65000 = 65°C). coretemp 드라이버가 위 MSR을 추상화합니다.

TSC 관련 MSR

TSC(Time Stamp Counter)는 가장 자주 사용되는 MSR 중 하나로, 고해상도 시간 측정의 기반입니다.

MSR주소설명
IA32_TSC0x10TSC 카운터 값 (RDMSR 또는 RDTSC로 읽기)
IA32_TSC_ADJUST0x3BTSC 보정 오프셋 (가상화/핫플러그 시 동기화용)
IA32_TSC_DEADLINE0x6E0APIC TSC-Deadline 모드 타이머 목표값
IA32_TSC_AUX0xC0000103RDTSCP로 읽는 보조 값 (보통 CPU ID)

TSC-Deadline 모드

TSC-Deadline 모드는 APIC 타이머의 최신 모드로, 지정한 TSC 값에 도달하면 인터럽트를 발생시킵니다. 기존 one-shot/periodic 모드보다 정밀합니다.

/* arch/x86/kernel/apic/apic.c — TSC-Deadline 타이머 설정 */
static void setup_APIC_tsc_deadline(u64 deadline)
{
    /* LVT Timer에 TSC-Deadline 모드 설정 */
    apic_write(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | LOCAL_TIMER_VECTOR);
    /* 목표 TSC 값 쓰기 — 이 값에 도달하면 인터럽트 */
    wrmsrl(MSR_IA32_TSC_DEADLINE, deadline);
}

TSC_ADJUST — 가상화 환경 TSC 동기화

KVM은 vCPU 마이그레이션 시 IA32_TSC_ADJUST를 사용하여 게스트가 인식하는 TSC 값을 보정합니다. 게스트가 보는 TSC = 물리 TSC + TSC_OFFSET + TSC_ADJUST입니다.

보안 MSR (Spectre/Meltdown 완화)

2018년 Spectre/Meltdown 취약점 발견 이후, CPU 벤더들은 소프트웨어 기반 완화를 지원하기 위한 MSR을 대거 추가했습니다.

IA32_ARCH_CAPABILITIES (0x10A)

CPU가 특정 취약점에 하드웨어적으로 면역인지 보고합니다(읽기 전용). 커널은 이 MSR을 읽어 불필요한 완화를 건너뜁니다.

비트이름의미
0RDCL_NOMeltdown(Rogue Data Cache Load) 면역
1IBRS_ALLIBRS가 모든 분기에 적용 (Enhanced IBRS)
2RSBAReturn Stack Buffer 대안 사용 (retpoline 주의)
3SKIP_L1DFL_VMENTRYVM 진입 시 L1D flush 불필요
4SSB_NOSpeculative Store Bypass 면역
5MDS_NOMicroarchitectural Data Sampling 면역
6IF_PSCHANGE_MC_NO페이지 크기 변경 시 MC 면역
7TSX_CTRLIA32_TSX_CTRL MSR 존재
8TAA_NOTSX Asynchronous Abort 면역

추론 실행 제어 MSR

MSR주소설명
IA32_SPEC_CTRL0x48IBRS(bit 0), STIBP(bit 1), SSBD(bit 2) 제어
IA32_PRED_CMD0x49IBPB(bit 0) — 분기 예측기 배리어 (쓰기 전용)
IA32_FLUSH_CMD0x10BL1D_FLUSH(bit 0) — L1 데이터 캐시 플러시 (쓰기 전용)

각 완화 기법의 동작

/* arch/x86/kernel/cpu/bugs.c — Spectre v2 완화 */

/* IBRS: 간접 분기가 하위 권한 예측을 사용하지 않음 */
static void spec_ctrl_enable_ibrs(void)
{
    u64 msr = this_cpu_read(x86_spec_ctrl_current);
    msr |= SPEC_CTRL_IBRS;
    native_wrmsrl(MSR_IA32_SPEC_CTRL, msr);
}

/* IBPB: 분기 예측기 전체 무효화 (컨텍스트 스위치 시) */
static void indirect_branch_prediction_barrier(void)
{
    native_wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
}

/* SSBD: 추론적 저장-로드 바이패스 비활성화 (Spectre v4) */
static void ssb_disable(void)
{
    u64 msr = this_cpu_read(x86_spec_ctrl_current);
    msr |= SPEC_CTRL_SSBD;
    native_wrmsrl(MSR_IA32_SPEC_CTRL, msr);
}

/* L1D Flush: VM 진입 전 L1 데이터 캐시 플러시 (L1TF 완화) */
static void l1d_flush_force(void)
{
    native_wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH);
}
성능 영향: IBRS/STIBP는 분기 예측 성능을 저하시킵니다. Enhanced IBRS(IA32_ARCH_CAPABILITIES.IBRS_ALL=1)가 있는 최신 CPU에서는 한 번 설정하면 지속되어 오버헤드가 적습니다. IBPB는 컨텍스트 스위치마다 발생하므로 프로세스 전환 비용이 증가합니다.

가상화 MSR

Intel VMX 관련 MSR

VMX(Virtual Machine Extensions) 기능을 보고하고 제어하는 MSR입니다. KVM 모듈이 VMX 초기화 시 이 MSR들을 읽어 지원되는 기능을 확인합니다.

MSR주소설명
IA32_VMX_BASIC0x480VMCS 크기, 메모리 타입, 기본 기능
IA32_VMX_PINBASED_CTLS0x481Pin-Based VM-Execution Controls 허용 비트
IA32_VMX_PROCBASED_CTLS0x482Primary Processor-Based Controls 허용 비트
IA32_VMX_PROCBASED_CTLS20x48BSecondary Processor-Based Controls
IA32_VMX_EXIT_CTLS0x483VM-Exit Controls 허용 비트
IA32_VMX_ENTRY_CTLS0x484VM-Entry Controls 허용 비트
IA32_VMX_EPT_VPID_CAP0x48CEPT/VPID 기능 보고
IA32_VMX_CR0_FIXED0/10x486/487VMX 모드에서 CR0 필수/허용 비트
IA32_VMX_CR4_FIXED0/10x488/489VMX 모드에서 CR4 필수/허용 비트

MSR 비트맵 (Intel VT-x)

VMCS의 MSR 비트맵은 게스트의 RDMSR/WRMSR이 VM exit를 유발할지 결정하는 4KB 비트맵입니다. 비트가 0이면 게스트가 직접 접근하고, 1이면 VM exit가 발생하여 KVM이 에뮬레이션합니다.

/* arch/x86/kvm/vmx/vmx.c — MSR 비트맵 설정 */
static void vmx_set_msr_bitmap_read(unsigned long *msr_bitmap,
                                     u32 msr, bool intercept)
{
    int f;
    if (msr <= 0x1FFF)
        f = 0;                 /* 하위 MSR 영역: 오프셋 0 */
    else if (msr >= 0xC0000000 && msr <= 0xC0001FFF)
        f = 1024;              /* 상위 MSR 영역: 오프셋 1024바이트 */
    else
        return;               /* 범위 밖 — 항상 intercept */

    msr &= 0x1FFF;
    if (intercept)
        __set_bit(msr, msr_bitmap + f / sizeof(long));
    else
        __clear_bit(msr, msr_bitmap + f / sizeof(long));
}

AMD SVM MSRPM (MSR Permission Map)

AMD SVM은 8KB MSRPM을 사용하며, 각 MSR에 대해 2비트(읽기/쓰기 각각)를 할당합니다.

MSRPM 오프셋MSR 범위비트 할당
0x000 ~ 0x7FF0x00000000 ~ 0x00001FFFbit 0 = read intercept, bit 1 = write intercept
0x800 ~ 0xFFF0xC0000000 ~ 0xC0001FFF위와 동일
0x1000 ~ 0x17FF0xC0010000 ~ 0xC0011FFF위와 동일

KVM의 MSR 에뮬레이션

/* arch/x86/kvm/x86.c — 게스트 MSR 읽기 에뮬레이션 */
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data)
{
    switch (index) {
    case MSR_IA32_TSC:
        *data = kvm_read_l1_tsc(vcpu, rdtsc());
        break;
    case MSR_IA32_SPEC_CTRL:
        *data = vcpu->arch.spec_ctrl;
        break;
    case MSR_IA32_ARCH_CAPABILITIES:
        *data = vcpu->arch.arch_capabilities;
        break;
    /* ... 수십 개의 MSR 에뮬레이션 */
    default:
        return kvm_x86_ops.get_msr(vcpu, index, data);
    }
    return 0;
}
성능 팁: MSR 비트맵에서 TSC, APERF/MPERF, SPEC_CTRL 등 빈번히 접근하는 MSR은 직접 통과(passthrough)로 설정하면 VM exit 오버헤드를 줄일 수 있습니다. 단, 보안 MSR은 반드시 인터셉트해야 합니다.

MTRR / PAT MSR

MTRR (Memory Type Range Registers)

MTRR은 물리 메모리 영역의 캐시 정책(Uncacheable, Write-Combining, Write-Through, Write-Back 등)을 설정합니다. 주로 BIOS가 초기화하며, 그래픽 프레임버퍼 등 MMIO 영역에 Write-Combining을 설정합니다.

MSR주소설명
IA32_MTRRCAP0xFEMTRR 기능: 가변 범위 수, FIX 지원, WC 지원
IA32_MTRR_DEF_TYPE0x2FF기본 메모리 타입 및 MTRR 활성화
IA32_MTRR_FIX64K_000000x250고정 범위: 0x00000~0x7FFFF (64KB 단위)
IA32_MTRR_FIX16K_800000x258고정 범위: 0x80000~0xBFFFF (16KB 단위)
IA32_MTRR_FIX4K_C00000x268~26F고정 범위: 0xC0000~0xFFFFF (4KB 단위)
IA32_MTRR_PHYSBASEn0x200+2n가변 범위 n의 base 주소 및 타입
IA32_MTRR_PHYSMASKn0x201+2n가변 범위 n의 마스크 및 유효 비트

메모리 타입 인코딩

약칭설명
0UCUncacheable — 캐시 사용 안 함
1WCWrite-Combining — 쓰기 결합 (프레임버퍼용)
4WTWrite-Through — 쓰기 즉시 반영
5WPWrite-Protect — 읽기는 캐시, 쓰기는 UC처럼
6WBWrite-Back — 가장 빠름 (일반 RAM)

PAT (Page Attribute Table)

PAT는 MTRR의 페이지 단위 확장으로, 페이지 테이블 엔트리의 PAT/PCD/PWT 비트 조합으로 8개 메모리 타입 중 하나를 선택합니다.

MSR주소설명
IA32_PAT0x2778개 PAT 엔트리 (각 8비트, 총 64비트)
/* arch/x86/mm/pat/memtype.c — PAT 초기화 */
void pat_init(void)
{
    u64 pat;

    /* Linux 기본 PAT 설정:
     * PAT0=WB PAT1=WC PAT2=UC- PAT3=UC
     * PAT4=WB PAT5=WC PAT6=UC- PAT7=UC */
    pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) |
          PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC);
    wrmsrl(MSR_IA32_CR_PAT, pat);
}

Linux 커널 MSR API

Linux 커널은 다양한 MSR 접근 래퍼 함수를 제공합니다. 모두 arch/x86/include/asm/msr.h에 정의되어 있습니다.

기본 접근 함수

함수서명설명
rdmsrrdmsr(msr, low, high)32비트 쌍으로 읽기
wrmsrwrmsr(msr, low, high)32비트 쌍으로 쓰기
rdmsrlrdmsrl(msr, val)64비트 값으로 읽기
wrmsrlwrmsrl(msr, val)64비트 값으로 쓰기

안전한(safe) 변형

존재하지 않는 MSR에 접근하면 #GP 예외가 발생합니다. safe 변형은 예외를 잡아 에러 코드를 반환합니다.

함수반환값설명
rdmsrl_safeint (0=성공, -EIO=실패)안전한 64비트 읽기
wrmsrl_safeint (0=성공, -EIO=실패)안전한 64비트 쓰기
rdmsr_safeint안전한 32비트 쌍 읽기
wrmsr_safeint안전한 32비트 쌍 쓰기
/* safe 변형 사용 예 — MSR 존재 여부 불확실할 때 */
u64 val;
int err;

err = rdmsrl_safe(MSR_IA32_ARCH_CAPABILITIES, &val);
if (err) {
    pr_info("IA32_ARCH_CAPABILITIES not supported\n");
} else {
    if (val & ARCH_CAP_RDCL_NO)
        pr_info("CPU is not vulnerable to Meltdown\n");
}

Cross-CPU MSR 접근

다른 CPU의 MSR을 읽고 쓰려면 IPI를 통해 해당 CPU에서 실행해야 합니다.

함수설명
rdmsr_on_cpu(cpu, msr, &lo, &hi)특정 CPU에서 MSR 읽기
wrmsr_on_cpu(cpu, msr, lo, hi)특정 CPU에서 MSR 쓰기
rdmsrl_on_cpu(cpu, msr, &val)64비트 버전
wrmsrl_on_cpu(cpu, msr, val)64비트 버전
rdmsr_safe_on_cpu안전한 Cross-CPU 읽기
주의: Cross-CPU MSR 접근은 IPI를 발생시키므로 인터럽트 비활성화 상태에서는 사용할 수 없습니다. 또한 대상 CPU가 오프라인이면 실패합니다.

/dev/cpu/N/msr — 유저 공간 접근

CONFIG_X86_MSR=y일 때 커널은 각 CPU별로 /dev/cpu/<N>/msr 캐릭터 디바이스를 생성합니다. pread()/pwrite()의 오프셋이 MSR 주소, 데이터가 8바이트 MSR 값입니다.

/* 유저 공간 MSR 읽기 예 (root 또는 CAP_SYS_RAWIO 필요) */
#include <fcntl.h>
#include <unistd.h>

int fd = open("/dev/cpu/0/msr", O_RDONLY);
uint64_t tsc;
pread(fd, &tsc, sizeof(tsc), 0x10);  /* IA32_TSC */
printf("TSC = %llu\n", tsc);
close(fd);

AMD 전용 MSR

AMD 프로세서는 0xC0010000~0xC001FFFF 범위에 고유 MSR을 가지고 있습니다.

MSR주소설명
MSR_AMD64_HWCR0xC0010015하드웨어 구성: SMM Lock, TSC Freq Sel, TLB Flush Filter 등
MSR_AMD64_SYSCFG0xC0010010시스템 구성: MTRR 확장, Tom2 활성화, IORRs 등
MSR_AMD64_NB_CFG0xC001001FNorthbridge 구성: 초기 APIC ID 크기 등
MSR_AMD64_PATCH_LEVEL0x0000008B마이크로코드 패치 수준
MSR_AMD64_PATCH_LOADER0xC0010020마이크로코드 로더 트리거
MSR_AMD64_OSVW_ID_LENGTH0xC0010140OS Visible Workarounds 길이
MSR_AMD64_OSVW_STATUS0xC0010141OS Visible Workarounds 상태
MSR_AMD64_DE_CFG0xC0011029Decode Config (LFENCE 직렬화 등)
MSR_AMD64_LS_CFG0xC0011020Load/Store Config (SSB 비활성화 등)
MSR_AMD_PPIN0xC00102F1Protected Processor ID Number

AMD LFENCE 직렬화

/* arch/x86/kernel/cpu/amd.c — LFENCE를 직렬화 명령어로 설정 */
static void init_amd_lfence(struct cpuinfo_x86 *c)
{
    u64 val;
    rdmsrl(MSR_AMD64_DE_CFG, val);
    if (!(val & BIT(1))) {
        val |= BIT(1);   /* LFENCE를 dispatch serializing으로 */
        wrmsrl(MSR_AMD64_DE_CFG, val);
    }
    set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
}

AMD SVM 관련 MSR

MSR주소설명
MSR_VM_CR0xC0010114SVM 잠금 및 활성화 제어
MSR_VM_HSAVE_PA0xC0010117호스트 상태 저장 영역 물리 주소
MSR_AMD64_SEV0xC0010131SEV(Secure Encrypted Virtualization) 상태
MSR_AMD64_SEV_ES0xC0010131SEV-ES/SEV-SNP 비트 포함

실전 예제

예제 1: 현재 CPU 주파수 읽기 (APERF/MPERF)

#include <linux/module.h>
#include <asm/msr.h>
#include <asm/cpu_device_id.h>

static int __init freq_init(void)
{
    u64 aperf0, aperf1, mperf0, mperf1;
    u64 tsc_khz_val = tsc_khz;
    unsigned long flags;

    local_irq_save(flags);
    rdmsrl(MSR_IA32_APERF, aperf0);
    rdmsrl(MSR_IA32_MPERF, mperf0);
    local_irq_restore(flags);

    msleep(100);  /* 100ms 대기 */

    local_irq_save(flags);
    rdmsrl(MSR_IA32_APERF, aperf1);
    rdmsrl(MSR_IA32_MPERF, mperf1);
    local_irq_restore(flags);

    /* freq = tsc_freq * delta_aperf / delta_mperf */
    u64 freq_khz = div64_u64(tsc_khz_val * (aperf1 - aperf0),
                              (mperf1 - mperf0));
    pr_info("CPU %d actual freq: %llu MHz\n",
           smp_processor_id(), freq_khz / 1000);

    return 0;
}

module_init(freq_init);
MODULE_LICENSE("GPL");

예제 2: PMU 카운터로 IPC 측정

/* 고정 카운터로 Instructions Per Cycle 측정 */
static void measure_ipc(void)
{
    u64 inst0, inst1, cycles0, cycles1;

    /* 고정 카운터 활성화: OS + USR 모드 */
    wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0x33);  /* CTR0, CTR1 활성화 */
    wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL,
          (1ULL << 32) | (1ULL << 33));  /* Fixed CTR0,1 전역 활성화 */

    rdmsrl(MSR_CORE_PERF_FIXED_CTR0, inst0);    /* Instructions Retired */
    rdmsrl(MSR_CORE_PERF_FIXED_CTR1, cycles0);  /* Unhalted Cycles */

    /* ... 측정 대상 코드 ... */

    rdmsrl(MSR_CORE_PERF_FIXED_CTR0, inst1);
    rdmsrl(MSR_CORE_PERF_FIXED_CTR1, cycles1);

    pr_info("IPC = %llu.%02llu\n",
           (inst1 - inst0) / (cycles1 - cycles0),
           ((inst1 - inst0) * 100 / (cycles1 - cycles0)) % 100);
}

예제 3: CPU 코어 온도 읽기

static int read_core_temp(int cpu)
{
    u32 eax, edx;
    int tjmax, offset;

    /* TjMax (보통 100°C) */
    rdmsr_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
    tjmax = (eax >> 16) & 0xFF;

    /* Digital Readout */
    rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, &edx);
    if (!(eax & (1 << 31)))
        return -1;  /* 값이 유효하지 않음 */

    offset = (eax >> 16) & 0x7F;
    return tjmax - offset;  /* °C */
}

예제 4: TSC 기반 정밀 시간 측정

static inline u64 rdtsc_ordered(void)
{
    /* LFENCE + RDTSC 로 순서 보장 */
    barrier();
    return rdtsc();
}

static void benchmark(void)
{
    u64 t0, t1;
    unsigned long flags;

    local_irq_save(flags);
    t0 = rdtsc_ordered();

    /* 측정 대상 코드 */
    some_function();

    t1 = rdtsc_ordered();
    local_irq_restore(flags);

    pr_info("Elapsed: %llu cycles (%llu ns)\n",
           t1 - t0,
           div64_u64((t1 - t0) * 1000000, tsc_khz));
}

MSR 디버깅

msr-tools 패키지

유저 공간에서 MSR을 직접 읽고 쓸 수 있는 도구입니다.

# 설치 (Debian/Ubuntu)
sudo apt install msr-tools

# msr 커널 모듈 로드
sudo modprobe msr

# IA32_TSC (0x10) 읽기 — CPU 0
sudo rdmsr -p 0 0x10

# IA32_EFER (0xC0000080) 읽기 — 모든 CPU
sudo rdmsr -a 0xC0000080

# IA32_MISC_ENABLE (0x1A0) 읽기 — 비트별 출력
sudo rdmsr -p 0 -b 0x1A0

# IA32_SPEC_CTRL (0x48) 읽기 — Spectre 완화 상태
sudo rdmsr -p 0 0x48

# MSR 쓰기 (주의: 잘못된 값은 시스템 크래시 유발)
sudo wrmsr -p 0 0x48 0x7   # IBRS + STIBP + SSBD 활성화

perf 도구를 이용한 PMU 확인

# PMU 하드웨어 이벤트 목록
perf list hw cache

# PMU 카운터 직접 지정 (event=0x2E, umask=0x41 = LLC-misses)
perf stat -e r412e ./program

# MSR 기반 이벤트 추적
perf stat -e cycles,instructions,cache-misses,branch-misses ./program

# Architectural MSR 기능 확인
perf stat -e cpu/event=0x00,umask=0x01/ -- sleep 1

커널 로그에서 MSR 관련 정보

# 부팅 시 MSR 관련 메시지
dmesg | grep -i msr

# Spectre/Meltdown 완화 상태
cat /sys/devices/system/cpu/vulnerabilities/*

# MTRR 설정 확인
cat /proc/mtrr

# PAT 설정 확인
dmesg | grep -i pat

일반적 함정과 주의사항

MSR 디버깅 시 주의:
  • #GP 예외: 존재하지 않는 MSR에 RDMSR/WRMSR 시 발생. 반드시 CPUID로 확인하거나 *_safe() 변형 사용
  • Reserved 비트: MSR의 예약 비트에 1을 쓰면 #GP 발생. 항상 Read-Modify-Write 패턴 사용
  • per-CPU 특성: 대부분의 MSR은 코어별로 독립적. CPU 0에서 쓴 값이 CPU 1에 적용되지 않음
  • Lock 비트: IA32_FEATURE_CONTROL 등의 Lock 비트가 설정되면 재부팅 전까지 변경 불가
  • 가상화 환경: VM 안에서 일부 MSR은 하이퍼바이저가 에뮬레이션하므로 물리 하드웨어와 값이 다를 수 있음
  • Lockdown LSM: Secure Boot 환경에서 /dev/cpu/*/msr을 통한 쓰기가 차단될 수 있음

MSR 주요 레퍼런스 테이블

자주 사용되는 ~70개 주요 MSR의 종합 레퍼런스입니다. 커널 헤더 arch/x86/include/asm/msr-index.h에서 전체 매크로를 확인할 수 있습니다.

주소커널 매크로이름R/W카테고리
0x10MSR_IA32_TSCTime Stamp CounterR/WTSC
0x1BMSR_IA32_APICBASEAPIC Base AddressR/WAPIC
0x3AMSR_IA32_FEAT_CTLFeature ControlR/W*제어
0x3BMSR_IA32_TSC_ADJUSTTSC AdjustR/WTSC
0x48MSR_IA32_SPEC_CTRLSpeculation ControlR/W보안
0x49MSR_IA32_PRED_CMDPrediction CommandW보안
0x8BMSR_IA32_UCODE_REVMicrocode RevisionR시스템
0xCEMSR_PLATFORM_INFOPlatform InfoR주파수
0xE7MSR_IA32_MPERFMax Performance CounterR/W주파수
0xE8MSR_IA32_APERFActual Performance CounterR/W주파수
0xFEMSR_IA32_MTRRCAPMTRR CapabilityRMTRR
0x10AMSR_IA32_ARCH_CAPABILITIESArch CapabilitiesR보안
0x10BMSR_IA32_FLUSH_CMDL1D Flush CommandW보안
0x174MSR_IA32_SYSENTER_CSSYSENTER CSR/W시스콜
0x175MSR_IA32_SYSENTER_ESPSYSENTER ESPR/W시스콜
0x176MSR_IA32_SYSENTER_EIPSYSENTER EIPR/W시스콜
0x186MSR_P6_EVNTSEL0Perf Event Select 0R/WPMU
0x198MSR_IA32_PERF_STATUSPerf StatusR주파수
0x199MSR_IA32_PERF_CTLPerf ControlR/W주파수
0x19AMSR_IA32_CLOCK_MODULATIONClock ModulationR/W
0x19BMSR_IA32_THERM_INTERRUPTThermal InterruptR/W
0x19CMSR_IA32_THERM_STATUSThermal StatusR/W
0x1A0MSR_IA32_MISC_ENABLEMisc EnableR/W제어
0x1A2MSR_IA32_TEMPERATURE_TARGETTemperature Target (TjMax)R
0x1ADMSR_TURBO_RATIO_LIMITTurbo Ratio LimitR주파수
0x1B1MSR_IA32_PACKAGE_THERM_STATUSPackage Thermal StatusR/W
0x200MSR_MTRR_PHYS_BASE(0)MTRR Phys Base 0R/WMTRR
0x250MSR_MTRR_FIX64K_00000MTRR Fixed 64KR/WMTRR
0x277MSR_IA32_CR_PATPage Attribute TableR/WPAT
0x2FFMSR_MTRR_DEF_TYPEMTRR Default TypeR/WMTRR
0x309MSR_CORE_PERF_FIXED_CTR0Fixed CTR: Inst RetiredR/WPMU
0x30AMSR_CORE_PERF_FIXED_CTR1Fixed CTR: Unhalted CyclesR/WPMU
0x30BMSR_CORE_PERF_FIXED_CTR2Fixed CTR: Ref CyclesR/WPMU
0x38DMSR_CORE_PERF_FIXED_CTR_CTRLFixed CTR ControlR/WPMU
0x38EMSR_CORE_PERF_GLOBAL_STATUSGlobal PMU StatusRPMU
0x38FMSR_CORE_PERF_GLOBAL_CTRLGlobal PMU ControlR/WPMU
0x480MSR_IA32_VMX_BASICVMX BasicRVMX
0x48BMSR_IA32_VMX_PROCBASED_CTLS2VMX Secondary ControlsRVMX
0x48CMSR_IA32_VMX_EPT_VPID_CAPEPT/VPID CapabilityRVMX
0x6E0MSR_IA32_TSC_DEADLINETSC DeadlineR/WTSC
0x770MSR_IA32_PM_ENABLEHWP EnableR/WHWP
0x771MSR_IA32_HWP_CAPABILITIESHWP CapabilitiesRHWP
0x774MSR_IA32_HWP_REQUESTHWP RequestR/WHWP
0xC0000080MSR_EFERExtended Feature EnableR/W제어
0xC0000081MSR_STARSYSCALL CS/SSR/W시스콜
0xC0000082MSR_LSTARSYSCALL RIP (64-bit)R/W시스콜
0xC0000084MSR_SYSCALL_MASKSYSCALL RFLAGS MaskR/W시스콜
0xC0000100MSR_FS_BASEFS Base (64-bit)R/W세그먼트
0xC0000101MSR_GS_BASEGS Base (64-bit)R/W세그먼트
0xC0000102MSR_KERNEL_GS_BASEKernel GS Base (SWAPGS)R/W세그먼트
0xC0000103MSR_TSC_AUXTSC Aux (RDTSCP)R/WTSC
0x1B0MSR_IA32_ENERGY_PERF_BIASEnergy Perf Bias (EPB)R/W전력
0x3F8MSR_PKG_C3_RESIDENCYPackage C3 ResidencyRC-State
0x3F9MSR_PKG_C6_RESIDENCYPackage C6 ResidencyRC-State
0x3FAMSR_PKG_C7_RESIDENCYPackage C7 ResidencyRC-State
0x3FCMSR_CORE_C3_RESIDENCYCore C3 ResidencyRC-State
0x3FDMSR_CORE_C6_RESIDENCYCore C6 ResidencyRC-State
0x3FEMSR_CORE_C7_RESIDENCYCore C7 ResidencyRC-State
0x606MSR_RAPL_POWER_UNITRAPL Power UnitRRAPL
0x610MSR_PKG_POWER_LIMITPackage Power Limit (PL1/PL2)R/WRAPL
0x611MSR_PKG_ENERGY_STATUSPackage Energy StatusRRAPL
0x614MSR_PKG_POWER_INFOPackage Power Info (TDP)RRAPL
0x618MSR_DRAM_POWER_LIMITDRAM Power LimitR/WRAPL
0x619MSR_DRAM_ENERGY_STATUSDRAM Energy StatusRRAPL
0x638MSR_PP0_POWER_LIMITCore Power Limit (PP0)R/WRAPL
0x639MSR_PP0_ENERGY_STATUSCore Energy Status (PP0)RRAPL
0x640MSR_PP1_POWER_LIMITGPU Power Limit (PP1)R/WRAPL
0x660MSR_CORE_C1_RESCore C1 ResidencyRC-State
0x772MSR_IA32_HWP_REQUEST_PKGHWP Package RequestR/WHWP
0x773MSR_IA32_HWP_INTERRUPTHWP Interrupt EnableR/WHWP
0x777MSR_IA32_HWP_STATUSHWP StatusR/WHWP
0xC0010015MSR_AMD64_HWCRAMD HW ConfigR/WAMD
0xC0010064MSR_AMD_PSTATE_DEF_BASEAMD P-State Def 0 (P0)RAMD 주파수
0xC0011029MSR_AMD64_DE_CFGAMD Decode ConfigR/WAMD
0xC00102B0MSR_AMD_CPPC_CAP1AMD CPPC CapabilitiesRAMD 주파수
0xC00102B1MSR_AMD_CPPC_ENABLEAMD CPPC EnableR/WAMD 주파수
0xC00102B3MSR_AMD_CPPC_REQAMD CPPC RequestR/WAMD 주파수