diff --git a/boot/mbr.asm b/boot/mbr.asm index 135763f..af44954 100644 --- a/boot/mbr.asm +++ b/boot/mbr.asm @@ -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 diff --git a/src/@rdos.asm b/src/@rdos.asm index 973a134..ccd2e3c 100644 --- a/src/@rdos.asm +++ b/src/@rdos.asm @@ -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