Files
crawos/source/bootload/boot.asm
2025-10-20 10:52:03 +01:00

298 lines
6.3 KiB
NASM

ORG 7C00h
BITS 16
jmp short main
nop
; Define Fat12 header
bdb_oem: db 'MSWIN4.1'
bdb_bytes_per_sector: dw 512
bdb_sectors_per_cluster: db 1
bdb_reserved_sectors: dw 1
bdb_fat_count: db 2
bdb_dir_entries_count: dw 0E0h
bdb_total_sectors: dw 2880
bdb_media_descriptor_type: db 0F0h
bdb_sectors_per_fat: dw 9
bdb_sectors_per_track: dw 18
bdb_heads: dw 2
bdb_hidden_sectors: dd 0
bdb_large_sector_count: dd 0
; extended boot record
ebr_drive_number: db 0
db 0
ebr_signature: db 29h
ebr_volume_id: db 12h, 34h, 56h, 78h
ebr_volume_label: db 'CrawShaw OS'
ebr_system_id: db 'FAT12 '
main:
; Setup registers
mov ax, 0
mov ds, ax ; ds = data segment pointer
mov es, ax ; es = extra segment pointer
mov ss, ax ; ss = stack pointer
mov sp, 7C00h
; Read from disk
;mov [ebr_drive_number], dl
;mov ax, 1
;mov cl, 1
;mov bx, 7E00h
;call disk_read
; Output boot text
mov si, boot_text
call print_string
; Load kernel
; 4 segments:
; reserved segment (bdb_reserved_segments, 1)
; FAT: (sectors_per_fat * fat_count) 9*2=18
; root dir: gives location of data
; data: stores the actual data
; Get LBA of root dir
mov ax, [bdb_sectors_per_fat]
mov bl, [bdb_fat_count]
xor bh,bh ; clear bh
mul bx ; 9 * 2 = 18
add ax, [bdb_reserved_sectors] ; The LBA of root dir
push ax ; Push to stack
mov ax, [bdb_dir_entries_count]
shl ax,5 ; ax *= 32 (shifting 5 times)
xor dx,dx ; Clear dx
div word [bdb_bytes_per_sector] ;32*num of entries)/bytes per sector
test dx,dx ; See if there's a remainder
jz root_dir_after
inc ax ; Add one if there's a remainder
root_dir_after:
mov cl, al
pop ax ; LBA of root dir
mov dl, [ebr_drive_number]
mov bx, buffer
call disk_read
xor bx,bx ; clear bx
mov di, buffer ; Loaded root dir into memory
search_for_kernel:
mov si, file_kernel_bin ; Move the name of the kernel into si
mov cx, 11
push di ; Preserve di
repe cmpsb ; Repeat a comparison of bytes between kernel name and current bytes until it finds a match
pop di ; Retrieve di
je found_kernel
add di, 32 ; Next directory entry
inc bx
cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist
jl search_for_kernel ; Repeat search
jmp kernel_not_found ; If the last dir has been searched, then there is no kernel
kernel_not_found:
mov si, kernel_load_error
call print_string
hlt
jmp halt
found_kernel:
mov si, kernel_found_text
call print_string
; Find kernel cluster
mov ax, [di+26]
mov [kernel_cluster], ax
mov ax, [bdb_reserved_sectors]
mov bx, buffer
mov cl, [bdb_sectors_per_fat]
mov dl, [ebr_drive_number]
call disk_read ; Load FAT from disk into memory
; Load kernel into memory
mov bx, kernel_load_segment
mov es, bx
mov bx, kernel_load_offset ; Setup memory that kernel will be loaded into
load_kernel_loop:
mov ax, [kernel_cluster]
add ax, 31 ; Setup offset so we can read the particular cluster
mov cl, 1 ;sectors to read
mov dl, [ebr_drive_number]
call disk_read
add bx, [bdb_bytes_per_sector]
; (kernel_cluster * 3) / 2
mov ax, [kernel_cluster]
mov cx, 3
mul cx
mov cx, 2
div cx
; setup buffers
mov si, buffer
add si, ax
mov ax, [ds:si]
or dx,dx
jz even
odd:
shr ax, 4 ;shift ax 4
jmp next_cluster_after
even:
and ax, 0fffh ; Gives the other 12 bits
next_cluster_after:
cmp ax, 0ff8h ; If the value is ff8h or bigger then we've reached the end of FAT
jae read_finish
mov [kernel_cluster], ax
jmp load_kernel_loop
read_finish: ; Load kernel
mov dl, [ebr_drive_number]
mov ax, kernel_load_segment
mov ds, ax
mov es, ax
jmp kernel_load_segment:kernel_load_offset ; Jump to the kernel code
hlt
halt:
jmp halt
; LBA = index of data segment on disk
; CHS = cylinder, header, sector
; input, LBA index: ax
; sector number: cx [0-5]
; cylinder: cx [6-15]
; head: dh
lba_to_chs:
push ax
push dx
xor dx,dx ; clear dx
div word [bdb_sectors_per_track] ;(LBA % sectors per track) + 1 = sector
inc dx ; sector, dx stores the remainder so we increment that.
mov cx,dx
xor dx,dx ; clear dx
div word [bdb_heads]
mov dh,dl ; head
mov ch,al
shl ah, 6
or CL, AH ; cylinder
pop ax
mov dl,al
pop ax
RET
disk_read:
push ax
push bx
push cx
push dx
push di
call lba_to_chs
mov ah, 02h
; repeat drive read 3 times (incase of random error)
mov di, 3 ; counter
retry:
stc
int 13h
jnc done_read
call disk_reset ; Reset drivers of disk
dec di
test di, di
jnz retry
fail_disk_read:
mov si, disk_read_fail
call print_string
hlt
jmp halt
disk_reset:
pusha
mov ah, 0 ; Reset drive
stc
int 13h
jc fail_disk_read
popa
ret
done_read:
pop di
pop dx
pop cx
pop bx
pop ax
ret
; SI = pointer to start of string to be printed
print_string:
push si
push ax
push bx
mov ah, 0Eh ; int 10h teletype function, we're telling the BIOS we will print something
.repeat:
lodsb ; Get char from si into al
cmp al, 0 ; Compare al to 0
je .done ; If char is zero, end of string
mov bh, 0
int 10h ; Otherwise, print it
jmp .repeat ; And move on to next char
.done:
; Print newline
mov ah, 0Eh
mov al, 13
int 10h
mov al, 10
int 10h
; Exit function
pop bx
pop ax
pop si
ret
boot_text: db '[OK] Boot sequence begun...', 0
kernel_found_text: db '[OK] Kernel located...', 0
disk_read_fail: db '[ERR] Failed to read disk!', 0
file_kernel_bin: db 'KERNEL BIN' ; Must have a double space between KERNEL and BIN
kernel_load_error: db '[ERR] Kernel not found!', 0
kernel_cluster: dw 0
kernel_load_segment: equ 2000h
kernel_load_offset: equ 0
times 510-($-$$) db 0 ; Fill up the next 510 bits with 0's
dw 0AA55h ; D
buffer: