From 1402a227f11e09369434ed16ec68f202c1d7090e Mon Sep 17 00:00:00 2001 From: nub31 Date: Sun, 24 Aug 2025 18:29:02 +0200 Subject: [PATCH] 64 bit support --- README.md | 4 +- grub.cfg | 4 -- makefile | 10 +-- src/boot.asm | 179 +++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 182 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8e2984e..a974b4b 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ - `make` - `grub` - `mtools` -- `i386-elf-gcc` -- `i386-elf-ld` +- `x86_64-elf-gcc` +- `x86_64-elf-ld` ## Building diff --git a/grub.cfg b/grub.cfg index a771cd1..8e64ec9 100644 --- a/grub.cfg +++ b/grub.cfg @@ -1,7 +1,3 @@ menuentry "nub-os" { multiboot2 /boot/kernel - boot } - -set default="nub-os" -set timeout=0 diff --git a/makefile b/makefile index 7e48c87..cd91884 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,8 @@ -CC = i386-elf-gcc -LD = i386-elf-ld +CC = x86_64-elf-gcc +LD = x86_64-elf-ld -CFLAGS = -m32 -ffreestanding -fno-builtin -Wall -Wextra -Werror -Wshadow -std=c23 -LDFLAGS = -m elf_i386 +CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Werror -Wshadow -std=c23 +LDFLAGS = all: .build/nub-os.iso @@ -28,4 +28,4 @@ build-dir: $(CC) $(CFLAGS) -c -o .build/vga.o src/vga.c .build/boot.o: build-dir src/boot.asm - nasm -f elf32 -o .build/boot.o src/boot.asm \ No newline at end of file + nasm -f elf64 -o .build/boot.o src/boot.asm \ No newline at end of file diff --git a/src/boot.asm b/src/boot.asm index 132b362..f5b1488 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -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 \ No newline at end of file + 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 \ No newline at end of file