Workstate on disk I/O rework

This commit is contained in:
Nero 2021-12-16 12:27:23 +00:00
parent 79a86bad49
commit e26adff688
2 changed files with 88 additions and 82 deletions

View File

@ -1,6 +1,7 @@
cpu 8086
%define seg 0x060
%define seg 0
%define off 0x700
org 0x7C00 - (seg << 4)
@ -16,24 +17,12 @@ init: cli
.retry: mov ax, 0x0208
mov cx, 2
mov dh, 0
mov bx, 0x100
mov bx, off
int 0x13
jc .retry
xor di, di
mov ax, 0x18CD
stosw
int 0x12
mov cl, 6
shl ax, cl
stosw
mov al, 2
stosb
mov ax, 0x18CD
stosw
jmp seg:0x100
jmp seg:off
times (0x1BE - ($-$$)) db 0

View File

@ -1,15 +1,15 @@
org 0x700
cseg equ 0x0
jmp init
%include "bpb.inc"
%include "farptr.inc"
; drive actually selected for I/O
dsknum db 0xFF
dap db 0x10, 0
dw 1
dapbuf dw dskbuf, 0
dskseek dw 0,0,0,0
; 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
@ -23,8 +23,6 @@ dinit xor ax, ax
mov es, cx
mov word [es:4*0x1E], dpt
mov word [es:4*0x1E+2], ds
; set segment addr in DAP
mov [dapbuf+2], cs
ret
align 16
@ -36,6 +34,8 @@ i13isp jmp short int13i
iret
align 16
; Entry point when user program calls int13h
; TODO: flush buffer and log out drive
int13i call int13
iret
@ -86,7 +86,7 @@ getprm test byte [dskflag], 4
; select a drive for io
; IN dl drive number
; dont do anything if drive already selected
select cmp dl, [dsknum]
select cmp dl, [drvnum]
je logfdd.ret
; clear out current contents
push dx
@ -140,7 +140,7 @@ loghdd sub dl, 2
sbb bx, 0xAA55
jnz .chs
; enable ebios and assume controller is configured
or byte [dskflag], (2+4)
or byte [dflags], DRVCTL | DRVEXT
; get chs data (needed or we cant load vbr)
.chs call getprm
; read mbr
@ -181,74 +181,68 @@ logerr stc
ret
; map sector into dskbuf
; sector number from partition start
; IN dx:ax sector number
map add ax, [bpb+BPBHS]
add dx, [bpb+BPBHS+2]
; absolute sector count
; skip doing a read if sector number matches
; IN dx:ax sector number
mapabs cmp ax, [dskseek]
jne l003
cmp dx, [dskseek+2]
je l002
; flush and read other sector
l003 push ax
; IN dx:ax absolute sector number
map cmp ax, [drvseek]
jne .do
cmp dx, [drvseek+2]
jne .do
ret
; flush previous contents
.do push ax
push dx
call flush
pop dx
pop ax
; store the sector number
mov [dskseek], ax
mov [dskseek+2], dx
jmp _read
; set sector number
mov [drvseek], ax
mov [drvseek+2], dx
; issue read cmd
mov ch, 2
jmp diskio
; mark dskbuf as containing unwritten changes
dirty or byte [cs:dskflag], 1 ; dirty
dirty or word [cs:dflags], DIRTY
l002 ret
; flush buffer if dirty
flush test byte [cs:dskflag], 1
flush test word [cs:dflags], DIRTY
jz l002
; low level read and write
; call again to retry, no input registers
; read or write is configured in cx
_write mov ch, 3
db 0x3D ; cmp ax, imm16: causes next 2 bytes to be skipped
_read mov ch, 2
mov cl, 1 ; read len
; issue write cmd
mov ch, 3
; Do disk I/O
; IN ch 2 = read
; 3 = write
; Sector number is read from [drvseek]
diskio mov cl, 1 ; read len
; DS := ES := CS
mov ax, cs
mov ds, ax
mov es, ax
call rstseg
; check if ebios supported
test byte [dskflag], 4
jz .l00
test word [dflags], DRVEXT
jz .noext
; set up regs for ebios call
mov ax, cx
or ah, 0x40
mov si, dap
jmp .do
; check if we can skip controller reset
.l00 test byte [dskflag], 2
jnz .l01
.noext test word [dflags], DRVRST
jnz .norst
; do controller reset
mov dl, [biosnum]
mov ah, 0
call int13
or byte [dskflag], 2
; put sectors per cylinder into bx
.l01 mov ax, [bpb+BPBSPT]
mul word [bpb+BPBNOS]
mov bx, ax
or word [dflags], DRVRST
; put linear sector num into dx:ax
mov ax, [dskseek]
mov dx, [dskseek+2]
; dx:ax = linear count, bx = sectors / cylinder
div bx
.norst mov ax, [drvseek]
mov dx, [drvseek+2]
; dx:ax = linear count
div word [drvspc]
; TODO: is it possible to get an overflow here?
xchg ax, dx
; dx = cylinder, ax = head * spt + sector
mov bl, [bpb+BPBSPT]
div byte bl
div byte [drvspt]
; dx = cylinder, al = head, ah = sector
xchg dl, dh
ror dl, 1
@ -274,34 +268,57 @@ _read mov ch, 2
call int13
jc .err
; clear dirty flag on success
and byte [dskflag], 0xFE
and word [dflags], ~DIRTY
clc
ret
; assume controller is misconfigured
.err and byte [dskflag], 0xFD
.err and word [dflags], ~DRVRST
; exit with carry flag set
stc
ret
init mov ax, 0x0e38
int 0x10
init mov ax, cs
; boot failure if loaded wrong
cmp ax, cseg
je $+4
int 0x18
halt hlt
jmp halt
section .bss
dap db 0x10, 0
dw 1
dw dskbuf, cseg
drvseek dw 0,0,0,0
; bios drive we end up using
biosnum resb 1
; bit 0 (1) - dirty flag for dskbuf
; bit 0 (1) - drive logged in (see drvnum)
; bit 1 (2) - controller configured
; bit 2 (4) - EBIOS supported
dskflag resb 1
; bit 3 (8) - dskbuf dirty
dflags dw 0
dpt resb 11
section .bss
bpb resb BPBSIZ
; drive currently logged in
drvnum resb 1
; number, just for bios
biosnum resb 1
; DPT tables for 4 floppy drives
dpt resb 4*14
; Information for logged in drive
drvss resb 1 ; sector size, 2^(7+n) bytes
drvcs resb 1 ; cluster size, 2^(7+n) bytes
alignb 4
drvspt resb 2 ; sectors per track
drvspc resb 2 ; sectors per cylinder
drvoff resb 4 ; partition offset
drvend resb 4 ; first sector after the partition
drvfat resb 4 ; offset to fat table
drvrd resb 4 ; offset of root directory
drvcla resb 4 ; offset to cluster area
drvfn resb 2 ; sectors per fat table
; disk buffer for I/O operations
alignb 2
dskbuf resb 512
dskbuf resb 1024