lesson 7, reading from disk

pull/6/head
Carlos Fenollosa 10 years ago
parent 83179b891e
commit 972701d279

@ -0,0 +1,54 @@
*Concepts you may want to Google beforehand: hard disk, cylinder, head, sector,
carry bit*
**Goal: Let the bootsector load data from disk in order to boot the kernel**
Our OS won't fit inside the bootsector 512 bytes, so we need to read data from
a disk in order to run the kernel.
Thankfully, we don't have to deal with turning spinning platters on and off,
we can just call some BIOS routines, like we did to print characters on the screen.
To do so, we set `al` to `0x02` (and other registers with the required cylinder, head
and sector) and raise `int 0x13`
You can access [a detailed int 13h guide here](http://stanislavs.org/helppc/int_13-2.html)
On this lesson we will use for the first time the *carry bit*, which is an extra bit
present on each register which stores when an operation has overflowed its current
capacity:
```nasm
mov ax, 0xFFFF
add ax, 1 ; ax = 0x0000 and carry = 1
```
The carry isn't accessed directly but used as a control structure by other operators,
like `jc` (jump if the carry bit is set)
The BIOS also sets `al` to the number of sectors read, so always compare it
to the expected number.
Code
----
Open and examine `boot_sect_disk.asm` for the complete routine that
reads from disk.
`boot_sect_main.asm` prepares the parameters for disk read and calls `disk_load`.
Notice how we write some extra data which does not actually belong to the boot
sector, since it is outside the 512 bits mark.
The boot sector is actually sector 1 (the first one, sectors start at 1)
of cylinder 0 of head 0 of hdd 0.
Thus, any bytes after byte 512 correspond to sector 2 of cylinder 0 of head 0 of hdd 0
The main routine will fill it with sample data and then let the bootsector
read it.
**Note: if you keep getting errors and your code seems fine, make sure that qemu
is booting from the right drive and set the drive on `dl` accordingly**
Try the flag `-fda` for example, qemu -fda boot_sect_main.bin` and set `dl` as `0x00`

@ -0,0 +1,46 @@
; load 'dh' sectors from drive 'dl' into ES:BX
disk_load:
pusha
; reading from disk requires setting specific values in all registers
; so we will overwrite our input parameters from 'dx'. Let's save it
; to the stack for later use.
push dx
mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
mov al, dh ; al <- number of sectors to read (0x01 .. 0x80)
mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
; 0x01 is our boot sector, 0x02 is the first 'available' sector
mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
; [es:bx] <- pointer to buffer where the data will be stored
; caller sets it up for us, and it is actually the standard location for int 13h
int 0x13 ; BIOS interrupt
jc disk_error ; if error (stored in the carry bit)
pop dx
cmp al, dh ; BIOS also sets 'al' to the # of sectors read. Compare it.
jne sectors_error
popa
ret
disk_error:
mov bx, DISK_ERROR
call print
call print_nl
mov dh, ah ; ah = error code, dl = disk drive that dropped the error
call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
jmp disk_loop
sectors_error:
mov bx, SECTORS_ERROR
call print
disk_loop:
jmp $
DISK_ERROR: db "Disk read error", 0
SECTORS_ERROR: db "Incorrect number of sectors read", 0

@ -0,0 +1,2 @@
times 256 dw 0x1234
times 256 dw 0xFECB

@ -0,0 +1,32 @@
[org 0x7c00]
mov bp, 0x8000 ; set the stack safely away from us
mov sp, bp
mov bx, 0x9000 ; es:bx = 0x0000:0x9000 = 0x09000
mov dh, 2 ; read 5 sectors
; the bios sets 'dl' for our boot disk number
; if you have trouble, use the '-fda' flag: 'qemu -fda file.bin'
call disk_load
mov dx, [0x9000] ; retrieve the first loaded word, 0xdada
call print_hex
call print_nl
mov dx, [0x9000 + 512] ; first word from second loaded sector, 0xface
call print_hex
jmp $
%include "../05-bootsector-functions-strings/boot_sect_print.asm"
%include "../05-bootsector-functions-strings/boot_sect_print_hex.asm"
%include "boot_sect_disk.asm"
; Magic number
times 510 - ($-$$) db 0
dw 0xaa55
; boot sector = sector 1 of cyl 0 of head 0 of hdd 0
; from now on = sector 2 ...
times 256 dw 0xdada ; sector 2 = 512 bytes
times 256 dw 0xface ; sector 3 = 512 bytes
Loading…
Cancel
Save