Switching into 64 bits mode
Using pieces of assember around the web [1], I synthesized the listing below. Assemble it with nasm [2]. It uses a multiboot header and is loaded by GRUB. It then sets up paging for 64 bits and enables 64 bits mode.
; ; See http://wiki.osdev.org/User:Stephanvanschaik/Setting_Up_Long_Mode ; Loader assembly to load the 64 bits kernel just after this file. ; Assume that we are loaded at 1M (0x100000) org 0x100000 ;default rel bits 32 ; Start in 32 bits mode. ; Multiboot header: ; Settings for multiboot header PAGE_ALIGN equ 1 << 0 MEM_INFO equ 1 << 1 KLUDGE equ 1 << 16 MAGIC equ 0x1BADB002 FLAGS equ PAGE_ALIGN | MEM_INFO | KLUDGE ; align and provide memory map CHECKSUM equ -(MAGIC+FLAGS) ; actual multiboot header: align 4 MultiBootHeader: dd MAGIC dd FLAGS dd CHECKSUM ; item below are present if bit 16 is set in flags dd MultiBootHeader ; physical address in file of header (will be 0x100000 if put at start) dd 0x100000 ; load_addr: load address, the address to start loading dd 0x0 ; load_end_addr: zero indicates to load whole file dd 0x0 ; bss_end_addr: zero indicates no bss segment present dd loader ; entry_addr: jump to here ; GDT, three entries: one for code, one for data GDT64: .Null: equ $ - GDT64 dw 0 dw 0 db 0 db 0 db 0 db 0 .Code: equ $ - GDT64 dw 0 dw 0 db 0 db 10011000b ; access db 00100000b ; granularity db 0 .Data: equ $ - GDT64 dw 0 dw 0 db 0 db 10010000b ; access db 00000000b ; granularity db 0 .Pointer: ; GDT pointer dw $ - GDT64 - 1 ; Limit dq GDT64 ; Base ; Start of loader code: loader: ; Prepare paging: ; PML4T - 0x1000 ; PDPT - 0x2000 ; PDT - 0x3000 ; PT - 0x4000 ; Clear the tables: mov edi, 0x1000 mov cr3, edi ; CR3 is the page table address! xor eax, eax mov ecx, 4096 rep stosd mov edi, cr3 ; restore edi mov DWORD [edi], 0x2003 ; present and readwrite, points to first PDPT add edi, 0x1000 mov DWORD [edi], 0x3003 ; present and readwrite, points to first PDT add edi, 0x1000 mov DWORD [edi], 0x4003 ; present and readwrite, points to first PT add edi, 0x1000 ; identity map the first two megabytes: mov ebx, 0x00000003 mov ecx, 512 ; Fill all PT entries at 0x4000 SetEntry: mov DWORD [edi], ebx add ebx, 0x1000 add edi, 8 loop SetEntry ; Enable paging: mov eax, cr4 or eax, 1 << 5 ; PAE-bit is bit 5 mov cr4, eax ; Set LM-bit (Long Mode bit): mov ecx, 0xC0000080 rdmsr or eax, 0x100 ; Set bit 8 (LM-bit) wrmsr ; Enable paging: mov eax, cr0 or eax, 0x80000000 ; Set bit 31 (PG-bit) mov cr0, eax ; Load the GDT: lgdt [GDT64.Pointer] ; Jump to 64 bits kernel: jmp GDT64.Code:Realm64 bits 64 ; realm64 Realm64: cli mov ax, GDT64.Data mov ds, ax mov es, ax mov fs, ax mov gs, ax ; Done! ; Setup stack pointer: mov rsp, stackEnd ; Put a B upper left corner mov al, 66 ; 'B' mov [0xb8000], al ; Jump to code that is glued after this file jmp einde align 16 dataEnd: ; reserve bytes for stack: stackBegin: resb 1024 stackEnd: einde: XCHG BX, BX ; bochs breakpoint jmp einde