Restructure kernel to use 1-segment COM convention

This commit is contained in:
Nero 2021-02-07 16:17:31 +00:00
parent 71c89387fc
commit 84b754551c
7 changed files with 369 additions and 448 deletions

View File

@ -1,5 +1,5 @@
PROGRAMS = hello.com PROGRAMS = hello.com
DISTFILES = kernel.bs $(PROGRAMS) DISTFILES = @rdos.com $(PROGRAMS)
ROMS = ROMS =
QEMU = qemu-system-i386 QEMU = qemu-system-i386
@ -43,7 +43,7 @@ host/%.elf: host/%.c
%.bs: boot/%.asm %.bs: boot/%.asm
$(NASM) $(NASM_ARGS) -o $@ $< $(NASM) $(NASM_ARGS) -o $@ $<
kernel.bs: kernel/*.asm @rdos.com: kernel/*.asm
# Special case: variations of FAT vbr # Special case: variations of FAT vbr
fat1.bs: boot/fat.asm fat1.bs: boot/fat.asm
@ -62,7 +62,7 @@ fat6.bs: boot/fat.asm
fd%.img: $(DISTFILES) $(SYS) fd%.img: $(DISTFILES) $(SYS)
mformat -C -i $@ -f $* -c 2 -v "$(LABEL)" :: mformat -C -i $@ -f $* -c 2 -v "$(LABEL)" ::
mcopy -i $@ $(DISTFILES) :: mcopy -i $@ $(DISTFILES) ::
$(SYS) $@ hello.com $(SYS) $@ @rdos.com
clean: clean:
rm -f *.com *.bs *.0 *.lst *.img *.bin *.rom rm -f *.com *.bs *.0 *.lst *.img *.bin *.rom

View File

@ -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 $-$$

38
com/@rdos.asm Normal file
View File

@ -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

View File

@ -117,14 +117,14 @@ int main(int argc, char** argv) {
char* putsfunc = ptr; char* putsfunc = ptr;
// assemble puts function // assemble puts function
ptr = push_imm16(ptr, 0xAC5E); //ptr = push_imm16(ptr, 0xAC5E);
ptr = push_imm16(ptr, 0xC084); //ptr = push_imm16(ptr, 0xC084);
ptr = push_imm16(ptr, 0x0874); //ptr = push_imm16(ptr, 0x0874);
ptr = push_imm16(ptr, 0x0EB4); //ptr = push_imm16(ptr, 0x0EB4);
ptr = push_imm16(ptr, 0xDB31); //ptr = push_imm16(ptr, 0xDB31);
ptr = push_imm16(ptr, 0x10CD); //ptr = push_imm16(ptr, 0x10CD);
ptr = push_imm16(ptr, 0xF3EB); //ptr = push_imm16(ptr, 0xF3EB);
ptr = push_imm16(ptr, 0xE6FF); //ptr = push_imm16(ptr, 0xE6FF);
// assemble entry point to our main code // assemble entry point to our main code
push_jmp(bs, ptr); push_jmp(bs, ptr);

View File

@ -1,5 +0,0 @@
DPTMTT equ 2
DPTSS equ 3
DPTSPT equ 4
DPTSIZE equ 11

View File

@ -5,349 +5,310 @@
; - dirty: inform that dskbuf has been written to ; - dirty: inform that dskbuf has been written to
; access is done by accessing dskbuf directly ; access is done by accessing dskbuf directly
DPTSIZE equ 11
DPTSPT equ 4
section .bss section .bss
; drive actually selected for I/O ; bios drive we end up using
dsknum: resb 1 biosnum resb 1
; bios drive we end up using ; bit 0 (1) - dirty flag for dskbuf
biosnum: resb 1 ; bit 1 (2) - controller configured
; bit 2 (4) - EBIOS supported
dskflag resb 1
dap: resw 2 ; disk buffer for I/O operations
.buf: resw 2 dskbuf resb 512
; current sector number
; absolute, ignores partition
dskseek: resd 2
; bit 0 (1) - dirty flag for dskbuf dpt resb DPTSIZE
; bit 1 (2) - controller configured bpb resb BPBSIZ4
; bit 2 (4) - EBIOS supported
dskflag: resb 1
; disk buffer for I/O operations section .data
dskbuf: resb 512
dpt: resb DPTSIZE ; drive actually selected for I/O
bpb: resb BPBSIZ4 dsknum db 0xFF
dap db 0x10, 0
dw 1
dapbuf dw dskbuf, 0
dskseek dw 0,0,0,0
section .text section .text
; initial setup for disk i/o ; initial setup for disk i/o
dinit: ; copy previously set DPT to our data area ; copy previously set DPT to our data area
push ds dinit xor ax, ax
push cs mov es, ax
pop es les bx, [es:4*0x1E]
lds si, [es:4*0x1E] mov dx, dpt
mov di, dpt mov cx, 11
mov cx, 11 call lodfar
rep movsb ; set interrupt vector
; set vector mov es, cx
mov word [cs:4*0x1E], dpt mov word [es:4*0x1E], dpt
mov word [cs:4*0x1E+2], ds mov word [es:4*0x1E+2], ds
; set to invalid drive ; set segment addr in DAP
mov byte [cs:dsknum], 0xFF mov [dapbuf+2], cs
pop ds ret
ret
; int 13 stub ; int 13 stub
int13: ; debug output ; this is meant as a central place to implement
push bx ; stack switching or some other safeguards
push dx int13 int 0x13
push cx ret
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
; get drive parameters ; get drive parameters
; read BIOS int13h/AH=8 values ; read BIOS int13h/AH=8 values
; DPT data gets copied over our dpt ; DPT data gets copied over our dpt
; CHS data gets inserted into our bpb ; CHS data gets inserted into our bpb
getprm: ; skip if EBIOS extension enabled getprm test byte [dskflag], 4
test byte [cs:dskflag], 4 jnz .ret
jnz .ret ; do the query
; do the query mov ah, 8
mov ah, 8 mov dl, [biosnum]
mov dl, [cs:biosnum] call int13
call int13 ; bail out if error
; bail out if error jc .ret
jc .ret ; ignore CHS values if odd
; ignore CHS values if odd test cl, cl
test cl, cl jz .nochs
jz .nochs ; get and store sector number
; get and store sector number and cx, 0x3F
and cx, 0x3F mov word [bpb+BPBSPT], cx
mov word [cs:bpb+BPBSPT], cx ; get and store number of heads
; get and store number of heads xchg dl, dh
xchg dl, dh and dx, 0xFF
and dx, 0xFF inc dx
inc dx mov [bpb+BPBNOS], dx
mov [cs:bpb+BPBNOS], dx ; test if DPT ptr is non-zero
; test if DPT ptr is non-zero .nochs mov ax, es
.nochs: mov ax, es or ax, di
or ax, di test ax, ax
test ax, ax jz .ret
jz .ret ; copy BIOS dpt table over ours
; DS:SI = ES:DI mov dx, dpt
mov ax, es mov bx, di
mov ds, ax call lodfar
mov si, di .ret ret
; ES:DI = dpt
xor ax, ax
mov es, ax
mov di, dpt
; do the copy
mov cx, 11
rep movsb
.ret: ret
; log in drive ; log in drive
; IN dl drive number ; IN dl drive number
logdrv: ; DS := CS ; dont do anything if drive already selected
push cs logdrv cmp dl, [dsknum]
pop ds je logfdd.ret
; dont do anything if drive already selected ; clear out current contents
cmp dl, [dsknum] push dx
je logfdd.ret call flush
; clear out current contents mov ax, 0xFFFF
push dx mov [dskseek], ax
push ds mov [dskseek+2], ax
call flush mov byte [dskflag], 0
pop ds pop dx
mov ax, 0xFFFF ; set current drive number
mov [dskseek], ax mov [dsknum], dl
mov [dskseek+2], ax ; fork off if hdd
mov byte [dskflag], 0 cmp dl, 2
pop dx jnc loghdd
; set current drive number
mov [dsknum], dl
; fork off if hdd
cmp dl, 2
jnc loghdd
logfdd: ; save info for bios ; save info for bios
mov [biosnum], dl logfdd mov [biosnum], dl
; reset dpt to defaults ; reset dpt to defaults
push ds call getprm
call getprm ; set default geometry (1.44 MB floppy)
pop ds mov word [bpb+BPBNOS], 2
; set default geometry (1.44 MB floppy) mov word [bpb+BPBSPT], 18
mov word [bpb+BPBNOS], 2 ; load boot sector
mov word [bpb+BPBSPT], 18 xor ax, ax
; load boot sector xor dx, dx
push ds call mapabs
xor ax, ax ; copy bios parameter block
xor dx, dx ; TODO: guess from first byte of FAT if BPB invalid
call mapabs call rstseg
pop ds mov si, dskbuf+BPBOFF
; copy bios parameter block mov di, bpb
; TODO: guess from first byte of FAT if BPB invalid mov cx, BPBSIZ4
push ds rep movsb
pop es ; copy SPT to DPT
mov si, dskbuf+BPBOFF mov al, [bpb+BPBSPT]
mov di, bpb mov [dpt+4], al
mov cx, BPBSIZ4 ; make sure partition offset is forced zero
rep movsb xor ax, ax
; copy SPT to DPT mov [bpb+BPBHS], ax
mov al, [bpb+BPBSPT] mov [bpb+BPBHS+2], ax
mov [dpt+4], al .ret ret
; 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
loghdd: sub dl, 2 cmp dl, 4
cmp dl, 4 jnc logerr
jnc logerr push dx
push dx mov dl, 0x80
mov dl, 0x80 mov byte [biosnum], dl
mov byte [biosnum], dl ; test for ebios extensions
; test for ebios extensions mov ah, 0x41
mov ah, 0x41 mov bx, 0x55AA
mov bx, 0x55AA call int13
call int13 sbb bx, 0xAA55
sbb bx, 0xAA55 jnz .chs
jnz .chs ; enable ebios and assume controller is configured
; enable ebios and assume controller is configured or byte [dskflag], (2+4)
or byte [dskflag], (2+4) ; get chs data (needed or we cant load vbr)
; initialize DAP .chs call getprm
mov word [dap], 0x10 ; read mbr
mov word [dap+2], 1 xor ax, ax
mov word [dap+4], dskbuf xor dx, dx
xor ax, ax call mapabs
mov word [dap+6], ax ; get partition number
mov word [dap+12], ax pop bx
mov word [dap+14], ax xor bh, bh
; get chs data (needed or we cant load vbr) mov cl, 4
.chs: call getprm sal bx, cl
; read mbr ; bail out if no partition
xor ax, ax cmp byte [dskbuf+0x1be+bx+4], 0
xor dx, dx je logerr
call mapabs ; load partition offset
; get partition number mov ax, [dskbuf+0x1be+bx+8]
pop bx mov dx, [dskbuf+0x1be+bx+8+2]
xor bh, bh ; save to to stack
mov cl, 4 push dx
sal bx, cl push ax
; bail out if no partition ; load vbr
cmp byte [cs:dskbuf+0x1be+bx+4], 0 call mapabs
je logerr ; copy bpb
; load partition offset mov si, dskbuf+BPBOFF
mov ax, [cs:dskbuf+0x1be+bx+8] mov di, bpb
mov dx, [cs:dskbuf+0x1be+bx+8+2] mov cx, BPBSIZ4
; save to to stack rep movsb
push dx ; fix CHS data
push ax call getprm
; load vbr ; fix partition offset
call mapabs pop word [bpb+BPBHS]
; copy bpb pop word [bpb+BPBHS+2]
mov ax, cs ;pop [bpb+BPBNOS]
mov ds, ax ;pop [bpb+BPBSPT]
mov es, ax ret
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
logerr: stc logerr stc
ret ret
mapclu: ; counting from begin of cluster area ; counting from begin of cluster area
mov bx, [cs:bpb+BPBRDE] mapclu mov bx, [bpb+BPBRDE]
mov cl, 4 mov cl, 4
shr bx, cl ; 32 bytes per entry shr bx, cl ; 32 bytes per entry
add ax, bx add ax, bx
adc dx, 0 adc dx, 0
maprd: ; counting from beginning of dir ; counting from beginning of dir
; add fat table sizes ; add fat table sizes
xor ch, ch maprd xor ch, ch
mov cl, byte [cs:bpb+BPBFN] mov cl, byte [bpb+BPBFN]
.loop: add ax, [cs:bpb+BPBFS] .loop add ax, [bpb+BPBFS]
adc dx, 0 adc dx, 0
loop .loop loop .loop
mapfat: ; counting from beginning of FAT ; counting from beginning of FAT
; add reserved sector count ; add reserved sector count
add ax, [cs:bpb+BPBRSC] mapfat add ax, [bpb+BPBRSC]
adc dx, 0 adc dx, 0
map: ; count from partition start ; count from partition start
add ax, [cs:bpb+BPBHS] map add ax, [bpb+BPBHS]
add dx, [cs:bpb+BPBHS+2] add dx, [bpb+BPBHS+2]
mapabs: ; absolute sector count ; absolute sector count
; skip doing a read if sector number matches ; skip doing a read if sector number matches
cmp ax, [cs:dskseek] mapabs cmp ax, [dskseek]
jne read jne read
cmp dx, [cs:dskseek+2] cmp dx, [dskseek+2]
jne read jne read
ret ret
read: push ax read push ax
push dx push dx
call flush call flush
pop dx pop dx
pop ax pop ax
; store the sector number ; store the sector number
mov [cs:dskseek], ax mov [cs:dskseek], ax
mov [cs:dskseek+2], dx mov [cs:dskseek+2], dx
; do the actual read ; do the actual read
; low level read and write ; low level read and write
; call again to retry, no input registers ; call again to retry, no input registers
; read or write is configured in cx ; read or write is configured in cx
_read: mov ch, 2 _read mov ch, 2
db 0x3D ; cmp ax, imm16: causes next instr to be skipped db 0x3D ; cmp ax, imm16: causes next instr to be skipped
_write: mov ch, 3 _write mov ch, 3
mov cl, 1 ; read len mov cl, 1 ; read len
; DS := ES := CS ; DS := ES := CS
mov ax, cs mov ax, cs
mov ds, ax mov ds, ax
mov es, ax mov es, ax
; check if ebios supported ; check if ebios supported
test byte [dskflag], 4 test byte [dskflag], 4
jz .l00 jz .l00
mov ax, cx mov ax, cx
or ah, 0x40 or ah, 0x40
mov si, dap mov si, dap
jmp .do jmp .do
; check if we can skip controller reset ; check if we can skip controller reset
.l00: test byte [dskflag], 2 .l00 test byte [dskflag], 2
jnz .l01 jnz .l01
; do controller reset ; do controller reset
mov dl, [biosnum] mov dl, [biosnum]
mov ah, 0 mov ah, 0
call int13 call int13
or byte [dskflag], 2 or byte [dskflag], 2
.l01: ; put sectors per cylinder into bx .l01 ; put sectors per cylinder into bx
mov ax, [bpb+BPBSPT] mov ax, [bpb+BPBSPT]
mul word [bpb+BPBNOS] mul word [bpb+BPBNOS]
mov bx, ax mov bx, ax
; put linear sector num into dx:ax ; put linear sector num into dx:ax
mov ax, [dskseek] mov ax, [dskseek]
mov dx, [dskseek+2] mov dx, [dskseek+2]
; dx:ax = linear count, bx = sectors / cylinder ; dx:ax = linear count, bx = sectors / cylinder
div bx div bx
xchg ax, dx xchg ax, dx
; dx = cylinder, ax = head * spt + sector ; dx = cylinder, ax = head * spt + sector
mov bl, [bpb+BPBSPT] mov bl, [bpb+BPBSPT]
div byte bl div byte bl
; dx = cylinder, al = head, ah = sector ; dx = cylinder, al = head, ah = sector
xchg dl, dh xchg dl, dh
ror dl, 1 ror dl, 1
ror dl, 1 ror dl, 1
or dl, ah or dl, ah
inc dx inc dx
; al: head number ; al: head number
; dh bit 0-7: cylinder bits 0-7 ; dh bit 0-7: cylinder bits 0-7
; dl bit 0-5: sector bits 0-5 ; dl bit 0-5: sector bits 0-5
; dl bit 6-7: cylinder bits 8-9 ; dl bit 6-7: cylinder bits 8-9
; shuffle values around for bios ; shuffle values around for bios
xchg ax, cx xchg ax, cx
xchg cx, dx xchg cx, dx
xchg dh, dl xchg dh, dl
mov bx, dskbuf mov bx, dskbuf
.do: mov dl, [biosnum] .do mov dl, [biosnum]
; ah: subfunction selected via cx previously ; ah: subfunction selected via cx previously
; al: 1 = reading 1 sector ; al: 1 = reading 1 sector
; cx: sector and cylinder number ; cx: sector and cylinder number
; dh: head number ; dh: head number
; dl: drive number ; dl: drive number
; bx: offset to disk buffer ; bx: offset to disk buffer
call int13 call int13
jc .err jc .err
; clear dirty flag on success ; clear dirty flag on success
and byte [dskflag], 0xFE and byte [dskflag], 0xFE
clc clc
ret ret
.err: ; assume controller is misconfigured .err ; assume controller is misconfigured
and byte [dskflag], 0xFD and byte [dskflag], 0xFD
; exit with carry flag set ; exit with carry flag set
stc stc
ret ret
; mark dskbuf as containing unwritten changes ; mark dskbuf as containing unwritten changes
dirty: or byte [cs:dskflag], 1 ; dirty dirty or byte [cs:dskflag], 1 ; dirty
ret ret
; flush buffer if dirty ; flush buffer if dirty
flush: test byte [cs:dskflag], 1 flush test byte [cs:dskflag], 1
jz .ret jz .ret
; TODO: error handling & retries ; TODO: error handling & retries
jmp _write jmp _write
.ret: ret .ret ret

34
kernel/far.asm Normal file
View File

@ -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