From 84b754551c8c43e28fcd88cee75a9649ac4198ad Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Sun, 7 Feb 2021 16:17:31 +0000 Subject: [PATCH] Restructure kernel to use 1-segment COM convention --- Makefile | 6 +- boot/kernel.asm | 107 --------- com/@rdos.asm | 38 +++ host/sys.c | 16 +- inc/dpt.asm | 5 - kernel/drive.asm | 611 ++++++++++++++++++++++------------------------- kernel/far.asm | 34 +++ 7 files changed, 369 insertions(+), 448 deletions(-) delete mode 100644 boot/kernel.asm create mode 100644 com/@rdos.asm delete mode 100644 inc/dpt.asm create mode 100644 kernel/far.asm diff --git a/Makefile b/Makefile index fb95607..3012944 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PROGRAMS = hello.com -DISTFILES = kernel.bs $(PROGRAMS) +DISTFILES = @rdos.com $(PROGRAMS) ROMS = QEMU = qemu-system-i386 @@ -43,7 +43,7 @@ host/%.elf: host/%.c %.bs: boot/%.asm $(NASM) $(NASM_ARGS) -o $@ $< -kernel.bs: kernel/*.asm +@rdos.com: kernel/*.asm # Special case: variations of FAT vbr fat1.bs: boot/fat.asm @@ -62,7 +62,7 @@ fat6.bs: boot/fat.asm fd%.img: $(DISTFILES) $(SYS) mformat -C -i $@ -f $* -c 2 -v "$(LABEL)" :: mcopy -i $@ $(DISTFILES) :: - $(SYS) $@ hello.com + $(SYS) $@ @rdos.com clean: rm -f *.com *.bs *.0 *.lst *.img *.bin *.rom diff --git a/boot/kernel.asm b/boot/kernel.asm deleted file mode 100644 index f712638..0000000 --- a/boot/kernel.asm +++ /dev/null @@ -1,107 +0,0 @@ - cpu 8086 - org 0x0700 - -%include "inc/bpb.asm" -%include "inc/mbr.asm" -%include "inc/dpt.asm" - -init: cli - xor ax, ax - mov ds, ax - mov es, ax - mov ss, ax - mov sp, ax - - mov si, 0x7C00 - ; relocate to 00700 - mov di, text_start - mov cx, text_length + rodata_length + data_length - rep movsb - ; clear out bss section - mov cx, bss_length - rep stosb - ; jump to copy - call 0:relinit - -section .rodata - -%define V 0x %+ VERSION -version: dd V - -section .text - -relinit: ; print banner - push word [version] - push word [version+2] - call printf - db "RDOS ",2,2, 0x0A, 0x0D, 0 - ; initialize the disk i/o - call dinit - ; init 21h vector - mov word [0x21*4], int21 - mov word [0x21*4+2], cs - ; set current PSP, directly after us - mov ax, stack - mov cl, 4 - shr ax, cl - mov word [curpsp], ax - ; also the DTA - mov bx, dta - call setdta - ; set current drive to boot drive - mov al, dl - rol al, 1 - rol al, 1 - or dl, al - and dl, 3 - call setdd - - mov bx, testfcb - call fndfst - -restart: -hlt: hlt - jmp hlt - -%include "kernel/psp.asm" -%include "kernel/syscall.asm" -%include "kernel/char.asm" -%include "kernel/fcb.asm" -%include "kernel/drive.asm" -%include "kernel/printf.asm" - -section .bss - -dta: resb 128 - -section .data - -testfcb: db 0 - db "HELLO ", "COM" - times 30 db 0 - -section .text - -text_start equ $$ -text_length equ $-$$ - -section .rodata - -rodata_start equ $$ -rodata_length equ $-$$ - -section .data - -data_start equ $$ -data_length equ $-$$ - -section .bss - - resw 256 ; 512b kern stack - alignb 16 -stack: ; stack grows into this ^ - ; this is also the end marker - ; programs with their psp start here - -bss_start equ $$ -bss_length equ $-$$ diff --git a/com/@rdos.asm b/com/@rdos.asm new file mode 100644 index 0000000..34a62e2 --- /dev/null +++ b/com/@rdos.asm @@ -0,0 +1,38 @@ + org 0x100 + + jmp init + +%defstr V VERSION +banner: db "RDOS ", V, 0x0A, 0x0D, 0, 0x1A + +%include "kernel/far.asm" +%include "inc/bpb.asm" +%include "kernel/drive.asm" + +section .text + +init: call rstseg + mov si, banner +.l01: lodsb + test al, al + jz .l02 + mov ah, 0x0e + xor bx, bx + int 0x10 + jmp .l01 +.l02: + call dinit + + mov dl, 0 + call logdrv + + xor ax, ax + xor dx, dx + call maprd + + inc word [dskbuf+0x80] + call dirty + call flush + +hlt: hlt + jmp hlt diff --git a/host/sys.c b/host/sys.c index d873d33..a5d3b67 100644 --- a/host/sys.c +++ b/host/sys.c @@ -117,14 +117,14 @@ int main(int argc, char** argv) { char* putsfunc = ptr; // assemble puts function - ptr = push_imm16(ptr, 0xAC5E); - ptr = push_imm16(ptr, 0xC084); - ptr = push_imm16(ptr, 0x0874); - ptr = push_imm16(ptr, 0x0EB4); - ptr = push_imm16(ptr, 0xDB31); - ptr = push_imm16(ptr, 0x10CD); - ptr = push_imm16(ptr, 0xF3EB); - ptr = push_imm16(ptr, 0xE6FF); + //ptr = push_imm16(ptr, 0xAC5E); + //ptr = push_imm16(ptr, 0xC084); + //ptr = push_imm16(ptr, 0x0874); + //ptr = push_imm16(ptr, 0x0EB4); + //ptr = push_imm16(ptr, 0xDB31); + //ptr = push_imm16(ptr, 0x10CD); + //ptr = push_imm16(ptr, 0xF3EB); + //ptr = push_imm16(ptr, 0xE6FF); // assemble entry point to our main code push_jmp(bs, ptr); diff --git a/inc/dpt.asm b/inc/dpt.asm deleted file mode 100644 index 9586925..0000000 --- a/inc/dpt.asm +++ /dev/null @@ -1,5 +0,0 @@ -DPTMTT equ 2 -DPTSS equ 3 -DPTSPT equ 4 - -DPTSIZE equ 11 diff --git a/kernel/drive.asm b/kernel/drive.asm index 757bc63..39697bc 100644 --- a/kernel/drive.asm +++ b/kernel/drive.asm @@ -5,349 +5,310 @@ ; - dirty: inform that dskbuf has been written to ; access is done by accessing dskbuf directly +DPTSIZE equ 11 +DPTSPT equ 4 + section .bss - ; drive actually selected for I/O -dsknum: resb 1 + ; bios drive we end up using +biosnum resb 1 - ; 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 -dap: resw 2 -.buf: resw 2 - ; current sector number - ; absolute, ignores partition -dskseek: resd 2 + ; disk buffer for I/O operations +dskbuf resb 512 - ; bit 0 (1) - dirty flag for dskbuf - ; bit 1 (2) - controller configured - ; bit 2 (4) - EBIOS supported -dskflag: resb 1 +dpt resb DPTSIZE +bpb resb BPBSIZ4 - ; disk buffer for I/O operations -dskbuf: resb 512 +section .data -dpt: resb DPTSIZE -bpb: resb BPBSIZ4 + ; 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 -dinit: ; copy previously set DPT to our data area - push ds - push cs - pop es - lds si, [es:4*0x1E] - mov di, dpt - mov cx, 11 - rep movsb - ; set vector - mov word [cs:4*0x1E], dpt - mov word [cs:4*0x1E+2], ds - ; set to invalid drive - mov byte [cs:dsknum], 0xFF - pop ds - ret + ; 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 -int13: ; debug output - push bx - push dx - push cx - push ax - call printf - db "int13 CALL AX=",2," CX=",2," DX=",2," BX=",2,0x0A,0x0D,0 - ; do the call - int 0x13 - jc .err - ret -.err: push ax - call printf - db "DISK ERR AX=",2,0x0A,0x0D,0 - stc - 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: ; skip if EBIOS extension enabled - test byte [cs:dskflag], 4 - jnz .ret - ; do the query - mov ah, 8 - mov dl, [cs: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 [cs:bpb+BPBSPT], cx - ; get and store number of heads - xchg dl, dh - and dx, 0xFF - inc dx - mov [cs:bpb+BPBNOS], dx - ; test if DPT ptr is non-zero -.nochs: 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: 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 + call lodfar +.ret ret - ; log in drive - ; IN dl drive number -logdrv: ; DS := CS - push cs - pop ds - ; dont do anything if drive already selected - cmp dl, [dsknum] - je logfdd.ret - ; clear out current contents - push dx - push ds - call flush - pop ds - 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 + ; log in drive + ; IN dl drive number + ; dont do anything if drive already selected +logdrv 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: ; save info for bios - mov [biosnum], dl - ; reset dpt to defaults - push ds - call getprm - pop ds - ; set default geometry (1.44 MB floppy) - mov word [bpb+BPBNOS], 2 - mov word [bpb+BPBSPT], 18 - ; load boot sector - push ds - xor ax, ax - xor dx, dx - call mapabs - pop ds - ; copy bios parameter block - ; TODO: guess from first byte of FAT if BPB invalid - push ds - pop es - 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 + ; save info for bios +logfdd mov [biosnum], dl + ; reset dpt to defaults + call getprm + ; 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 + 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 + ; make sure partition offset is forced zero + xor ax, ax + mov [bpb+BPBHS], ax + mov [bpb+BPBHS+2], ax +.ret ret - ; assumes that DS == CS -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) - ; initialize DAP - mov word [dap], 0x10 - mov word [dap+2], 1 - mov word [dap+4], dskbuf - xor ax, ax - mov word [dap+6], ax - mov word [dap+12], ax - mov word [dap+14], ax - ; 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 [cs:dskbuf+0x1be+bx+4], 0 - je logerr - ; load partition offset - mov ax, [cs:dskbuf+0x1be+bx+8] - mov dx, [cs:dskbuf+0x1be+bx+8+2] - ; save to to stack - push dx - push ax - ; load vbr - call mapabs - ; copy bpb - mov ax, cs - mov ds, ax - mov es, ax - mov si, dskbuf+BPBOFF - mov di, bpb - mov cx, BPBSIZ4 - rep movsb - ; fix CHS data - call getprm - ; fix partition offset - pop ax - pop dx - mov [cs:bpb+BPBHS], ax - mov [cs:bpb+BPBHS+2], dx - 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 +logerr stc + ret -mapclu: ; counting from begin of cluster area - mov bx, [cs: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 [cs:bpb+BPBFN] -.loop: add ax, [cs:bpb+BPBFS] - adc dx, 0 - loop .loop -mapfat: ; counting from beginning of FAT - ; add reserved sector count - add ax, [cs:bpb+BPBRSC] - adc dx, 0 -map: ; count from partition start - add ax, [cs:bpb+BPBHS] - add dx, [cs:bpb+BPBHS+2] -mapabs: ; absolute sector count - ; skip doing a read if sector number matches - cmp ax, [cs:dskseek] - jne read - cmp dx, [cs:dskseek+2] - jne read - ret + ; counting from begin of cluster area +mapclu mov bx, [bpb+BPBRDE] + mov cl, 4 + shr bx, cl ; 32 bytes per entry + add ax, bx + adc dx, 0 + ; counting from beginning of dir + ; add fat table sizes +maprd xor ch, ch + mov cl, byte [bpb+BPBFN] +.loop add ax, [bpb+BPBFS] + adc dx, 0 + loop .loop + ; counting from beginning of FAT + ; add reserved sector count +mapfat add ax, [bpb+BPBRSC] + adc dx, 0 + ; count from partition start +map add ax, [bpb+BPBHS] + add dx, [bpb+BPBHS+2] + ; absolute sector count + ; skip doing a read if sector number matches +mapabs 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 [cs:dskseek], ax - mov [cs:dskseek+2], dx - ; do the actual read +read push ax + push dx + call flush + pop dx + pop ax + ; store the sector number + mov [cs:dskseek], ax + mov [cs:dskseek+2], dx + ; do the actual read - ; low level read and write - ; call again to retry, no input registers - ; read or write is configured in cx -_read: mov ch, 2 - db 0x3D ; cmp ax, imm16: causes next instr to be skipped -_write: mov ch, 3 - 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 -.l01: ; 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 - ; 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 -.err: ; assume controller is misconfigured - and byte [dskflag], 0xFD - ; exit with carry flag set - stc - ret + ; low level read and write + ; call again to retry, no input registers + ; read or write is configured in cx +_read mov ch, 2 + db 0x3D ; cmp ax, imm16: causes next instr to be skipped +_write mov ch, 3 + 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 +.l01 ; 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 + ; 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 +.err ; assume controller is misconfigured + and byte [dskflag], 0xFD + ; exit with carry flag set + stc + ret - ; mark dskbuf as containing unwritten changes -dirty: or byte [cs:dskflag], 1 ; dirty - ret + ; mark dskbuf as containing unwritten changes +dirty or byte [cs:dskflag], 1 ; dirty + ret - ; flush buffer if dirty -flush: test byte [cs:dskflag], 1 - jz .ret - ; TODO: error handling & retries - jmp _write -.ret: ret + ; flush buffer if dirty +flush test byte [cs:dskflag], 1 + jz .ret + ; TODO: error handling & retries + jmp _write +.ret ret diff --git a/kernel/far.asm b/kernel/far.asm new file mode 100644 index 0000000..239cd2b --- /dev/null +++ b/kernel/far.asm @@ -0,0 +1,34 @@ + ; reset segments +rstseg mov ax, cs + mov ds, ax + mov es, ax + ret + + ; copy to far memory + ; IN es:bx far memory ptr (preserved) + ; ds:dx local ptr (preserved) + ; cx number of bytes to transfer + ; OUT cx set to zero + ; si & di trashed +stofar mov si, dx + mov di, bx + rep movsb + ret + + ; copy from far memory + ; IN es:bx far memory ptr (preserved) + ; ds:dx local ptr (preserved) + ; cx number of bytes to copy + ; OUT cx set to zero + ; si & di trashed +lodfar call xchgdes + mov si, bx + mov di, dx + rep movsb + + ; exchange es and ds +xchgdes push ds + push es + pop ds + pop es + ret