summaryrefslogtreecommitdiff
path: root/src/boot/boot.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot/boot.asm')
-rw-r--r--src/boot/boot.asm227
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: