implement bpb parsing

This commit is contained in:
Nero 2021-12-20 20:08:37 +00:00
parent e26adff688
commit f1c414bb26
1 changed files with 152 additions and 86 deletions

View File

@ -6,24 +6,11 @@ cseg equ 0x0
%include "farptr.inc"
; dflags bitfields
DRVLOG equ 0x01 ; bit 0 (1) - drive logged in (see drvnum)
DRVRST equ 0x02 ; bit 1 (2) - controller configured
DRVEXT equ 0x04 ; bit 2 (4) - EBIOS supported
DIRTY equ 0x08 ; bit 3 (8) - dskbuf dirty
; initial setup for disk i/o
; copy previously set DPT to our data area
dinit xor ax, ax
mov es, ax
les bx, [es:4*0x1E]
mov dx, dpt
mov cx, 11
call lodfar
; set interrupt vector
mov es, cx
mov word [es:4*0x1E], dpt
mov word [es:4*0x1E+2], ds
ret
DRVLOG equ 0x01 ; bit 0 - drive logged in (see drvnum)
DRVCTL equ 0x02 ; bit 1 - controller configured
DRVEXT equ 0x04 ; bit 2 - EBIOS supported
DIRTY equ 0x08 ; bit 3 - dskbuf dirty
DRVCHS equ 0x10 ; bit 4 - CHS geometry known
align 16
; IBM Interrupt Sharing Protocol structure
@ -52,8 +39,11 @@ int13 pushf
; read BIOS int13h/AH=8 values
; DPT data gets copied over our dpt
; CHS data gets inserted into our bpb
getprm test byte [dskflag], 4
getprm test byte [dflags], DRVEXT
jnz .ret
; fallback non-zero values (5 1/4", 160kB)
mov word [drvspt], 8
mov word [drvspc], 8
; do the query
mov ah, 8
mov dl, [biosnum]
@ -65,12 +55,16 @@ getprm test byte [dskflag], 4
jz .nochs
; get and store sector number
and cx, 0x3F
mov word [bpb+BPBSPT], cx
; get and store number of heads
mov word [drvspt], cx
; get and store number heads
xchg dl, dh
and dx, 0xFF
inc dx
mov [bpb+BPBNOS], dx
; multiply with sectors per track
mov ax, dx
mul cx
; store sectors per cylinder
mov [drvspc], ax
; test if DPT ptr is non-zero
.nochs mov ax, es
or ax, di
@ -87,98 +81,128 @@ getprm test byte [dskflag], 4
; IN dl drive number
; dont do anything if drive already selected
select cmp dl, [drvnum]
je logfdd.ret
je getprm.ret
; clear out current contents
push dx
call flush
mov ax, 0xFFFF
mov [dskseek], ax
mov [dskseek+2], ax
mov byte [dskflag], 0
mov [drvseek], ax
mov [drvseek+2], ax
and word [dflags], ~(DRVLOG|DRVCTL|DRVEXT|DIRTY|DRVCHS)
pop dx
; set current drive number
mov [dsknum], dl
mov [drvnum], dl
; fork off if hdd
cmp dl, 2
jnc loghdd
logfdd mov [biosnum], dl
; assume some default values
xor ax, ax
mov word [bpb+BPBHS], ax
mov word [bpb+BPBHS+2], ax
mov word [bpb+BPBNOS], 2 ; 5 1/4" 360kB
mov word [bpb+BPBSPT], 9
; reset dpt to defaults
and dx, 0x0D
; query bios for geometry and DPT
call getprm
; load boot sector
; assume 512 bytes per sector
; TODO: read this from DPT
mov byte [drvss], 2
; fill partition offset with zeroes
xor ax, ax
xor dx, dx
call mapabs
; copy bios parameter block
; TODO: guess from first byte of FAT if BPB invalid
call rstseg
mov si, dskbuf+BPBOFF
mov di, bpb
mov cx, BPBSIZ
rep movsb
; copy SPT to DPT
mov al, [bpb+BPBSPT]
mov [dpt+4], al
.ret ret
mov di, drvoff
stosw
stosw
; fill partition end with 1's
not ax
stosw
stosw
; shared code with loghdd
jmp rdbpb
loghdd sub dl, 2
cmp dl, 4
jnc logerr
push dx
mov dl, 0x80
; Log in a drive on a hard disk
; IN dl bits 0-1: partition number
; bits 2-7: drive number
; Partition offset is read from MBR
; split drive & partition number
loghdd mov dh, dl
and ah, 0x3
shr dl, 1
shl dl, 1
add dl, 0x80
; partition number in DH
mov byte [biosnum], dl
; test for ebios extensions
push dx
; test for EBIOS extensions
mov ah, 0x41
mov bx, 0x55AA
call int13
sbb bx, 0xAA55
jnz .chs
; enable ebios and assume controller is configured
or byte [dflags], DRVCTL | DRVEXT
; get chs data (needed or we cant load vbr)
.chs call getprm
; read mbr
jnz .noeb
; enable EBIOS and assume controller is configured
or word [dflags], DRVCTL | DRVEXT
; hard disks are always assumed to be 512 bytes / sector
.noeb mov byte [drvss], 2
; query BIOS for geometry
call getprm
or word [dflags], DRVCHS
; read MBR
xor ax, ax
xor dx, dx
call mapabs
call map
; get partition number
pop bx
xor bh, bh
mov cl, 4
sal bx, cl
; bail out if no partition
; bail out if partition undef
cmp byte [dskbuf+0x1be+bx+4], 0
je logerr
je .ret
; load partition offset
mov ax, [dskbuf+0x1be+bx+8]
mov dx, [dskbuf+0x1be+bx+8+2]
; save to to stack
push dx
push ax
; load vbr
call mapabs
; copy bpb
mov si, dskbuf+BPBOFF
mov di, bpb
mov cx, BPBSIZ
rep movsb
; fix CHS data
call getprm
; fix partition offset
pop word [bpb+BPBHS]
pop word [bpb+BPBHS+2]
;pop [bpb+BPBNOS]
;pop [bpb+BPBSPT]
ret
; store partition offset
mov [drvoff], ax
mov [drvoff+2], dx
; add partition length
add ax, [dskbuf+0x1be+bx+12]
adc dx, [dskbuf+0x1be+bx+12+2]
; partitions after 4 TB mark not allowed
jc .ret
; store partition end
mov [drvend], ax
mov [drvend+2], dx
.ret ret
logerr stc
ret
; parse bios parameter block from drvoff
; drvoff and biosnum need to be set up
rdbpb mov ax, [drvoff]
mov dx, [drvoff+2]
call map
; read partition start
mov ax, [drvoff]
mov dx, [drvoff+2]
; add reserved sectors
add ax, [dskbuf+BPBOFF+BPBRSC]
adc dx, 0
jc .ret
; save offset of fat table
mov [drvfat], ax
mov [drvfat+2], dx
; calculate length of all fat tables
mov ah, 0
mov al, [dskbuf+BPBOFF+BPBFN]
mov dx, [dskbuf+BPBOFF+BPBFS]
mov [drvfn], dx
mul dx
add ax, [drvfat]
adc dx, [drvfat+2]
; save offset of root directory
mov [drvrd], ax
mov [drvrd+2], dx
; calculate length of root directory
mov ax, [dskbuf+BPBOFF+BPBRDE]
mov cl, [drvss]
add cl, 2
shr ax, cl
; read offset to cluster area
; read cluster size
.ret ret
; map sector into dskbuf
; skip doing a read if sector number matches
@ -227,13 +251,13 @@ diskio mov cl, 1 ; read len
mov si, dap
jmp .do
; check if we can skip controller reset
.noext test word [dflags], DRVRST
.noext test word [dflags], DRVCTL
jnz .norst
; do controller reset
mov dl, [biosnum]
mov ah, 0
call int13
or word [dflags], DRVRST
or word [dflags], DRVCTL
; put linear sector num into dx:ax
.norst mov ax, [drvseek]
mov dx, [drvseek+2]
@ -272,16 +296,58 @@ diskio mov cl, 1 ; read len
clc
ret
; assume controller is misconfigured
.err and word [dflags], ~DRVRST
.err and word [dflags], ~DRVCTL
; exit with carry flag set
stc
ret
; Get interrupt vector
; IN al interrupt number
; OUT es:bx vector
getint mov bl, al
mov bh, 0
; multiply with 4
add bx, bx
add bx, bx
les bx, [cs:bx]
ret
; Set interrupt vector
; IN al interrupt number
; ds:dx vector
setint mov bl, al
mov bh, 0
; multiply with 4
add bx, bx
add bx, bx
mov [cs:bx], dx
mov [cs:bx+2], ds
ret
init mov ax, cs
; boot failure if loaded wrong
cmp ax, cseg
je $+4
int 0x18
call rstseg
; fetch current DPT
les bx, [4*0x1E]
mov dx, dpt
mov cx, 11
call lodfar
; set interrupt vector
mov word [4*0x1E], dpt
mov word [4*0x1E+2], ds
; save int 13 handler
les bx, [4*0x13]
mov [i13isp+2], bx
mov [i13isp+4], es
; install ours
mov word [4*0x13], int13i
mov [4*0x13+2], cs
mov ax, 0x0e37
int 0x10
halt hlt
jmp halt