# 리눅스 부팅 과정: 전원 버튼에서 커널까지

> Clean Markdown view of GeekNews topic #23925. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=23925](https://news.hada.io/topic?id=23925)
- GeekNews Markdown: [https://news.hada.io/topic/23925.md](https://news.hada.io/topic/23925.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-10-26T19:34:01+09:00
- Updated: 2025-10-26T19:34:01+09:00
- Original source: [0xkato.xyz](https://www.0xkato.xyz/linux-boot/)
- Points: 2
- Comments: 1

## Topic Body

- 컴퓨터의 **전원 버튼을 누른 순간부터 리눅스 커널이 실행되기까지**의 과정을 단계별로 설명한 기술 해설  
- 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**: 가상 주소와 물리 주소

## Comments



### Comment 45475

- Author: neo
- Created: 2025-10-26T19:34:02+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45707658) 
- 정말 좋은 글이었음. 몇 달 전 나도 **Linux 부팅 과정**에 대해 글을 썼는데, 디스크 I/O 측면(디스크에 무엇이 있고, 어떻게 로드되는지)에 좀 더 초점을 맞췄음  
  내 글은 [Booting x86-64](https://blog.davidv.dev/posts/booting-x86-64/)에서 볼 수 있음
- 페이지 소스에 이런 코드가 있었음  
  ```html
  &lt;!-- Femboy Mode Button - Hidden on Mobile --&gt;
  &lt;button class="rave-button" id="raveButton" onclick="toggleRaveMode()" title="Femboy Mode" style="display: none;"&gt;
    &lt;span class="button-text"&gt;uwu&lt;/span&gt;
  &lt;/button&gt;
  ```  
  이게 뭐지 하는 느낌이었음
  - 아직 **작업 중인 기능**임
- **UEFI**는 펌웨어가 구현한 인터페이스임. 즉, 펌웨어 자체가 아니라 펌웨어와 대화하기 위한 표준 인터페이스라는 뜻임  
  “UEFI가 머신을 시작한다”는 표현은 약간 잘못된 용어 사용임. 실제로는 펌웨어가 머신을 시작하고, 우리는 UEFI를 통해 펌웨어와 통신함  
  이 글은 현대 펌웨어의 흥미로운 부분들을 많이 생략하고 있음. 예를 들어 `ExitBootServices()`를 호출할 때 이미 **long mode**에 진입해 있음. 굳이 real/protected 모드 전환 과정을 거칠 필요가 없음
  - 이런 내용을 더 읽을 수 있는 자료가 어디 있는지 궁금함
- 전원 버튼이 정말로 CPU를 직접 켜는지 궁금했음. 아마도 **Intel Management Engine**(또는 AMD의 유사 기능)이 항상 켜져 있다가 전원 버튼 신호를 받아 CPU를 시작시키는 구조일 수도 있음
  - 그 역할은 **Embedded Controller(EC)** 가 담당한다고 생각함. 부트로더가 CPU를 올리기 전에 동작하는 부분임  
    Chromebook에서는 이 부분이 **coreboot** 부트로더와 함께 오픈소스로 공개되어 있음  
    관련 문서는 [Chromium EC Zephyr README](https://chromium.googlesource.com/chromiumos/platform/ec/+/HEAD/docs/zephyr/README.md)에서 볼 수 있음
- 이 글보다 좀 더 **상세한 버전의 글**을 찾고 있음. 마이크로프로세서 데이터시트를 통째로 읽고 싶진 않지만, UEFI/BIOS 이전 단계까지 좀 더 깊게 다루는 자료가 있으면 좋겠음
- 글이 흥미롭긴 한데, 한편으로는 왜 **16진수(HEX)** 설명까지 들어가야 하는지 의문이었음. 이런 수준의 글을 읽는 사람이 그걸 모를까 싶었음  
  또 한 가지 궁금한 점은, 물리적인 전원 버튼을 누르는 순간 어떻게 **reset vector**로 연결되는가 하는 부분임. 이건 하드웨어와 전자회로의 마법 같은 영역임
  - HN은 IT 전문가만 보는 곳이 아님. Linux 부팅 과정이 궁금하지만 16진수 개념을 잘 모르거나 잊은 사람도 있을 수 있음
- 주제는 흥미롭지만 **너무 초보자 대상**으로 느껴졌음
  - “전원이 안정화되면 CPU는 real mode로 리셋된다” 같은 설명을 보면, 내 **할머니가 이런 걸 이해할 정도로 능숙한 분**인가 싶었음
  - 대학에서 **독자 분석(audience analysis)** 을 배웠는데, 어떤 지식이 이미 있다고 가정할지, 어떤 용어나 약어를 풀어야 할지 판단하는 게 중요함. 기술 글쓰기에서 이건 일종의 예술임
- 모바일에서 읽기 힘들었음. 글자색이 너무 흐림
  - 데스크톱 브라우저에서도 **스타일링이 별로**였음. Firefox나 Firefox Mobile의 **리더 모드**를 쓰면 훨씬 읽기 좋음
  - 약간 **자기비하식 디자인**처럼 보였음
- GRUB이 언급되긴 했지만 자세히 다루지 않았음  
  관련해서는 [Pixelbeat의 디스크 구조 문서](https://www.pixelbeat.org/docs/disk/)가 도움이 됨
- 이 글을 보고 예전에 **Facebook 기술 면접**을 봤던 기억이 났음. 2010년쯤 Production Engineer 포지션 전화 인터뷰였는데, “Linux 서버의 부팅 과정을 설명하라”는 질문을 받았음  
  더 깊이 들어가서 설명하라는 힌트 외엔 아무 도움도 없었음. 결국 더블린으로 이사하지 않았고, 뭐 surveillance capitalism 어쩌고 하면서 포도는 아직 덜 익은 셈이었음
