mirror of
https://github.com/cfenollosa/os-tutorial.git
synced 2024-10-27 20:34:19 +00:00
lesson 7, reading from disk
This commit is contained in:
parent
83179b891e
commit
972701d279
54
07-bootsector-disk/README.md
Normal file
54
07-bootsector-disk/README.md
Normal file
@ -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`
|
||||||
|
|
46
07-bootsector-disk/boot_sect_disk.asm
Normal file
46
07-bootsector-disk/boot_sect_disk.asm
Normal file
@ -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
|
2
07-bootsector-disk/boot_sect_fakedisk.asm
Normal file
2
07-bootsector-disk/boot_sect_fakedisk.asm
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
times 256 dw 0x1234
|
||||||
|
times 256 dw 0xFECB
|
32
07-bootsector-disk/boot_sect_main.asm
Normal file
32
07-bootsector-disk/boot_sect_main.asm
Normal file
@ -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…
Reference in New Issue
Block a user