짱해커가 되어보자

[#1.5] 시작해보자 본문

프로젝트/OS 개발!

[#1.5] 시작해보자

Spadework 2017. 7. 17. 10:48

OS 개발 프로젝트 #1.5



OS개발하는 방법으로, 오로지 2진수만을 사용해서 할 수도 있다.

그래서 이 책의 OS를 만드는 처음 부분은 2진수만을 입력해서 한다.



이렇게, 2진수만 사용해서 1,474,560 Byte 크기의 파일을 만들어준다.

이 코드는 1440*1024 디스플레이를 구성하는 코드라 보면 된다.

실행을 하게 되면, 'hello, world'가 출력된다.


그리고 어쩌면 일부의 사람들이 궁금할 수도 있는 점이,

2진수를 작성한다고 했는데, 왜 16진수로 작성을 할까?

이러한 궁금증이 있을 수 있는데, 이의 답은 2진수와 16진수의 관계에 있다.

간략하게 설명을 하자면, 2진수에서 16진수로의 변환이 쉬우며, 반대인 16진수에서 2진수로의 변환도 쉽기 때문이다.

여기까지만 설명을하겠다. 만약 궁금하다면 검색을 해서 알아보면 될 것 같다.




그러면, 언제까지고 2진수만 사용해서 개발을 할 수는 없으니,

한 단계 나아간 어셈블리어로 개발을 해보겠다.

DB	0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f ; DB = Data Byte (Byte = 8bit, 한 바이트를 (메모리에)쓰는 명령어)
DB	0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
DB	0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
DB	0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
DB	0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
DB	0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4f
DB	0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41
DB	0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00
RESB	16								; RESB = 옆의 숫자만큼 DB 0x00 반복
DB	0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB	0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB	0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB	0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB	0xee, 0xf4, 0xeb, 0xfd, 0x0a, 0x0a, 0x68, 0x65
DB	0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72
DB	0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00
RESB	368
DB	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
DB	0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB	4600
DB	0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB	1469432


이번엔 어셈블리어 코드인데, 이 코드는 위에 나온 바이너리 코드를 어셈블리어 버전으로 작성한 것이다.

그러다 보니 (별 의미가 없다) 똑같이 코드가 길다.

그러나 어셈블리어는 명색의 프로그래밍 언어이다 보니, 0바이트 채우는 부분을 명령어로 쉽게 작성할 수 있다.

여기까지 작성한 코드를 '.nas'파일로 저장한 후에, 컴파일러를 돌리게 되면 이미지파일이 생성된다.

실행 결과는 당연히 이전 코드와 같다.


여기까지는 뭐 딱히 발전된 부분이 많이 보이지 않는다.

하지만 다음으로 보게 될 코드부터 갑자기 확 발전한다.



; TAB=4

; 이하는 표준적인 FAT12 포맷 플로피 디스크를 위한 기술

		DB		0xeb, 0x4e, 0x90
		DB		"HELLOIPL"	; boot sector의 이름은 자유롭게 써도 좋다(8바이트)
		DW		512		; 1섹터의 크기(512로 해야 함)
		DB		1		; 클러스터의 크기(1섹터로 해야 함)
		DW		1		; FAT가 어디에서 시작될까(보통은 1섹터째부터)
		DB		2		; FAT의 개수(2로 해야 함)
		DW		224		; 루트 디렉토리 영역의 크기(보통은 224엔트리로 한다)
		DW		2880		; 드라이브 크기(2880섹터 해야 함)
		DB		0xf0		; 미디어 타입(0xf0해야 함
		DW		9		; FAT영역 길이(9섹터로 해야 함)
		DW		18		; 1트럭에 몇개의 섹터가 있을까(18로 해야 함)
		DW		2		; 헤드 수(2로 해야 함)
		DD		0		; 파티션을 사용하지 않기 때문에 여기는 반드시 0
		DD		2880		; 드라이브 크기를 한번 더 write
		DB		0,0,0x29	; 잘 모르지만 이 값으로 해 두면 좋은 것 같다
		DD		0xffffffff	; 아마, 볼륨 시리얼 번호
		DB		"HELLO-OS   "	; 디스크 이름(11바이트)
		DB		"FAT12   "	; 포맷 이름(8바이트)
		RESB	18			; 우선 18바이트를 비어둔다

; 프로그램 본체

		DB		0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
		DB		0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
		DB		0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
		DB		0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
		DB		0xee, 0xf4, 0xeb, 0xfd

; 메세지 부분

		DB		0x0a, 0x0a		; 개행을 2개
		DB		"hello, world"
		DB		0x0a			; 개행
		DB		0

		RESB	0x1fe-$				; 0 x001fe까지를 0x00로 채우는 명령

		DB		0x55, 0xaa

; 이하는 boot sector이외의 부분을 기술

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432


이렇게 우리가 모르는 코드들이 나열되어 있다.


일단 위의 코드를 분석하기 전에, 우리가 여태까지 봤던 어셈블리어를 알아보겠다.

(맨 처음에 했던 두개의 코드 제외)


DB

Data Byte의 약자로, 1바이트(8비트)를 작성함

DW

Data Word의 약자로, 2바이트(16비트)를 작성함

DD

Data Double-Word의 약자로, 4바이트(32비트)를 작성함

RESB

0x00을 반복 작성함

$

현재 커서의 위치를 불러


이렇게 다섯 개 정도가 있다.


플로피 디스크 포맷은 전문적으로 팔 것이 아니므로, 넘어가도록 하겠다.

RESB	0x1fe-$

코드를 보면 이러한 부분이 있는데, 이 코드에서 $는 현재 행을 표시하며

앞의 0x1fe는 10진수로 변환을 하였을 때, 510이 나온다.


그래서 이 코드는 510-'현재까지 작성한 바이트'를 계산해서, 나온 숫자만큼 0x00을 채우게 된다.

이게 왜 필요한지는 지금부터 알아보겠다.


먼저 OS가 실행되는 과정에 대해 알아보자면,

 '디스크 이미지를 넣는다 -> 부팅이 된다'를 세세히 보게 되면


1. 디스크에 OS 이미지를 넣는다

2. 디스크의 첫 번째 섹터를 확인한다

3. 만약 섹터의 마지막 2바이트가 '55 AA'로 끝나는지 확인한다

4. 만약 그렇게 끝난다면, 처음부터 읽어온다



이 과정을 '부트 섹터'라고 부른다.


여기서 섹터는, 디스크의 B 부분을 말하며, 1섹터는 512바이트이다.


그리고 2번 과정에서 이 섹터 중에서 첫 번째 섹터를 불러오고, 마지막의 2바이트를 검사한다.

그렇기 때문에, 부트 섹터 부분은 무조건 512바이트가 되어야 한다. 

('0x00'으로 채워서라도 맞춰야한다)


그래서 'RESB    0x1fe-$'을 통해 부족한 디스크의 용량을 꽉꽉 채워준다.

그리고 이를 통해 마지막 2바이트가 '55 AA'가 되면, 해당 섹터의 첫 부분부터 불러오기 시작한다.



여기서 이러한 의문점이 들 수가 있다

부트 섹터에 OS이미지가 들어가는데, 512바이트면 부족하지 않을까?


라는 의문점이 들을 텐데, 대답은 부족한 것이 맞다.


그래서 부트 섹터에는 나머지 디스크에 있는 코드를 불러오게 하며, 나머지 이미지를 불러오게 된다.

이러한 역할을 담당하는 것을 'IPL(initial program load)'이라 부른다.


여기까지 보면, 부트 섹터가 IPL을 포함하고, IPL이 나머지 부분을 불러오는 것을 알 수 있다.

여기서 우리가 자주 듣는 '부트(boot)'란 개념이 나온다.

부트는 간략하게 설명하면, 부트 섹터로 넘겨주는 것이라 보면 된다.


이 단어의 뜻은 '자신의 힘으로 이루다'라는 뜻을 가지는데,

책에서는 이 단어의 어원을 설명하는데, 재밌다 궁금하면 찾아보면 될 것 같다. 




여기까지가 이번 글의 내용이다.


이번 글에서는 부트 섹터, IPL 정도만 알면 될 것 같고, 나머지는 다음 글에서 적어보겠다.

[Makefile, 레지스터와 메모리]

'프로젝트 > OS 개발!' 카테고리의 다른 글

[#2] Makefile제작해보자  (0) 2017.07.20
[#1] 시작해보자  (0) 2017.07.17
[#0] 들어가기 전  (0) 2017.07.14
Comments