From b7d596d758ab860c2904e68eada72e4f2c50744d Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Tue, 14 Dec 2021 17:43:47 +0000 Subject: [PATCH] kernel: integrate existing farptr and drive code --- kernel/drive.asm | 323 ------------------------------- src/@rdos.asm | 305 ++++++++++++++++++++++++++++- kernel/far.asm => src/farptr.inc | 4 +- 3 files changed, 306 insertions(+), 326 deletions(-) delete mode 100644 kernel/drive.asm rename kernel/far.asm => src/farptr.inc (94%) diff --git a/kernel/drive.asm b/kernel/drive.asm deleted file mode 100644 index 75b9aa5..0000000 --- a/kernel/drive.asm +++ /dev/null @@ -1,323 +0,0 @@ -; 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 - -BPBOFF equ 0xB - -; DOS 2.0 BPB -BPBSS equ 0 ; word -BPBSC equ 2 ; byte -BPBRSC equ 3 ; word -BPBFN equ 5 ; byte -BPBRDE equ 6 ; word -BPBTS equ 8 ; word -BPBMD equ 10 ; byte -BPBFS equ 11 ; word -BPBSIZ2 equ 13 ; size constant - -; DOS 3.31 BPB -BPBSPT equ 0x0D ; word -BPBNOS equ 0x0F ; word -BPBHS equ 0x11 ; dword -BPBLTS equ 0x15 ; dword -BPBSIZ3 equ 25 ; size constant - -; DOS 3.4 EBPB -BPBDN equ 0x19 ; byte -BPBFALG equ 0x1A ; byte -BPBSIG equ 0x1B ; byte -BPBSER equ 0x1C ; dword serial number -BPBSIZ4 equ 32 ; size constant - -; Disk parameter table (int 1E) -DPTSIZE equ 11 -DPTSPT equ 4 - -section .bss - - ; bios drive we end up using -biosnum resb 1 - - ; 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 - alignb 2 -dskbuf resb 512 - -dpt resb DPTSIZE -bpb resb BPBSIZ4 - -section .data - - ; 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 - -section .text - - ; initial setup for disk i/o - ; copy previously set DPT to our data area -dinit xor ax, ax - mov es, ax - les bx, [es:4*0x1E] - mov dx, dpt - mov cx, 11 - call lodfar - ; set interrupt vector - 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 - - ; int 13 stub - ; this is meant as a central place to implement - ; stack switching or some other safeguards -int13 int 0x13 - ret - - ; get drive parameters - ; read BIOS int13h/AH=8 values - ; DPT data gets copied over our dpt - ; CHS data gets inserted into our bpb -getprm test byte [dskflag], 4 - jnz .ret - ; do the query - mov ah, 8 - mov dl, [biosnum] - call int13 - ; bail out if error - jc .ret - ; ignore CHS values if odd - test cl, cl - jz .nochs - ; get and store sector number - and cx, 0x3F - mov word [bpb+BPBSPT], cx - ; get and store number of heads - xchg dl, dh - and dx, 0xFF - inc dx - mov [bpb+BPBNOS], dx - ; test if DPT ptr is non-zero -.nochs mov ax, es - or ax, di - test ax, ax - jz .ret - ; copy BIOS dpt table over ours - mov dx, dpt - mov bx, di - mov cx, 11 - call lodfar -.ret ret - - ; select a drive for io - ; IN dl drive number - ; dont do anything if drive already selected -select cmp dl, [dsknum] - je logfdd.ret - ; clear out current contents - 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 - ; fork off if hdd - cmp dl, 2 - jnc loghdd - -logfdd mov [biosnum], dl - ; assume some default values - xor ax, ax - mov word [bpb+BPBHS], ax - mov word [bpb+BPBHS+2], ax - mov word [bpb+BPBNOS], 2 ; 5 1/4" 360kB - mov word [bpb+BPBSPT], 9 - ; reset dpt to defaults - call getprm - ; 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 - call rstseg - mov si, dskbuf+BPBOFF - mov di, bpb - mov cx, BPBSIZ4 - rep movsb - ; copy SPT to DPT - mov al, [bpb+BPBSPT] - mov [dpt+4], al -.ret ret - -loghdd sub dl, 2 - cmp dl, 4 - jnc logerr - push dx - mov dl, 0x80 - mov byte [biosnum], dl - ; test for ebios extensions - mov ah, 0x41 - mov bx, 0x55AA - call int13 - sbb bx, 0xAA55 - jnz .chs - ; enable ebios and assume controller is configured - or byte [dskflag], (2+4) - ; get chs data (needed or we cant load vbr) -.chs call getprm - ; read mbr - xor ax, ax - xor dx, dx - call mapabs - ; get partition number - pop bx - xor bh, bh - mov cl, 4 - sal bx, cl - ; bail out if no partition - cmp byte [dskbuf+0x1be+bx+4], 0 - je logerr - ; load partition offset - mov ax, [dskbuf+0x1be+bx+8] - mov dx, [dskbuf+0x1be+bx+8+2] - ; save to to stack - push dx - push ax - ; load vbr - call mapabs - ; copy bpb - mov si, dskbuf+BPBOFF - mov di, bpb - mov cx, BPBSIZ4 - rep movsb - ; fix CHS data - call getprm - ; fix partition offset - pop word [bpb+BPBHS] - pop word [bpb+BPBHS+2] - ;pop [bpb+BPBNOS] - ;pop [bpb+BPBSPT] - ret - -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 - push dx - call flush - pop dx - pop ax - ; store the sector number - mov [dskseek], ax - mov [dskseek+2], dx - jmp _read - - ; mark dskbuf as containing unwritten changes -dirty or byte [cs:dskflag], 1 ; dirty -l002 ret - - ; flush buffer if dirty -flush test byte [cs:dskflag], 1 - 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 - ; DS := ES := CS - mov ax, cs - mov ds, ax - mov es, ax - ; check if ebios supported - test byte [dskflag], 4 - jz .l00 - 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 - ; 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 - ; 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 bx, dskbuf -.do mov dl, [biosnum] - ; 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 - ; assume controller is misconfigured -.err and byte [dskflag], 0xFD - ; exit with carry flag set - stc - ret diff --git a/src/@rdos.asm b/src/@rdos.asm index cd4f9f8..973a134 100644 --- a/src/@rdos.asm +++ b/src/@rdos.asm @@ -1,4 +1,307 @@ - mov ax, 0x0e38 + 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 + + ; initial setup for disk i/o + ; copy previously set DPT to our data area +dinit xor ax, ax + mov es, ax + les bx, [es:4*0x1E] + mov dx, dpt + mov cx, 11 + call lodfar + ; set interrupt vector + 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 + ; IBM Interrupt Sharing Protocol structure +i13isp jmp short int13i + dw 0,0xFFFF + dw 0x424B + db 0 + iret + align 16 + +int13i call int13 + iret + + ; Wrapper around int 13h +int13 pushf + call far [i13isp+2] + ; TODO: on error: reset & retry + ; TODO: record errors + ; TODO: multi-track reading + ; TODO: handle DMA boundaries + ret + + ; get drive parameters + ; read BIOS int13h/AH=8 values + ; DPT data gets copied over our dpt + ; CHS data gets inserted into our bpb +getprm test byte [dskflag], 4 + jnz .ret + ; do the query + mov ah, 8 + mov dl, [biosnum] + call int13 + ; bail out if error + jc .ret + ; ignore CHS values if odd + test cl, cl + jz .nochs + ; get and store sector number + and cx, 0x3F + mov word [bpb+BPBSPT], cx + ; get and store number of heads + xchg dl, dh + and dx, 0xFF + inc dx + mov [bpb+BPBNOS], dx + ; test if DPT ptr is non-zero +.nochs mov ax, es + or ax, di + test ax, ax + jz .ret + ; copy BIOS dpt table over ours + mov dx, dpt + mov bx, di + mov cx, 11 + call lodfar +.ret ret + + ; select a drive for io + ; IN dl drive number + ; dont do anything if drive already selected +select cmp dl, [dsknum] + je logfdd.ret + ; clear out current contents + 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 + ; fork off if hdd + cmp dl, 2 + jnc loghdd + +logfdd mov [biosnum], dl + ; assume some default values + xor ax, ax + mov word [bpb+BPBHS], ax + mov word [bpb+BPBHS+2], ax + mov word [bpb+BPBNOS], 2 ; 5 1/4" 360kB + mov word [bpb+BPBSPT], 9 + ; reset dpt to defaults + call getprm + ; 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 + call rstseg + mov si, dskbuf+BPBOFF + mov di, bpb + mov cx, BPBSIZ + rep movsb + ; copy SPT to DPT + mov al, [bpb+BPBSPT] + mov [dpt+4], al +.ret ret + +loghdd sub dl, 2 + cmp dl, 4 + jnc logerr + push dx + mov dl, 0x80 + mov byte [biosnum], dl + ; test for ebios extensions + mov ah, 0x41 + mov bx, 0x55AA + call int13 + sbb bx, 0xAA55 + jnz .chs + ; enable ebios and assume controller is configured + or byte [dskflag], (2+4) + ; get chs data (needed or we cant load vbr) +.chs call getprm + ; read mbr + xor ax, ax + xor dx, dx + call mapabs + ; get partition number + pop bx + xor bh, bh + mov cl, 4 + sal bx, cl + ; bail out if no partition + cmp byte [dskbuf+0x1be+bx+4], 0 + je logerr + ; load partition offset + mov ax, [dskbuf+0x1be+bx+8] + mov dx, [dskbuf+0x1be+bx+8+2] + ; save to to stack + push dx + push ax + ; load vbr + call mapabs + ; copy bpb + mov si, dskbuf+BPBOFF + mov di, bpb + mov cx, BPBSIZ + rep movsb + ; fix CHS data + call getprm + ; fix partition offset + pop word [bpb+BPBHS] + pop word [bpb+BPBHS+2] + ;pop [bpb+BPBNOS] + ;pop [bpb+BPBSPT] + ret + +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 + push dx + call flush + pop dx + pop ax + ; store the sector number + mov [dskseek], ax + mov [dskseek+2], dx + jmp _read + + ; mark dskbuf as containing unwritten changes +dirty or byte [cs:dskflag], 1 ; dirty +l002 ret + + ; flush buffer if dirty +flush test byte [cs:dskflag], 1 + 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 + ; DS := ES := CS + mov ax, cs + mov ds, ax + mov es, ax + ; check if ebios supported + test byte [dskflag], 4 + jz .l00 + 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 + ; 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 + ; 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 bx, dskbuf +.do mov dl, [biosnum] + ; 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 + ; assume controller is misconfigured +.err and byte [dskflag], 0xFD + ; exit with carry flag set + stc + ret + +init mov ax, 0x0e38 int 0x10 halt hlt jmp halt + +section .bss + + ; bios drive we end up using +biosnum resb 1 + + ; bit 0 (1) - dirty flag for dskbuf + ; bit 1 (2) - controller configured + ; bit 2 (4) - EBIOS supported +dskflag resb 1 + +dpt resb 11 + +bpb resb BPBSIZ + + ; disk buffer for I/O operations + alignb 2 +dskbuf resb 512 diff --git a/kernel/far.asm b/src/farptr.inc similarity index 94% rename from kernel/far.asm rename to src/farptr.inc index a799241..b98729c 100644 --- a/kernel/far.asm +++ b/src/farptr.inc @@ -21,13 +21,13 @@ stofar mov si, dx ; cx number of bytes to copy ; OUT cx set to zero ; si & di trashed -lodfar call xchgdes +lodfar call swpds mov si, bx mov di, dx rep movsb ; exchange es and ds -xchgdes push ds +swpds push ds push es pop ds pop es