diff --git a/CMakeLists.txt b/CMakeLists.txt index 38fe3a8d..576771e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,13 +5,15 @@ set(CMAKE_CXX_COMPILER_WORKS 1) set(CMAKE_CROSSCOMPILING true) -project(Luna LANGUAGES C CXX ASM) +project(Luna LANGUAGES C CXX ASM_NASM) set(LUNA_ROOT ${CMAKE_CURRENT_LIST_DIR}) set(CMAKE_C_COMPILER x86_64-luna-gcc) set(CMAKE_CXX_COMPILER x86_64-luna-g++) +set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) + set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/x86-64-luna) add_subdirectory(kernel) \ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 9e7a3e4f..65604d76 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -7,30 +7,45 @@ set(SOURCES src/arch/Serial.cpp ) +# x86-64 specific set(SOURCES ${SOURCES} src/arch/x86_64/IO.cpp src/arch/x86_64/Serial.cpp src/arch/x86_64/MMU.cpp + src/arch/x86_64/CPU.cpp ) -add_compile_options(-Os) +# x86-64 specific +set(ASM_SOURCES + src/arch/x86_64/CPU.asm +) -add_compile_options(-pedantic -Wall -Wextra -Werror -Wvla) -add_compile_options(-Wdisabled-optimization -Wformat=2 -Winit-self) -add_compile_options(-Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) -add_compile_options(-Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) -add_compile_options(-fno-rtti -ffreestanding -fno-exceptions) -add_compile_options(-fno-asynchronous-unwind-tables -fno-omit-frame-pointer) -add_compile_options(-nostdlib -mcmodel=kernel) -add_compile_options(-mno-red-zone) - -add_compile_options(-mno-80387 -mno-mmx -mno-sse -mno-sse2) - -add_link_options(-lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mno-red-zone -mcmodel=kernel) +add_library(moon-asm STATIC ${ASM_SOURCES}) add_executable(moon ${SOURCES}) +target_link_libraries(moon moon-asm) + +target_compile_options(moon PRIVATE -Os) + +target_compile_options(moon PRIVATE -pedantic -Wall -Wextra -Werror -Wvla) +target_compile_options(moon PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) +target_compile_options(moon PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(moon PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(moon PRIVATE -fno-rtti -ffreestanding -fno-exceptions) +target_compile_options(moon PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer) +target_compile_options(moon PRIVATE -nostdlib -mcmodel=kernel) + +# x86-64 specific +target_compile_options(moon PRIVATE -mno-red-zone) +target_compile_options(moon PRIVATE -mno-80387 -mno-mmx -mno-sse -mno-sse2) + +target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel) + +# x86-64 specific +target_link_options(moon PRIVATE -mno-red-zone) + set_target_properties(moon PROPERTIES CXX_STANDARD 20) target_include_directories(moon PUBLIC ${LUNA_ROOT}/luna) diff --git a/kernel/src/Init.cpp b/kernel/src/Init.cpp index 85cc9dbf..25018f87 100644 --- a/kernel/src/Init.cpp +++ b/kernel/src/Init.cpp @@ -1,6 +1,7 @@ #include "Init.h" #include "Framebuffer.h" #include "MemoryManager.h" +#include "arch/CPU.h" #include "arch/Serial.h" #include "bootboot.h" #include @@ -21,4 +22,6 @@ void Init::early_init() { Framebuffer::init(); MemoryManager::init(); + + CPU::platform_init(); } \ No newline at end of file diff --git a/kernel/src/arch/CPU.h b/kernel/src/arch/CPU.h new file mode 100644 index 00000000..c2aa77e1 --- /dev/null +++ b/kernel/src/arch/CPU.h @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace CPU +{ + Result identify(); + void platform_init(); + + [[noreturn]] void efficient_halt(); +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/CPU.asm b/kernel/src/arch/x86_64/CPU.asm new file mode 100644 index 00000000..3a889598 --- /dev/null +++ b/kernel/src/arch/x86_64/CPU.asm @@ -0,0 +1,17 @@ +global enable_sse +enable_sse: + mov rax, cr0 + and ax, 0xFFFB ;clear coprocessor emulation CR0.EM + or ax, 0x2 ;set coprocessor monitoring CR0.MP + mov cr0, rax + mov rax, cr4 + or ax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + mov cr4, rax + ret + +global enable_write_protect +enable_write_protect: + mov rax, cr0 + or eax, 0x80000 ;set write-protect CR0.WP + mov cr0, rax + ret \ No newline at end of file diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp new file mode 100644 index 00000000..eeb32306 --- /dev/null +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -0,0 +1,44 @@ +#include "arch/CPU.h" +#include +#include +#include + +extern "C" void enable_sse(); +extern "C" void enable_write_protect(); + +namespace CPU +{ + Result identify() + { + static char brand_string[49]; + + u32 buf[4]; + if (!__get_cpuid(0x80000002, &buf[0], &buf[1], &buf[2], &buf[3])) return err; + memcpy(brand_string, buf, 16); + if (!__get_cpuid(0x80000003, &buf[0], &buf[1], &buf[2], &buf[3])) return err; + memcpy(&brand_string[16], buf, 16); + if (!__get_cpuid(0x80000004, &buf[0], &buf[1], &buf[2], &buf[3])) return err; + memcpy(&brand_string[32], buf, 16); + + brand_string[48] = 0; // null-terminate it :) + + return brand_string; + } + + void platform_init() + { + enable_sse(); + enable_write_protect(); + } + + [[noreturn]] void efficient_halt() // Halt the CPU, using the lowest power possible. On x86-64 we do this using the + // "hlt" instruction, which puts the CPU into a low-power idle state until the + // next interrupt arrives... and we disable interrupts beforehand. + { + asm volatile("cli"); // Disable interrupts + loop: + asm volatile("hlt"); // Let the cpu rest and pause until the next interrupt arrives... which in this case should + // be never (unless an NMI arrives) :) + goto loop; // Safeguard: if we ever wake up, start our low-power rest again + } +} \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index fa03a90c..8747cc4f 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -1,18 +1,13 @@ #include "Framebuffer.h" #include "Init.h" #include "MemoryManager.h" +#include "arch/CPU.h" #include "arch/MMU.h" #include "arch/Serial.h" extern u8 fb[1]; -void hang() -{ - for (;;) - ; -} - -extern "C" void _start() +extern "C" [[noreturn]] void _start() { Init::check_magic(); Init::early_init(); @@ -21,6 +16,10 @@ extern "C" void _start() Framebuffer::rect(0, 0, 200, 200, 0xFF00FF00); + auto cpu_name_or_error = CPU::identify(); + + Serial::println(cpu_name_or_error.has_error() ? "Unable to determine CPU name" : cpu_name_or_error.release_value()); + Serial::println(MMU::get_physical((u64)fb).has_error() ? "fb is not mapped" : "fb is mapped!!"); const u64 address = 0xfffffffff8000000; @@ -31,28 +30,40 @@ extern "C" void _start() bool success = !rc.has_error(); int flags; - u8* ptr; + volatile u8* ptr; if (success) Serial::println("Mapped page :)"); else { Serial::println("Failed to map page"); - hang(); + CPU::efficient_halt(); } if (MMU::get_physical(address).release_value() == physical) Serial::println("Mapping is active ;)"); else { Serial::println("Mapping is not active"); - hang(); + CPU::efficient_halt(); } flags = MMU::get_flags(address).release_value(); if (flags & MMU::ReadWrite) Serial::println("Mapping is writable"); - if (flags & MMU::NoExecute) Serial::println("Mapping is not executable"); + if (flags & MMU::User) Serial::println("Mapping is user accessible"); - ptr = (u8*)address; + auto rrc = MMU::remap(address, MMU::ReadWrite | MMU::User); + if (rrc.has_error()) + { + Serial::println("Failed to change flags of mapping"); + CPU::efficient_halt(); + } + + flags = MMU::get_flags(address).release_value(); + + if (flags & MMU::ReadWrite) Serial::println("Mapping is now writable"); + if (flags & MMU::User) Serial::println("Mapping is now user accessible"); + + ptr = (volatile u8*)address; *ptr = 8; @@ -62,21 +73,16 @@ extern "C" void _start() if (urc.has_error()) { Serial::println("Failed to unmap page"); - hang(); + CPU::efficient_halt(); } if (urc.release_value() != physical) { Serial::println("unmap returned a different address than the one we mapped"); - hang(); + CPU::efficient_halt(); } - Serial::println("Unmapped memory, writing to it should crash"); + Serial::println("Successfully unmapped address"); - *ptr = 16; - - Serial::println("ERROR: we should have crashed by this point"); - - for (;;) - ; + CPU::efficient_halt(); } \ No newline at end of file