리눅스 커널 시작 과정을 이해하기

리눅스 시스템을 부팅하는 과정은 현대 컴퓨팅에서 가장 복잡한 순서 중 하나입니다. 개발자와 시스템 설계자에게는 하드웨어 전원 켜짐부터 완전하게 동작하는 운영 체제로의 전환을 이해하는 것이 커널 패닉 디버깅, 부팅 시간 최적화, 맞춤형 하드웨어 드라이버 개발에 필수적입니다.

이 가이드는 리눅스 커널 시작의 복잡한 여정을 탐구하며, 컴파일된 바이너리 조각이 CPU를 장악하고 아키텍처별 하드웨어를 초기화할 수 있게 하는 기술적 메커니즘을 상세히 설명합니다.

부트로더와 bzImage

시작 과정의 핵심은 bzImage(Big Zipped Image)입니다. 부트로더—예를 들어 GRUB 또는 systemd-boot—는 이 압축된 커널 이미지를 메모리로 로드하는 역할을 합니다. 커널이 일부 부트 섹터에 원시 비압축 형태로 저장하기에는 너무 크기 때문에, bzImage 형식은 커널을 압축하여 공간을 절약하고 동일 이미지의 layanan(서비스) 영역에 저장할 수 있게 합니다.

부트로더가 제어권을 넘겨주면 커널은 압축 해제 과정을 시작합니다. setup code라고 알려진 작은 어셈블리 코드 조각이 가장 먼저 실행됩니다. 이 코드는 CPU와 기본 메모리 관리를 준비한 뒤 메인 커널 진입점으로 점프하는 역할을 합니다.

하드웨어 및 아키텍처 초기화

커널이 C 코드를 실행하기 전에 기본 환경을 구축해야 합니다. 이는 여러 중요한 단계들을 포함합니다:

  • CPU 초기화: 커널은 CPU 레지스터를 설정하고 실모드에서 보호 모드(x86 아키텍처의 경우)로 전환하여 시스템의 나머지 메모리 접근을 가능하게 해야 합니다.
  • 메모리 매핑: 커널은 가상 메모리를 활성화하기 위해 초기 페이지 테이블을 설정합니다. 이는 커널이 가상 주소 공간에서 동작하도록 하여 물리 메모리 위치와 커널의 논리적 관점을 분리하는 중요한 단계입니다.
  • 메모리 관리: 커널은 물리 RAM을 효율적으로 관리하기 위해 메모리 할당자(슬랩 할당자와 버디 시스템)를 초기화합니다.

initrd와 initramfs의 역할

커널 시작에서 가장 큰 도전 과제 중 하나는 "닭과 달걀" 문제입니다: 커널은 루트 파일시스템을 읽기 위해 디스크 컨트롤러를 구동해야 하지만, 해당 디스크 컨트롤러용 드라이버는 커널 이미지를 작게 유지하기 위해 종종 모듈로 컴파일됩니다.

이를 해결하기 위해 리눅스는 initrd(initial RAM disk) 또는 initramfs(initial RAM filesystem)를 사용합니다. 이는 부트로더가 커널과 함께 메모리에 로드하는 작고 임시적인 파일시스템이며, 디스크의 실제 루트 파일시스템을 마운트하는 데 필요한 필수 드라이버와 스크립트를 포함합니다.

유사한 시스템을 구현한 커뮤니티 구성원들(예: LTSP 프로젝트)이 언급했듯이, TFTP를 통해 커널을 가져오고 NFS를 통해 루트 파일시스템을 마운트하는 기능은 이 메커니즘의 강력한 활용 사례이며, 디스크 없는 부팅과 시스템 이미지의 중앙 집중식 관리가 가능하게 합니다.

사용자 공간으로 전환

필요한 드라이버가 initramfs에서 로드되고 루트 파일시스템이 마운트되면, 커널은 최종 전환을 수행합니다. init 프로세스(보통 /sbin/init 또는 systemd)를 찾아서 프로세스 1(PID 1)이 됩니다.

이 과정은 커널 시작 순서의 끝과 사용자 공간의 시작을 의미합니다. 이제 커널은 단일 스레드·단일 코어 실행 모드에서 완전한 멀티태스킹 환경으로 전환되어 하드웨어 자원을 관리하고 애플리케이션 실행에 필요한 시스템 콜을 제공합니다.

Sources