Chaotic World

chaotic21c.egloos.com

포토로그 마이가든 방명록



USB Floppy Disk Drive를 이용한 Boot image 만들기

플로피 디스크의 MBR에 부트이미지를 작성하여 디스켓으로 부팅을 해 볼 것이다.
이게 웬 구시대적인 단어인가...하지만 난 지금 USB FDD밖에 없다... 그 흔한 USB 메모리스틱은 없고...ㅋㅋ
뭐..이걸 쓰나 저걸 쓰나.. 결론적으론 부팅디바이스만 달라질 뿐 똑같은 내용이 필요한 것이니 그냥 통과~ ㅎㅎ
( USB memory stick이 우연찮게 생겨서 같은 부트 이미지를 넣어서 부팅을 해 보았더니 똑같은 결과를 얻을 수 있었다. ^^ )

간단하게 부팅과정을 살펴보면,
전원버튼을 눌러 파워서플라이로부터 메인보드로 전원이 들어가면 곧 BIOS(Basic Input Output System)가 실행이 된다.
메인보드에 연결되어 있는 여러 장치들에 대한 점검(POST-Power On Self Test)을 하고 이상이 없으면
부팅디바이스로 지정된 미디어(HDD이거나 USB이거나 혹은 FDD)의 MBR에 있는 내용을
메모리의 0x07C00으로 옮긴 후, 이것을 실행하게 된다.

어?? 왜 0x07C00이야?? 이것은 초기 real mode로 동작하는 시스템에서 메모리 맵을 그렇게 구성하였기 때문이다.
( 참조 : http://wiki.osdev.org/Memory_Map_(x86) )

그럼 일단 예제코드를 보자.
(이 코드는 '만들면서 배우는 OS 커널의 구조와 원리'라는 책에 소개되어 있는 것을 토대로 하고 있음을 밝혀둔다.)

 1 [org 0]                        ; 이 코드가 몇 번지를 기준으로 하는지 알려주는 부분
 2 [bits 16]                      ; 이 코드는 16bits로 되어 있음
 3     jmp 0x07C0:start           ; 이 boot image가 load된 0x07C00으로 far jump를 한다.
                                  ; 점프하고 난 후에 실행되어야 할 부분이 start레이블이
                                  ; 있는 부분이라 뒤에 offset으로 start의 위치를 더하는 것

 4
 5 start:
 6     mov ax, cs                 ; 이 곳을 실행할 시점에 CS에는 0x07C0가 들어 있음
 7     mov ds, ax                 ; DS를 CS와 같은 값으로 assign
 8
 9     mov ax, 0xB800             ; 비디오 메모리의 세그먼트
10     mov es, ax                 ; ES에 값을 assign
11     mov di,    0x0             ; DI(Destination Index) 레지스터.
                                  ; 데이터나 문자열 등을 처리할 때 사용된다.
                                  ; 화면의 제일 윗 줄 첫 번째 칸부터 사용할 것을 나타냄
12     mov ax, word [msgBack]     ; 써야할 데이터의 address assign
13     mov cx, 0x7C0              ; 반복횟수 설정. 화면 전체를 '.'로 채우게 되는데
                                  ; 80칸*25줄=2000개를 그려야 하므로 2000번 반복

14
15 paint:
16     mov word [es:di], ax       ; 현재 ES에는 비디오 메모리 세그먼트가 들어 있는 상태.
                                  ; 여기에 12라인에서 가져온 address를 assign

17     add di, 0x2                ; 첫 줄, 첫 칸에 '.'를 찍고 다음 칸을 그리기 위해 이동
18     dec cx                     ; 반복횟수에서 1 감소
19     jnz paint                  ; 0이 될 때까지 이 부분을 반복
20
21     jmp $                      ; $(현재 address)로 jump => infinite loop
22
23     msgBack db '.',0x67        ; 변수 msgBack을 정의. DB(Define Byte)로 '.'와 0x67의
                                  ; 두 바이트짜리 연속된 데이터를 갖는 변수를 설정

24
25     times 510-($-$$) db 0x0    ; $(현재 address)에서 $$(현재 Sector의 start address)를 빼고,
                                  ; 다시 510에서 뺀 것 만큼 0을 채움 -> 512 bytes에서 boot code와
                                  ; 관련되지 않은 부분(남는 부분)을 다 0으로

26
27     dw 0xAA55                  ; 510번지에 0xAA를, 511번지에 0x55를 정의.
                                  ; 이는 BIOS가 올바른 부트섹터인지 검사하는데 사용되는 약속된 값
                                  ; 일종의 Magic Number
                                  ; 제일 마지막 워드가 이렇게 정의되어 있어야 실행가능


자, 이제 코딩이 끝났으면 boot.asm과 같은 이름으로 저장을 하고,
바이너리 형태로 컴파일을 하여 디스크에 옮긴 뒤 부팅을 시켜보자.

내가 현재 이것을 테스트 하기 위해 사용하는 환경은 Fedora11이다.
먼저, 어셈블리로 부트 이미지를 생성.
$nasm -f bin -o boot.bin boot.asm

이제 이 이미지를 디스크로 옮겨보자.
fdisk로 옮길 위치 확인.
$fdisk -l

혹시 아무것도 나오지 않는다면, 루트 권한으로 실행.
그리고, 이미지 카피.
$dd if=boot.bin of=/dev/sdb

다 되었다.
이제 USB Floppy Disk Drive가 연결된 채로 재부팅을 시켜보면,
화면 한 가득 '.'이 찍히는 것을 볼 수 있을 것이다. 제대로 만들어졌을 경우......^^;;

추가로 VGA 메모리의 구조와 사용법을 간단하게 살펴보면,
+---------------------------------+  C000:0000
|  VGA text color
+---------------------------------+  B800:0000
|  VGA text monochrome
+---------------------------------+  B000:0000
|  VGA framebuffer
+---------------------------------+  A000:0000
요런 모양이 된다. 컬러 텍스트를 모니터에 표시하려면 B800:0000부터 데이터를 집어 넣으면 되는 것인데,
한 글자를 표시하는데 2 bytes가 필요하다. 2 bytes 중 1 byte는 ASCII코드가 들어가고,
나머지 1 byte는 글자색과 배경색이 각각 4 bits씩 차지하게 된다.

글자색은 0부터 F까지 16가지 색상을 표현할 수 있고, 배경색은 0부터 7까지 8가지 색상을 기본으로
9부터 F까지는 앞의 배경색을 반복하되 글자가 깜빡거리는 효과가 나타난다.

이건 뭐 하나씩 해보면 쉽게 알 수 있다. ㅎㅎ

추가로 어셈블리로 컴파일 된 바이너리를 다시 어셈블리 코드로 만드는 방법도 알아두자.
이렇게 역어셈블되어 나온 코드는 프로그래머가 코딩한 것과는 약간 다른 모양이 된다.
$ndisasm -b 16 boot.bin

이렇게 보면 어셈블리 코드가 실제 어떤 어드레스와 매칭이 되는지 한눈에 볼 수 있을 것이다.


트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://chaotic21c.egloos.com/tb/9948755 [도움말]