From 21df8160611102ab1dc3364dcc6517911acd4e86 Mon Sep 17 00:00:00 2001 From: Braeden Sowinski Date: Mon, 5 Jun 2023 09:20:10 -0700 Subject: [PATCH] FAT filesystem --- run.sh | 1 + src/bootloader/boot.asm | 246 +++++++++++++++++++++++++++++++--------- src/kernel/main.asm | 43 +++---- 3 files changed, 211 insertions(+), 79 deletions(-) create mode 100755 run.sh diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..1528419 --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +qemu-system-i386 -fda build/main_floppy.img \ No newline at end of file diff --git a/src/bootloader/boot.asm b/src/bootloader/boot.asm index d174ae6..bfa1960 100644 --- a/src/bootloader/boot.asm +++ b/src/bootloader/boot.asm @@ -1,7 +1,7 @@ org 0x7C00 bits 16 -%define ENDL 0x0A +%define ENDL 0x0D, 0x0A ; ; FAT12 header @@ -36,7 +36,189 @@ ebr_system_id: db 'FAT12 ' ; 8 bytes ; start: - jmp main + ; setup data segments + mov ax, 0 ; can't write to ds/es directly + mov ds, ax + mov es, ax + + ; setup stack + mov ss, ax + mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory + + ; some BIOSes might start us at 07C0:0000 instead of 0000:7C00, make sure we are in the + ; expected location + push es + push word .after + retf + +.after: + ; read something from floppy disk + ; BIOS should set DL to drive number + mov [ebr_drive_number], dl + + ; show loading message + mov si, msg_loading + call puts + + ; read drive parametes (sectors per track and head count), + ; instead of relying on data on formatted disk + push es + mov ah, 08h + int 13h + jc floppy_error + pop es + + and cl, 0x3F ; remove top 2 bits + xor ch, ch + mov [bdb_sectors_per_track], cx ; sector count + + inc dh + mov [bdb_heads], dh ; head count + + ; read FAT root directory + mov ax, [bdb_sectors_per_fat] ; compute LBA of root directory = reserved + fats * sectors_per_fat + mov bl, [bdb_fat_count] + xor bh, bh + mul bx ; ax = (fats * sectors_per_fat) + add ax, [bdb_reserved_sectors] ; ax = LBA of root directory + push ax + + ; compute size of root directory = (32 * number_of_entries) / bytes_per_sector + mov ax, [bdb_dir_entries_count] + shl ax, 5 ; ax *= 32 + xor dx, dx ; dx = 0 + div word [bdb_bytes_per_sector] ; number of sectors we need to read + + test dx, dx ; if dx != 0, add 1 + jz .root_dir_after + inc ax ; division remainder != 0, add 1 + ; this means we have a sector only partially filled with entries + +.root_dir_after: + + ; read root directory + mov cl, al ; cl = number of sectors to read = size of root directory + pop ax ; ax = LBA of root directory + mov dl, [ebr_drive_number] ; dl = drive number (we saved it previously) + mov bx, buffer ; es:bx = buffer + call disk_read + + ; search for kernel.bin + xor bx, bx + mov di, buffer + +.search_kernel: + mov si, file_kernel_bin + mov cx, 11 ; compare up to 11 characters + push di + repe cmpsb + pop di + je .found_kernel + + add di, 32 + inc bx + cmp bx, [bdb_dir_entries_count] + jl .search_kernel + + ; kernel not found + jmp kernel_not_found_error + +.found_kernel: + + ; di should have the address to the entry + mov ax, [di + 26] ; first logical cluster field (offset 26) + mov [kernel_cluster], ax + + ; load FAT from disk into memory + mov ax, [bdb_reserved_sectors] + mov bx, buffer + mov cl, [bdb_sectors_per_fat] + mov dl, [ebr_drive_number] + call disk_read + + ; read kernel and process FAT chain + mov bx, KERNEL_LOAD_SEGMENT + mov es, bx + mov bx, KERNEL_LOAD_OFFSET + +.load_kernel_loop: + + ; read next cluster + mov ax, [kernel_cluster] + add ax, 31 ; first cluster = (cluster numer - 2) * sectors_per_cluster + start_sector + ; start sector = reserved + fats + root directory size = 1 + 18 + 134 == 33 + mov cl, 1 + mov dl, [ebr_drive_number] + call disk_read + + add bx, [bdb_bytes_per_sector] + + ; compute location of next cluster + mov ax, [kernel_cluster] + mov cx, 3 + mul cx + mov cx, 2 + div cx ; ax = index of entry in FAT, dx = cluster mod 2 + + mov si, buffer + add si, ax + mov ax, [ds:si] ; read entry from FAT table at index ax + + or dx, dx + jz .even + +.odd: + shr ax, 4 + jmp .next_cluster_after + +.even: + and ax, 0x0FFF + +.next_cluster_after: + cmp ax, 0x0FF8 ; end of chain + jae .read_finish + + mov [kernel_cluster], ax + jmp .load_kernel_loop + +.read_finish: + + ; jump to our kernel + mov dl, [ebr_drive_number] ; boot device in dl + + mov ax, KERNEL_LOAD_SEGMENT ; set segment registers + mov ds, ax + mov es, ax + + jmp KERNEL_LOAD_SEGMENT:KERNEL_LOAD_OFFSET + + jmp wait_key_and_reboot ; should never happen + + cli ; disable interrupts, this way CPU can't get out of "halt" state + hlt + +; +; Error handlers +; + +floppy_error: + mov si, msg_read_failed + call puts + jmp wait_key_and_reboot + +kernel_not_found_error: + mov si, msg_kernel_not_found + call puts + jmp wait_key_and_reboot + +wait_key_and_reboot: + mov ah, 0 + int 16h ; wait for keypress + jmp 0FFFFh:0 ; jump to beginning of BIOS, should reboot + +.halt: + cli ; disable interrupts, this way CPU can't get out of "halt" state + hlt ; ; Prints a string to the screen. @@ -63,51 +245,6 @@ puts: pop si ret -main: - - ; setup data segments - mov ax, 0 ; can't write to ds/es directly - mov ds, ax - mov es, ax - - ; setup stack - mov ss, ax - mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory - - ; read something from floppy disk - ; BIOS should set DL to drive number - mov [ebr_drive_number], dl - - mov ax, 1 ; LBA=1, second sector from disk - mov cl, 1 ; 1 sector to read - mov bx, 0x7E00 ; data should be after the bootloader - call disk_read - - ; print hello wrold message - mov si, msg_hello - call puts - - cli ; disable interrupts, this way CPU can't get out of "halt" state - hlt - -; -; Error handlers -; - -floppy_error: - mov si, msg_read_failed - call puts - jmp wait_key_and_reboot - -wait_key_and_reboot: - mov ah, 0 - int 16h ; wait for keypress - jmp 0FFFFh:0 ; jump to beginning of BIOS, should reboot - -.halt: - cli ; disable interrupts, this way CPU can't get out of "halt" state - hlt - ; ; Disk routines ; @@ -214,9 +351,16 @@ disk_reset: popa ret -msg_hello: db 'Hello World!', ENDL, 0 -msg_read_failed: db 'Read from disk failed!', ENDL, 0 +msg_loading: db 'Loading...', ENDL, 0 +msg_read_failed: db 'Read from disk failed!', ENDL, 0 +msg_kernel_not_found: db 'KERNEL.BIN file not found!', ENDL, 0 +file_kernel_bin: db 'KERNEL BIN' +kernel_cluster: dw 0 + +KERNEL_LOAD_SEGMENT equ 0x2000 +KERNEL_LOAD_OFFSET equ 0 - times 510-($-$$) db 0 -dw 0AA55h \ No newline at end of file +dw 0AA55h + +buffer: \ No newline at end of file diff --git a/src/kernel/main.asm b/src/kernel/main.asm index 9d4a622..87ea35d 100644 --- a/src/kernel/main.asm +++ b/src/kernel/main.asm @@ -1,10 +1,17 @@ -org 0x7C00 +org 0x0 bits 16 -%define ENDL 0x0A +%define ENDL 0x0D, 0x0A start: - jmp main + + ; print message + mov si, msg_hello + call puts + +.halt: + cli + hlt ; ; Prints a string to the screen. @@ -15,43 +22,23 @@ puts: ; save registers we will modify push si push ax + push bx .loop: lodsb ; loads next character in al or al, al ; verify if next character is null? jz .done - mov ah, 0x0e ; call bios interrupt + mov ah, 0x0E ; call bios interrupt + mov bh, 0x10 ; set page number to 0 int 0x10 jmp .loop .done: + pop bx pop ax pop si ret -main: - - ; setup data segments - mov ax, 0 ; can't write to ds/es directly - mov ds, ax - mov es, ax - - ; setup stack - mov ss, ax - mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory - - ; print message - mov si, ms_hello - call puts - - hlt - -.halt: - jmp .halt - -ms_hello: db 'Hello World!', ENDL, 0 - -times 510-($-$$) db 0 -dw 0AA55h \ No newline at end of file +msg_hello: db 'Hello World!', ENDL, 0