[Linux] 1. Linux 부팅 과정에 대해서 알아보자
들어가며
이번 시간에는 Linux 운영체제의 부팅 과정에 대해서 알아보도록 하자.
먼저, 부팅(Booting)이란 무엇일까?
이는 '컴퓨터를 시작할 때 컴퓨터 자기 자신을 구동시킬 프로그램을 스스로 불러내는 동작'을 일컫는다.
인간도 잠에서 깨어나 움직이려면 준비 과정이 필요하듯이 컴퓨터도 준비 과정이 필요하다.
들어가기에 앞서서, 크게 중요한 단어 두 가지와 전반적인 부팅 과정을 알아보고 가겠다.
중요 키워드 두 개: Boot loader & Kernel
Boot Loader
Boot loader는 컴퓨터가 처음 커졌을 때, 운영체제를 불러오는 역할을 한다.
당신이 연극을 보러 갔다고 생각해보자.
표를 들고 입장하는 과정에서 안내해주는 사람이 아무도 없다면 당신을 포함한 관객들은 분명 혼란에 빠질 것이다.
이 때, 안내원은 Boot loader와 유사하다.
극장 문 앞에서 표를 확인하고, 관객들을 각자의 자리에 안내하는 역할을 통해 극장 안의 질서 유지할 수 있다.
마찬가가지로, Boot loader는 운영체제가 실행될 수 있도록 필요한 초기 설정을 하고, Kernel을 메모리에 올려 실행되도록 안내하는 역할을 한다.
Kernel
외람된 말이지만, 씨앗의 내부를 kernel이라고 한다.
장차 미래의 양분이 되기도 하고 유전적인 정보를 담고 있는 부분이기에 매우 중요한 부분이고 외부에서 접근을 할 수 없도록 단단한 것이 특징이다.
컴퓨터에서도 마찬가지이다.
Kernel은 운영체제의 핵심 부분으로, 컴퓨터에서 H/W와 S/W가 상호작용할 수 있도록 중간에서 조율하는 역할을 한다.
마치, 오케스트라의 지휘자와 같다고 할 수 있다.
Kernel을 통해 CPU, 메모리, 디스크 등 다양한 하드웨어 자원들이 효율적으로 사용되도록 조율하고, 프로그램이 제대로 동작할 수 있도록 관리한다.
전반적인 부팅과정
Linux 운영체제의 부팅은 크게 4가지로 분류된다.
해당 내용이 꽤나 긴 감이 없지 않아 있어서, 전반적으로 큰 그림을 한 번 그리고 상세하게 각 내용을 살펴보도록 하겠다.
Stage 1: H/W가 담당한다. 전원이 켜지는 순간과 장비의 이상을 탐지하는 단계이다.
1. 컴퓨터 전원을 켬
2. BIOS 프로그램의 전원이 켜짐
3. 메모리와 CPU가 작동함
4. BIOS 프로그램이 실행됨
5. POST를 통해서 컴퓨터의 이상 유무를 검사함
6. HDD, CD-ROM 등 H/W의 부팅 매체를 검사하여 Boot loader의 위치를 찾아서 실행시킴
Stage 2: Boot loader가 담당한다. Boot loader가 실행되고 커널을 실행하기까지의 과정이다.
1. Boot loader가 core.img 파일을 실행시키고 configuration 파일과 파일 시스템을 위한 드라이버를 로드함.
2. Boot loader가 파일 시스템에 접근하여 커널을 압축 해제하여 실행시키고, 커널이 필요로 하는 모든 드라이버와 모듈, 파일 시스템 등이 담긴 RAM 디스크 파일을 메모리에 로드함.
3. Boot loader가 시스템 제어권을 Kernel에게 넘김
Stage 3: Kernel이 본격적으로 실행된다.
Stage 4: system 초기화 단계로, 파일을 읽어들여서 그 내용을 순서에 따라 시스템을 초기화하는 단계이다.
Stage 1: Hardware
파워 버튼을 통해 컴퓨터 장치에 전원이 공급되면 메인보드에서 Reset Vector를 통해 CPU가 BIOS 코드를 호출하도록 한다.
CPU는 ROM(Read Only Memory)에 저장된 BIOS를 실행하게 된다.
실행된 BIOS는 Legacy BIOS라고도 불리며, 하드디스크의 첫 Sector를 읽어서 첫 Sector에 지시된 주소에 있는 코드를 실행하도록 하는 부팅 절차를 따른다.
모든 intel CPU의 경우에 전원 공급 직후에는 real mode로 동작하게 되는데, 이 시점에서는 전체 메모리의 1MB 영역(0xFFFFFFFF)까지만 접근할 수 있다는 것이 특징이다.
이는 1979년도에 생산된 intel CPU 8086이나, 최신 CPU나 모두 같은 방식으로 동작한다.
BIOS를 실행한 CPU는 처음으로 EIP에 숨겨진 0xFFFFFFF0 주소로 이동하여 해당 주소의 명령어를 수행한다.
해당 주소는 BIOS나 EFI와 같은 펌웨어의 엔트리 포인트로 매핑되는 영역으로 Reset Vector라고도 불린다.
EIP란? Extend Instruction Pointer의 약자로 메모리에 등록되어 있는 CPU가 할 일이 담긴 code의 주소를 가르키는 포인터이다.
추후, 실행된 BIOS에 의해서 POST 검사가 이루어진다.
POST는 Post, get Mapping할 때의 Post가 아니다.
이는 Power On Self Test의 약자로, 흔히 본체 전원을 켰을 때에 "삐" 소리가 나는 과정이라고 한다.
CPU, 메모리, 제어장치, BIOS 내의 자체 코드, 주변 장치 등에 대한 검사를 진행한 후에 H/W들을 초기화하는 작업이다.
POST 과정이 이상 없이 진행이 완료되면 검색된 부팅매체(하드디스크, CD ROM 등)에서 Boot loader를 불러들인다.
해당 디바이스의 Partition Table을 검색하여 시동 Sector를 설정한다.
만약, 디바이스가 파티션이 되어 있다면 시동 Sector를 MBR로 설정하고, 그렇지 않다면 VBR로 설정한다.
(MBR: Master Boot Record의 약자로, VBR: )
시동 Sector가 설정되었다면, BIOS가 시동 Sector에서 Boot loader 코드를 찾는다.
BIOS가 하드 디스크의 MBR(Master Boot Record)에서 Boot loader를 찾고, 해당 Boot loader의 configuration 파일도 찾으면, Boot loader는 약 3~5초 간의 시간을 카운트다운한다.
이 시간 동안에는 사용자는 아무 키를 눌러 Boot loader에 개입할 수 있어서 Boot option을 변경하거나, 다른 OS를 선택하거나, 다른 Kernel을 선택할 수가 있다.)
그 후에 이를 메모리에 적재시키고 BIOS를 종료하여 시스템 제어권을 Boot loader에게 전달한다.
Stage 2: Boot loader(GRUB)
Linux에서 사용하는 Boot loader는 대표적으로 LILO(Linux Loader)와 GRUB(Grand Unified Boot loader)가 있다.
그 중에서 GRUB에 대해서 알아보도록 하겠다.
GRUB는 운영체제가 시동되기 이전에 미리 실행되면서 커널이 올바르게 실행되기 위해 필요한 모든 관련 작업을 마무리하고 최종적으로 운영체제를 실행시키기 위한 목적을 가진 프로그램이다.
GRUB은 1 -> 1.5 -> 2로 총 3단계로 구성되어 있는데, 그 중에서 2단계의 비중이 제일 큰 편이다.
GRUB Stage 1에서는 MBR이나 VBR에 저장되어 있는 Boot image가 메모리에 로드되고 실행되는 것을 뜻한다.
core.img의 첫 번째 Sector가 로드되는 것이다.
GRUB Stage 1.5는 MBR과 첫번째 partition 사이에 있는 블록인 MBR gap에 저장된 core.img가 메모리에 로드되고 실행되는 것을 과정이다.
GRUB Stage 2는 /boot/grub 파일 시스템에 직접 접근하여 vmlinuz(kernel이 압축되어 있는 파일) 파일을 압축 해제하여 메모리에 로드하고 Kernel이 필요로하는 모든 드라이버와 모듈, 파일 시스템(ext2, ext3, ...) 등이 담긴 RAM 디스크 파일(initrd.img)를 메모리에 로드한다.
참고로, Kernel은 메모리에 로드되기 이전에 /boot 아래 압축된 파일 형태로 존재한다.
마지막으로 Kernel image를 불러들이고 최종적으로 시스템 제어권을 kernel에게 넘겨준다.
Stage 3: Kernel
본격적으로 kernel 파일이 실행되는 단계이다.
Stage 2단계까지 진행이 되었다면 Boot loader는 kernel 파일과 RAM 디스크 파일을 메모리에 로드해놓은 상태이다. ( vmlinux-2.6.26-2.686, initrd.img-2.6.26-2-686)
Kernel은 컴퓨터의 각종 H/W를 사용하는 데 필요한 드라이버와 모듈을 불러온다.
해당 시점에서는 주로 H/W의 실패 부분을 찾는다.
관련된 기능이 올바르게 작동하지 않는 문제를 차단해야하기 때문인데, 매우 드물지만 특정 H/W용 드라이버가 없다거나 엉뚱한 드라이버가 로드되는 경우가 있는데, 이를 방지한다.
H/W의 실패가 없다면 로드된 kernel 파일을 실행하고, console에 관련된 정보를 띄어준다.
PCI bus를 점검하고 감지된 주변 장치를 확인한 후에 /var/log/dmesg/ 파일에 로그를 저장한다.
Kernel은 swapper 프로세서(PID 0)를 호출하고, swapper는 kernel이 사용할 각 장치 드라이브들을 초기화한다.
그 후에 Root file system("/" 경로)를 읽기 전용으로 마운트하는데, 이 과정에서 마운트 실패 시에 "Kernel Panic"이라는 오류를 발생시킨다.
만약, 마운트가 성공적으로 실행되었다면 언마운트 후에 Root file system을 읽기 + 쓰기 모드로 다시 마운트하는 작업을 진행하고 Init 프로세스(PID 1)를 호출한다.
Stage 4: Init
Init은 이제 컴퓨터가 실행될 때의 필요한 환경 및 Linux 시스템을 초기화하는 단계이다.
Init system은 크게 sysVinit와 systemd로 구분된다.
sysVinit: 오래된 방식의 초기화 시스템이다.
- sysVinit 1(Configuration. the file /etc/inittab): /etc/inittab의 초기 시스템 구성 파일을 읽어 초기 시스템 구성을 설정한다. 여기서 운영 모드, run level, 콘솔 설정 등을 확인한다.
- sysVinit 2(initailization. the file /etc/init.d/rc): 시스템 초기화 과정이 시작된다. /etc/init.d/rc.S 스크립트가 실행되어 스왑 영역을 로드하고 불필요한 파일 제거, 파일 시스템 점검 및 마운트, 네트워크 활성화 등의 작업이 수행된다.
- sysVinit 3(Services. /etc/init.d 및 /etc/rcN.d 디렉토리들): 지정된 런레벨에 해당하는 스크립트 및 서비스들이 실행된다. /etc/init.d 디렉토리 안의 실행 가능한 서비스들 모두 실행되며, run level별로 실행할 서비스는 /etc/rcN.d에서 관리된다. (S01: 런레벨 1에서 활성화, K01: 런레벨 1에서 비활성화)
systemd: 현대 Linux 배포판에서 널리 사용되는 초기화 시스템.
systemd는 대표적으로 Ubuntu Linux의 init system이다.
Sysvinit에 비해 시작속도가 빠르고, 리눅스 시스템을 보조하는 풀타임 프로세스로 상주한다.
Target 유닛을 사용하여 부팅 시퀀스나 특정 상태를 정의한다.