64bit 멀티코어 OS 원리와 구조 - Day 1

이 글은 ‘64비트 멀티코어 OS 원리와 구조 - 한승훈 저자’을 공부하며 정리한 내용을 작성했습니다.

세상에서 가장 간단한 BootLoader

부트 로더를 정상적으로 불러오기 위해서는 한가지 규칙이 있다. 먼저 부트 섹터 512Byte의 마지막 2Byte는 반드시 0x55, 0xAA를 가져야 한다. 아래는 세상에서 가장 간단한 부트로더를 작성한 소스 코드이다.

1
2
3
4
5
6
7
8
[ORG 0x00]
[BITS 16]

SECTION .text
jmp $
times 510 - ($ - $$) db 0x00
db 0x55
db 0xAA

위 코드에서 [ORG 0x00]은 0x00 메모리 주소에서 시작한다는 의미이며, [BITS 16]은 아래 코드는 16bit라고 알려준다. SECTION .text은 .text 섹션의 시작을 의미하고 jmp $은 현재 위치에서 무한 Loop을 하며 대기하게 한다. 여기까지 총 몇 Byte가 작성된 지 소스 코드로는 확인이 어렵기에 510byte (512byte에서 마지막 0x55, 0xAA 2byte를 뺀 숫자)만큼 채우기 위해서 times 510 - ($ - $$) db 0x00이라고 표현한다. 이 의미는 $(현재 주소)이에서 $$(섹션의 주소)를 뺀 값, 다시 말해 총 생성된 opcode 크기를 뺀 나머지를 0x00으로 채우겠다는 의미이다. 이후 0x55, 0xAA를 채우면 정확히 512byte 크기의 바이너리 파일이 생성되게 된다.

화면 버퍼 제어

어릴 적 컴퓨터를 키면 깜빡이는 커서와 함께 뜻 모를 영어들이 주룩주룩 나오는 걸 본 기억이 있다. 현재 작성된 Boot Loader에 위와 같은 기능을 구현하기 위해서는 비디오 메모리에 형식에 맞춰 데이터를 넣어주는 거로 구현할 수 있다. 그러기 위해선 비디오 메모리의 시작 주소 0xB8000에 문자 1 Byte, 속성 1 Byte 총 2 Byte인 형식에 맞춰 가로 80, 세로 25자 총 4000 Byte에 작성하게 된다.

1
2
3
4
5
6
7
8
... 생략 ...
SECTION .text
mov ax, 0xb800
mov ds, ax
mov byte[0x00], 'J'
mov byte[0x01], 0x4A
jmp $
... 생략 ...

이렇게 작성하고 QEMU를 실행하면 첫 글자가 빨간 배경의 J가 보이게 된다.

세그먼트 초기화

BIOS가 Boot Loader를 디스크에서 메모리(메모리의 0x7c00에 복사한다.)에 복사를 하게 되고 Boot Loader가 코드를 수행하기 전 세그먼트를 초기화하지 않으면 BIOS에서 사용했던 세그먼트 값으로 인해 예기치 못한 오류가 생길 수 있다. 그렇기 때문에 Boot Loader에선 먼저 세그먼트를 초기화 해주는 게 중요하다. 이 책에서는 CS(코드 세그먼트), DS(데이터 세그먼트), ES(비디오 메모리를 위해 사용될 세그먼트)를 각각 0x07c0, 0x07c0, 0xb800으로 초기화한다. 여기서 CS는 mov 명령어로 수정할 수 없기 때문에 jmp 명령어를 이용하는데 코드는 다음과 같다.

1
2
3
4
5
6
jmp 0x07c0:START
START:
mov ax, 0x07c0
mov ds, ax
mov ax, 0xb800
mov es, ax

화면 정리 및 메세지 출력

우리는 지금까지 Boot loader를 만들고, 세그먼트를 초기화했다. 이제 미리 출력된 메시지를 지우고, 우리의 메시지를 출력하도록 해보자.

먼저 화면을 정리하기 위해서는 기존 비디오 메모리에 있던 내용을 지워줄 필요가 있다.

1
2
3
4
5
i = 0
while i<80*25*2
vdomem[i]=0
vdomem[i+1]=0x0A
i+=2

의사 코드로 표현하면 위 코드처럼 표현할 수 있다. 이를 어셈블리어로 움기면 다음과 같다.

1
2
3
4
5
6
7
	mov si, 0
.SCREENCLEARLOOP:
mov byte[es:si], 0
mov byte[es:si+1], 0x0a
add si, 2
cmp si, 80*25*2
jl .SCREENCLEARLOOP

다음으로 문자열을 출력하는 코드를 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	mov si, 0
mov di, 0
.MESSAGELOOP:
mov cl, byte[si+MESSAGE1]
cmp cl, 0
je .MESSAGED

mov byte [es:di], cl
add si, 1
add di, 2

jmp .MESSAGELOOP
.MESSAGED:

MESSAGE1: db 'JUNOS BootLoader...!', 0

최종 BootLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[ORG 0x00]
[BITS 16]

SECTION .text

jmp 0x07c0:START
START:
mov ax, 0x07c0
mov ds, ax
mov ax, 0xb800
mov es, ax

mov si, 0
.SCREENCLEARLOOP:
mov byte[es:si], 0
mov byte[es:si+1], 0x0a
add si, 2
cmp si, 80*25*2
jl .SCREENCLEARLOOP

mov si, 0
mov di, 0
.MESSAGELOOP:
mov cl, byte[si+MESSAGE1]
cmp cl, 0
je .MESSAGED
mov byte [es:di], cl
add si, 1
add di, 2
jmp .MESSAGELOOP
.MESSAGED:
jmp $

MESSAGE1: db 'JUNOS BootLoader...!', 0

times 510 - ($ - $$) db 0x00
db 0x55
db 0xAA
Share