diff options
Diffstat (limited to 'src/entry/bootsector.asm')
-rw-r--r-- | src/entry/bootsector.asm | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/entry/bootsector.asm b/src/entry/bootsector.asm new file mode 100644 index 0000000..1beb850 --- /dev/null +++ b/src/entry/bootsector.asm @@ -0,0 +1,172 @@ +; MIT License, Copyright (c) 2021 Marvin Borner + +; This file includes definitions to reduce magic numbers +%include "src/entry/definitions.asm" + +bits 16 ; Real mode is 16 Bit +org LOCATION ; Bootsector location + +global _start +_start: + jmp .skip_bpb ; Some BIOSes override the BPB area + dd "START" + nop + times 87 db 0 ; Fill BPB area with 0 +.skip_bpb: + + ; Clear registers (some BIOSes are weird) + xor bx, bx + mov ds, bx + mov es, bx + mov ss, bx + ; Other registers may contain relevant data + + mov sp, LOCATION ; Set stack (top) pointer - grows downwards + + mov ax, SCREEN_CLEAR ; Clear screen command + int SCREEN_INT ; CLEAR! + + ; Print friendly welcome message + mov si, hello_msg + call print + + call disk_support ; Is disk supported? Implicitly verifies that this is a 386+ architecture + mov esp, LOCATION ; Clear upper 16 Bit of esp, now that 16 Bit support is guaranteed + cli ; Disable interrupts + + jmp load_stage ; Load and execute main stage + +; Print function uses si as string pointer +print: + ; a and b regs get partially destroyed - push for restoration + push bx + push ax + + mov ah, SCREEN_OUT ; Set VGA command + xor bh, bh ; Clear b register (according to BIOS spec) +.putch: + lodsb ; Load next string byte (using ds:si) + test al, al ; Test loaded byte + jz .end ; End if al is zero (using previous test); NULL-termination + int SCREEN_INT ; WRITE! + jmp .putch ; Continue +.end: + ; Restore ax/bx + pop ax + pop bx + ret + +; Check if disk is supported using ID checks and LBA test +disk_support: + ; BIOS puts the disk id into dl + cmp dl, 0x80 + jb disk_error ; Error if below 0x80 - probably floppy disk + cmp dl, 0x8f + ja disk_error ; Error if above 0x8f - invalid + + ; Check if int 0x13 and LBA are supported + mov ah, DISK_EXT_CHECK ; Set needed interrupt values + mov bx, DISK_EXT_CHECK_REQ + int DISK_INT ; CHECK! + jc disk_error ; Carry means something went wrong + cmp bx, DISK_EXT_CHECK_RESP + jne disk_error ; Response is incorrect => error! + ret + +; Read sectors from disk using dap information +disk_read: + mov si, dap + mov ah, DISK_READ + int DISK_INT + jc error_loop + ret + +; Loads the main stage (main.c) +load_stage: + mov bx, loader + mov [dap.dest], bx + call disk_read + + lgdt [gdt] ; Load GDT + + ; Set protected mode (32 Bit mode) + mov eax, cr0 + or ax, 1 ; Set PE (Protection Enable) Bit + mov cr0, eax + + jmp 0x08:protected_mode + +bits 32 +protected_mode: + ; Set segment registers + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + call loader + jmp error_loop +bits 16 + +; Error handling +error_loop: + cli ; Disable interrupts + hlt ; Wait for interrupt; should wait forever + jmp error_loop ; Loop if returns anyway + +disk_error: + mov si, disk_msg + call print + jmp error_loop + +; Messages (NULL-terminated strings with newline/return) +hello_msg db "Hello world! Booting...", NEWLINE, RETURN, NULL +disk_msg db "Disk is invalid or unsupported", NEWLINE, RETURN, NULL + +; Disk configuration data for DISK_READ interrupt (filled according to spec) +dap: ; Disk Address Packet + db 0x10 ; Disk address packet size + db 0 ; Always 0 +.count: + dw 64 ; Number of sectors (512B each) to read ; 0x8000 +.dest: + dw 0 ; Destination offset + dw 0 ; Destination segment +.lba: + dd 1 ; LBA number ; Inter stage is directly after first LBA (0) + dd 0 ; More storage bytes + +; Global Descriptor Table (GDT) +gdt: + dw .size - 1 + 8 ; GDT size + dd .start - 8 ; GDT start address +.start: + ; Code + dw 0xffff ; Limit + dw 0x0000 ; Base (low 16 bits) + db 0x00 ; Base (mid 8 bits) + db 10011010b ; Access + db 11001111b ; Granularity + db 0x00 ; Base (high 8 bits) + + ; Data + dw 0xffff ; Limit + dw 0x0000 ; Base (low 16 bits) + db 0x00 ; Base (mid 8 bits) + db 10010010b ; Access + db 11001111b ; Granularity + db 0x00 ; Base (high 8 bits) +.end: +.size: equ .end - .start + +times SECTOR_SIZE - 2 - ($ - $$) db 0 ; Fill until 512 (SECTOR_SIZE) - 2 bytes; -2 because of 2B signature +dw SECTOR_END_SIG ; Bootsector end signature + +loader: +incbin "build/loader.bin" + +; Limit to 0x8000 due to ext2 superblock start at 1024 on partition 1 +times 0x8000 - ($ - $$) db 0 +superblock: |