|
ncloader
0.1
|
Disk I/O에 대한 협력 다이어그램:앞에서 Disk I/O 에 대한 이야기를 자주 했다. 하지만, 어떻게 할 수 있을까?
막상 I/O 를 하려고 하면 막막해진다.
H/W 를 제어하기 위해서 우리는 BIOS 가 제공하는 Service 들을 이용한다. BIOS Software 는 Embedded System 에서의 Firmware 와 같은 것이다. 이 Software 에는 다양한 서비스 함수들이 구현되어 있기 때문에, 우리는 가져다 쓰기만 하면 된다. 물론, Real mode(16 bits) 에서만 동작하는 것이므로, Protected mode (32 bits) 에서 사용하기는 어렵다.
일단 전체 BIOS Service Routine 에 대한 목록을 정리하면 다음과 같다.
http://www.bioscentral.com/misc/biosservices.htm
| Interrupt | Address | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 05h | 0000:0014h | Software | Print screen | ||||||||||||
| 10h | 0000:0040h | Software | Video service routine | ||||||||||||
| 11h | 0000:0044h | Software | Equipment list service routine | ||||||||||||
| 12h | 0000:0048H | Software | Memory size service routine | ||||||||||||
| 13h | 0000:004Ch | Software | Hard disk drive service | ||||||||||||
| 14h | 0000:0050h | Software | Serial communications service routines | ||||||||||||
| 15h | 0000:0054h | Software | System services support routines
| ||||||||||||
| 16h | 0000:0058h | Software | Keyboard support service routines | ||||||||||||
| 17h | 0000:005Ch | Software | Parallel printer support services | ||||||||||||
| 18h | 0000:0060h | Software | Load and run ROM BASIC | ||||||||||||
| 19h | 0000:0064h | Software | DOS loading routine | ||||||||||||
| 1Ah | 0000:0068h | Software | Real time clock service routines | ||||||||||||
| 1Bh | 0000:006Ch | Software | CRTL - BREAK service routines | ||||||||||||
| 1Ch | 0000:0070h | Software | User timer service routine | ||||||||||||
| 1Dh | 00000074h | Software | Video control parameter table | ||||||||||||
| 1Eh | 0000:0078h | Software | Floppy disk parameter routine | ||||||||||||
| 1Fh | 0000:007Ch | Software | Video graphics character routine | ||||||||||||
| 20h-3Fh | 0000:0080f - 0000:00FCh | Software | DOS interrupt points | ||||||||||||
| 40h | 0000:0100h | Software | Floppy disk revector routine | ||||||||||||
| 41h | 0000:0104h | Software | hard disk drive C: parameter table | ||||||||||||
| 42h | 0000:0108h | Software | EGA default video driver | ||||||||||||
| 43h | 0000:010Ch | Software | Video graphics characters | ||||||||||||
| 44h | 0000:0110h | Software | Novel Netware API | ||||||||||||
| 45h | 0000:0114h | Software | Not used | ||||||||||||
| 46h | 0000:0118h | Software | Hard disk drive D: parameter table | ||||||||||||
| 47h | 0000:011Ch - | Software | Not used | ||||||||||||
| 48h | Software | Not used | |||||||||||||
| 49h | 0000:0124h | Software | Not used | ||||||||||||
| 4Ah | 0000:0128h | Software | User alarm | ||||||||||||
| 4Bh-63h | 0000:012Ch - | Software | Not used | ||||||||||||
| 64h | Software | Novel Netware IPX | |||||||||||||
| 65h-66h | Software | Not used | |||||||||||||
| 67h | Software | EMS support routines | |||||||||||||
| 68h-6Fh | 0000:01BCh | Software | Not used | ||||||||||||
| 7Ah | Software | Novell Netware API | |||||||||||||
| 78h-FFh | 0000:03FCh | Software | Not used |
현재 우리가 필요한 것은 Disk 에 저장되어 있는 Stage 2 Boot Loader 를 메모리에 적재하는 일이다. Disk 를 읽기 위해서는, 위에 나열된 서비스 루틴들 중에, Low level disk services 를 이용하면 된다.
| Insturction | Int 13h |
|---|---|
| BIOS operation | Diskette service |
| Parameters | Ax, es:bx, cx, dx |
Int 13h 함수는 여러가지의 서로 다른 저 수준 디스크 서비스를 PC 프로그램을 위해 제공한다. 디스켓 시스템을 초기화 시키거나 디스켓의 상태를 가져오는 것, 원하는 섹터를 읽어 들이는 것, 섹터를 쓰는 것, 섹터를 검사하는 것, 디스크 트랙을 포맷하는 것 등 많은 기능을 제공한다. 이 인터럽트 루틴은 그 동안 많은 변화가 있었던 것 중 하나이다. 처음 이 루틴이 개발 되었을 때, 10 MB 의 하드 디스크는 매우 큰 용량이었다. 하지만, 요즘은 게임만 수백메가가 되기도 한다.
| AH | Input parameters | Output parameters | Description |
|---|---|---|---|
| 0 | DL : driver (0..7h is floppy, 80h..FFh is hard | AH: status(0 and carry clear if no error, error code if error) | Resets the specified disk dirver. Resetting a hard disk also resets the floppy drives. |
| 1 | DL: drive (as above) | AH: 0, AL: status of previous disk oepration | This call returns the following status values in AL 0: no error 1: invalid command 2: address mark not found 3: disk write protected 4: couldn’t find sector 5: reset error 6: removed media 7: bad parameter table 8: DMA overrun 9: DMA operation crossed 64K boundary 10: illegal sector flag 11: illegal track flag 12: illegal media 13: invalid # of sectors 14: control data address mark encountered 15: DMA error 16: CRC data error 17: ECC corrected data error 32: disk controller failed 64: seek error 128: timeout error 170: drive not ready 187: undefined rror 204: write error 224: status error 255: sense failure |
| 2 | AL: # of sectors to read ES:BX: buffer address CL: bits 0..5 sector # CL: bits 6/7 track bits CL: bits 8/9 CH: track bits 0..7 DL: drive # DH: bits 0..5: head # DH: bits 6/7: track bits 10/11 | AH: return status AL: burst error length Carry 0: success Carry 1: error | Reads the specified number of 512 bytes sectors from the disk. Data read must be 64 Kbytes or less |
| 3 | Same as (2) above | Same as (2) above | Writes the specified number of 512 byte sectors to the disk. Data written must not exceed 64 Kbytes in length |
| 4 | Same as (2) above except there is no need for a buffer | Same as (2) above | Verifies the data in the specified number of 512 bytes sectors on disk |
| 0xch | Same as (4) above except there is no need for a sector # | Same as (4) above | Sends the disk head to the specified track on the disk |
| 0x0dh | DL: drive # (80h or 81h) | AH: return status | Carry 0: no error Carry 1: error Reset the hard disk controller |
이 인터럽트 서비스 루틴을 이용하면 Boot loader 에서 디스크 엑세스를 직접할 수 있다. 하지만, 디스크를 엑세스 하기 위해서는 디스크의 구조에 대한 이해가 선행되어야 한다. 디스켓에는 Head 와 Track, Sector 가 있다. Track 은 Cylinder 라고 불리우기도 한다.
하나의 Track 에는 18개 (BPB에 기록됨)의 Sector 가 있으며, Head 에는 2개(BPB에 기록된)가 있다. Head 0, Track 0 번 다음에는 Head 1, Track 0번의 순서로 Sector 를 읽어야 한다. 즉 0 번 트랙에는 Head 0 과 Head 1 의 두 가지 경우를 포함하여 총 36 개의 Sector 가 존재하는 것이다. 예를 들어 20 번째 Sector 에 접근해야 한다면, Head 는 1번 Track 은 0 번 Sector 는 2번이 되어야 하는 것이다. 한가지 주의할 점은 인터럽트 핸들러를 이용한 섹터 접근시 시작 섹터가 0번이 아닌 1번이라는 것이다. 원하는 위치의 섹터를 읽어 들이는 함수를 구현하는 것은 커널 이미지 적재를 위해서 반드시 필요하다. 읽어 들이고 싶은 섹터 번호를 넘겨주면, 해당 번호를 이용해 Head 번화 Track 번호를 구해내는 함수라면 매우 유용할 것이다. 이 함수를 구현하기 위해서는 다음과 같은 순서를 따르면 된다.
인터럽트 호출이 끝나면 Carry flag 를 이용해 성공했는지를 판단해 주어야 한다. Carry 가 발생하지 않았다면 읽기에 성공한 것이다.
| Function | read_sector(segment, offset, sector) |
|---|---|
| Brief | 지정된 섹터를 메모리로 읽어 들인다. |
| Param | [in] segment - 적재할 대상 메모리 세그먼트 |
| Param | [in] offset - 세그먼트 내에서의 오프셋 |
| Param | [in] sector - 읽어들일 섹터 번호 |
| Return | void |
| Code |
read_sector:
push bp
mov bp, sp
pusha
mov ax, [bp+4]
mov bl, TWO_TRACKS
div bl ; qutient(al) == track
mov ch, al ; # of tracks
shr ax, 8 ; To divide remainder of the previous division
mov si, sector_per_track
sub si, BOOT
add si, [RELT]
mov bl, [si] ; Dividen
div bl ; quotient(al) == head
mov dh, al ; # of head
mov cl, ah ; sector starting number
inc cl
mov si, bootdrive
sub si, BOOT
add si, [RELT]
mov dl, [si]
mov ax, 0x0201 ; read a(1) sector
mov es, [bp+8]
mov bx, [bp+6]
int 0x13
popa
pop bp
ret
|