; 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 ; 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 ; load boot sector xor ax, ax xor dx, dx call mapabs ; copy bios parameter block lea si, [dskbuf+BPBOFF] mov di, bpb mov cx, BPBSIZ4 rep movsb ; make sure partition offset is forced zero xor ax, ax mov [bpb+BPBHS], ax mov [bpb+BPBHS+2], ax .ret: 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, [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 ; 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