From e096745c1382ae71e864821525414e4fb6cd3e97 Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Tue, 15 Dec 2020 23:29:35 +0000 Subject: [PATCH] Implement map-like sector access for floppy drives --- boot/kernel.asm | 13 +++- kernel/drive.asm | 183 ++++++++++++++++++++++++++++++----------------- kernel/fcb.asm | 2 +- 3 files changed, 131 insertions(+), 67 deletions(-) diff --git a/boot/kernel.asm b/boot/kernel.asm index 74f359d..38afa3b 100644 --- a/boot/kernel.asm +++ b/boot/kernel.asm @@ -31,8 +31,17 @@ print_banner: mov si, banner call dskrst - mov bx, testfcb - call fcbfst + mov dl, [defdrv] + call logdrv + + xor ax, ax + xor dx, dx + call maprd + + inc word [dskbuf+0x82] + + call dirty + call flush hlt: hlt jmp hlt diff --git a/kernel/drive.asm b/kernel/drive.asm index 17135f1..35d1926 100644 --- a/kernel/drive.asm +++ b/kernel/drive.asm @@ -1,10 +1,25 @@ +; code for disk i/o +; from outside, only the following methods are meant to be called: +; - logdrv: select drive DL to operate on +; - map*: map sector DX:AX into dskbuf +; - dirty: inform that dskbuf has been written to +; access is done by accessing dskbuf directly + section .bss ; drive actually selected for I/O dsknum: resb 1 + + ; bios drive we end up using +biosnum: resb 1 + ; current sector number + ; absolute, ignores partition dskseek: resd 1 + ; bit 0 - dirty flag for dskbuf +dskflag: resb 1 + ; disk buffer for I/O operations dskbuf: resb 512 @@ -13,69 +28,6 @@ bpb: resb BPBSIZ4 section .text -ret: ret - - ; Convert drive number into DL for int 13h - ; A=0, B=1, C=0x80 - ; IN dl dos drive number - ; OUT dl bios drive number -getdl: cmp dl, 2 - jc ret - mov dl, 0x80 - ret - - ; Ask BIOS for drive parameters - ; IN dl dos drive number - ; OUT CX,DH chs data - ; ES:DI DPT if floppy -qrychs: mov ah, 8 - les di, [0x1E*4] - int 0x13 - jc .defs - test cl, cl - jz .defs - ret - -.defs: mov cx, 0x2709 ; max track = 39, max sec = 9 - mov dh, 1 ; 2 heads - ret - - ; select drive - ; IN dl drive number -dsksel: cmp dl, byte [dsknum] - je ret - - call dskrst - - call getdl - push dx - call qrychs - - ; store CHS data in BPB - xor ax, ax - mov al, cl - mov [bpb+BPBSPT], ax - mov al, dh - inc ax - mov [bpb+BPBNOS], ax - - ; get dpt from bios if not hdd - pop dx - test dl, 0x80 - jnz .nodpt - push dx - mov dx, dpt - mov bx, di - mov cx, DPTSIZE - call lod - mov ax, [bpb+BPBSPT] - mov [dpt+DPTSPT], al - pop dx -.nodpt: - - - ret - dskrst: call flush mov ax, 0xFFFF mov [dsknum], al @@ -83,5 +35,108 @@ dskrst: call flush mov [dskseek+2], ax ret + ; log in drive + ; currently only supports 18 sectors 2 heads floppies + ; IN dl drive number +logdrv: mov [biosnum], dl + xor ax, ax + xor dx, dx + call read + + ; copy bios parameter block + lea si, [dskbuf+BPBOFF] + mov di, bpb + mov cx, BPBSIZ4 + rep movsb + + ; make sure partition offset is force zero + xor ax, ax + mov [bpb+BPBHS], ax + mov [bpb+BPBHS+2], ax + + ret + +calchs: mov bx, (18*2) + ; dx:ax = linear count, bx = sectors / cylinder + div bx + xchg ax, dx + ; dx = cylinder, ax = head * spt + sector + mov bl, 18 + 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 + shr bx, cl ; 32 bytes per entry + add ax, bx + adc dx, 0 +maprd: ; counting from beginning of dir + ; add fat table sizes + xor ch, ch + mov cl, byte [bpb+BPBFN] +.loop: add ax, [bpb+BPBFS] + adc dx, 0 + loop .loop +mapfat: ; counting from beginning of FAT + ; add reserved sector count + add ax, [bpb+BPBRSC] + adc dx, 0 +map: ; count from partition start + ;add ax, [BPBHS] + ;add dx, [BPBHS+2] + ; absolute sector count +mapabs: call read + ret + + ; hard read, absolute disk offset + ; TODO: retries on error + ; IN dx:ax +read: ; flush previous data if necessary + push ax + push dx + call flush + pop dx + pop ax + ; store the sector number + mov [dskseek], ax + mov [dskseek+2], dx + ; do the actual read + ; TODO: error handling & retries + call calchs + mov ax, 0x0201 + int 0x13 + ret + + ; mark dskbuf as containing unwritten changes +dirty: or byte [dskflag], 1 ; dirty + ret + ; flush buffer if dirty -flush: ret +flush: test byte [dskflag], 1 + jz .ret + ; load sector number + mov ax, [dskseek] + mov dx, [dskseek+2] + ; do the write + ; TODO: error handling & retries + call calchs + mov ax, 0x0301 + int 0x13 + ; remove dirty flag + and byte [dskflag], 0xFE +.ret: ret diff --git a/kernel/fcb.asm b/kernel/fcb.asm index aba293f..2e10f7b 100644 --- a/kernel/fcb.asm +++ b/kernel/fcb.asm @@ -17,7 +17,7 @@ setdrv: mov dl, [es:bx+fcb.drive] ; A=1 mov [es:bx+fcb.drive], dl ; A=1 ; now set as current i/o drive .nofix: dec dl ; A=0 for dsksel - jmp dsksel + jmp logdrv ; FCB open fcbopn: ; call fcbfst