Files
SUB-OS/boot/stage2.asm
T

273 lines
6.3 KiB
NASM

BITS 16
ORG 0x7E00
start2:
cli
; Ensure segment registers are zero
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
; Save boot drive number passed from stage 1 in DL
mov [boot_drive], dl
; Print Stage 2 startup message
mov si, msg_stage2_start
call print_string_16
; -------------------------------------------------------------
; Step 1: Enable A20 Line
; -------------------------------------------------------------
mov si, msg_a20
call print_string_16
in al, 0x92
test al, 2
jnz .a20_done
or al, 2
and al, 0xFE
out 0x92, al
.a20_done:
; -------------------------------------------------------------
; Step 2: Detect Memory via INT 15h, EAX=0xE820
; Destination: 0x9000 (count at 0x9000, entries at 0x9008)
; -------------------------------------------------------------
mov si, msg_mmap
call print_string_16
; Zero out count at 0x9000
mov dword [0x9000], 0
mov dword [0x9004], 0
mov di, 0x9008 ; Memory map entries destination
xor ebx, ebx ; Continuation value
xor bp, bp ; Entry counter
mov edx, 0x534D4150 ; 'SMAP' signature
mov eax, 0xE820
mov ecx, 24 ; Buffer size
int 0x15
jc .mmap_error
.mmap_loop:
inc bp
add di, 24
test ebx, ebx
jz .mmap_finished
mov edx, 0x534D4150
mov eax, 0xE820
mov ecx, 24
int 0x15
jc .mmap_finished
jmp .mmap_loop
.mmap_error:
; If E820 failed, create 1 fallback entry (128MB usable)
mov dword [0x9000], 1
mov dword [0x9004], 0
mov dword [0x9008], 0x100000 ; base = 1MB
mov dword [0x900C], 0
mov dword [0x9010], 0x07F00000 ; length = 127MB
mov dword [0x9014], 0
mov dword [0x9018], 1 ; type = 1 (USABLE)
mov dword [0x901C], 1
jmp .mmap_store_done
.mmap_finished:
mov word [0x9000], bp
mov word [0x9002], 0
mov dword [0x9004], 0
.mmap_store_done:
; -------------------------------------------------------------
; Step 3: Load Kernel from Disk to 0x10000 (Conventional RAM)
; 12 chunks x 64 sectors = 768 sectors (384 KB)
; -------------------------------------------------------------
mov si, msg_kernel_load
call print_string_16
mov word [kernel_dap_off], 0x0000
mov word [kernel_dap_seg], 0x1000
mov dword [kernel_dap_lba], 16
mov dword [kernel_dap_lba + 4], 0
mov cx, 6 ; 6 chunks * 64 sectors = 384 sectors (192 KB)
.kernel_chunk_loop:
push cx
mov ah, 0x42
mov dl, [boot_drive]
mov si, kernel_dap
int 0x13
jc .kernel_disk_error
; Advance LBA by 64 sectors
add dword [kernel_dap_lba], 64
; Advance Segment by 0x800 (64 sectors * 512 bytes = 32768 bytes = 0x800 paragraphs)
add word [kernel_dap_seg], 0x0800
pop cx
loop .kernel_chunk_loop
.kernel_loaded_ok:
; -------------------------------------------------------------
; Step 4: Set up Identity Paging for Long Mode (All 4 GB)
; -------------------------------------------------------------
; Clear 24 KB for 6 page tables (0x1000 - 0x6FFF)
mov ax, 0x0000
mov es, ax
mov di, 0x1000
mov cx, 6144
xor eax, eax
rep stosd
; PML4[0] -> PDPT at 0x2000
mov dword [0x1000], 0x2003
mov dword [0x1004], 0
; PDPT -> 4 PDs
mov dword [0x2000], 0x3003
mov dword [0x2004], 0
mov dword [0x2008], 0x4003
mov dword [0x200C], 0
mov dword [0x2010], 0x5003
mov dword [0x2014], 0
mov dword [0x2018], 0x6003
mov dword [0x201C], 0
; Map 4GB (2048 x 2MB pages)
mov di, 0x3000
mov eax, 0x00000083
mov cx, 2048
.map_4gb_loop:
mov [di], eax
mov dword [di + 4], 0
add eax, 0x200000
add di, 8
loop .map_4gb_loop
; -------------------------------------------------------------
; Step 5: Switch to 32-bit Protected Mode
; -------------------------------------------------------------
mov si, msg_entering_pm
call print_string_16
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:pm_entry
.kernel_disk_error:
mov si, msg_kernel_err
call print_string_16
.halt16:
cli
hlt
jmp .halt16
print_string_16:
pusha
mov ah, 0x0E
.p_loop:
lodsb
test al, al
jz .p_done
int 0x10
jmp .p_loop
.p_done:
popa
ret
; -----------------------------------------------------------------
; 32-Bit Protected Mode Entry Point
; -----------------------------------------------------------------
BITS 32
pm_entry:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x7C00
; Copy kernel from 0x10000 to 0x100000 (1MB mark) - 192 KB (384 sectors)
mov esi, 0x10000
mov edi, 0x100000
mov ecx, (384 * 512) / 4
rep movsd
; Enable PAE in CR4
mov eax, cr4
or eax, (1 << 5)
mov cr4, eax
; Load CR3
mov eax, 0x1000
mov cr3, eax
; Enable Long Mode in EFER MSR
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8)
wrmsr
; Enable Paging and Protected Mode
mov eax, cr0
or eax, (1 << 31) | (1 << 0)
mov cr0, eax
jmp 0x18:lm_entry
; -----------------------------------------------------------------
; 64-Bit Long Mode Entry Point
; -----------------------------------------------------------------
BITS 64
lm_entry:
mov ax, 0x20
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Arguments: RDI = 0x9008 (entries), RSI = count at 0x9000
mov rdi, 0x9008
mov rsi, [0x9000]
mov rax, 0x100000
jmp rax
; -----------------------------------------------------------------
; Data Section
; -----------------------------------------------------------------
BITS 16
align 4
boot_drive: db 0
msg_stage2_start: db "Stage 2: Loaded", 13, 10, 0
msg_a20: db "Stage 2: A20 enabled", 13, 10, 0
msg_mmap: db "Stage 2: Memory map detected", 13, 10, 0
msg_kernel_load: db "Stage 2: Loading kernel...", 13, 10, 0
msg_entering_pm: db "Stage 2: Jumping to 64-bit mode...", 13, 10, 0
msg_kernel_err: db "Stage 2: Kernel Disk Read Error!", 13, 10, 0
align 4
kernel_dap:
db 0x10
db 0
dw 64 ; 64 sectors per chunk (32 KB)
kernel_dap_off:
dw 0x0000
kernel_dap_seg:
dw 0x1000
kernel_dap_lba:
dq 16
%include "gdt.asm"