My code:
Code: Select all
bits 32
section .init
global check_cpuid
global check_x64_compatibility
global setup_x64
PAGE_PRESENT equ (1 << 0)
PAGE_WRITE equ (1 << 1)
PAGE_GLOBAL equ (1 << 8)
check_cpuid:
pushfd ; Get
pop eax
mov ecx, eax ; Save
xor eax, 0x200000 ; Flip
push eax ; Set
popfd
pushfd ; And test
pop eax
xor eax, ecx ; Mask changed bits
shr eax, 21 ; Move bit 21 to bit 0
and eax, 1 ; And mask others
push ecx
popfd ; Restore original flags
ret
check_x64_compatibility:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no_x64
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz .no_x64 ; They aren't, there is no long mode.
mov eax, 1
ret
.no_x64:
mov eax, 0
ret
setup_x64:
mov edx, 0x1000 ; Save the address of the first Page-Map Level-4 Table (PML4)
mov edi, edx
xor eax, eax
mov ecx, 0x1000 ; Size of memory to flush
rep stosd ; Flush
mov edi, edx
; Lower half mapping
lea eax, [edi + 0x1000] ; Put the address of the first Page Directory Pointer Table (PDPT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE ; Make present and writeable
mov [edi], eax ; Set the value of eax as the first PML4 entry
lea eax, [edi + 0x2000] ; Put the address of the first Page Directory Table (PDT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE
mov [edi + 0x1000], eax ; Set the value of eax as the first PDPT entry
lea eax, [edi + 0x3000] ; Put the address of the first Page Table (PT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE
mov [edi + 0x2000], eax ; Set the value of eax as the first PDT entry
; Higher half mapping
lea eax, [edi + 0x1FF8] ; Put the address of the last Page Directory Pointer Table (PDPT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE ; Make present and writeable
mov [edi + 0x0FF8], eax ; Set the value of eax as the last PML4 entry
lea eax, [edi + 0x2C00] ; Put the address of the last Page Directory Table (PDT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE
mov [edi + 0x1FF8], eax ; Set the value of eax as the 384th PDPT entry
lea eax, [edi + 0x3000] ; Put the address of the first Page Table (PT) to eax
or eax, PAGE_PRESENT | PAGE_WRITE
mov [edi + 0x2C00], eax ; Set the value of eax as the first PDT entry
mov edi, 0x4000 ; Point to the address of the first PT
mov ecx, 512 ; Number of entries to set
lea eax, [0x0] ; Put the first memory address to eax
.set_entry: ; Set the page entries
or eax, PAGE_PRESENT | PAGE_WRITE | PAGE_GLOBAL
mov [edi], eax ; Set the page in the PT
add eax, 0x1000 ; Add 4096 for next page
add edi, 8 ; Add 8 for next PT entry
loop .set_entry
.enable_pae: ; Enable PAE by setting the PAE bit (bit 5)
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
.set_paging_entry: ; Point CR3 at the PML4
mov cr3, edx
.enable_long_mode: ; Enable Long Mode by setting the LM bit (bit 8)
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
.enable_paging: ; Enable Paging by setting the PG bit (bit 31)
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
Code: Select all
bits 32
section .init
global kinit
global load_gdt
extern KERNEL_VIRTUAL_BASE, tmp_stack
extern check_cpuid, check_x64_compatibility, setup_x64
extern load_gdt
kinit:
call check_cpuid
cmp eax, 1
jne .error
call check_x64_compatibility
cmp eax, 1
jne .error
call setup_x64
mov eax, gdt64.pointer
call load_gdt
jmp gdt64.code:yeah_here_we_go
.error:
mov byte [0xB8000], 'E'
mov byte [0xB8001], 0xE | 0 << 4 ; background black, foreground yellow
mov byte [0xB8002], 'R'
mov byte [0xB8003], 0xE | 0 << 4
mov byte [0xB8004], 'R'
mov byte [0xB8005], 0xE | 0 << 4
mov byte [0xB8006], 'O'
mov byte [0xB8007], 0xE | 0 << 4
mov byte [0xB8008], 'R'
mov byte [0xB8009], 0xE | 0 << 4
mov byte [0xB800A], '!'
mov byte [0xB800B], 0xE | 0 << 4
.game_over:
cli
hlt
jmp .game_over
bits 64
section .init
yeah_here_we_go:
cli ; Clear the interrupt flag.
mov byte [0xB8000], 'L'
mov byte [0xB8001], 0xE | 0 << 4
mov byte [0xB8002], 'o'
mov byte [0xB8003], 0xE | 0 << 4
mov byte [0xB8004], 'a'
mov byte [0xB8005], 0xE | 0 << 4
mov byte [0xB8006], 'd'
mov byte [0xB8007], 0xE | 0 << 4
mov byte [0xB8008], 'i'
mov byte [0xB8009], 0xE | 0 << 4
mov byte [0xB800A], 'n'
mov byte [0xB800B], 0xE | 0 << 4
mov byte [0xB800C], 'g'
mov byte [0xB800D], 0xE | 0 << 4
mov byte [0xB800E], '.'
mov byte [0xB800F], 0xE | 0 << 4
mov byte [0xB8010], '.'
mov byte [0xB8011], 0xE | 0 << 4
mov byte [0xB8012], '.'
mov byte [0xB8013], 0xE | 0 << 4
lea rcx, [kentry]
jmp rcx
extern kmain
extern __cxa_finalize
kentry:
call kmain
sub esp, 4
mov [esp], dword 0x0
call __cxa_finalize
add esp, 4
.end:
cli
hlt
jmp .end
gdt64:
.null: equ $ - gdt64 ; The null descriptor.
dq 0
.code: equ $ - gdt64 ; The code descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10011000b ; Access.
db 00100000b ; Granularity.
db 0 ; Base (high).
.data: equ $ - gdt64 ; The data descriptor.
dw 0 ; Limit (low).
dw 0 ; Base (low).
db 0 ; Base (middle)
db 10010000b ; Access.
db 00000000b ; Granularity.
db 0 ; Base (high).
align 4
dw 0
.pointer: ; The GDT-pointer.
dw $ - gdt64 - 1 ; Limit.
dd gdt64
Code: Select all
ENTRY(kinit)
OUTPUT(elf64_x86_64)
KERNEL_VIRTUAL_BASE = 0xFFFFFFFFF0000000;
SECTIONS
{
. = 0x100000; /* 0x0000000000100000 */
kernel_init_start = .;
.init :
{
*(.multiboot)
*(.init)
}
kernel_init_end = .;
. += KERNEL_VIRTUAL_BASE;
kernel_main_start = .;
.text ALIGN(0x1000) : AT(ADDR(.text) - KERNEL_VIRTUAL_BASE)
{
*(.text)
*(.gnu.linkonce.t*)
}
.data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_VIRTUAL_BASE)
{
__init_array = .;
KEEP(*( .init_array ));
KEEP(SORT_BY_NAME(*)( .init_array));
__init_array_end = .;
__fini_array = .;
KEEP(*( .fini_array ));
KEEP(SORT_BY_NAME(*)( .fini_array ));
__fini_array_end = .;
*(.data)
*(.gnu.linkonce.d*)
*(.rodata*)
*(.gnu.linkonce.r*)
}
.bss ALIGN(0x1000) : AT(ADDR(.bss) - KERNEL_VIRTUAL_BASE)
{
*(COMMON)
*(.bss)
*(.gnu.linkonce.b*)
}
/DISCARD/ :
{
*(.comment)
*(.eh_frame)
}
kernel_main_end = .;
}
[EDIT]
Ok, got it finally. I misunderstood how the paging works..
Thanks for all your help