2007년 08월 21일
01 부트 스트랩
01. 시작하기 전에
이곳에서는 PC의 BIOS에 저장되어있는 프로그램을 통해 플로피 디스크에 읽어들여 RAM에 저장하고,
RAM에 저장된 프로그램을 실행시킨다.
02. BIOS와 부트 시퀀스
부트 시퀀스(Boot Sequence)는 시스템에 전원이 들어오거나 시스템을 재시작하는 경우 커널을 로드하기 까지의 일련의 과정이라고
할 수 있다. 이 과정 중에는 주기억장치에서 커널을 메모리에 적재하는 등의 여러가지 작업들이 있지만, 그 중에서 가장 선행되는 작업
은 BIOS(Basic Input/Output System)에 의해 행해지는 검증 작업이다.
BIOS는 IBM 호환 기종의 PC에서 전원이 들어오자 마자 구동되는 플래시 메모리(Flash Memory)내의 펌웨어이며, 흔히 ROM BIOS라고도 부른다.
- BIOS의 기능
- CPU상태, 메모리, 여러장치, 포트등이 사용가능한지를 검증
- 커널과 PC 디바이스간의 인터페이스 제공
- OS 내지 응용 프로그램에서의 하드웨어를 호출할수 있는 창구 역할
02.1 BIOS의 역할
우선 BIOS의 역할에 대해서 알아 보자.
- 시스템에 장착된 모든 하드웨어들이 정상적으로 동작하는지 테스트를 실시하며, 이를 POST(Power-On Self-Test)라고 한다. 이 과정에서 메모리,
하드디스크, CD-ROM, 키보드 등을 체크하며 문제가 있는 경우 비프(beep)음이나 화면 출력을 통해 오류를 알려준다. - 동일 시스템에 다른 BIOS칩이 존재한는 경우 이를 호출하여 활성화 시킨다. 그래픽카드나 SCSI카드의 경우 독립적이 BIOS가 있는 경우가 있으므로
메인보드 BIOS가 이를 활성화시켜 주어야 한다. - 하드디스크나 보드의 클록 등을 설정할 수 있는 관리 기능을 제공한다. CMOS셋업을 통해서 메인보드를 비롯한 주변장치들의 설정을 변경할수 있으며,
여기서 설정한 데이터는 메인보드 내의 EEPROM에 저장된다.
POST과정을 정상적으로 마친 경우 시스템에 연결되어 있는 주변장치들의 초기화 하며, 이는 차후 OS에 각 장치들의 인터페이스를 제공할 수 있게 한다. - 디스크의 첫 번째 섹터를 읽어 들이며, DOS를 예로 들면 MBR의 부트 코드를 실행 시켜 소프트웨어적인 부팅을 수행 시킨다.
위의 단계까지 BIOS는 부팅 가능 장치를 검색하고 실행 시켜 주는 역할까지를 완수한다.
02.2 부트 시퀀스
BIOS의 일반적인 시퀀스를 알아보자.
- PC에 전원이 들어온후 일련의 과정을 거쳐 BIOS루틴이 시작된다.
- 기존에 저장되어있는 CMOS 설정 값을 읽는다. 이때 읽어 들이는 값들은 하드웨어를 직접적으로 제어 할수 있는 값들이다. CPU의 클록 설정부터
주기억장치의 부트 시퀀스까지 많은 데이터들을 가져온다. - 인터럽트 핸들러와 장치 드라이버를 로드한다. PC내에서 주변장치간의 통신은 대부분 인터럽트를 통해서 이루어지므로 인터럽트 핸들러는 비교적
초기에 설정 되며, 이때 인터럽트 벡터 역시 초기화 된다. 이 인터럽트 벡터를 기반으로 대부분의 커널에서 확장된 인터럽트 벡터를 자체적으로 생성
하여 가지고 있으며, 이를 이용해서 응용 프로그램 내외적으로 통신을 가능케 한다. - 레지스터 영역과 파워 관리 영역을 초기화 한다.
- POST(Power-On Self-Test)를 수행한다. 이는 시스템 내의 장치들을 검사하여 오류가 있는지를 찾아내며, 문제가 발견되면 그에 해당하는 비프음을 낸 뒤
정지한다. POST수행 결과가 정상이라면 BIOS는 INT 19 (인터럽트19)를 발생시켜 다음 과정을 진행하도록 한다.
시스템 내의 비디오 카드를 검색하고, 비디오 카드 안에 또 다른 BIOS가 있는지를 확인한다. 만약 비디오 카드에 BIOS가 있다면 이를 호출해서 비디오 카드
자체적으로 초기화를 진행하도록 한다. 대부분의 비디오 카드는 이 시점에 비디오 카드의 간략한 정보를 화면에 출력해 보여주기도 한다. - 비디오 카드 검색을 마치고 나면 기타 장치들을 검색하고, 해당 장치 내에 BIOS가 있다면 이를 호출하여 실행 시킨다. 이때 플로피 디스크 또는 하드 디스크
등을 검색하게 된다. - BIOS의 시작 화면이 출력되며 기타 정보들을 화면에 디스플레이 한다. 이때 BIOS의 제조사 및 버전 정보, 제조일, Setup 키(F1, Del 등), 시스템 로고, 시리얼
넘버등을 확인할 수 있다. 즉, PC를 켜면 본격적으로 부팅 과정을 볼 수 있는 화면이 나오는 것이다. - 기타 장치들의 추가 테스트를 진행한다. 이 테스트는 각 장치들의 제조사에서 자체적으로 체크하는 루틴으로서 에러 메세지가 화면에 출력되어 디버깅하기에
용이하다. 이때 메모리, 디스크 드라이브, DMA, 키보드 등 다양한 테스트를 진행한다. - BIOS에서 검사한 시스템 정보들을 화면에 출력한다. 이로써 BIOS의 부트 시퀀스(Boot Sequence)중 POST과정을 완료하게 된다.
- OS를 불러오기 위한 작업으로 부팅 가능한 저장장치를 검사하며, 이는 CMOS에 설정되어 있는 부팅 가능 장치 순서대로 검사하게된다. 이때 정상적으로 저
장장치가 검색되면 해당 장치의 부트 섹터를 호출한다. 만약 하드디스크라면 첫 번째 섹터를 호출하여 MBR의 부트 코드가 실행된다.
위의 과정으로 부트 시퀀스가 진행이 된다는 것을 알수가 있다. 우리가 코드를 작성하고 진행되는 것은 10번 부터이다. 즉 이제 부터 작성한 코드가 동작하는 시점은
10번 부터가 여기서 작성한 코드가 실행되는 시점이라고 할 수 있다.
03. Boot.txt 작성
지금까지 BIOS의 역할과 부팅했을때의 과정을 알아 보았다. 그럼 첫 번째 섹터 즉 MBR영역에 프로그램을 작성해서 넣어서 부팅을 시도해보자.
아래의 코드는 간단한다. 부팅 후 화면에 간단한 문자를 출력해주는 프로그램이다.
이곳에서는 BIOS에서 디스크에 첫번째 섹터에 저장되어있던 프로그램을 실행시킨다. 즉 제어권이 여기서 작성한 프로그램으로 넘어 온것을 말한다.
여기서는 시작 오프셋 설정과, 레지스터 설정 및 비디오 메모리에 문자를 쓰는 방법, MBR 인식을 위한 Magic Number 설정에 대해서 알아 본다.
- [org 0]
[bits 16]
jmp 0x07C0:start ;far jmp 를 한다. - start:
mov ax, cs ;cs 에는 0x07C0 이 들어 있다.
mov ds, ax ;ds 를 cs 와 같게 해준다. - mov ax, 0xB800 ;비디오 메모리의 세그먼트를
mov es, ax ;es 레지스터에 넣는다.
mov di, 0 ;제일 윗 줄의 처음에 쓸 것이다.
mov ax, word [msgBack] ;써야 할 데이터의 주소값을 지정한다.
mov cx, 0x7FF ;화면 전체에 쓰기 위해서는
;0x7FF(10진수 2047)개의 WORD 가 필요하다.
paint:
mov word [es:di], ax ;비디오 메모리에 쓴다.
add di,2 ;한 WORD를 썼으므로, 2를 더한다.
dec cx ;한 WORD를 썼으므로, CX 의 값을 하나 줄인다.
jnz paint ;CX 가 0이 아니면, paint로 점프하여
;나머지를 더 쓴다.
mov edi, 0 ;제일 윗 줄의 처음에 쓸 것이다.
mov byte [es:edi], 'A' ;비디오 메모리에 쓴다.
inc edi ;한 개의 BYTE를 썼으므로 1을 더한다.
mov byte [es:edi], 0x06 ;배경색을 쓴다.
inc edi ;한 개의 BYTE를 썼으므로 1을 더한다.
mov byte [es:edi], 'B'
inc edi
mov byte [es:edi], 0x06
inc edi
mov byte [es:edi], 'C'
inc edi
mov byte [es:edi], 0x06
inc edi
mov byte [es:edi], '1'
inc edi
mov byte [es:edi], 0x06
inc edi
mov byte [es:edi], '2'
inc edi
mov byte [es:edi], 0x06
inc edi
mov byte [es:edi], '3'
inc edi
mov byte [es:edi], 0x06- jmp $ ;이 번지에서 무한루프를 돈다.
- msgBack db '.', 0xE7 ;배경색으로 사용할 데이터
- times 510-($-$$) db 0 ;여기서 부터, 509 번지까지 0 으로 채운다. $: 현재 주소, $$: 현재 Section의 시작 주소
dw 0xAA55 ;510 번지에 0xAA 를, 511 번지에 0x55 를 넣어 둔다.
04. Code View
주요 코드를 보도록 하자.
- [org 0]
[bits 16]
jmp 0x07C0:start ;far jmp 를 한다.
[org 0]
- orgin 이라고 불리며, 이 프로그램이 메모리의 몇 번지에서 실행 해야 하는지를 컴파일러에게 알려주는 선언문이다.
- 정확하게 말하면 프로그램상에서 사용될 오프셋의 기준을 마련하는 것이다.
[bits 16]
- 16비트용으로 되어 있다는 의미를 컴파일러에게 알려 주는 선언 문이다. 이후에 32bit 모드로 변경을 할경우 [bits 32]로 설정을 할 수 있다.
jmp 0x07C0:start
- 코드 세그먼트의 0x7C0의 오프셋 start:로 점프하라는 명령이다
- 위의 같이 하는 이유는 바이오스가 디스크의 MBR(첫 512바이트)를 읽어들여 램의 물리 주소 0x07C00 번지에 복사한 후 0x7C00으로 점프를 하게 되는데,
바이오스가 점프할때 0x0000:7C00 방식으로 점프하기 때문에 CPU에 의해 자동적으로 CS(코드세그먼트) 레지스터에는 0x0000이, ip(프로그램 카운터)
레지스터에는 0x7C00이 들어있는 상태가 된다. 이 상태에서 위 코드를 실행 하면 start: 로 점프를 하게 되고, CS에는 0x7C00이 ip에는 0x5(start:)가 들어
가게 된다. - 위 코드를 사용할 경우 오프셋을 0 에서 부터 편리하게 사용할 수 있게 된다.
- 위의 코드를 넣지 않을 경우 [org 0] -> [org 0x7C00]으로 변경을 해야된다.
- mov ax, cs ;cs 에는 0x07C0 이 들어 있다.
mov ds, ax ;ds 를 cs 와 같게 해준다.
위의 코드는 코드 세그먼트와 데이터 세그먼트를 같게 만들어 주는 코드이다. 위의 코드에서는 코드 영역에 데이터 부분도 같이 존재 하기 때문에 코드 영역과
데이터 영역을 같게 하여 접근을 편리하게 하고 있다. 즉 코드 세그먼트와 데이터 세그먼트를 같은 값으로 사용하겠다는 의미이다.
추가적으로 CS, DS, ES 등의 세그먼트 레지스터에 값을 넣을 때는 꼭 ax, bx 등의 범용 레지스터를 매개로 사용하여 넣어야 한다.
- mov ax, 0xB800 ;비디오 메모리의 세그먼트를
mov es, ax ;es 레지스터에 넣는다.
mov di, 0 ;제일 윗 줄의 처음에 쓸 것이다.
mov ax, word [msgBack] ;써야 할 데이터의 주소값을 지정한다.
mov cx, 0x7FF ;화면 전체에 쓰기 위해서는
;0x7FF(10진수 2047)개의 WORD 가 필요하다.
paint:
mov word [es:di], ax ;비디오 메모리에 쓴다.
add di,2 ;한 WORD를 썼으므로, 2를 더한다.
dec cx ;한 WORD를 썼으므로, CX 의 값을 하나 줄인다.
jnz paint ;CX 가 0이 아니면, paint로 점프하여
;나머지를 더 쓴다.
위의 코드는 비디오 메모리 영역에 "."을 출력하는 부분이다.
- 0xB800을 ES 레지스터에 넣는 것을 볼수가 있는데 메모리 영역중 0xB800 에 값을 넣게 되면 해당 글자가 출력이 된다.
- paint 아랫 부분은 0x7FF 만큼 해당 문자를 출력하는 부분이다.
- mov edi, 0 ;제일 윗 줄의 처음에 쓸 것이다.
mov byte [es:edi], 'A' ;비디오 메모리에 쓴다.
inc edi ;한 개의 BYTE를 썼으므로 1을 더한다.
mov byte [es:edi], 0x06 ;배경색을 쓴다.
inc edi ;한 개의 BYTE를 썼으므로 1을 더한다.
위의 코드는 실제 비디오 메모리 영역에 데이터를 쓰는 형식을 보여 주고 있다.
- byte []는 C 언어에서 char* 와 같은 1바이트형 포인터 이다. 즉 이 주소에 한 바이트만 쓰기를 하겠다는 뜻이다.
- 비디오 메모리에 글자는 쓰는 형식은 1바이트 문자, 1바이트 배경색을 쓰게 되면 화면에 해당 문자가 출력 된다.
- dw 0xAA55 ;510 번지에 0xAA 를, 511 번지에 0x55 를 넣어 둔다.
위 부분은 Boot.txt 부분에서의 가장 중요한 부분 중 하나라고 할 수 있다.
PC 부팅 시 바이오스가 디스크의 처음 MBR부분은 복사할 때 디스크의 이곳이 MBR이 맞는지 확인 하게 되는데, 이때 MBR의 제일 끝부분의 한 워드(2byte)
"0xAA55" (Magic Number)값이 있으면 MBR이라고 확인하게 된다. 만약 이 부분을 넣지 않게 되면 부팅이 되지 않을 것이다.
05. 비디오 메모리
비디오 메모리 영역은 보통 램과는 달리 하드웨어적으로 모니터에 글씨를 문자 단위로 나타내거나 그림을 픽셀 단위로 나타낸다.
그러나 프로그래밍을 할때는 비디오 메모리에 값을 읽고, 쓰는 동작은 RAM을 사용한는 것과 방법이 같다.
여기서는 컬러 텍스트 모드 비디오 메모리를 사용 방법에 대해 알아본다.
위의 그림에서와 같이 컬러 텍스트는 0xB800:0000 부터 0xB800:FFFF의 한개의 세그먼트를 사용하게 된다.
모니터의 한 면에는 가로 80개, 세로 25개의 문자를 나타내는데, 글자 수는 총 2000자(0x7D0)이다. 이 글자 수로는 한개의 세그먼트(0xFFFF)를
다 사용하기에는 수가 적으므로 페이지를 나누어 0xB800:0000 ~ 0xB800:1000, 0xB800:1001 ~ 0xB800:2000, ... 와 같이 여러 개의 면을 사용하도록
하드웨어가 구성 되어있다.
글자를 나타내는 데에는 2바이트를 사용한다.
위 그림과 같이 첫 번째는 글자의 ASCII코드(8bit)를 지정하고, 두 번째 바이트는 글자의 배경색(4bit)과 글자의 색(4bit)을 지정하게 된다.
다음은 글자 및 배경색에 대한 구성표이다.
위의 표와 같이 색을 지정하며, 맨 위의 비트가 모두 0으로 되어있는데 이것을 1로 해주면 색이 깜박이게 된다.
06. 출력 화면
아래 화면은 위의 코드를 컴파일하여 바이너리 파일을 첫 번째 섹터에 Write한 후 VMware를 이용하여 부팅을 한 화면이다.
화면과 같이 한 화면에 "." 문자를 출력하고 ABC123을 출력한 것을 알수가 있다.
아래의 화면은 BIOS 의 초기화 과정 후 MBR 영역(1Sector)을 메모리의 특정 번지(0x7C00)으로 로드한 후
특정 번지로 점프하여 실행한 화면이라고 할 수 있다.
00. 참고 자료
- 임베디드 개발자를 위한 파일시스템의 원리와 실습
- 인텔 프로세서(보호모드)에 대한 동영상
http://www.techworld.co.kr/seminar/seminar_content.asp?seminar_no=006
이 글은 스프링노트에서 작성되었습니다.
# by | 2007/08/21 17:35 | ┣ OS | 트랙백 | 덧글(0)





☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]