Load kernel off of FAT12 disk

This commit is contained in:
Juhani Krekelä 2021-06-30 20:35:07 +03:00
parent 8da504ca2d
commit 9a829fc71c
3 changed files with 173 additions and 24 deletions

View File

@ -3,10 +3,12 @@
all: nor86.img all: nor86.img
nor86.img: bootsector.bin kernel.bin nor86.img: bootsector.bin kernel.bin CC0 README.md
rm -f $@ rm -f $@
mkdosfs -C $@ 1440 mkdosfs -C $@ 1440
rw -i bootsector.bin -o $@ rw -i bootsector.bin -o $@
mcopy -i $@ CC0 ::
mcopy -i $@ README.md ::
mcopy -i $@ kernel.bin :: mcopy -i $@ kernel.bin ::
.asm.bin: .asm.bin:

View File

@ -45,7 +45,7 @@ _start:
; Save bootdrive ; Save bootdrive
mov [drivenumber], dl mov [drivenumber], dl
root_dir: calc_constants:
; Disk organization: ; Disk organization:
; Reserved sectors (MBR) ; Reserved sectors (MBR)
; FAT1 ; FAT1
@ -58,16 +58,51 @@ root_dir:
add ax, [reservedsectors] add ax, [reservedsectors]
mov [rootdir], ax mov [rootdir], ax
; Data area comes after root dir, so we need to add the size of
; the root dir in sectors
; One root dir entry is 32 bytes, and one sector has 512 bytes
; Therefore 512 / 32 = 16 entries correspond to a sector
; However, we can't just do a shift, since we need to round up
; For integers, ceil(x/y) = floor((x+y-1)/y)
mov ax, [rootdirentries]
add ax, 15
shr ax, 1
shr ax, 1
shr ax, 1
shr ax, 1
mov [rootdirsectors], ax
fat:
; FAT1 (the main one) follows right after bootsector(s)
mov ax, [reservedsectors]
call chs call chs
; TODO: handle possible crossing of track boundary
mov ax, [sectorsperfat]
mov ah, 2
mov dl, [drivenumber]
mov bx, 0x8000
int 0x13
root_dir:
mov ax, [rootdir]
call chs
; TODO: handle possible crossing of track boundary
mov ax, [rootdirsectors]
mov ah, 2 mov ah, 2
mov al, 14 ; TODO: don't hardcode
mov dl, [drivenumber] mov dl, [drivenumber]
mov bx, 0x500 mov bx, 0x500
int 0x13 int 0x13
print_root: search_root:
mov byte [0x500 + 32*224], 0 ; TODO: don't hardcode mov bx, [rootdirentries]
shr ax, 1
shr ax, 1
shr ax, 1
shr ax, 1
shr ax, 1
mov byte [bx + 0x500], 0
mov si, 0x500 mov si, 0x500
.entry: .entry:
cmp byte [si], 0 cmp byte [si], 0
@ -80,36 +115,137 @@ print_root:
jmp .entry jmp .entry
.isfile: .isfile:
mov ah, 0xe mov cx, 11
mov cx, 8 mov bx, kernel_name
.name:
.compare:
lodsb lodsb
int 0x10 cmp al, [bx]
loop .name jne .nomatch
inc bx
loop .compare
mov al, ' ' jmp found
int 0x10
mov cx, 3 .nomatch:
.ext: ; Each entry is 32 bytes long
lodsb ; During each iteration of the compare loop, si is
int 0x10 ; incremented and cx is decremented
loop .ext ; At the top of the loop, si + cx = entry_start + 11, but
; when we jump here si has been incremented by one already
mov al, 13 ; while cx is still the same
int 0x10 ; Therefore, si + cx is one more, so add extra - 1 here
mov al, 10 add si, 32 - 11 - 1
int 0x10 add si, cx
add si, 32 - 11
jmp .entry jmp .entry
.end: .end:
notfound:
; TODO: Better error messages
mov ax, 0x0e00 + '?'
int 0x10
hang: hang:
hlt hlt
jmp hang jmp hang
found:
; SI points to 11 bytes after the start of the entry, so adjust all
; offsets
; TODO: Handle zero-length files
mov ax, [si - 11 + 26] ; First cluster
push ax
; Load OS at the start of the memory
mov bx, 0x500
push bx
.tosector
; Adjust the cluster number to account for first two
; "clusters" in the FAT being used for metadata
sub ax, 2
; Scale by number of sectors per cluster
xor bx, bx
mov bl, [sectorspercluster]
mul word bx
; Offset by number of non-data sectors before data area
add ax, [rootdir]
add ax, [rootdirsectors]
; Load sectors
pop bx
xor cx, cx
mov cl, [sectorspercluster]
mov dl, [drivenumber]
.loop:
push ax
push cx
call chs
mov ah, 2
mov al, 1
int 0x13
pop cx
pop ax
add bx, 512
inc ax
loop .loop
.next:
pop ax
; Multiply by 1.5 to get offset into the table
; This rounds down, which is what we want in order to get
; the first byte of the address
mov si, ax
shl si, 1
add si, ax
shr si, 1
; Load the entry from FAT
mov dx, [si + 0x8000]
; Two clusters, 0xABC and 0xXYZ, are stored as
; BC ZA XY
; ^ where we start reading on even cluster numbers
; ^^^^^ loading word → 0xZABC
; ^ where we start reading on odd cluster numbers
; ^^^^^ loading word: 0xXYZA
test ax, 1
jnz .odd
.even:
and dx, 0x0fff
jmp .check_cluster
.odd:
shr dx, 1
shr dx, 1
shr dx, 1
shr dx, 1
.check_cluster:
mov ax, dx
; End of chain
cmp ax, 0xFF8
jg execute_kernel
push ax
push bx
jmp .tosector
execute_kernel:
mov dl, [drivenumber]
jmp 0:0x500
chs: chs:
push ax push ax
push bx push bx
@ -154,7 +290,10 @@ chs:
%include "hexprint.inc" %include "hexprint.inc"
kernel_name: db "KERNEL BIN"
times 510-($-$$) db 0 times 510-($-$$) db 0
db 0x55, 0xaa db 0x55, 0xaa
_end: _end:
rootdir equ _end rootdir equ _end
rootdirsectors equ _end + 2

View File

@ -0,0 +1,8 @@
org 0x500
mov ax, 0x0e40
int 0x10
hang:
hlt
jmp hang