diff options
Diffstat (limited to 'src/boot/boot.asm')
-rw-r--r-- | src/boot/boot.asm | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/boot/boot.asm b/src/boot/boot.asm new file mode 100644 index 0000000..c3cb57e --- /dev/null +++ b/src/boot/boot.asm @@ -0,0 +1,227 @@ +; legacy BIOS PC-boot code, starts in 16-bit real mode + +; BIOS always loads us to this location + [org 0x7c00] + +; 16-bit real-mode + [bits 16] + +; export a map of boot loader symbols for debugging + [map symbols boot.map] + +; initialize segment registers + mov ax, 0 + mov ds, ax + mov es, ax + mov ss, ax + +; dl contains the boot drive, primarily because that's the last function +; called by the BIOS MBR loader, we remember that for loading additional +; blocks from the boot medium + mov [BOOT_DRIVE], dl + +; make sure we know the location of the stack by setting it on our own +; this stack is only used in real mode in stage 1, so it's growing from +; 0xffff down + mov bp, 0xFFFF + mov sp, bp + +; print out some information about CPU mode and BIOS boot drive + mov si, MESSAGE_REAL_MODE + call print_string + + mov si, MESSAGE_BOOT_DRIVE + call print_string + mov ax, dx + call print_hex + call print_newline + +; print we are going to load stage 2 of the boot blocks + mov si, MESSAGE_LOADING_STAGE_2 + call print_string + +; load stage 2 with simple load method to 0x7e00 (directly +; after the boot sector) + mov dl, [BOOT_DRIVE] + call read_stage2_from_disk + call print_newline + +; jump over variables and subroutines of stage 1 and execute stage 2 + jmp stage2 + +%include "boot/stage1_functions.asm" + +DISK_ERROR: + db "DISK ERROR ", 0 + +SHORT_READ: + db "DISK SHORT READ", 0 + +MESSAGE_REAL_MODE: + db "Started in 16-bit Real Mode", 13, 10, 0 + +MESSAGE_BOOT_DRIVE: + db "Booting from drive ", 0 + +MESSAGE_LOADING_STAGE_2: + db "Loading stage 2 boot loader", 0 + +MESSAGE_DETECTING_DISK_GEOMETRY: + db "Detecting disk geometry ", 0 + +MESSAGE_LOADING_KERNEL: + db "Loading kernel", 0 + +BOOT_DRIVE: + db 0 + +; pad rest of sector with zeroes so we get 512 bytes in the end +times 510-($-$$) db 0 + +; magic number of a boot sector +dw 0xaa55 + +stage2: + +; print a message that we are indeed in stage 2 now + mov si, MESSAGE_STAGE_2_LOADED + call print_string + +; detect disk geometry (works for real floppies only?) + mov cl, [BOOT_DRIVE] + and cl, 0x80 + jnz .not_a_floppy + + mov si, MESSAGE_DETECTING_DISK_GEOMETRY + call print_string + mov dl, [BOOT_DRIVE] + call detect_disk_geometry + mov dl, [BOOT_DRIVE] + call probe_and_fix_disk_geometry + call print_newline +.not_a_floppy: + +; print a message we are now loading the kernel + mov si, MESSAGE_LOADING_KERNEL + call print_string + + +; load kernel to 0x8400 (directly after stage 2 +; of the boot loader) + mov dl, [BOOT_DRIVE] + call read_from_disk + call print_newline + +; turn off disk motor + call kill_motor + +; check A20 gate + mov si, MESSAGE_STAGE_2_CHECKING_A20 + call print_string + call check_and_enable_A20 + cmp ax, 1 + je .A20_enabled + mov si, MESSAGE_STAGE_2_A20_DISABLED + call print_string +; jmp .halt_os_realmode + +.A20_enabled: + mov si, MESSAGE_STAGE_2_A20_ENABLED + call print_string + +; remember current position on screen, otherwise we loose this +; information after switching to protected mode + call current_row + mov [CURSOR_Y], dh + +; enter protected mode + call switch_to_protected_mode + +; we should never get here, but just in case + jmp $ + +; stop loading in real mode +.halt_os_realmode: + mov si, MESSAGE_HALTED_REAL + call print_string +.loop: cli + hlt + jmp .loop + +MESSAGE_STAGE_2_LOADED: + db "Stage 2 boot sectors loaded", 13, 10, 0 + +MESSAGE_STAGE_2_CHECKING_A20: + db "Checking A20 address gate... ", 0 + +MESSAGE_STAGE_2_A20_ENABLED: + db " ...enabled", 13, 10, 0 + +MESSAGE_STAGE_2_A20_DISABLED: + db " ...disabled", 13, 10, 0 + +MESSAGE_HALTED_REAL: + db "Operating system halted in real mode", 13, 10, 0 + +%include "boot/stage2_real_functions.asm" +%include "boot/stage2_switch_mode.asm" +%include "boot/stage2_a20.asm" + +[bits 32] + +BEGIN_PROTECTED_MODE: + +; we switched to protected mode + mov si, MESSAGE_PROTECTED_MODE + call pm_print_string + call pm_print_newline + +; check sanity of kernel by searching for MAGIC string at a given +; position + call check_magic + cmp ax, 1 + jnz .halt_os_pm + +; print a message before we call the C level kernel + mov si, MESSAGE_CALL_C_ENTRY + call pm_print_string + call pm_print_newline + +; call our kernel + call kernel_main + +; restore cursor variables from VGA hardware + call read_hardware_vga_cursor + +; "kernel halted" message, when we terminate the C kernel +.halt_os_pm: + mov si, MESSAGE_HALTED + call pm_print_string + call pm_print_newline + +; end of C, disable interupts again, NMIs can still happen +; make sure we loop endlessly here but without burning too +; much CPU + cli +.loop: + hlt + jmp .loop + +MESSAGE_PROTECTED_MODE: + db "Switched to 32-bit Protected Mode", 0 + +MESSAGE_CALL_C_ENTRY: + db "Calling C entry function", 0 + +MESSAGE_HALTED: + db "Operating system halted", 0 + +%include "boot/stage2_pm_functions.asm" +%include "boot/stage2_check_magic.asm" + +; make sure we have full sectors, stage 1 is 512 bytes, so we +; have to will up 3 sectors +times 2048-($-$$) db 0 + +; position is 0x8400 now for the C entry +kernel_main: |