diff --git a/kernel/drive.asm b/kernel/drive.asm index bfd0c32..7f9a0eb 100644 --- a/kernel/drive.asm +++ b/kernel/drive.asm @@ -17,7 +17,9 @@ biosnum: resb 1 ; absolute, ignores partition dskseek: resd 1 - ; bit 0 - dirty flag for dskbuf + ; bit 0 (1) - dirty flag for dskbuf + ; bit 1 (2) - controller configured + ; bit 2 (4) - EBIOS supported dskflag: resb 1 ; disk buffer for I/O operations @@ -42,6 +44,13 @@ dinit: ; copy previously set DPT to our data area mov word [4*0x1E+2], ds ret + ; int 13 stub + ; place reserved for stack switches +int13: ;int 3 + int 0x13 + ;int 3 + ret + ; restore DPT to default values if possible ; IN dl bios drive number rstdpt: mov ah, 8 @@ -109,35 +118,6 @@ logdrv: ; dont do anything if drive already selected mov [bpb+BPBHS+2], ax .ret: ret -calchs: ; put sectors per cylinder into bx - mov ax, [bpb+BPBSPT] - mul word [bpb+BPBNOS] - mov bx, ax - ; put linear sector num into dx:ax - mov ax, [dskseek] - mov dx, [dskseek+2] - ; dx:ax = linear count, bx = sectors / cylinder - div bx - xchg ax, dx - ; dx = cylinder, ax = head * spt + sector - mov bl, [bpb+BPBSPT] - div byte bl - ; 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, [biosnum] - mov bx, dskbuf - ret - mapclu: ; counting from begin of cluster area mov bx, [bpb+BPBRDE] mov cl, 4 @@ -175,10 +155,66 @@ read: push ax mov [dskseek], ax mov [dskseek+2], dx ; do the actual read - ; TODO: error handling & retries - call calchs - mov ax, 0x0201 - int 0x13 + + ; set the operation code and back it up to the stack +_read: mov ch, 2 + db 0x3D ; cmp ax, imm16: causes next instr to be skipped +_write: mov ch, 3 + mov cl, 1 ; read len + ; TODO: do ebios i/o + ; check if we can skip controller reset + test byte [dskflag], 2 + jnz .l01 + ; do controller reset + mov dl, [biosnum] + mov ah, 0 + call int13 + or byte [dskflag], 2 +.l01: ; put sectors per cylinder into bx + mov ax, [bpb+BPBSPT] + mul word [bpb+BPBNOS] + mov bx, ax + ; put linear sector num into dx:ax + mov ax, [dskseek] + mov dx, [dskseek+2] + ; dx:ax = linear count, bx = sectors / cylinder + div bx + xchg ax, dx + ; dx = cylinder, ax = head * spt + sector + mov bl, [bpb+BPBSPT] + div byte bl + ; 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 + ; shuffle values around for bios + xchg ax, cx + xchg cx, dx + xchg dh, dl + mov dl, [biosnum] + mov bx, dskbuf + ; ah: subfunction selected via cx previously + ; al: 1 = reading 1 sector + ; cx: sector and cylinder number + ; dh: head number + ; dl: drive number + ; bx: offset to disk buffer + call int13 + jc .err + ; clear dirty flag on success + and byte [dskflag], 0xFE + clc + ret +.err: ; assume controller is misconfigured + and byte [dskflag], 0xFD + ; exit with carry flag set + stc ret ; mark dskbuf as containing unwritten changes @@ -188,11 +224,6 @@ dirty: or byte [dskflag], 1 ; dirty ; flush buffer if dirty flush: test byte [dskflag], 1 jz .ret - ; do the write ; TODO: error handling & retries - call calchs - mov ax, 0x0301 - int 0x13 - ; remove dirty flag - and byte [dskflag], 0xFE + jmp _write .ret: ret