## Align modules on page boundaries ----+ ## Always provide memory information --+| ## Header contains video mode fields -+|| ## Not an ELF image ----+ ||| ## | ||| ## v vvv .equ MBHF, 0b00000000000000010000000000000011 # Fool LD! .global _start _start: ## magic flags checksum mbhdr: .long 0x1BADB002, MBHF, -(0x1BADB002 + MBHF) .long mbhdr, 0x100000, 0, 0, start ## hdraddr loadaddr le bss entry (le = load end addr) magic: .long 0 mbptr: .long 0 cpuid_d: .long 0 cpuidx_d: .long 0 .equ initial_stack, 0x106000 .code32 start: # Set up stack movl $initial_stack, %esp movl %esp, %ebp pushl $2 # only reserved bit set popf cld # save some vars movl %eax, (magic) movl %ebx, (mbptr) # get highest normal function movl $0, %eax cpuid cmpl $1, %eax jb halt # get function bits incl %eax cpuid movl %edx, (cpuid_d) # get highest EXT function movl $0x80000000, %eax cpuid cmpl $0x80000001, %eax jb halt # get EXT function bits incl %eax cpuid btl $29, %edx # Long Mode jz halt movl %edx, (cpuidx_d) # save edx movl $0xC0000080, %eax rdmsr btsl $8, %eax # LME btl $20, (cpuidx_d) # NX? jnc 1f btsl $11, %eax # NX 1: wrmsr # Use the area at (0x3F0000-0x400000) for pagetables. .equ pg_l4t, 0x3F0000 .equ pg_pdpt, 0x3F1000 .equ pg_dir0, 0x3F2000 .equ pg_dir3, 0x3F3000 .equ pg_dir0_tbl0, 0x3F4000 .equ pg_dir0_tbl1, 0x3F5000 .equ pg_dir0_tbl2, 0x3F6000 .equ pg_dir3_tbl0, 0x3F7000 .equ pg_dir3_tbl1, 0x3F8000 .equ pg_dir3_tbl383, 0x3F9000 .equ pg_dir3_tbl384, 0x3FA000 # Zero 'em all! movl $0x3F0000, %edi movb $0, %al movl $0xB000, %ecx rep stosb # These addresses are all 64-bits, but # we don't have to specify the zero high-ends # since everything was zeroed above. # One l4t entry. movl $pg_pdpt | 0x7, (pg_l4t) # Two PDPT entries. movl $pg_dir0 | 0x7, (pg_pdpt) movl $pg_dir3 | 0x7, (pg_pdpt+24) # Pagedir 0: 3 PDEs. movl $pg_dir0_tbl0 | 0x7, (pg_dir0) movl $pg_dir0_tbl1 | 0x7, (pg_dir0+8) movl $pg_dir0_tbl2 | 0x7, (pg_dir0+16) # Pagedir 3: 4 PDEs. movl $pg_dir3_tbl0 | 0x7, (pg_dir3) movl $pg_dir3_tbl1 | 0x7, (pg_dir3+8) movl $pg_dir3_tbl383 | 0x7, (pg_dir3+3064) movl $pg_dir3_tbl384 | 0x7, (pg_dir3+3072) jmp 1f map: movl %ebx, %eax movl %edx, %ecx movl %eax, (%edi) addl $8, %edi addl $0x1000, %eax dec %ecx jnz map ret # ID-map 0-6M. 1: movl $0x000003, %ebx # addr movl $0x200, %edx # count movl $pg_dir0_tbl0, %edi call map addl $0x200000, %ebx movl $pg_dir0_tbl1, %edi call map addl $0x200000, %ebx movl $pg_dir0_tbl2, %edi call map # Map kernel. movl $0xC0000003, %ebx movl $pg_dir3_tbl0, %edi call map addl $0x200000, %ebx movl $pg_dir3_tbl1, %edi call map # Map VRAM. movl $0xB8000 | 0x3, (pg_dir3_tbl384) # Map and use stack. movl $0x100000 | 0x3, (pg_dir3_tbl383+4088) addl $0xEFEFF000, %esp # Map the pagetables with a fractal recursive memory mapper. movl $pg_l4t | 0x3, (pg_l4t+4088) # Enable paging. movl $pg_l4t, %eax movl %eax, %cr3 movl %cr4, %eax btl $6, (cpuid_d) # PAE? jnc halt btsl $5, %eax # PAE btl $14, (cpuid_d) # MCE? jnc 1f btsl $6, %eax # MCE 1: btl $24, (cpuid_d) # FXSR? jnc 1f btsl $9, %eax # OSFXSR 1: btl $25, (cpuid_d) # SSE? jnc 1f btsl $10, %eax # OSXMMEXCPT movl %eax, %cr4 movl %cr0, %eax btsl $31, %eax # PG movl %eax, %cr0 jmp 1f # We're paging, in compatiblility mode. 1: lgdt (gdtr) movw $0x10, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss ljmp $0x18, $64f .code64 64: cmpl $0x464C457F, (kernel) # 45=E 4C=L 46=F: the ELF signature in little-endian order. jnz halt movzwq (kernel+54), %r8 # e_phentsize movw (kernel+56), %r9w # e_phnum xorq %r10, %r10 movq $kernel, %rax addq (kernel+32), %rax # e_phoff # rax -> first Phdr phdr: cmpl $1, (%rax) # p_type == PT_LOAD? jnz 2f movq $kernel, %rsi addq 8(%rax), %rsi # p_offset: rsi = addr to read from movq 16(%rax), %rdi # p_vaddr: rdi = addr to write to subl $0xBFC06000, %edi # Load relative to 0x400000 instead of 0xC0006000 movq 32(%rax), %rcx # p_filesz rep movsb movq %rcx, %rbx movq 40(%rax), %rcx # p_memsz subq %rcx, %rbx # subtract p_filesz = BSS size jz 1f pushq %rax movb $0, %al rep stosb popq %rax 1: movq 40(%rax), %rbx # p_memsz addq 16(%rax), %rbx # p_vaddr subl $0xC0006000, %ebx cmpq %rbx, %r10 jl 2f movq %rbx, %r10 # store highest offset in r10 2: addq %r8, %rax decw %r9w jnz phdr movq (kernel+24), %r11 # entry point # Launch kernel movl (magic), %r8d movl (mbptr), %r9d movq %r8, %rdi # First arg movq %r9, %rsi # Second arg movq %r10, %rdx # Third arg call *%r11 halt: cli hlt 1: jmp 1b # DATA gdt: .byte 0, 0, 0, 0, 0, 0, 0, 0 # null .byte 0xFF, 0xFF, 0, 0, 0, 0x9B, 0xDF, 0 # code32 .byte 0xFF, 0xFF, 0, 0, 0, 0x93, 0xDF, 0 # data .byte 0xFF, 0xFF, 0, 0, 0, 0x9B, 0xAF, 0 # code64 gdtr: .word 0x20 .long gdt ##1: .space 0x6000-1b 1: .space 0x5FFF kernel: