커널 아키텍처 (Kernel Architecture)

x86_64, ARM64, RISC-V 아키텍처별 커널 구조, 부팅 과정, 주소 공간 레이아웃을 상세히 다룹니다.

관련 표준: Intel SDM (x86/x64 아키텍처), ARM Architecture Reference Manual (AArch64), UEFI 2.10 — 커널이 지원하는 주요 프로세서 아키텍처와 펌웨어 인터페이스 규격입니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.

리눅스 커널 개요 (Linux Kernel Overview)

리눅스 커널은 1991년 Linus Torvalds가 처음 공개한 이래, 현재 세계에서 가장 널리 사용되는 운영체제 커널입니다. 서버, 데스크탑, 임베디드 기기, 스마트폰(Android), 슈퍼컴퓨터에 이르기까지 거의 모든 컴퓨팅 영역에서 동작합니다. 커널은 하드웨어와 사용자 공간(user space) 사이에서 추상화 계층 역할을 하며, 다음과 같은 핵심 기능을 담당합니다:

참고: 2024년 기준 리눅스 커널 소스 코드는 약 3,600만 줄 이상이며, 전 세계 수천 명의 개발자가 참여하는 가장 큰 오픈소스 프로젝트 중 하나입니다. 지원 아키텍처는 x86, ARM, ARM64, RISC-V, MIPS, PowerPC, s390 등 20개 이상입니다.

모놀리식 vs 마이크로커널 (Monolithic vs Microkernel)

운영체제 커널 설계에는 크게 두 가지 접근 방식이 있습니다. 모놀리식 커널(Monolithic Kernel)은 모든 핵심 서비스(프로세스 관리, 메모리 관리, 파일시스템, 드라이버 등)가 하나의 커다란 커널 이미지 안에서 동일한 주소 공간(커널 공간)에서 실행됩니다. 반면 마이크로커널(Microkernel)은 최소한의 기능만 커널에 포함하고 나머지는 사용자 공간 서버로 분리합니다.

리눅스는 모놀리식 커널입니다. 그러나 순수한 모놀리식이 아닌, 동적으로 적재 가능한 커널 모듈(Loadable Kernel Module, LKM)을 지원하여 모듈화의 유연성을 확보합니다. 이를 "모듈형 모놀리식(Modular Monolithic)" 커널이라고도 합니다.

  ┌─────────────────────────────────────────────────────────────┐
  │                     모놀리식 커널 (Linux)                    │
  │  ┌──────────┬──────────┬──────────┬──────────┬──────────┐  │
  │  │ Process  │ Memory   │   VFS    │ Network  │ Device   │  │
  │  │   Mgmt   │   Mgmt   │          │  Stack   │ Drivers  │  │
  │  └──────────┴──────────┴──────────┴──────────┴──────────┘  │
  │               모두 Ring 0 (커널 공간)에서 실행                │
  └─────────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────────┐
  │                     마이크로커널 (Minix, QNX)                │
  │  ┌──────────────────────────────────────────────────────┐   │
  │  │  User Space: FS 서버 │ 드라이버 서버 │ 네트워크 서버  │   │
  │  └──────────────────────────────────────────────────────┘   │
  │  ┌──────────────────────────────────────────────────────┐   │
  │  │         커널: IPC, 스케줄링, 기본 메모리 관리          │   │
  │  └──────────────────────────────────────────────────────┘   │
  └─────────────────────────────────────────────────────────────┘
TIP: 모놀리식 커널의 장점은 서브시스템 간 함수 호출이 직접적이어서 성능이 뛰어나다는 것입니다. 마이크로커널은 IPC(프로세스 간 통신)를 통해 서비스 간 통신하므로 오버헤드가 있지만, 격리성과 안정성이 우수합니다. Linus Torvalds와 Andrew Tanenbaum 사이의 유명한 "모놀리식 vs 마이크로커널" 논쟁은 OS 설계 철학에서 중요한 역사적 사건입니다.

x86_64 아키텍처 (x86_64 Architecture)

x86_64(또는 AMD64, Intel 64)는 데스크탑과 서버 환경에서 가장 널리 사용되는 아키텍처입니다. x86의 32비트 아키텍처를 64비트로 확장한 것으로, 리눅스 커널에서 가장 오랫동안 지원해 온 아키텍처 중 하나입니다.

부팅 과정 (Boot Process)

x86_64 시스템의 부팅 과정은 펌웨어에서 시작하여 커널이 완전히 초기화될 때까지 여러 단계를 거칩니다. 현대 시스템에서는 UEFI가 표준이지만, 레거시 BIOS도 여전히 지원됩니다.

  x86_64 부팅 과정 (Boot Sequence)
  ═══════════════════════════════════════════════════════════

  ┌───────────┐    ┌───────────────┐    ┌──────────────────┐
  │  BIOS /   │───→│  Bootloader   │───→│   Linux Kernel   │
  │   UEFI    │    │ (GRUB2/sysli) │    │   (vmlinuz)      │
  └───────────┘    └───────────────┘    └──────────────────┘
       │                  │                      │
  POST & HW 초기화   Stage1: MBR/ESP 로드    decompress_kernel()
  CPU Real Mode      Stage2: 커널 이미지 로드  start_kernel()
  메모리 맵 감지      initrd/initramfs 로드    rest_init()
                     커널 커맨드라인 전달       → init 프로세스 실행

  ─── 상세 흐름 ───────────────────────────────────────────
  1. 전원 ON → CPU가 리셋 벡터(0xFFFFFFF0)에서 실행 시작
  2. BIOS/UEFI 펌웨어: POST, 하드웨어 초기화, 부트 디바이스 선택
  3. Bootloader 1단계: MBR(512바이트) 또는 UEFI ESP에서 로드
  4. Bootloader 2단계: 파일시스템 인식, 커널+initramfs 로드
  5. Real Mode → Protected Mode → Long Mode (64-bit) 전환
  6. startup_64() → x86_64_start_kernel() → start_kernel()
  7. 아키텍처 초기화, 메모리 설정, 스케줄러 초기화
  8. rest_init() → kernel_init() → /sbin/init 실행
주의: UEFI 부팅에서는 EFI Stub 기능을 통해 bootloader 없이 커널을 직접 부팅할 수 있습니다. 이 경우 커널 이미지가 직접 UEFI 애플리케이션으로 동작하며, CONFIG_EFI_STUB=y 설정이 필요합니다.

커널의 x86_64 엔트리 포인트는 어셈블리로 작성되어 있습니다. 다음은 핵심 부팅 코드의 간략화된 예시입니다:

/* arch/x86/kernel/head_64.S - x86_64 커널 엔트리 포인트 (간략화) */

SYM_CODE_START_NOALIGN(startup_64)
    /* 세그먼트 레지스터 초기화 */
    xorl    %eax, %eax
    movl    %eax, %ds
    movl    %eax, %es
    movl    %eax, %ss
    movl    %eax, %fs
    movl    %eax, %gs

    /* 초기 페이지 테이블 설정 (Identity mapping) */
    leaq    early_top_pgt(%rip), %rax
    movq    %rax, %cr3

    /* 스택 포인터 설정 */
    leaq    init_thread_union+THREAD_SIZE(%rip), %rsp

    /* C 코드로 점프 */
    call    x86_64_start_kernel
SYM_CODE_END(startup_64)

주소 공간 레이아웃 (Address Space Layout)

x86_64에서는 48비트 가상 주소 공간(256TB)을 사용합니다. 이 공간은 사용자 영역(하위)과 커널 영역(상위)으로 명확하게 분리됩니다. 최신 커널에서는 5-level paging을 통해 57비트(128PB) 주소 공간도 지원합니다. 다음 다이어그램은 4-level paging 기준 주소 공간 레이아웃을 보여줍니다:

x86_64 가상 주소 공간 레이아웃 (4-Level Paging, 48-bit) 0xFFFFFFFF_FFFFFFFF 0xFFFFFFFF_80000000 0xFFFFFFFE_80000000 0xFFFFFC00_00000000 0xFFFF8880_00000000 0xFFFF8000_00000000 0x00007FFF_FFFFFFFF 0x00000000_00000000 Kernel text mapping (512MB) Kernel text (실제 커널 코드, __START_KERNEL_map) Modules space (1.5GB) vmalloc / ioremap 영역 Direct mapping of all physical memory Guard hole / unused 비정규 주소 영역 (Non-canonical hole) Stack (grows downward) mmap 영역 (shared libs, anonymous) Heap (grows upward) BSS / Data / Text (ELF segments) NULL pointer guard page Kernel Space (128 TB) User Space (128 TB) grows grows
x86_64 가상 주소 공간 레이아웃 - 커널 공간(상위 128TB)과 사용자 공간(하위 128TB)

세그먼테이션과 페이징 (Segmentation & Paging)

x86_64에서 세그먼테이션은 사실상 flat model로 사용됩니다. 모든 세그먼트의 베이스가 0이고 리미트가 최대값으로 설정되어, 세그먼테이션은 사실상 비활성화된 상태입니다. 그러나 GDT(Global Descriptor Table)는 여전히 존재하며, 커널/사용자 모드 전환과 TSS(Task State Segment)를 위해 필수적입니다.

페이징은 4단계 페이지 테이블을 사용합니다 (5단계 페이징은 CONFIG_X86_5LEVEL=y로 활성화):

  x86_64 4-Level Page Table Walk (48-bit VA)
  ═══════════════════════════════════════════════════════════

  가상 주소 (48-bit):
  ┌──────┬──────┬──────┬──────┬──────────┐
  │ PGD  │ PUD  │ PMD  │ PTE  │  Offset  │
  │[47:39│[38:30│[29:21│[20:12│  [11:0]  │
  │ 9bit │ 9bit │ 9bit │ 9bit │  12bit   │
  └──┬───┴──┬───┴──┬───┴──┬───┴────┬─────┘
     │      │      │      │        │
     ▼      ▼      ▼      ▼        │
  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐  │
  │ PGD  │→ │ PUD  │→ │ PMD  │→ │ PTE  │──┘→ 물리 주소
  │ table│  │ table│  │ table│  │ table│      (최대 52-bit)
  └──────┘  └──────┘  └──────┘  └──────┘
     ↑
    CR3 레지스터

링 구조 (Protection Rings)

x86_64는 4개의 특권 레벨(Ring 0 ~ Ring 3)을 제공하지만, 리눅스에서는 실제로 Ring 0(커널 모드)Ring 3(사용자 모드) 두 레벨만 사용합니다. Ring 1과 Ring 2는 사용되지 않으며, 가상화 확장(VT-x)에서는 Ring -1(VMX root mode)이라는 개념이 추가됩니다.

/* arch/x86/include/asm/segment.h - GDT 세그먼트 정의 */

/*
 * GDT 레이아웃 (간략화):
 *  Entry 0: NULL 디스크립터 (CPU 요구사항)
 *  Entry 1: Kernel Code Segment (CS) - DPL=0
 *  Entry 2: Kernel Data Segment (DS) - DPL=0
 *  Entry 3: User Code Segment (CS)   - DPL=3
 *  Entry 4: User Data Segment (DS)   - DPL=3
 *  Entry 5: TSS (Task State Segment)
 */
#define GDT_ENTRY_KERNEL_CS   1
#define GDT_ENTRY_KERNEL_DS   2
#define GDT_ENTRY_DEFAULT_USER_CS 3
#define GDT_ENTRY_DEFAULT_USER_DS 4

/* 세그먼트 셀렉터 값 (index << 3 | RPL) */
#define __KERNEL_CS  (GDT_ENTRY_KERNEL_CS * 8)     /* 0x08 - Ring 0 */
#define __KERNEL_DS  (GDT_ENTRY_KERNEL_DS * 8)     /* 0x10 - Ring 0 */
#define __USER_CS    (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3) /* 0x1B - Ring 3 */
#define __USER_DS    (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3) /* 0x23 - Ring 3 */
SYSCALL/SYSRET: x86_64에서 시스템 콜은 SYSCALL 명령어를 사용합니다. 이 명령어는 Ring 3에서 Ring 0으로 전환하며, MSR_LSTAR 레지스터에 저장된 시스템 콜 핸들러 주소로 점프합니다. SYSRET으로 사용자 모드로 복귀합니다. 이전의 int 0x80 방식보다 훨씬 빠릅니다.

ARM64 아키텍처 (ARM64 / AArch64 Architecture)

ARM64(AArch64)는 모바일 기기부터 서버, 슈퍼컴퓨터까지 빠르게 확산되고 있는 아키텍처입니다. Apple Silicon(M1/M2/M3), AWS Graviton, Ampere Altra 등 고성능 ARM64 프로세서가 서버 시장에서도 중요한 위치를 차지하고 있습니다.

Exception Level (EL0 ~ EL3)

ARM64는 x86의 Ring 구조 대신 Exception Level(EL)이라는 4단계 특권 모델을 사용합니다. 각 EL은 명확한 역할을 가지며, 하위 EL에서 상위 EL로의 전환은 exception 발생 시에만 가능합니다.

  ARM64 Exception Level 구조
  ═══════════════════════════════════════════════

  특권 높음 ↑
            │  ┌─────────────────────────────┐
     EL3    │  │  Secure Monitor (ATF/TF-A)  │  ← ARM Trusted Firmware
            │  └─────────────────────────────┘
            │  ┌─────────────────────────────┐
     EL2    │  │  Hypervisor (KVM)           │  ← 가상화 지원
            │  └─────────────────────────────┘
            │  ┌─────────────────────────────┐
     EL1    │  │  OS Kernel (Linux)          │  ← 커널 모드
            │  └─────────────────────────────┘
            │  ┌─────────────────────────────┐
     EL0    │  │  User Applications          │  ← 사용자 모드
            │  └─────────────────────────────┘
  특권 낮음 ↓

  전환 방식:
    EL0 → EL1 : SVC (Supervisor Call) 명령어
    EL1 → EL2 : HVC (Hypervisor Call) 명령어
    EL2 → EL3 : SMC (Secure Monitor Call) 명령어
    상위 → 하위 : ERET (Exception Return) 명령어

ARM64 부팅 과정 (Boot Process)

ARM64의 부팅 과정은 x86과 상당히 다릅니다. 대부분의 ARM64 시스템은 Device Tree를 사용하여 하드웨어 구성 정보를 커널에 전달합니다. 부팅 프로토콜은 커널 이미지의 시작점에 명시된 규약을 따릅니다.

  ARM64 부팅 시퀀스
  ═══════════════════════════════════════════════════════════
  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐
  │ BootROM  │──→│ BL1/BL2  │──→│ U-Boot / │──→│  Linux   │
  │ (SoC)    │   │ (TF-A)   │   │  UEFI    │   │  Kernel  │
  └──────────┘   └──────────┘   └──────────┘   └──────────┘
                      │              │               │
                  EL3에서 시작    EL2로 전환       EL2/EL1에서 실행
                  보안 초기화     DTB 주소 전달    head.S → start_kernel()
                                 커널 로드         MMU 활성화

  ── 상세 ──
  1. BootROM: SoC 내장 ROM에서 실행, 첫 부트로더(BL1) 로드
  2. BL1 (Trusted Firmware): EL3에서 실행, 보안 초기화
  3. BL2: 추가 펌웨어 로드 (BL31=EL3 런타임, BL33=Normal World)
  4. BL33 (U-Boot/UEFI): 커널 이미지와 DTB 로드
  5. 커널은 x0에 DTB 물리 주소를 받아 시작
  6. primary_entry() → __primary_switch() → start_kernel()

MMIO와 Device Tree

ARM 시스템에서 하드웨어 레지스터에 접근하는 기본 방식은 MMIO(Memory-Mapped I/O)입니다. x86의 Port I/O(in/out 명령어)와 달리, ARM은 메모리 주소에 하드웨어 레지스터를 매핑하고 일반 메모리 접근 명령어(LDR/STR)로 제어합니다.

Device Tree(DT)는 하드웨어 구성을 기술하는 데이터 구조입니다. DTS(Device Tree Source) 파일로 작성하고, DTC(Device Tree Compiler)로 DTB(Device Tree Blob) 바이너리로 컴파일합니다. 커널은 부팅 시 DTB를 파싱하여 하드웨어 정보를 인식합니다.

/* 간단한 Device Tree 예시 (arch/arm64/boot/dts/example.dts) */

/dts-v1/;

/ {
    model = "Example ARM64 Board";
    compatible = "vendor,example-board";

    #address-cells = <2>;
    #size-cells = <2>;

    memory@80000000 {
        device_type = "memory";
        reg = <0x0 0x80000000 0x0 0x40000000>; /* 1GB @ 0x80000000 */
    };

    uart0: serial@9000000 {
        compatible = "arm,pl011", "arm,primecell";
        reg = <0x0 0x09000000 0x0 0x1000>; /* MMIO 영역 */
        interrupts = <0 1 4>;              /* GIC SPI #1, level */
        clock-names = "uartclk", "apb_pclk";
    };

    gic: interrupt-controller@8000000 {
        compatible = "arm,gic-v3";
        #interrupt-cells = <3>;
        interrupt-controller;
        reg = <0x0 0x08000000 0x0 0x10000>,  /* GICD */
              <0x0 0x080A0000 0x0 0xF60000>; /* GICR */
    };
};
TIP: Device Tree 소스 파일은 arch/arm64/boot/dts/ 디렉토리에 위치하며, 제조사별로 하위 디렉토리가 구성됩니다. make dtbs 명령으로 모든 DTB 파일을 빌드할 수 있습니다. dtc -I dtb -O dts 명령으로 DTB를 다시 DTS로 역컴파일할 수도 있습니다.

RISC-V 아키텍처 (RISC-V Architecture)

RISC-V는 UC Berkeley에서 설계한 오픈 소스 ISA(Instruction Set Architecture)로, 라이센스 비용 없이 누구나 자유롭게 구현할 수 있습니다. 리눅스 커널은 RISC-V를 공식적으로 지원하며, SiFive, StarFive 등의 칩에서 이미 리눅스가 동작합니다.

특권 모드 (Privilege Modes)

RISC-V는 3단계 특권 모드를 정의합니다. 각 모드는 CSR(Control and Status Register) 접근 권한이 다릅니다.

  RISC-V 특권 모드 계층
  ═══════════════════════════════════════════════

  특권 높음 ↑
            │  ┌───────────────────────────────┐
  M-mode    │  │  Machine Mode (OpenSBI/BBL)   │
  (최고특권) │  │  - 하드웨어 직접 접근           │
            │  │  - 타이머, IPI 관리             │
            │  │  - SBI 콜 처리                  │
            │  └───────────────────────────────┘
            │           ↕ ecall
            │  ┌───────────────────────────────┐
  S-mode    │  │  Supervisor Mode (Linux)       │
  (커널)    │  │  - 페이지 테이블 관리 (satp)    │
            │  │  - 인터럽트/예외 처리            │
            │  │  - 커널 코드 실행               │
            │  └───────────────────────────────┘
            │           ↕ ecall
            │  ┌───────────────────────────────┐
  U-mode    │  │  User Mode (Applications)      │
  (사용자)  │  │  - 일반 애플리케이션             │
            │  │  - 시스템 콜로 S-mode 진입       │
            │  └───────────────────────────────┘
  특권 낮음 ↓

SBI (Supervisor Binary Interface)

SBI는 S-mode(커널)와 M-mode(펌웨어) 사이의 표준 인터페이스입니다. 리눅스 커널은 SBI 호출을 통해 타이머 설정, 프로세서 간 인터럽트(IPI) 전송, 콘솔 출력 등의 기계 수준 작업을 수행합니다. OpenSBI가 가장 널리 사용되는 SBI 구현체입니다.

/* arch/riscv/include/asm/sbi.h - SBI 호출 인터페이스 (간략화) */

/* SBI Extension IDs */
#define SBI_EXT_TIME           0x54494D45  /* "TIME" */
#define SBI_EXT_IPI            0x735049    /* "sPI"  */
#define SBI_EXT_RFENCE         0x52464E43  /* "RFNC" */
#define SBI_EXT_HSM            0x48534D    /* "HSM"  */

/* SBI 호출 수행 (ecall 명령어 사용) */
struct sbiret {
    long error;
    long value;
};

static inline struct sbiret sbi_ecall(int ext, int fid,
    unsigned long arg0, unsigned long arg1,
    unsigned long arg2, unsigned long arg3)
{
    struct sbiret ret;

    register unsigned long a0 asm("a0") = arg0;
    register unsigned long a1 asm("a1") = arg1;
    register unsigned long a6 asm("a6") = fid;
    register unsigned long a7 asm("a7") = ext;

    asm volatile("ecall"
        : "+r"(a0), "+r"(a1)
        : "r"(a6), "r"(a7)
        : "memory");

    ret.error = a0;
    ret.value = a1;
    return ret;
}

RISC-V 부팅 과정 (Boot Process)

RISC-V의 부팅 과정은 ARM64와 유사하게 여러 펌웨어 단계를 거칩니다. 현재 가장 일반적인 조합은 ZSBL → OpenSBI → U-Boot → Linux입니다.

  RISC-V 부팅 시퀀스
  ═══════════════════════════════════════════════════════════
  ┌───────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐
  │  ZSBL     │──→│ OpenSBI  │──→│ U-Boot   │──→│  Linux   │
  │ (BootROM) │   │ (M-mode) │   │ (S-mode) │   │  Kernel  │
  └───────────┘   └──────────┘   └──────────┘   └──────────┘
       │               │              │               │
  하드웨어 초기화   SBI 인터페이스    DTB 전달       head.S 진입
  M-mode 실행     타이머/IPI 설정   커널 로드       setup_vm()
                  S-mode로 전환     initramfs 로드  start_kernel()

  ── RISC-V 커널 엔트리 흐름 ──
  1. OpenSBI가 a0=hartid, a1=dtb_addr을 설정하고 커널로 점프
  2. _start (arch/riscv/kernel/head.S) 진입
  3. setup_vm() - 초기 페이지 테이블 설정
  4. relocate_enable_mmu() - MMU 활성화
  5. start_kernel() → C 코드 시작
HART: RISC-V에서 CPU 코어에 해당하는 개념을 HART(Hardware Thread)라고 합니다. 멀티코어 시스템에서는 여러 HART가 존재하며, 부팅 시 하나의 HART만 부팅 코드를 실행하고 나머지는 WFI(Wait For Interrupt) 상태에서 대기합니다.

특권 레벨 비교 (Privilege Level Comparison)

세 아키텍처의 특권 레벨 구조를 비교하면 설계 철학의 차이를 명확히 알 수 있습니다. 다음 다이어그램은 x86_64, ARM64, RISC-V의 특권 레벨을 나란히 비교합니다:

아키텍처별 특권 레벨 비교 (Privilege Level Comparison) x86_64 ARM64 (AArch64) RISC-V High Low Ring -1 (VMX Root) Hypervisor Ring 0 Kernel Mode Ring 1, 2 (미사용) Ring 3 User Mode EL3 Secure Monitor (TrustZone) EL2 Hypervisor (KVM) EL1 OS Kernel (Linux) EL0 User Applications M-mode Machine (OpenSBI) S-mode Supervisor (Linux) U-mode User Applications Legend = Linux 커널 실행 레벨 = 동등 레벨 연결
x86_64, ARM64, RISC-V의 특권 레벨 비교 - 각 아키텍처에서 리눅스 커널이 실행되는 레벨이 굵은 테두리로 표시됨

위 다이어그램에서 주목할 점은 리눅스 커널이 각 아키텍처에서 다른 특권 레벨에서 동작한다는 것입니다:

VHE (Virtualization Host Extensions): ARM64에서 CONFIG_ARM64_VHE=y가 활성화되면, 리눅스 커널이 EL2에서 직접 실행될 수 있습니다. 이를 통해 KVM 호스트 커널이 EL2에서 동작하고, 게스트 OS가 EL1에서 실행되어 가상화 전환 오버헤드가 크게 줄어듭니다.

start_kernel() - 커널 초기화 진입점 (Kernel Init Entry)

모든 아키텍처에서 아키텍처별 초기화가 완료되면 start_kernel() 함수가 호출됩니다. 이 함수는 init/main.c에 정의되어 있으며, 커널의 공통 초기화를 수행하는 핵심 함수입니다.

/* init/main.c - start_kernel() 함수 (핵심 흐름 간략화) */

asmlinkage __visible void __init start_kernel(void)
{
    /* 아키텍처 의존적 초기화 (이전 단계에서 일부 수행) */
    setup_arch(&command_line);     /* 아키텍처별 설정 */

    /* 부팅 초기 메모리 할당자 (memblock) */
    setup_per_cpu_areas();          /* Per-CPU 영역 설정 */

    /* 핵심 서브시스템 초기화 */
    trap_init();                     /* 예외/인터럽트 벡터 설정 */
    mm_core_init();                  /* 메모리 관리 초기화 */
    sched_init();                    /* 스케줄러 초기화 */
    init_IRQ();                      /* 인터럽트 컨트롤러 설정 */
    time_init();                     /* 타이머 초기화 */
    console_init();                  /* 콘솔 초기화 */

    /* VFS 및 기타 서브시스템 */
    vfs_caches_init();              /* VFS 캐시 초기화 */
    signals_init();                  /* 시그널 초기화 */
    proc_root_init();               /* procfs 초기화 */

    /* 나머지 초기화 - kernel_init 스레드 생성 */
    arch_call_rest_init();          /* rest_init() → kernel_init() */

    /*
     * rest_init()에서:
     *  1. kernel_init 커널 스레드 생성 (PID 1의 전신)
     *  2. kthreadd 커널 스레드 생성 (PID 2)
     *  3. 현재 스레드는 idle 스레드(PID 0)가 됨
     *
     * kernel_init()에서:
     *  1. initcall 실행 (드라이버 초기화 등)
     *  2. /sbin/init 또는 /init 실행 → PID 1 프로세스
     */
}
주의: start_kernel()은 인터럽트가 비활성화된 상태에서 실행됩니다. 이 함수가 실행되는 동안에는 단일 CPU만 활성화되어 있으며, 나머지 CPU(Secondary CPU)는 smp_init()이 호출될 때까지 대기 상태입니다.

커널 소스 트리 구조 (Kernel Source Tree Structure)

리눅스 커널 소스 코드는 기능별로 잘 정리된 디렉토리 구조를 가지고 있습니다. 커널 개발을 시작할 때 이 구조를 이해하는 것이 매우 중요합니다.

  linux/                         ← 커널 소스 루트
  ├── arch/                      ← 아키텍처 의존적 코드
  │   ├── x86/                   ← x86/x86_64 아키텍처
  │   │   ├── boot/              ←   부트 코드 (bzImage 생성)
  │   │   ├── kernel/            ←   프로세스, 시스템 콜, SMP
  │   │   ├── mm/                ←   x86 페이지 테이블, TLB
  │   │   ├── include/           ←   x86 전용 헤더
  │   │   └── entry/             ←   시스템 콜/인터럽트 진입점
  │   ├── arm64/                 ← ARM64 (AArch64)
  │   │   ├── boot/dts/          ←   Device Tree 소스
  │   │   ├── kernel/            ←   ARM64 커널 코드
  │   │   └── mm/                ←   ARM64 메모리 관리
  │   └── riscv/                 ← RISC-V
  │       ├── kernel/            ←   RISC-V 커널 코드
  │       └── mm/                ←   RISC-V 메모리 관리
  │
  ├── kernel/                    ← 핵심 커널 코드 (아키텍처 독립)
  │   ├── sched/                 ←   스케줄러 (CFS, RT, DL, EEVDF)
  │   ├── locking/               ←   잠금 프리미티브
  │   ├── irq/                   ←   인터럽트 프레임워크
  │   ├── time/                  ←   타이머, clocksource
  │   ├── bpf/                   ←   eBPF 서브시스템
  │   └── rcu/                   ←   RCU (Read-Copy-Update)
  │
  ├── mm/                        ← 메모리 관리 (아키텍처 독립)
  │   ├── page_alloc.c           ←   Buddy allocator
  │   ├── slub.c                 ←   SLUB 할당자
  │   ├── vmalloc.c              ←   vmalloc 영역 관리
  │   ├── mmap.c                 ←   메모리 매핑
  │   └── oom_kill.c             ←   OOM Killer
  │
  ├── fs/                        ← 파일시스템
  │   ├── ext4/                  ←   ext4 파일시스템
  │   ├── btrfs/                 ←   Btrfs 파일시스템
  │   ├── proc/                  ←   procfs (/proc)
  │   ├── sysfs/                 ←   sysfs (/sys)
  │   └── namei.c                ←   경로 탐색 (pathname lookup)
  │
  ├── drivers/                   ← 디바이스 드라이버 (가장 큰 디렉토리)
  │   ├── char/                  ←   문자 디바이스
  │   ├── block/                 ←   블록 디바이스
  │   ├── net/                   ←   네트워크 디바이스 드라이버
  │   ├── gpu/                   ←   GPU 드라이버 (DRM)
  │   ├── pci/                   ←   PCI 버스 드라이버
  │   ├── usb/                   ←   USB 드라이버
  │   └── of/                    ←   Open Firmware / Device Tree
  │
  ├── net/                       ← 네트워킹 스택
  │   ├── core/                  ←   소켓, sk_buff 등 핵심
  │   ├── ipv4/                  ←   IPv4 프로토콜
  │   ├── ipv6/                  ←   IPv6 프로토콜
  │   ├── netfilter/             ←   Netfilter (iptables/nftables)
  │   └── xdp/                   ←   XDP (eXpress Data Path)
  │
  ├── include/                   ← 커널 공통 헤더 파일
  │   ├── linux/                 ←   핵심 커널 API 헤더
  │   ├── asm-generic/           ←   아키텍처 공통 ASM 헤더
  │   └── uapi/                  ←   사용자 공간 API 헤더
  │
  ├── init/                      ← 커널 초기화 (start_kernel() 등)
  │   └── main.c                 ←   start_kernel() 정의
  │
  ├── ipc/                       ← IPC (공유 메모리, 세마포어, 메시지 큐)
  ├── security/                  ← 보안 모듈 (SELinux, AppArmor)
  ├── crypto/                    ← 암호화 API
  ├── lib/                       ← 커널 내부 라이브러리 함수
  ├── scripts/                   ← 빌드 스크립트, 도구
  ├── tools/                     ← 사용자 공간 도구 (perf 등)
  ├── Documentation/             ← 커널 문서
  ├── Kconfig                    ← 최상위 설정 파일
  └── Makefile                   ← 최상위 빌드 파일
TIP: drivers/ 디렉토리가 전체 소스의 약 60% 이상을 차지합니다. 커널의 핵심 로직은 kernel/, mm/, fs/, net/에 집중되어 있으며, 이 디렉토리들의 코드를 이해하면 커널의 핵심 동작 원리를 파악할 수 있습니다. 소스 코드 탐색에는 Bootlin Elixir Cross-referencer가 매우 유용합니다.

arch/ 디렉토리 상세 (Architecture Directory Detail)

arch/ 디렉토리 아래의 각 아키텍처 디렉토리는 비슷한 하위 구조를 가집니다. 이는 커널의 아키텍처 추상화 설계 원칙을 반영합니다:

커널은 이러한 구조를 통해 아키텍처 독립적인 코드(kernel/, mm/ 등)와 아키텍처 의존적인 코드(arch/)를 깔끔하게 분리합니다. 새로운 아키텍처를 지원하려면 주로 arch/ 아래에 해당 아키텍처 디렉토리를 추가하면 됩니다.

빌드 설정 예시 (Build Configuration)

각 아키텍처의 기본 설정 파일(defconfig)로 빠르게 커널을 빌드할 수 있습니다:

# x86_64 기본 설정으로 커널 빌드
make x86_64_defconfig
make -j$(nproc)

# ARM64 크로스 컴파일
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make defconfig
make -j$(nproc) Image dtbs

# RISC-V 크로스 컴파일
export ARCH=riscv
export CROSS_COMPILE=riscv64-linux-gnu-
make defconfig
make -j$(nproc)

# QEMU로 빌드된 커널 테스트 (x86_64)
qemu-system-x86_64 \
    -kernel arch/x86/boot/bzImage \
    -initrd /path/to/initramfs.cpio.gz \
    -append "console=ttyS0" \
    -nographic

요약 (Summary)

이 문서에서는 리눅스 커널이 지원하는 주요 세 아키텍처의 핵심 개념을 살펴보았습니다. 각 아키텍처의 특성을 다음 표로 정리합니다:

항목 x86_64 ARM64 RISC-V
특권 레벨 Ring 0-3 (+ VMX) EL0-EL3 U/S/M mode
커널 실행 레벨 Ring 0 EL1 (VHE: EL2) S-mode
시스템 콜 방식 SYSCALL/SYSRET SVC 명령어 ECALL 명령어
부팅 펌웨어 BIOS/UEFI BootROM + TF-A ZSBL + OpenSBI
HW 정보 전달 ACPI/E820 Device Tree / ACPI Device Tree
주소 공간 48/57-bit VA 48/52-bit VA Sv39/Sv48/Sv57
페이지 크기 4KB (기본) 4KB / 16KB / 64KB 4KB (기본)
I/O 방식 Port I/O + MMIO MMIO MMIO
인터럽트 컨트롤러 APIC (LAPIC + I/O APIC) GIC (v2/v3/v4) PLIC / APLIC+IMSIC
가상화 VT-x / AMD-V EL2 + VHE H-extension
다음 단계: 커널 아키텍처의 기본 개념을 이해했다면, 다음으로 빌드 시스템 (Build System) 문서에서 실제로 커널을 빌드하는 방법을 학습하거나, 메모리 관리 (Memory Management) 문서에서 각 아키텍처의 페이지 테이블과 메모리 할당 메커니즘을 심층적으로 살펴볼 수 있습니다.

CPU 제조사 아키텍처 매뉴얼 (Architecture Software Developer's Manuals)

리눅스 커널 개발에서 각 CPU 제조사의 공식 아키텍처 매뉴얼은 가장 권위 있고 정확한 참조 문서입니다. 커널 코드의 아키텍처 의존 부분(arch/ 디렉토리)을 이해하거나 수정할 때 반드시 해당 매뉴얼을 참조해야 합니다.

Intel® 64 and IA-32 Architectures Software Developer's Manual (Intel SDM)

볼륨내용커널 개발 활용
Vol. 1 기본 아키텍처 데이터 타입, 실행 환경, 명령어 개요, x87 FPU, SSE/AVX
Vol. 2 (A-Z) 명령어 세트 레퍼런스 개별 명령어의 opcode, 동작, 예외 조건 — 인라인 어셈블리 작성 시 필수
Vol. 3 (A-D) 시스템 프로그래밍 가이드 보호 모드, 페이징, 인터럽트/예외, MSR, APIC, VT-x — 커널 개발 핵심 볼륨
Vol. 4 MSR (Model-Specific Register) CPU 모델별 MSR 목록, 성능 카운터, 전력 관리 레지스터
Optimization Manual 최적화 레퍼런스 마이크로아키텍처 세부사항, 분기 예측, 캐시 동작, SIMD 최적화 가이드
활용 팁: 커널의 arch/x86/ 코드를 분석할 때 Vol. 3이 가장 자주 참조됩니다. 특히 페이지 테이블 구조(Chapter 4), 인터럽트/예외 처리(Chapter 6), APIC(Chapter 10), VT-x(Chapter 23-33)는 커널 개발자의 필독 장입니다. Intel SDM은 5,000페이지 이상이므로 전체를 읽기보다 필요한 챕터를 색인으로 찾아 참조하는 방식이 효율적입니다.

AMD64 Architecture Programmer's Manual (AMD APM)

볼륨내용커널 개발 활용
Vol. 1 애플리케이션 프로그래밍 레지스터, 데이터 타입, 명령어 개요
Vol. 2 시스템 프로그래밍 Long Mode, 페이징, 시스템 콜(SYSCALL/SYSRET), SMM, AMD-V(SVM)
Vol. 3 범용/SIMD 명령어 x86-64 명령어 인코딩, SSE/AVX 상세
Vol. 4 128/256-bit 미디어 명령어 XOP, FMA4 등 AMD 전용 확장
Vol. 5 64-bit 미디어/x87 명령어 레거시 FPU, 3DNow! 명령어
Intel SDM과의 차이점: AMD APM Vol. 2는 AMD-V(SVM) 가상화를 상세히 다루며, 이는 Intel VT-x와 구조적으로 다릅니다. KVM 코드에서 arch/x86/kvm/svm/ 디렉토리는 AMD APM Vol. 2의 SVM 챕터를 직접 구현한 것입니다. 또한 AMD의 SEV(Secure Encrypted Virtualization)와 SME(Secure Memory Encryption)는 AMD 고유 기능입니다.

ARM Architecture Reference Manual (ARM ARM)

문서내용커널 개발 활용
ARMv8-A ARM (DDI 0487) AArch64/AArch32 ISA 레퍼런스 A64 명령어, 시스템 레지스터, 예외 모델, MMU, GIC 인터페이스
ARMv9-A ARM ARMv9 확장 포함 SVE2, MTE(Memory Tagging), RME(Realm Management), CCA
ARM Cortex-A TRM 코어별 Technical Reference Manual 캐시 구조, TLB, 분기 예측기, 구현 정의(IMPLEMENTATION DEFINED) 동작
GIC Architecture Spec Generic Interrupt Controller GICv2/v3/v4 인터럽트 분배, LPI, ITS — drivers/irqchip/irq-gic-*
SMMU Architecture Spec System MMU (IOMMU) DMA 주소 변환, 디바이스 격리 — drivers/iommu/arm/arm-smmu-*
AMBA/AXI/ACE Spec 버스 프로토콜 캐시 일관성(coherency), 배리어 동작, DMA 전송 특성
주의 — IMPLEMENTATION DEFINED: ARM 아키텍처 매뉴얼에는 "IMPLEMENTATION DEFINED"로 표기된 동작이 많습니다. 이는 각 SoC/코어 구현에 따라 달라지므로, 실제 하드웨어에서의 동작은 해당 코어의 TRM(Technical Reference Manual)과 SoC 벤더의 데이터시트를 추가로 확인해야 합니다.

RISC-V Specifications

문서내용커널 개발 활용
Unprivileged ISA (Volume I) 기본 정수 ISA + 표준 확장 RV64I, M/A/F/D/C 확장, 원자적 명령어(AMO), 벡터(V) 확장
Privileged ISA (Volume II) 특권 아키텍처 M/S/U 모드, CSR, 페이지 테이블(Sv39/48/57), 인터럽트/예외, H 확장(가상화)
SBI Specification Supervisor Binary Interface OpenSBI와의 인터페이스, 타이머/IPI/리모트 fence 호출
PLIC Specification Platform-Level Interrupt Controller 외부 인터럽트 라우팅, 우선순위 — drivers/irqchip/irq-sifive-plic.c
AIA Specification Advanced Interrupt Architecture APLIC + IMSIC, MSI 기반 인터럽트 — 차세대 RISC-V 인터럽트 체계
RISC-V의 특징: RISC-V 스펙은 오픈 표준으로 누구나 무료로 접근할 수 있습니다. 커널 코드에서는 arch/riscv/ 하위의 구현이 스펙의 각 챕터와 직접 대응됩니다. 특히 Privileged ISA Vol. II의 페이지 테이블과 예외 처리 챕터는 커널 개발의 핵심 참조 문서입니다.

매뉴얼 효과적 활용법

상황참조 문서참조 섹션
페이지 테이블 워크 디버깅 Intel SDM Vol. 3 Ch. 4 / ARM ARM D5 / RISC-V Priv. Ch. 4 페이지 테이블 엔트리 형식, 비트 필드 의미
인터럽트 핸들러 작성 Intel SDM Vol. 3 Ch. 6, 10 / GIC Spec / PLIC Spec IDT 구조, APIC 프로그래밍, EOI 처리
메모리 배리어 선택 Intel SDM Vol. 3 Ch. 8 / ARM ARM B2 / RISC-V Unpriv. Ch. 14 메모리 순서 모델, fence/barrier 명령어
KVM 가상화 구현 Intel SDM Vol. 3 Ch. 23-33 / AMD APM Vol. 2 / ARM ARM D1 VMCS/VMCB 구조, VM entry/exit, EPT/NPT, EL2
전력 관리 (cpuidle/cpufreq) Intel SDM Vol. 3 Ch. 14 / ACPI Spec / ARM DEN0024A C-state, P-state, MWAIT, WFI
보안 기능 구현 각 제조사 보안 가이드 Intel CET, ARM MTE/PAC/BTI, AMD SEV/SME
추가 권장 문서:
  • ACPI Specification — 전원 관리, 디바이스 열거, 테이블(DSDT/SSDT) — x86과 ARM64 서버 모두 사용
  • UEFI Specification — EFI stub, Boot Services, Runtime Services
  • PCI Express Base Specification — PCIe 구성 공간, MSI/MSI-X, AER, SR-IOV
  • IOMMU Specification — Intel VT-d Spec / AMD IOMMU Spec / ARM SMMU Spec
  • Devicetree Specification — ARM/RISC-V 하드웨어 기술, 바인딩 규칙
  • 각 SoC 벤더 데이터시트 — Qualcomm, Samsung, Broadcom, SiFive 등 벤더별 구현 상세

x86 CPU 실행 모드 심화 (Operating Modes)

x86 프로세서는 리셋 후 Real Mode에서 시작하여 여러 모드를 거쳐 Long Mode에 도달합니다. 리눅스 커널 부팅 과정은 이 모드 전환을 순차적으로 수행하며, 각 모드의 특성을 이해하는 것은 부트로더 코드와 커널 초기화 코드를 분석하는 데 필수적입니다.

모드 전환 흐름

Real Mode 16-bit, 1MB Protected Mode 32-bit, 4GB PAE Mode 32-bit, 64GB Compatibility 32-bit (in 64) Long Mode 64-bit, 256TB+ PE=1 PAE=1 EFER.LME=1 CS.L=0

Real Mode (리얼 모드)

특성설명
비트 폭16비트 레지스터, 20비트 주소 (세그먼트:오프셋 = 세그먼트×16 + 오프셋)
주소 공간1MB (0x00000 ~ 0xFFFFF), A20 게이트로 확장 가능
보호 기능없음 — 모든 코드가 전체 메모리/I/O 포트 접근 가능
인터럽트IVT(Interrupt Vector Table) at 0x0000 (256 × 4바이트)
커널 사용부트로더 초기 단계, BIOS 서비스 호출, A20 활성화
; arch/x86/boot/header.S — 리눅스 부팅 초기 (Real Mode)
; BIOS가 이 코드를 0x7C00에 로드하여 실행

; A20 게이트 활성화 (20번째 주소 라인)
; A20이 비활성이면 1MB 이상 주소에 접근 불가
    in      al, 0x92        ; Fast A20 (System Port)
    or      al, 2
    out     0x92, al

; Protected Mode로 전환 준비
    lgdt    [gdt_ptr]        ; GDT 로드
    mov     eax, cr0
    or      eax, 1           ; PE (Protection Enable) 비트 설정
    mov     cr0, eax         ; → Protected Mode 진입!
    jmp     0x08:pm_entry   ; far jump로 CS 갱신 (GDT 셀렉터 0x08)

Protected Mode (보호 모드)

특성설명
비트 폭32비트 레지스터, 32비트 주소
주소 공간4GB (PAE 미사용 시), 세그먼테이션 + 페이징
보호 기능Ring 0~3, 세그먼트 기반 접근 제어, 페이지 기반 보호
핵심 자료구조GDT(Global Descriptor Table), IDT(Interrupt Descriptor Table), TSS(Task State Segment)
커널 사용32비트 리눅스 커널 (i386), 64비트 부팅 과정의 중간 단계
/* GDT 엔트리 구조 (Intel SDM Vol.3 Section 3.4.5) */
struct gdt_entry {
    u16 limit_low;        /* 세그먼트 크기 [15:0] */
    u16 base_low;         /* 베이스 주소 [15:0] */
    u8  base_mid;          /* 베이스 주소 [23:16] */
    u8  access;            /* P | DPL(2) | S | Type(4) */
    u8  granularity;       /* G | D/B | L | AVL | Limit[19:16] */
    u8  base_high;         /* 베이스 주소 [31:24] */
} __attribute__((packed));

/* Linux의 GDT 레이아웃 (arch/x86/include/asm/segment.h) */
/* 인덱스 0: NULL 디스크립터 (필수) */
/* __KERNEL_CS (0x10): Ring 0 코드 세그먼트, DPL=0 */
/* __KERNEL_DS (0x18): Ring 0 데이터 세그먼트, DPL=0 */
/* __USER_CS   (0x23): Ring 3 코드 세그먼트, DPL=3 */
/* __USER_DS   (0x2B): Ring 3 데이터 세그먼트, DPL=3 */
/* Per-CPU GDT: 각 CPU마다 별도의 TSS, TLS 엔트리 */

/* 주의: Long Mode에서는 세그먼테이션이 거의 비활성화 */
/* CS, SS만 의미 있고 나머지 세그먼트의 base/limit은 무시됨 */
/* 단, FS/GS base는 MSR(FS_BASE, GS_BASE)로 설정하여 */
/* per-CPU 데이터 및 TLS 접근에 사용 */

PAE (Physical Address Extension)

/* PAE 모드: 32비트 CPU에서 4GB 이상 물리 메모리 접근 */
/* CR4.PAE=1로 활성화 */
/* 페이지 테이블 엔트리가 32비트 → 64비트로 확장 */
/* 물리 주소: 36비트 → 최대 64GB */

/* PAE 페이지 테이블 구조:
 *   PDPT (4 엔트리) → PD (512 엔트리) → PT (512 엔트리) → 4KB 페이지
 *   CR3 → PDPT (32바이트, 4 × 8바이트 엔트리)
 */

/* PAE는 NX(No-Execute) 비트의 전제 조건 */
/* PTE bit 63 = NX: 해당 페이지의 코드 실행 금지 */
/* → 스택/힙 실행 방지 (DEP/W^X) */

/* Long Mode 전환에도 PAE 활성화 필수 (전제 조건) */

Long Mode (IA-32e Mode / 64-bit Mode)

/* Long Mode 전환 순서 (Intel SDM Vol.3 Section 9.8.5) */
/*
 * 1. Protected Mode에서 시작 (PE=1)
 * 2. PAE 활성화: CR4.PAE = 1
 * 3. 4-level 페이지 테이블 설정: CR3 = PML4 물리 주소
 * 4. Long Mode 활성화: IA32_EFER.LME = 1 (MSR 0xC0000080)
 * 5. 페이징 활성화: CR0.PG = 1
 *    → 이 순간 Long Mode 진입 (IA32_EFER.LMA=1 자동 설정)
 * 6. far jump로 64비트 코드 세그먼트로 점프 (CS.L=1)
 */

/* arch/x86/boot/compressed/head_64.S — 실제 커널 모드 전환 */
/* Long Mode 전환 코드 (간략화) */
    movl    $MSR_EFER, %ecx
    rdmsr
    btsl    $_EFER_LME, %eax   /* LME 비트 설정 */
    wrmsr                          /* EFER에 기록 */

    movl    %cr0, %eax
    orl     $X86_CR0_PG, %eax   /* PG 비트 설정 */
    movl    %eax, %cr0             /* → Long Mode 활성화! */

    ljmp    $__KERNEL_CS, $startup_64  /* 64-bit 코드로 점프 */

Long Mode 서브모드

서브모드CS.LCS.D동작용도
64-bit Mode 1 0 64비트 주소/오퍼랜드, RIP-relative, 확장 레지스터(R8~R15) 커널, 64비트 유저 프로세스
Compatibility Mode 0 1 32비트 주소/오퍼랜드 (Protected Mode와 동일한 명령어 인코딩) 32비트 유저 프로세스 실행 (ia32 compat)
Compatibility Mode와 커널: 64비트 리눅스에서 32비트 바이너리를 실행하면 유저 공간은 Compatibility Mode(CS.L=0)로 동작하지만, 시스템 콜로 커널에 진입하면 항상 64-bit Mode로 전환됩니다. arch/x86/entry/entry_64_compat.Sentry_SYSENTER_compatentry_SYSCALL_compat가 이 전환을 처리합니다.

CPU 모드 전환 주의사항

모드 전환 시 핵심 주의사항:
  • GDT/IDT 준비 — Protected/Long Mode 전환 전에 반드시 유효한 GDT를 설정. 잘못된 GDT는 Triple Fault → 리셋
  • A20 게이트 — Real→Protected 전환 전 A20 활성화 필수. 비활성 시 홀수 MB 주소에 접근 불가
  • Identity Mapping — 모드 전환 직후 코드가 실행되는 주소에 대해 가상=물리 매핑(identity mapping)이 있어야 함. 없으면 즉시 페이지 폴트
  • PAE 선행 — Long Mode 진입에 PAE 필수. PAE 없이 LME 설정 후 PG 활성화하면 #GP
  • CR3 유효성 — Long Mode에서 CR3는 PML4/PML5 테이블의 물리 주소. 잘못된 값은 즉시 크래시
  • 5-level 페이징 (LA57) — Intel Ice Lake+에서 CR4.LA57=1로 PML5 활성화 시 57비트 가상 주소 (128PB). 커널 CONFIG_X86_5LEVEL 필요
  • UEFI 부팅 — UEFI는 이미 Protected/Long Mode로 진입한 상태에서 커널을 호출. EFI stub은 모드 전환 없이 직접 커널 초기화 진행

제어 레지스터(CR) 요약

레지스터주요 비트기능
CR0 PE, PG, WP, NE, MP, TS 보호모드(PE), 페이징(PG), 쓰기 보호(WP), FPU 상태(TS/MP)
CR2 (전체) Page Fault 발생 시 폴트 주소 저장
CR3 PCD, PWT, PCID 페이지 테이블 베이스(PML4/PML5), PCID로 TLB 태깅
CR4 PAE, PSE, PGE, OSFXSR, OSXSAVE, LA57, PCIDE, SMEP, SMAP, PKE PAE, 큰 페이지(PSE), 전역 페이지(PGE), SIMD(OSFXSR), 보안(SMEP/SMAP)
CR8 (TPR) [3:0] Task Priority Register — 인터럽트 우선순위 마스킹 (Long Mode 전용)
EFER (MSR) LME, LMA, SCE, NXE Long Mode 활성화(LME/LMA), SYSCALL(SCE), NX 비트(NXE)