Rework fat boot sector, load FAT only once instead of partial

This commit is contained in:
Nero 2020-09-23 23:01:50 +00:00
parent 31eac279c2
commit adf67d9723
1 changed files with 123 additions and 202 deletions

View File

@ -19,7 +19,7 @@ params: times bpb_size db 0
init: xor ax, ax
mov ss, ax
mov sp, 0x7C00
mov sp, ax
; save potential partition table entry
push ds
@ -36,232 +36,153 @@ init: xor ax, ax
%include "inc/booterr.asm"
; offsets relative to FS
readd: ; add offset of cluster data area to DX:AX
push cx
mov di, [bp+bpb.direntries]
mov cl, 4
shr di, cl ; 32 bytes per entry
add ax, di
adc dx, 0
pop cx
readr: ; add offset to rootdir to DX:AX (FAT12/FAT16 only)
push cx
xor ch, ch
mov cl, byte [bp+bpb.fatnumber]
fatlp: add ax, [bp+bpb.fatsectors]
adc dx, 0
loop fatlp
pop cx
readf: ; add offset to FAT table to DX:AX
add ax, word [bp+bpb.reservedsects]
adc dx, 0
readp: ; read sector DX:AX from partition
add ax, word [bp+bpb.sectoroffset]
adc dx, word [bp+bpb.sectoroffset+2]
jnc ($+5)
call errcll
read_: ; read sector DX:AX from disk
; uses basic CHS disk IO
; this cant reliable read over track boundaries
; so we read each single sector in loop over CX
chslp: push ax
; Read sectors from disk
; IN ES:DI target buffer
; DX:AX absulute 32-bit sector number
; CX numeber of sectors
read: push ax
push cx
push dx
push bx
; calculate CHS data
div word [bp+bpb.tracksectors] ; ax:temp = (lba / spt)
inc dx ; dx:sector = (lba % spt) + 1
mov cl, dl ; sector number
xor dx, dx
div word [bp+bpb.heads] ; ax:cylinder = (tmp / heads)
; dx:head = (tmp % heads)
mov ch, al ; cylinder number
mov dh, dl ; head number
mov dl, [bp+bpb.drivenum] ; drive number
xchg ax, bx
mov al, byte [bp+bpb.heads]
mul byte [bp+bpb.tracksectors]
xchg ax, bx
; set up read buffer
mov es, bx
xor bx, bx
; call bios
; dx:ax = lba
div word bx
xchg ax, dx
; dx = cylinder, ax = head * tracksectors + sector
div byte [bp+bpb.tracksectors]
; dx = cylinder, al = head, ah = sector
xchg dl, dh
ror dl, 1
ror dl, 1
or dl, ah
inc dx
; al: head number
; dh bit 0-7: cylinder bits 0-7
; dl bit 0-5: sector bits 0-5
; dl bit 6-7: cylinder bits 8-9
mov cx, dx
mov dh, al
mov dl, [bp+bpb.drivenum]
mov ax, 0x0201
int 0x13
jnc ($+5)
call errcll
mov bx, di
int 0x13
jc errjmp
pop bx
pop dx
pop cx
pop ax
; increment sector num + write offset
add ax, 1
adc dx, 0
add bx, 0x20
; loop on CX
loop chslp
add di, 0x200
loop read
ret
next: ; Advances DX:AX to next FAT entry
push ax
push bx
; 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
mov bx, 0xA0
%ifdef FAT12
; FAT item might span over two sectors
mov cx, 2
%else
mov cx, 1
%endif
call readf
pop bx
; get address of cluster within sector
pop si
%ifdef FAT12
push si
; times 1.5
mov ax, si
shr ax, 1
add si, ax
add si, buf
lodsw
pop si
test si, 1
jz .odd
.even: mov cl, 4
shr ax, cl
jmp .done
.odd: and ax, 0x0FFF
.done: xor dx, dx
%endif
%ifdef FAT16
; double
sal si, 1
; make sure its within sector range
and si, 0x1FF
add si, buf
; load word
lodsw
xor dx, dx
%endif
ret
; reads current cluster into [dest]
readc: ; load cluster number
push ax
push dx
; 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 cl, [bp+bpb.clustersects]
l02: shr cl, 1
jz l02e
clc
rcl ax, 1
rcl dx, 1
jmp l02
l02e:
; dx:ax is now sector num in data area
mov cx, [bp+bpb.clustersects]
xor ch, ch
call readd
xchg di, cx
mov cl, 5
sal di, cl
add bx, di
pop dx
pop ax
ret
; Load root directory
loadr: mov ax, [bp+bpb.direntries]
rootdirsects: mov bx, [bp+bpb.direntries]
mov cl, 4
shr ax, cl
mov cx, ax
xor ax, ax
xor dx, dx
mov bx, 0x07C0
jmp readr
; Load file identified by fsattr
; Directory data is expected at 0x07C00
loadf: mov si, (0x7C00-0x20)
sloop: add si, 0x20
; check if entry is valid
mov al, [si]
; unallocated direntry
test al, al
jnz ($+5)
call errcll
; deleted files
cmp al, 0xE2
je sloop
; check attr
mov al, [si+11]
and al, 0x5C
cmp al, ah
jne sloop
mov ax, [si+0x1A]
mov dx, [si+0x14]
; Load cluster chain DX:AX to 0x07C00
load: mov bx, 0x07C0
lloop: call readc
call next
%ifdef FAT12
cmp word ax, 0x0FF8
%endif
%ifdef FAT16
cmp word ax, 0xFFF8
%endif
jc lloop
shr bx, cl ; 32 bytes per entry
ret
main: ; Set up BP to point to BPB
; Relative addressing saves one instruction byte per access
mov bp, params
; Save DL contents
offset_cluster: ; add offset of cluster data area to DX:AX
call rootdirsects
add ax, bx
adc dx, 0
offset_rootdir: ; add length of fat table times number of fats
xor ch, ch
mov cl, byte [bp+bpb.fatnumber]
.loop: add ax, [bp+bpb.fatsectors]
adc dx, 0
loop .loop
offset_fat: ; add reserved sectors
add ax, [bp+bpb.reservedsects]
adc dx, 0
offset_part: ; add partition offset
add ax, [bp+bpb.sectoroffset]
add dx, [bp+bpb.sectoroffset+2]
ret
resetbuf: xor ax, ax
mov dx, ax
mov di, buf
ret
main: mov bp, params
mov [bp+bpb.drivenum], dl
; load root directory
call loadr
call resetbuf
call offset_rootdir
call rootdirsects
mov cx, bx
call read
; search for first system file
mov ah, 0x04
call loadf
; search for file
mov bx, buf
mov cx, [bp+bpb.direntries]
.loop: push cx
mov si, filename
mov di, bx
add bx, 0x20
mov cx, 0x0B
repe cmpsb
pop cx
loopne .loop
jne err_not_found
push word [bx-0x20+0x1A]
; restore drive number
mov dl, [bp+bpb.drivenum]
; load fat table
call resetbuf
call offset_fat
mov cx, [bp+bpb.fatsectors]
call read
; restore potential partition table
pop si
; fetch cluster numbers (FAT12-specific)
mov di, 0x0500
pop ax
readfat: stosw
mov bx, ax
shr bx, 1
pushf
add bx, ax
mov ax, [buf+bx]
popf ; CF: 0=even, 1=odd entry
jc .odd
and ax, 0x0FFF
jmp .both
.odd: mov cl, 4
shr ax, cl
.both: cmp ax, 0xFF8
jc readfat
xor ax, ax
stosw
; load clusters
mov si, 0x500
mov di, 0x7C00
loadclus: lodsw
sub ax, 2
jc .jump
mul byte [bp+bpb.clustersects]
call offset_cluster
xor cx, cx
mov cl, [bp+bpb.clustersects]
call read
jmp loadclus
.jump: pop si
pop ds
jmp 0x7C00
; Padding and signature
times (0x1FE - ($-$$)) db 0
err_not_found:
hlt: hlt
jmp hlt
times (0x1F3 - ($-$$)) db 0
filename: db "KERNEL ", "BS "
dw 0xAA55
buf: