2. 내 PC를 부팅하자

들어가기

이번 정리에서는 조금 코드 레벨로 들어간다.

본론

2.1 부팅과 부트 로더

모든 OS는 동등하게 512바이트 크기의 부트 로더에서 시작.

2.1.1 부팅과 BIOS

  • 부팅은 OS가 실행되기 전까지 수행되는 작업 과정.
  • 부팅 과정 중 하드웨어와 관련된 작업을 BIOS가 담당, BIOS가 수행하는 테스트나 초기화를 POST라고 부름.
  • BIOS는 펌웨어로 전원이 켜짐과 동시에 프로세서가 가장 먼저 실행하는 코드.
  • BIOS에서 제공하는 기능은 인터럽트를 통해 사용 가능.
  • BIOS의 가장 중요한 일은 부트 로더 이미지를 메모리로 복사하는 단계.
  • 부트 로더는 저장 매체의 가장 앞부분에 존재.
    – 다양한 장치로 부팅할수 있으므로 BIOS는 POST가 완료된 후 여러장치의 앞부분을 검사.
    – 부팅 가능한 모든 장치를 검사했는데 부트 로더를 찾을 수 없다면 에러.

2.1.2 부트 로더의 역할과 구성

  • 저장 매체에서 첫 번째 MBR에 있는 작은 프로그램.
  • 부트 로더의 가장 중요한 일은 OS 이미지를 메모리에 복사.
  • BIOS는 디스크에서 읽은 첫 번째 섹터(512 바이트)가 정삭적인 부트 로더인지 가장 마지막 2 바이트를 확인.
    – 마지막 2 바이트 값이 0x55, 0xAA라면 정상적인 부트 로더.

2.2 부트 로더 제작을 위한 준비

2.2.1 이클립스 프로젝트 생성

  • C 프로젝트를 만들되 프로젝트 유형은 Makefile로 설정.

2.2.2 OS의 디렉터리 구조 생성

  • 리얼 모드, 보호 모드, IA-32e 모드 별로 코드를 나눠서 관리.

2.2.3 makefile 파일 생성

make 프로그램

  • 소스 파일을 이용해 자동으로 실행 파일 또는 라이브러리 파일로 만들어주는 빌드 관련 유틸리티.
  • 소스 파일과 목적 파일을 비교한 뒤 마지막 빌드 후 수정된 파일만 선택하여 빌드.
  • make 프로그램이 빌드를 자동으로 수행하기 위해 각 소스 파일의 의존 관계나 빌드 순서, 옵션 등을 makefile에 작성.

make 문법

1
2
3
4
Target : Dependency
<tab> Command
<tab> Command
<tab> Command

  • Target은 생성할 파일, Dependency는 Target 생성에 필요한 소스, Command는 Dependency에 관련된 파일이 수정되면 실행할 명령.
1
2
3
4
5
6
7
8
9
10
11
12
# a.c, b.c를 통해 output.exe 파일을 생성하는 예제

all : output.exe

a.o : a.c
gcc -c a.c

b.0 : b.c
gcc -c b.c

output.exe : a.o b.o
gcc -o output.exe a.o b.o
  • all은 make를 실행하면서 옵션으로 Target을 명시하지 않으면 사용하는 기본 Target.
1
2
3
4
5
6
7
8
9
10
all : output.exe

libtest.a :
make -C Library

ouput.o : output.c
gcc -c output.c

output.exe : libtest.a output.o
gcc -o output.exe output.o -ltest -L ./
  • make는 빌드를 수행하는 도중에 다른 make를 실행 가능.
    – 즉, 계층적 실행이 가능.
    – 최상위 디렉터리의 하위에 Library 있고, 빌드 과정에서 Library 디렉터리를 빌드 해야하면 C 옵션을 사용.

OS용 makefile 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
all: BootLoader Disk.img
BootLoader:
@echo
@echo ================== Build BootLoader ==================
@echo

make -C 00.BootLoader

@echo
@echo ================== Build Complete ==================
@echo

Disk.img: 00.BootLoader/BootLoader.bin
@echo
@echo ================== Disk Image Build Start ==================
@echo

cp 00.BootLoader/BootLoader.bin Disk.img

@echo ================== All Build Complete ==================

clean:
make -C 00.BootLoader clean
rm -f Disk.img

  • 최상위 makefile의 목적은 OS이미지 생성을 위한 각 하위 디렉터리의 makefile 실행.
1
2
3
4
5
6
7
8
9
# 00.BootLoader 내의 makefile

all: BootLoader.bin

BootLoader.bin: BootLoader.asm
nasm -o BootLoader.bin BootLoader.asm

clean:
rm -f BootLoader.bin
  • 부트 로더 makefile의 목적은 BootLoader.asm을 빌드하여 BootLoader.bin을 생성.

2.3 부트 로더 제작과 테스트

2.3.1 세상에서 가장 간단한 부트 로더

  • 부트 로더를 메모리에 정삭적으로 복사하려면 마지막 2 바이트만 잘 저장하면 됨.

asm 코드 보기

  • 마지막 2 바이트 0x55, 0xAA로 세팅 확인.

2.3.2 QEMU 실행

  • QEMU로 Disk.img를 로드해 실행해 보면 부트 로더가 정상적으로 작동.

2.3.3 화면 버퍼와 화면 제어

  • 위에서 본 asm 코드를 보면 현재 동작 중인 화면 모드와 관련된 비디오 메모리의 주소를 할당.
  • PC 부팅 후 기본 설정되는 화면 모드는 텍스트 모드(가로 80문자, 세로 25문자)로 메모리 주소 0xB8000에서 시작.
  • 화면에 표시되는 문자는 1 바이트의 속성값과 1바이트의 문자값, 총 2 바이트로 구성되며 화면을 구성하는 총 메모리 크기는 80x25x2 = 4000 바이트.

2.3.4 세그먼트 레지스터 초기화와 Hello, World!

세그먼트 레지스터 초기화

  • 이전 BIOS가 부트 로더를 실행했을때 세그먼트에는 BIOS가 사용했던 값들이 저장.
  • Ox07C0으로 초기화.
    – BIOS가 부트 로더를 읽어 메모리에 복사하는 위치가 0x07C00.
    – 0x07C00부터 512 바이트 범위에 코드(code segment)와 데이터(data segment)가 존재.

화면 정리 및 부팅 메시지 출력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mov si, 0

.SCREENCLEANLOOP:
mov byte [ es: si], 0

mov byte [ es: si + 1], 0x0A

add si, 2

cmp si, 80 * 25 * 2

jl .SCREENCLEANLOOP

mov si, 0
mov di, 0

  • QEMU를 실행하면 BIOS가 출력한 메시지 때문에 지저분 -> 정리할 필요.
    – 화면 정리는 0xB8000부터 4000 바이트를 모두 0으로 채움(문자 부분만).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.MESSAGELOOP:
mov cl, byte [ si + MESSAGE1 ]

cmp cl, 0
je .MESSAGEEND

mov byte [ es: di ], cl

add si, 1
add di, 2

jmp .MESSAGELOOP

.MESSAGEEND:
jmp $

MESSAGE1: db 'OS BootLoader Start!!', 0
  • 화면 출력을 나타내는 di 인덱스는 속성값은 바꾸지 않아 2 증가, 문자열 인덱스 si는 1 증가.

2.3.5 부트 로더 테스트

  • 다시 makefile로 빌드 후 QEMU를 실행해보면 정상작동.
  • MESSAGE1을 어떻게 바꾸냐에 따라 문자 변경 가능.
    – 친구에게 인증하려고 저 문구 작성.

마치며

역시 좀 어렵다.
첫 번째는 무작정 코드를 작성하면서 책을 읽고 블로깅의 정리를 위해 2번째 읽고 있다. 몇번 읽어야 이해가 완전히 될까. 그래도 정리를 하면서 이전보다는 확실히 더 깊게 알게된건 확실하다.

Share