; 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 dpt: resb DPTSIZE bpb: resb BPBSIZ4 section .text ; initial setup for disk i/o dinit: ; copy previously set DPT to our data area lds si, [4*0x1E] mov di, dpt mov cx, 11 rep movsb ; restore DS xor ax, ax mov ds, ax ; set vector mov word [4*0x1E], dpt mov word [4*0x1E+2], ds ret ; restore DPT to default values if possible ; IN dl bios drive number rstdpt: mov ah, 8 int 0x13 jc .ret mov ax, es or ax, di test ax, ax jz .ret ; DS:SI = ES:DI mov ax, es mov ds, ax mov si, di ; ES:DI = dpt xor ax, ax mov es, ax mov di, dpt ; do the copy mov cx, 11 rep movsb .ret: ; restore DS to 0 xor ax, ax mov ds, ax ret ; log in drive ; currently only supports 18 sectors 2 heads floppies ; IN dl drive number logdrv: ; dont do anything if drive already selected cmp dl, [dsknum] je .ret ; clear out current contents .force: push dx call flush mov ax, 0xFFFF mov [dskseek], ax mov [dskseek+2], ax mov byte [dskflag], 0 pop dx ; set current drive number mov [dsknum], dl ; save info for bios mov [biosnum], dl ; reset dpt to defaults call rstdpt ; set default geometry (1.44 MB floppy) mov word [bpb+BPBNOS], 2 mov word [bpb+BPBSPT], 18 ; load boot sector xor ax, ax xor dx, dx call mapabs ; copy bios parameter block ; TODO: guess from first byte of FAT if BPB invalid mov si, dskbuf+BPBOFF mov di, bpb mov cx, BPBSIZ4 rep movsb ; copy SPT to DPT mov al, [bpb+BPBSPT] mov [dpt+4], al ; make sure partition offset is forced zero xor ax, ax mov [bpb+BPBHS], ax 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 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, [bpb+BPBHS] add dx, [bpb+BPBHS+2] mapabs: ; absolute sector count ; skip doing a read if sector number matches cmp ax, [dskseek] jne read cmp dx, [dskseek+2] jne read ret read: 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: 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 .ret: ret