format ELF64 extrn kmain PML4_TABLE = 0x1000 E820_MMAP = 0xf000 MSR_EFER = 0xc0000080 include 'bios.inc' include 'page.inc' include 'segdesc.inc' section '.boot' executable writeable org 0x7c00 use16 jmp far 0x0000:@f ; ensure cs = 0x0000 @@: xor ax, ax mov ds, ax mov es, ax ; put stack directly bellow bootloader mov ss, ax mov sp, $$ cld mov [boot_disk], dl bios_disk_read ($$+0x200), 0, 0, 2, 57, disk_error bios_e820_mmap E820_MMAP, e820_error bios_a20_enable bios_vga_write_mode_3 page_table_init_real PML4_TABLE ; disable IRQs mov al, 0xff out 0xa1, al out 0x21, al lidt [dummy_idtr] ; enable PAE (1<<5) and PGE (1<<7) mov eax, (1 shl 7) or (1 shl 5) mov cr4, eax ; point cr3 at PML4 mov edx, edi mov cr3, edx ; enable long mode mov ecx, MSR_EFER rdmsr or eax, (1 shl 8) wrmsr ; enable protected mode mov ebx, cr0 or ebx, (1 shl 31) or (1 shl 0) mov cr0, ebx lgdt [gdtr] jmp far (gdt.kcode-gdt):longmode e820_error: ; change beginning of error message ("disk" -> "e820") mov dword [errmsg], 0x30323865 disk_error: mov si, errmsg mov ah, 0x0e jmp @f .loop: int 0x10 @@: lodsb test al, al jnz .loop ; wait until keypress, then jump to reset vector (reboot) xor ah, ah int 0x16 jmp far 0xffff:0x0000 use64 longmode: mov ax, (gdt.kdata-gdt) mov ds, ax mov es, ax mov ss, ax cli ; copy kernel to 0x100000 mov ecx, (57*0x200)/8 mov esi, 0x7e00 mov edi, 0x100000 rep movsq xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx xor edi, edi xor esi, esi ; put stack at top of addressable memory mov esp, 0x200000 mov ebp, esp ; manually encoded 'jmp rel32', fasm throws an 'invalid use of symbol' ; error when generating code for a jmp to an external symbol after ; setting code origin with 'org' directive or a 'virtual at X' block. db 0xe9 dd kmain-$-4 align 4 dw 0 label gdtr fword .limit dw (gdt.sizeof - 1) .addr dd gdt align 4 errmsg db "disk error: press any key to reboot",0 align 8 gdt: .null dq 0 .kcode seg_desc 0, 0, (GDT_CODE_64 or SEG_PRIV0) .kdata seg_desc 0, 0, (GDT_DATA_64 or SEG_PRIV0) .ucode seg_desc 0, 0, (GDT_CODE_64 or SEG_PRIV3) .udata seg_desc 0, 0, (GDT_DATA_64 or SEG_PRIV3) .sizeof = $ - gdt align 4 boot_disk db 0, 0 label dummy_idtr fword .limit dw 0 .addr dd 0 if ($-$$) <= 510 db 510-($-$$) dup 0 else display "ERR: boot sector image exceeds 512 bytes",10 assert ($-$$) <= 510 end if db 0x55,0xaa