rdos/boot/fat32.asm

215 lines
3.2 KiB
NASM

; Bootsector for FAT32 filesystems
org 0x0800
jmp short init
nop
; WORD reserved sector count
rsc: equ ( $$ + 0x00E )
; BYTE number of sectors per cluster
sc: equ ( $$ + 0x00D )
; BYTE number of FATs
fn: equ ( $$ + 0x010 )
; DWORD hidden sector count (partition offset)
po: equ ( $$ + 0x01C )
; DWORD sectors per FAT
sf: equ ( $$ + 0x024 )
; BYTE drive number (we set it from dl)
dn: equ ( $$ + 0x040 )
; Area for BPB
times (0x5A - ($-$$)) db 0
init: xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
mov si, sp
mov di, 0x0800
mov cx, 0x0100
rep movsw
jmp 0x0:main
msg: pop si
mloop: lodsb
test al, al
jz mend
mov ah, 0x0e
mov bx, 7
int 0x10
jmp mloop
mend: push si
ret
err: call msg
db "DISKERR", 0x0A, 0x0D, 0
hlt: hlt
jmp hlt
; Requires DWORD ptr and QWORD sector on the stack
read: pop bp
push cx
mov ax, 0x10
push ax
mov ah, 0x42
mov dl, 0x80
mov si, sp
mov di, [si+4]
int 0x13
jc err
pop ax
pop cx
push bp
ret
; Advances [clus] to next FAT entry
next: ; push upper two words for sector num
xor ax, ax
push ax
push ax
; get current cluster number
mov ax, [clus]
mov dx, [clus+2]
; shift 2 left for dword-sized FAT entries
; shift 9 right for sector size
mov cl, 7
shftl: clc
rcr dx, 1
rcr ax, 1
loop shftl
; add reserved sector count
add ax, word [rsc]
adc dx, 0
; push lower dword of sector number
push dx
push ax
; push ptr to target buffer
push cs
mov ax, buf
push ax
mov cx, 1
call read
; get lower part of cluster number
mov si, [clus]
; multiply with 4
sal si, 1
sal si, 1
; make sure its within sector range
and si, 0x1FF
add si, buf
mov di, clus
; copy dword from FAT to [clus]
movsw
movsw
; 1x QWORD, 1x DWORD = 12 bytes
add sp, 12
ret
; reads current cluster into [dest]
readc: ; load cluster number
mov ax, [clus]
mov dx, [clus+2]
; subtract the two dummy entries from FAT start
sub ax, 2
sbb dx, 0
; convert cluster number to sector number
; this is some cheapo multiplication with 2^n
mov ch, [sc]
l02: shr cl, 1
jz l02e
clc
rcl dx, 1
rcl ax, 1
jmp l02
l02e:
; dx:ax is now sector num in data area
; get number of FATs
xor ch, ch
mov cl, byte [fn]
; add their sizes up
floop: add ax, [sf]
adc dx, [sf+2]
loop floop
; add reserved sector count
add ax, [rsc]
add dx, 0
; push sector num QWORD
xor cx, cx
push cx
push cx
push dx
push ax
; push target buffer DWORD
; dest gives the segment register
mov ax, [dest]
push ax
push cx
; push sector count
; always an full cluster
mov cx, [sc]
xor ch, ch
call read
cmp cl, [sc]
jne err
xchg bx, cx
mov cl, 5
sal bx, cl
add [dest], bx
add sp, 12
ret
loadf: call readc
call next
cmp word [clus+2], 0x0FFF
jne loadf
ret
main: call loadf
mov ax, [dest]
int 3
xor ah,ah
int 0x16
int 0x19
jmp hlt
; the packing is so that it looks nice in a hexdump
times (0x1E0 - ($-$$)) db 0
; directory the kernel is in
tdir: db "RDOS ", 0
; current cluster number
clus: dd 2
times (0x1F0 - ($-$$)) db 0
; filename for the kernel
tfile: db "KERNEL BS ", 0
; segment register for data
dest: dw 0x07c0
; Padding and signature
times (0x1FE - ($-$$)) db 0
dw 0xAA55
buf: