- 컴퓨터의 전원 버튼을 누른 순간부터 리눅스 커널이 실행되기까지의 과정을 단계별로 설명한 기술 해설
- CPU가 리얼 모드(real mode) 에서 시작해 프로텍티드 모드(protected mode) 와 롱 모드(long mode) 로 진입하는 과정을 구체적으로 다룸
-
BIOS/UEFI 펌웨어, 부트로더(GRUB) , 커널 압축 해제 및 주소 재배치 등 각 단계의 역할과 동작 원리를 상세히 기술
-
메모리 매핑, 인터럽트, 페이지 테이블, kASLR 등 커널 초기화에 필요한 핵심 개념을 간결한 예시와 함께 설명
- 리눅스 부팅의 내부 메커니즘을 이해함으로써 시스템 아키텍처, 보안, 성능 최적화에 대한 통찰을 제공
Part 1 — 전원 버튼에서 커널의 첫 실행까지
-
전원 버튼을 누르면 CPU가 리얼 모드(real mode) 로 리셋되어 초기 명령을 실행
- 리얼 모드는 8086 시절부터 존재한 단순한 주소 체계로, 세그먼트(segment) 와 오프셋(offset) 을 조합해 물리 주소를 계산
- 예: physical_address = (segment << 4) + offset
- CPU는 리셋 후 0xFFFFFFF0 주소(리셋 벡터)로 점프해 펌웨어로 제어를 넘김
-
레지스터(register) 는 CPU 내부의 초고속 저장 슬롯로, CS(코드 세그먼트), IP(명령 포인터) 등이 있음
- CS는 현재 코드의 위치, IP는 다음 실행 명령을 가리킴
BIOS와 UEFI
-
BIOS 는 오래된 펌웨어로, POST(전원 자가 진단) 후 부팅 순서를 확인하고 부팅 가능한 디스크를 탐색
- 부팅 가능한 디스크는 첫 512바이트 섹터 끝이 0x55AA로 표시됨
- BIOS는 이 섹터를 0x7C00 주소로 복사 후 점프해 실행
-
UEFI 는 현대적 대체 기술로, 파일시스템을 직접 이해하고 더 큰 부트 프로그램을 로드 가능
- BIOS와 달리 “첫 섹터” 제약이 없으며, OS에 더 풍부한 시스템 정보를 전달
부트로더(bootloader)
-
부트로더 는 커널을 메모리에 적재하고 실행 준비를 하는 프로그램
- 대표적으로 GRUB 이 사용되며, 설정 파일을 읽고 커널과 초기 램디스크(initrd)를 메모리에 로드
- 커널 파일은 리얼 모드용 작은 설정 프로그램과 압축된 커널 본체로 구성
- GRUB은 커널 위치, 커맨드라인, initrd 위치 등의 정보를 setup header 구조체에 기록 후 커널 설정 코드로 점프
설정 프로그램(setup code)
- 커널 실행 전 예측 가능한 작업 공간을 만드는 역할 수행
- 세그먼트 레지스터(CS, DS, SS)를 정렬하고 direction flag 를 클리어해 메모리 복사가 일정하게 동작하도록 설정
-
스택(stack) 을 생성해 함수 호출 시 임시 데이터를 저장
-
BSS 영역(초기값 0으로 시작해야 하는 전역 변수 공간)을 0으로 초기화
-
earlyprintk 옵션이 있으면 시리얼 포트를 설정해 초기 디버그 메시지 출력 가능
- 펌웨어에 RAM 맵(e820) 을 요청해 사용 가능한 메모리 영역과 예약 영역을 파악
- 모든 준비가 끝나면 첫 C 함수인 main을 호출, 이후 모드 전환 단계로 진입
인터럽트(interrupt)
-
인터럽트 는 CPU가 현재 작업을 잠시 멈추고 긴급 처리를 수행하는 메커니즘
- 키 입력, 타이머 등 하드웨어 이벤트가 대표적
-
마스크 가능 인터럽트 는 일시 차단 가능, NMI(Non-Maskable Interrupt) 는 항상 처리됨
- 모드 전환 중에는 예기치 않은 인터럽트를 방지하기 위해 일시적으로 차단
Part 2 — 리얼 모드에서 32비트, 그리고 64비트로
- 현대 리눅스는 x86_64 아키텍처의 롱 모드(long mode) 에서 동작
- 리얼 모드 → 프로텍티드 모드 → 롱 모드 순으로 단계적 전환 필요
프로텍티드 모드(protected mode)
- 1980년대 한계를 넘기 위해 도입된 32비트 모드로, 두 가지 핵심 구조를 가짐
-
GDT(Global Descriptor Table) : 세그먼트의 시작 주소, 크기, 권한을 정의
- 리눅스는 플랫 모델(flat model) 을 사용해 전체 32비트 공간을 하나의 연속 영역으로 단순화
-
IDT(Interrupt Descriptor Table) : 인터럽트 발생 시 호출할 핸들러 주소를 저장
- 부팅 중에는 최소한의 IDT만 로드하고, 커널 초기화 후 완전한 IDT를 설치
모드 전환 과정
- 설정 코드가 먼저 인터럽트 비활성화, PIC 칩 정지, A20 라인 활성화, 수학 보조 프로세서 초기화 수행
- A20 라인은 1MB 주소 래핑 문제를 해결하기 위한 역사적 장치
- 최소한의 GDT와 IDT를 로드한 뒤, CR0 레지스터의 PE 비트를 설정하고 far jump 수행
- 이로써 프로텍티드 모드 진입, 세그먼트 및 스택 포인터를 새 주소 체계에 맞게 재설정
제어 레지스터(control registers)
-
CR0: 프로텍티드 모드 활성화
-
CR3: 페이지 테이블의 최상위 주소 저장
-
CR4: PAE 등 확장 기능 활성화
롱 모드(long mode) 진입 준비
- 64비트 모드로 전환하려면 두 가지 조건 필요
-
페이징(paging) 활성화: 가상 주소와 물리 주소 간 매핑 수행
-
EFER 레지스터의 LME(Long Mode Enable) 비트 설정
- 페이지 테이블은 4KB 단위 페이지를 매핑하며, 초기 부팅 시에는 2MB 단위의 identity map 으로 단순 구성
페이징 활성화 절차
-
PAE 기능을 CR4에서 켜고, 저주소 영역을 2MB 단위로 커버하는 최소 페이지 테이블 생성
- 최상위 테이블 주소를 CR3에 기록 후 페이징 활성화
- EFER의 LME 비트를 세팅하고 64비트 코드로 점프해 롱 모드 진입
- 주소와 레지스터가 64비트 폭으로 확장된 상태에서 커널 실행 준비 완료
Part 3 — 커널 압축 해제, 주소 수정, 그리고 자기 이동
- 이제 CPU는 64비트 모드이며, 메모리에는 압축된 커널 이미지 가 존재
- 작은 64비트 스텁(stub)이 커널을 해제하고 주소를 조정하는 역할 수행
초기 정리 및 안전 장치 설정
- 스텁은 자신의 실제 실행 위치를 계산하고, 커널이 겹칠 경우 자기 복사(self-relocation) 로 안전한 위치로 이동
- 자신의 BSS 영역 초기화, 간단한 IDT 로드 (페이지 폴트와 NMI 핸들러 포함)
- 페이지 폴트 발생 시 누락된 매핑을 즉시 추가해 복구
- 커널, 부트 파라미터, 커맨드라인 버퍼 등 필요한 영역에 대한 identity 매핑 생성
커널 압축 해제
-
extract_kernel 함수가 실행되어 커널 압축을 해제
- gzip, xz, zstd, lzo 등 다양한 압축 알고리듬 지원
- 해제 후 ELF 헤더 를 읽어 코드/데이터 섹션을 올바른 주소로 복사
- 커널이 빌드된 주소와 실제 로드 주소가 다를 경우 재배치(relocation) 수행
- 주소를 포함한 명령어나 포인터를 수정해 실제 메모리 위치에 맞춤
- 모든 준비가 끝나면 start_kernel 함수 로 점프하며, 본격적인 커널 초기화 시작
커널의 자기 이동(kASLR)
-
kASLR (Kernel Address Space Layout Randomization) 은 커널의 물리·가상 주소를 무작위화해 공격 난이도 상승
- 부팅 시 두 개의 기준(base)을 무작위로 선택
- 물리적 베이스: 커널이 실제로 위치할 RAM 주소
- 가상 베이스: 커널이 사용할 가상 주소 시작점
- 선택 과정
- 부트로더, initrd, 커맨드라인 버퍼 등 보호해야 할 영역 목록 작성
- 펌웨어의 메모리 맵을 스캔해 충분히 큰 빈 영역 탐색
- 하드웨어 난수 명령 등에서 얻은 엔트로피 로 무작위 슬롯 선택
- 적절한 영역이 없으면 기본 주소로 복귀하며, nokaslr 옵션 시 무작위화 비활성화
용어 요약
-
Hexadecimal(16진수) : 0x 접두어로 표시, 하드웨어 비트 구조와 정렬이 용이
-
Register: CPU 내부의 임시 저장소 (CS, DS, SS, IP, SP 등)
-
Segment/Offset: 리얼 모드 주소 계산 방식 (segment * 16 + offset)
-
BIOS/UEFI: 시스템 초기화 및 부트 프로그램 로드 담당 펌웨어
-
Bootloader(GRUB) : 커널 로드 및 시스템 정보 전달
-
Stack/BSS: 함수 임시 저장소 및 0으로 초기화된 전역 변수 영역
-
Interrupt/NMI: 하드웨어·소프트웨어 이벤트 처리 메커니즘
-
GDT/IDT: 세그먼트 및 인터럽트 정의 테이블
-
A20 Line: 1MB 주소 래핑 방지 스위치
-
Protected Mode/Long Mode: 32비트 및 64비트 실행 모드
-
Paging/Page Tables: 가상 주소와 물리 주소