플로피 디스크의 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 커널의 구조와 원리'라는 책에 소개되어 있는 것을 토대로 하고 있음을 밝혀둔다.)
자, 이제 코딩이 끝났으면 boot.asm과 같은 이름으로 저장을 하고,
바이너리 형태로 컴파일을 하여 디스크에 옮긴 뒤 부팅을 시켜보자.
내가 현재 이것을 테스트 하기 위해 사용하는 환경은 Fedora11이다.
먼저, 어셈블리로 부트 이미지를 생성.
이제 이 이미지를 디스크로 옮겨보자.
fdisk로 옮길 위치 확인.
혹시 아무것도 나오지 않는다면, 루트 권한으로 실행.
그리고, 이미지 카피.
다 되었다.
이제 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까지는 앞의 배경색을 반복하되 글자가 깜빡거리는 효과가 나타난다.
이건 뭐 하나씩 해보면 쉽게 알 수 있다. ㅎㅎ
추가로 어셈블리로 컴파일 된 바이너리를 다시 어셈블리 코드로 만드는 방법도 알아두자.
이렇게 역어셈블되어 나온 코드는 프로그래머가 코딩한 것과는 약간 다른 모양이 된다.
이렇게 보면 어셈블리 코드가 실제 어떤 어드레스와 매칭이 되는지 한눈에 볼 수 있을 것이다.
이게 웬 구시대적인 단어인가...하지만 난 지금 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 |
이렇게 보면 어셈블리 코드가 실제 어떤 어드레스와 매칭이 되는지 한눈에 볼 수 있을 것이다.




최근 덧글