; 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 ; 0x2000 down, we should really not set it above 0x7c00, as this is ; exacly the place, where we load stage 2 and the kernel to! (was 0xffff, ; which was a really bad idea after the kernel got bigger than roughly ; 32k!) mov bp, 0x2000 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 0x8800 (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: ; make sure registers have known values xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi ; 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_entry ; 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 5 sectors (gives 6 in total for stage 1 and 2) times 3070-($-$$) db 0 ; magic number of stage 2 dw 0xAABB ; position is 0x8800 now for the C entry kernel_entry: