diff --git a/Makefile b/Makefile index 2fe8394..c14cf79 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -LD = i686-elf-ld +LD = x86_64-elf-ld LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld all: prepare cpu kernel_code drivers libc userspace mem link iso diff --git a/kernel/Makefile b/kernel/Makefile index cbe85cf..018ced4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@ OBJS = kernel_main.o -CC = i686-elf-gcc # cross-compiler +CC = x86_64-elf-gcc # cross-compiler CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile index 38757eb..417471d 100644 --- a/kernel/cpu/Makefile +++ b/kernel/cpu/Makefile @@ -1,4 +1,4 @@ -OBJS = main.asm.o ports.asm.o \ +OBJS = main.asm.o main64.asm.o ports.asm.o \ gdt.asm.o idt.asm.o \ interrupts.asm.o header.asm.o diff --git a/kernel/cpu/main.asm b/kernel/cpu/main.asm index d107ace..f03547b 100644 --- a/kernel/cpu/main.asm +++ b/kernel/cpu/main.asm @@ -5,23 +5,169 @@ ; Released under GPLv3 ; ; https://github.com/ice-bit/vulcanos ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -GLOBAL kernel_loader -EXTERN kernel_main + +EXTERN long_mode_start [BITS 32] ; Ensure we are in protected mode section .text kernel_loader: mov esp, kernel_stack + KERNEL_STACK_SZ ; Define stack pointer + ; Now we need to switch to Long Mode(i.e., 64bit mode) + ; to do that, we first need to check if we actually are + ; being loaded by a multiboot compliant bootloader. Then, + ; we will execute CPUID instruction in order to obtain details + ; about out CPU(i.e., if the CPU supports long mode). + call check_multiboot + call check_cpuid + call check_long_mode + + ; After that, we need to setup paging + call setup_page_tables + call enable_paging + + ; We also need to load a GDT + lgdt[gdt64.pointer] + jmp gdt64.code_segment:long_mode_start push eax ; Set multiboot header register - call kernel_main ; Call kernel's main function + + +check_multiboot: + ; To prove that we are being loaded by a multiboot + ; bootloader, we can read the EAX register to see if + ; it contains the magic number + cmp eax, 0xE85250D6 + jne .multiboot_panic + ret + +.multiboot_panic: + ; We handle this error by showing a special code + mov al, "M" + jmp error ; Call print routine + +check_cpuid: + ; To check if CPUID is available we need to flip + ; ID bit of the flag register, if this is possibile + ; then CPUID instruction is available. In order to achieve + pushfd ; Push flag register into the stack + pop eax ; Pop the stack + mov ecx, eax ; Make a copy of the stack + xor eax, 1 << 21 ; Flip ID bit(21th) from the eax register + push eax + popfd ; Restore flag register into the stack + pushfd + pop eax + push ecx + popfd + cmp eax, ecx ; If values are the same, then CPUID is not available + je .cpuid_panic + ret ; Otherwise return + +.cpuid_panic: + mov al, "C" + jmp error ; Call print routine + + +check_long_mode: + ; Check if CPU supports extended processor info + mov eax, 0x80000000 ; Store magic number + cpuid ; CPUID instruction takes EAX by default + ; CPUID will set EAX a value greater than the magic number + ; if the processor supports extended processor info + cmp eax, 0x80000001 ; Magic number + 1 + jb .long_mode_panic + ; Otherwise we can use extended processor info + ; to check if long mode is available + mov eax, 0x80000001 + cpuid + ; CPUID, with this magic number, will set LM bit(29th) + ; if and only if long mode is available + test edx, 1 << 29 + jz .long_mode_panic + ret + +.long_mode_panic: + mov al, "L" + jmp error ; Call print routine + + +setup_page_tables: + mov eax, page_table_l3 + or eax, 0b11 + mov [page_table_l4], eax + + mov eax, page_table_l2 + or eax, 0b11 + mov [page_table_l3], eax + .loop: - jmp .loop ; If the kernel returns, go into an endless loop - ; This will prevent the CPU to execure any non-kernel - ; instructions. + mov eax, 0x200000 ; 2MiB + mul ecx + or eax, 0b10000011 + mov [page_table_l2 + ecx * 8], eax + + mov ecx, 0 ; Counter + inc ecx ; Increment counter + cmp ecx, 512 ; Check if whole table is being mapped + jne .loop ; if not, repeat + ret + +enable_paging: + ; Pass page table location to the cpu + mov eax, page_table_l4 + mov cr3, eax + ; Enable PAE + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax; + ; Enable long mode + mov ecx, 0xC0000000 + rdmsr + or eax, 1 << 8 + wrmsr + ; Enable paging + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax + + ret + +error: ; Prints "ERR: X" where X stands ofr the given error code + ; This routine will just print the error code in video memory + ; Let's understand what those hex codes actually mean: + ; 0xB8000 is the begin of the VGA text buffer, each byte will + ; contain one character. 0x4F is the color code; it means + ; white text on read background. 0x52 is the ASCII code for + ; the letter 'R', while 0x45 stands for the letter 'E', + ; 0x3A stands for the symbol ':' and 0x20 is just a space. + ; Do note that addressing is in little endian ordering and + ; that one space is begin overwritten by the ASCII byte. + ; previous NEW CONTENT + mov dword [0xB8000], 0x4F524F45 ; [] ER + mov dword [0xB8004], 0x4F3A4F52 ; [ER] R: + mov dword [0xB8008], 0x4F204F20 ; [ERR:] + mov byte [0xB800a], al ; Print the error code + hlt ; Halt the CPU KERNEL_STACK_SZ equ 4096 ; Stack size(4KiB) section .bss -align 4 +align 4096 +page_table_l4: + resb 4096 +page_table_l3: + resb 4096 +page_table_l2: + resb 4096 kernel_stack: - resb KERNEL_STACK_SZ ; Reserver 4KiB for kernel's stack \ No newline at end of file + resb KERNEL_STACK_SZ ; Reserver 4KiB for kernel's stack + + +section .rodata +gdt64: + dq 0 ; zero entry +.code_segment: equ $ - gdt64 + dq (1 << 4) | (1 << 44) | (1 << 47) | (1 << 53) ; Code segment + ; executable, descriptor, present 64bit flags +.pointer: + dw $ - gdt64 - 1 + dd gdt64 \ No newline at end of file diff --git a/kernel/cpu/main64.asm b/kernel/cpu/main64.asm new file mode 100644 index 0000000..c0695a7 --- /dev/null +++ b/kernel/cpu/main64.asm @@ -0,0 +1,27 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +GLOBAL long_mode_start +GLOBAL kernel_loader +EXTERN kernel_main +section .text +[BITS 64] ; Ensure we are in long mode + +long_mode_start: + xor ax, ax + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Call the kernel's main method + call kernel_main ; Call kernel's main function + .loop: + jmp .loop ; If the kernel returns, go into an endless loop + ; This will prevent the CPU to execure any non-kernel + ; instructions. \ No newline at end of file diff --git a/kernel/drivers/Makefile b/kernel/drivers/Makefile index da29a61..cc6734f 100644 --- a/kernel/drivers/Makefile +++ b/kernel/drivers/Makefile @@ -1,7 +1,7 @@ OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \ fs.o cpuid.o -CC = i686-elf-gcc # cross-compiler +CC = x86_64-elf-gcc # cross-compiler CFLAGS = -m32 -fno-stack-protector -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -ffreestanding -Wall -Wextra -Werror -g -c diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index 597a9dd..4d66dad 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -6,7 +6,7 @@ * https://github.com/ice-bit/vulcanos * *****************************************/ #include "drivers/tty.h" -#include "drivers/gdt.h" +//#include "drivers/gdt.h" #include "drivers/idt.h" #include "drivers/timer.h" #include "drivers/keyboard.h" @@ -41,9 +41,9 @@ void kernel_main(unsigned long magic, uint32_t addr) { printf("Loading kernel, wait please..."); - gdt_setup(); // Setup Global Descriptor Table - PRTOK - printf(" - Loaded GDT"); + // gdt_setup(); // Setup Global Descriptor Table + // PRTOK + // printf(" - Loaded GDT"); idt_setup(); // Setup Interrupt Descriptor Table PRTOK diff --git a/kernel/libc/Makefile b/kernel/libc/Makefile index 4b5621a..5babad3 100644 --- a/kernel/libc/Makefile +++ b/kernel/libc/Makefile @@ -1,7 +1,7 @@ OBJS = stdio.o string.o panic.o time.o VER := $(shell git rev-parse --short HEAD) -CC = i686-elf-gcc # cross-compiler +CC = x86_64-elf-gcc # cross-compiler CFLAGS = -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c diff --git a/kernel/mem/Makefile b/kernel/mem/Makefile index 73b9ae4..b24ebf2 100644 --- a/kernel/mem/Makefile +++ b/kernel/mem/Makefile @@ -1,6 +1,6 @@ OBJS = paging.o kheap.o ordered_array.o -CC = i686-elf-gcc # cross-compiler +CC = x86_64-elf-gcc # cross-compiler CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c all:${OBJS} diff --git a/kernel/userspace/Makefile b/kernel/userspace/Makefile index fb310a7..7bd0439 100644 --- a/kernel/userspace/Makefile +++ b/kernel/userspace/Makefile @@ -1,7 +1,7 @@ OBJS = shell.o fetch.o VER := $(shell git rev-parse --short HEAD) -CC = i686-elf-gcc # cross-compiler +CC = x86_64-elf-gcc # cross-compiler CFLAGS = -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c all:${OBJS}