Files
ClassicOS/bootloader/boot.asm

231 lines
5.5 KiB
NASM

; ==============================================================================
; boot.asm - First Stage Bootloader (CHS Based)
; ==============================================================================
[BITS 16]
[ORG 0x7C00]
start:
cli ; Disable interrupts
mov [bootdev], dl ; Save boot device number (from BIOS in DL)
; Setup stack safely below EBDA area (choose 0x0000:0x7A00)
xor ax, ax ; AX = 0
mov ss, ax ; Stack segment = 0x0000
mov sp, 0x7A00 ; Stack offset = 0x7A00
; Initialize DS, ES for zero-based segments
xor ax, ax
mov ds, ax
mov es, ax
; Load second-stage bootloader (boot1.asm) to 0x7E00
mov si, 0x7E00 ; Destination offset (ES already zero, so physical 0x7E00)
mov al, 1 ; Number of sectors to read (adjust if needed)
mov cl, 1 ; Starting sector (CHS - sector number, 1-based)
call read_chs
jc disk_error ; Jump if carry set (read error)
; Load kernel to 0x100000 (1 MB)
mov si, 0x0000 ; Destination offset
mov ax, 0x1000 ; ES = 0x1000 (0x1000:0x0000 = 1 MB)
mov es, ax
xor bx, bx
mov al, 16 ; Number of sectors for kernel (example)
mov cl, 2 ; Starting sector (adjust as per your disk layout)
call read_chs
jc disk_error
; Memory Validation: Verify checksum of second stage bootloader
mov si, 0x7E00 ; Start of second stage
mov cx, 512 ; Size in bytes (adjust if more sectors loaded)
call verify_checksum
jc disk_error ; Jump if checksum fails
; Enable A20 line
call enable_a20
jc a20_error ; Jump if A20 enable fails
; Setup Global Descriptor Table
call setup_gdt
; Switch to protected mode and jump to second stage at 0x08:0x7E00
call switch_to_pm
disk_error:
mov si, disk_error_msg
call print_string_16
jmp halt
a20_error:
mov si, a20_error_msg
call print_string_16
jmp halt
; ----------------------------------------------------------------
; Verify Checksum Routine
; Uses SI = start address, CX = byte count
; Simple XOR checksum over bytes, expects result 0
verify_checksum:
push ax
push bx
push di
mov di, si
xor al, al
xor bx, bx
.verify_loop:
lodsb
xor bl, al
loop .verify_loop
test bl, bl
jz .checksum_ok
stc ; Set carry on checksum error
jmp .done
.checksum_ok:
clc ; Clear carry on success
.done:
pop di
pop bx
pop ax
ret
; ----------------------------------------------------------------
; CHS Disk Read Routine
; AL = number of sectors
; CL = starting sector (1-based)
; SI = destination offset (Segment:ES already set)
read_chs:
pusha
push dx
mov cx, 5
.retry:
mov ah, 0x02 ; BIOS read sector
mov dl, [bootdev] ; Drive number
int 0x13
jc .error ; Carry flag set = error
pop dx
popa
ret
.error:
dec cx
jz disk_error
xor ah, ah
int 0x13
jmp .retry
; ----------------------------------------------------------------
enable_a20:
; Fast A20 gate method
in al, 0x92
or al, 0x02
out 0x92, al
; Fallback method (keyboard controller)
jc .fallbackenable_a20:
; Fast A20 method
in al, 0x92
or al, 0x02
and al, 0xFE ; Clear bit 0 to avoid fast A20 issues on some systems
out 0x92, al
; Verify A20
call check_a20
jnc .done
; Fallback method
mov al, 0xAD
out 0x64, al
; ... (rest of keyboard controller code)
.done:
ret
check_a20:
in al, 0x64 ; Read keyboard controller status
test al, 0x02 ; Check if input buffer is full
jnz check_a20 ; Wait until empty
mov al, 0xD0 ; Command: read output port
out 0x64, al
.wait_output:
in al, 0x60 ; Read output port value
test al, 0x02 ; Check A20 gate bit (bit 1)
jnz .a20_enabled ; If set, A20 enabled
xor al, al ; Clear carry to indicate failure
stc ; Set carry for failure, jc will jump
ret
.a20_enabled:
clc ; Clear carry flag to indicate success
ret
.fallback:
mov al, 0xAD
out 0x64, al
mov al, 0xD0
out 0x64, al
in al, 0x60
or al, 0x02
mov al, 0xD1
out 0x64, al
mov al, 0xAE
out 0x64, al
ret
; ----------------------------------------------------------------
gdt_start:
dq 0x0000000000000000 ; Null descriptor
dq 0x00CF9A000000FFFF ; 32-bit code segment (selector 0x08)
dq 0x00CF92000000FFFF ; 32-bit data segment (selector 0x10)
dq 0x00009A000000FFFF ; 16-bit code segment for real mode (selector 0x18)
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
gdt_end:
setup_gdt:
lgdt [gdt_descriptor]
ret
; ----------------------------------------------------------------
switch_to_pm:
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:0x7E00
; ----------------------------------------------------------------
print_string_16:
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
ret
disk_error_msg db "Disk error!", 0
a20_error_msg db "A20 error!", 0
halt:
cli
hlt
bootdev db 0
sectors_per_track dw 63
heads_per_cylinder dw 255
times 510 - ($ - $$) db 0
dw 0xAA55