64 bit support

This commit is contained in:
nub31
2025-08-24 18:29:02 +02:00
parent ff664b0687
commit 1402a227f1
4 changed files with 182 additions and 15 deletions

View File

@@ -19,14 +19,185 @@ align 16
resb 16384
stack_top:
extern kernel_main
align 4096
pml4_table:
resb 4096
pdp_table:
resb 4096
pd_table:
resb 4096
section .text
bits 32
global _start
_start:
mov esp, stack_top
call kernel_main
; Check if CPU supports 64-bit mode
call check_multiboot
call check_cpuid
call check_long_mode
; Set up paging for 64-bit mode
call set_up_page_tables
call enable_paging
; Load GDT and jump to 64-bit mode
lgdt [gdt64.pointer]
jmp gdt64.code:long_mode_start
check_multiboot:
cmp eax, 0x36d76289
jne .no_multiboot
ret
.no_multiboot:
mov al, 'M'
jmp error
check_cpuid:
; Copy flags to eax through the stack
pushfd
pop eax
; Copy flags to ecx for a later comparison
mov ecx, eax
; Flit the cpuid bit
xor eax, 1 << 21
; Copy eax (with the flipped cpuid bit) back to flags
push eax
popfd
; Copy flags back to eax. The cpiuid bit will be flipped if cpuid is supported
pushfd
pop eax
; Restore flags from the original flags stored in ecx
push ecx
popfd
; Compare eax and ecx. If thry are equal, cpuid is not supported
cmp eax, ecx
je .no_cpuid
ret
.no_cpuid:
mov al, 'I'
jmp error
check_long_mode:
; Test if extended processor info is available
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no_long_mode
; Test if long mode is available
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .no_long_mode
ret
.no_long_mode:
mov al, 'L'
jmp error
; todo(nub): This is copy pasted. I will research hat it does later
set_up_page_tables:
; Map first PML4 entry to PDP table
mov eax, pdp_table
or eax, 0b11 ; present + writable
mov [pml4_table], eax
; Map first PDP entry to PD table
mov eax, pd_table
or eax, 0b11 ; present + writable
mov [pdp_table], eax
; Map each PD entry to a huge 2MiB page
mov ecx, 0 ; counter variable
.map_pd_table:
; Map ecx-th PD entry to a huge page that starts at address (2MiB * ecx)
mov eax, 0x200000 ; 2MiB
mul ecx ; Start address of ecx-th page
or eax, 0b10000011 ; present + writable + huge
mov [pd_table + ecx * 8], eax ; Map ecx-th entry
inc ecx ; Increase counter
cmp ecx, 512 ; If counter == 512, the whole PD table is mapped
jne .map_pd_table ; Else map the next entry
ret
; todo(nub): This is copy pasted. I will research hat it does later
enable_paging:
; Load PML4 to cr3 register (cpu uses this to access the PML4 table)
mov eax, pml4_table
mov cr3, eax
; Enable PAE-flag in cr4 (Physical Address Extension)
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; Set the long mode bit in the EFER MSR (model specific register)
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; Enable paging in the cr0 register
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
error:
mov byte [0xb8000], '['
mov byte [0xb8002], ' '
mov byte [0xb8004], 'E'
mov byte [0xb8005], 4
mov byte [0xb8006], 'R'
mov byte [0xb8007], 4
mov byte [0xb8008], 'R'
mov byte [0xb8009], 4
mov byte [0xb800a], ' '
mov byte [0xb800c], ']'
mov byte [0xb800e], ':'
mov byte [0xb8010], ' '
mov byte [0xb8012], al
cli
hang:
.hang:
hlt
jmp hang
jmp .hang
section .rodata
gdt64:
dq 0
.code: equ $ - gdt64
dq (1<<43) | (1<<44) | (1<<47) | (1<<53)
.pointer:
dw $ - gdt64 - 1
dq gdt64
section .text
bits 64
long_mode_start:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
extern kernel_main
call kernel_main
cli
.hang:
hlt
jmp .hang