From 8fd51fb47d66cb29edd19c7ae9af218574788117 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 12 Jan 2023 13:20:38 +0200 Subject: [PATCH] Kernel: Replace Paging{.h,.cpp} with better MMU{.h,.cpp} --- kernel/arch/i386/APIC.cpp | 8 +-- kernel/arch/i386/MMU.cpp | 98 ++++++++++++++++++++++++++++++++ kernel/arch/i386/Paging.cpp | 100 --------------------------------- kernel/arch/i386/VESA.cpp | 4 +- kernel/arch/i386/make.config | 1 - kernel/include/kernel/MMU.h | 20 +++++++ kernel/include/kernel/Paging.h | 14 ----- kernel/kernel/kernel.cpp | 57 +++++++++---------- 8 files changed, 150 insertions(+), 152 deletions(-) create mode 100644 kernel/arch/i386/MMU.cpp delete mode 100644 kernel/arch/i386/Paging.cpp create mode 100644 kernel/include/kernel/MMU.h delete mode 100644 kernel/include/kernel/Paging.h diff --git a/kernel/arch/i386/APIC.cpp b/kernel/arch/i386/APIC.cpp index 4c59f4a8..57860f44 100644 --- a/kernel/arch/i386/APIC.cpp +++ b/kernel/arch/i386/APIC.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -211,7 +211,7 @@ namespace APIC static void ParseMADT(RSDPDescriptor* rsdp) { RSDT* root = (RSDT*)(rsdp->revision == 2 ? ((RSDPDescriptor20*)rsdp)->xsdt_address : rsdp->rsdt_address); - Paging::MapPage((uint32_t)root); + MMU::Get().AllocatePage((uint32_t)root); uint32_t sdt_entry_count = (root->header.length - sizeof(root->header)) / (rsdp->revision == 2 ? 8 : 4); for (uint32_t i = 0; i < sdt_entry_count; i++) @@ -366,8 +366,8 @@ namespace APIC if (s_local_apic == 0 || s_io_apic == 0) return false; - Paging::MapPage(s_io_apic); - Paging::MapPage(s_local_apic); + MMU::Get().AllocatePage(s_io_apic); + MMU::Get().AllocatePage(s_local_apic); // Enable Local APIC SetMSR(IA32_APIC_BASE, (s_local_apic & 0xFFFFF000) | IA32_APIC_BASE_ENABLE, 0); diff --git a/kernel/arch/i386/MMU.cpp b/kernel/arch/i386/MMU.cpp new file mode 100644 index 00000000..e5d15b9b --- /dev/null +++ b/kernel/arch/i386/MMU.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +#include + +#define PRESENT (1 << 0) +#define READ_WRITE (1 << 1) + +// bits 31-12 set +#define PAGE_MASK 0xfffff000 +#define PAGE_SIZE 0x00001000 + +static MMU* s_instance = nullptr; + +void MMU::Intialize() +{ + ASSERT(s_instance == nullptr); + s_instance = new MMU(); +} + +MMU& MMU::Get() +{ + ASSERT(s_instance); + return *s_instance; +} + +static uint64_t* allocate_page_aligned_page() +{ + uint64_t* page_directory = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE); + ASSERT(page_directory); + ASSERT(((uintptr_t)page_directory % PAGE_SIZE) == 0); + memset(page_directory, 0, PAGE_SIZE); + return page_directory; +} + +MMU::MMU() +{ + m_page_descriptor_pointer_table = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32); + ASSERT(m_page_descriptor_pointer_table); + ASSERT(((uintptr_t)m_page_descriptor_pointer_table % 32) == 0); + + // create and zero out all page directories + for (int i = 0; i < 4; i++) + { + uint64_t* page_directory = allocate_page_aligned_page(); + m_page_descriptor_pointer_table[i] = (uint64_t)page_directory | PRESENT; + } + + // create and identity map first 4 MiB + uint64_t* page_directory1 = (uint64_t*)(m_page_descriptor_pointer_table[0] & PAGE_MASK); + for (uint64_t i = 0; i < 2; i++) + { + uint64_t* page_table = allocate_page_aligned_page(); + for (uint64_t j = 0; j < 512; j++) + page_table[j] = (i << 21) | (j << 12) | READ_WRITE | PRESENT; + + page_directory1[i] = (uint64_t)page_table | READ_WRITE | PRESENT; + } + + // dont map first page (0 -> 4 KiB) so that nullptr dereference + // causes page fault :) + uint64_t* page_table1 = (uint64_t*)page_directory1[0]; + page_table1[0] = 0; + + // reload this new pdpt + asm volatile("movl %0, %%cr3" :: "r"(m_page_descriptor_pointer_table)); +} + +void MMU::AllocatePage(uintptr_t address) +{ + uint32_t pdpte = (address & 0xC0000000) >> 30; + uint32_t pde = (address & 0x3FE00000) >> 21; + uint32_t pte = (address & 0x001FF000) >> 12; + + ASSERT(pdpte < 4); + + uint64_t* page_directory = (uint64_t*)(m_page_descriptor_pointer_table[pdpte] & PAGE_MASK); + if (!(page_directory[pde] & PRESENT)) + { + uint64_t* page_table = allocate_page_aligned_page(); + page_directory[pde] = (uint64_t)page_table | READ_WRITE | PRESENT; + } + + uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK); + page_table[pte] = (address & PAGE_MASK) | READ_WRITE | PRESENT; + + asm volatile("invlpg (%0)" :: "r"(address & PAGE_MASK) : "memory"); +} + +void MMU::AllocateRange(uintptr_t address, ptrdiff_t size) +{ + uintptr_t s_page = address & PAGE_MASK; + uintptr_t e_page = (address + size - 1) & PAGE_MASK; + for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE) + AllocatePage(page); +} diff --git a/kernel/arch/i386/Paging.cpp b/kernel/arch/i386/Paging.cpp deleted file mode 100644 index 9769d578..00000000 --- a/kernel/arch/i386/Paging.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include - -#include - -#define PRESENT (1 << 0) -#define READ_WRITE (1 << 1) -#define PAGE_SIZE (1 << 7) - -namespace Paging -{ - - static uint64_t s_page_directory_pointer_table[4] __attribute__((aligned(0x20))); - static uint64_t s_page_directory[4 * 512] __attribute__((aligned(4096))); - - static bool HasRequirements() - { - uint32_t ecx, edx; - CPUID::GetFeatures(ecx, edx); - if (!(edx & CPUID::Features::EDX_PAE)) - { - derrorln("PAE not supported, halting"); - return false; - } - - return true; - } - - void Initialize() - { - if (!HasRequirements()) - asm volatile("hlt"); - - // Disable paging - asm volatile( - "movl %cr0, %ebx;" - "andl $0x7fffffff, %ebx;" - "movl %ebx, %cr0;" - ); - - // Identity map first 2 (2 MiB) pages - memset(s_page_directory, 0x00, sizeof(s_page_directory)); - s_page_directory[0] = (0x00 << 21) | PAGE_SIZE | READ_WRITE | PRESENT; - s_page_directory[1] = (0x01 << 21) | PAGE_SIZE | READ_WRITE | PRESENT; - - // Initialize PDPTEs - for (int i = 0; i < 4; i++) - s_page_directory_pointer_table[i] = (uint64_t)(&s_page_directory[512 * i]) | PRESENT; - - asm volatile( - // Enable PAE - "movl %%cr4, %%eax;" - "orl $0x20, %%eax;" - "movl %%eax, %%cr4;" - - // Load PDPT address to cr3 - "movl %0, %%cr3;" - - // Enable paging - "movl %%cr0, %%eax;" - "orl $0x80000000, %%eax;" - "movl %%eax, %%cr0;" - - :: "r" (s_page_directory_pointer_table) - : "eax" - ); - } - - void MapPage(uintptr_t address) - { - if (address != ((address >> 21) << 21)) - { - dprintln("aligning 0x{8H} to 2 MiB boundary -> 0x{8H}", address, (address >> 21) << 21); - address = (address >> 21) << 21; - } - - uint32_t pde = address >> 21; - - dprintln("mapping pde {} (0x{8H} - 0x{8H})", pde, pde << 21, ((pde + 1) << 21) - 1); - - if (s_page_directory[pde] & PRESENT) - { - dprintln("page already mapped"); - return; - } - - // Map and flush the given address - s_page_directory[pde] = address | PAGE_SIZE | READ_WRITE | PRESENT; - asm volatile("invlpg (%0)" :: "r"(address) : "memory"); - } - - void MapPages(uintptr_t address, size_t size) - { - address = (address >> 21) << 21; - for (size_t offset = 0; offset < size; offset += 1 << 21) - MapPage(address + offset); - } - -} \ No newline at end of file diff --git a/kernel/arch/i386/VESA.cpp b/kernel/arch/i386/VESA.cpp index 74790617..f5f3b481 100644 --- a/kernel/arch/i386/VESA.cpp +++ b/kernel/arch/i386/VESA.cpp @@ -1,8 +1,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -104,7 +104,7 @@ namespace VESA s_height = framebuffer.height; s_mode = framebuffer.type; - Paging::MapPages(s_addr, s_pitch * s_height); + MMU::Get().AllocateRange(s_addr, s_pitch * s_height); if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) { diff --git a/kernel/arch/i386/make.config b/kernel/arch/i386/make.config index 160017ec..01eea5c0 100644 --- a/kernel/arch/i386/make.config +++ b/kernel/arch/i386/make.config @@ -10,5 +10,4 @@ $(ARCHDIR)/CPUID.o \ $(ARCHDIR)/GDT.o \ $(ARCHDIR)/IDT.o \ $(ARCHDIR)/MMU.o \ -$(ARCHDIR)/Paging.o \ $(ARCHDIR)/VESA.o \ diff --git a/kernel/include/kernel/MMU.h b/kernel/include/kernel/MMU.h new file mode 100644 index 00000000..d47fee51 --- /dev/null +++ b/kernel/include/kernel/MMU.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +class MMU +{ +public: + static void Intialize(); + static MMU& Get(); + + void AllocatePage(uintptr_t); + void AllocateRange(uintptr_t, ptrdiff_t); + +private: + MMU(); + +private: + uint64_t* m_page_descriptor_pointer_table; +}; diff --git a/kernel/include/kernel/Paging.h b/kernel/include/kernel/Paging.h deleted file mode 100644 index 4b208d5a..00000000 --- a/kernel/include/kernel/Paging.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -namespace Paging -{ - - void Initialize(); - - void MapPage(uintptr_t address); - void MapPages(uintptr_t address, size_t size); - -} \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index ddc479f2..bf0b5c4e 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -28,70 +27,66 @@ struct ParsedCommandLine bool force_pic = false; }; -ParsedCommandLine ParseCommandLine(const char* command_line) +ParsedCommandLine ParseCommandLine() { ParsedCommandLine result; - const char* start = command_line; + if (!(g_multiboot_info->flags & 0x02)) + return result; + + const char* start = g_kernel_cmdline; + const char* current = g_kernel_cmdline; while (true) { - if (!*command_line || *command_line == ' ' || *command_line == '\t') + if (!*current || *current == ' ' || *current == '\t') { - if (command_line - start == 6 && memcmp(start, "noapic", 6) == 0) + if (current - start == 6 && memcmp(start, "noapic", 6) == 0) result.force_pic = true; - if (!*command_line) + if (!*current) break; - start = command_line + 1; + start = current + 1; } - command_line++; + current++; } return result; } -extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic) +extern "C" void kernel_main() { DISABLE_INTERRUPTS(); Serial::initialize(); - if (magic != 0x2BADB002) + if (g_multiboot_magic != 0x2BADB002) { dprintln("Invalid multiboot magic number"); return; } + auto cmdline = ParseCommandLine(); - dprintln("hello from 64 bit protected mode!"); + kmalloc_initialize(); + dprintln("kmalloc initialized"); - Paging::Initialize(); + MMU::Intialize(); + dprintln("MMU initialized"); - dprintln("paging enabled"); - - return; - - s_multiboot_info = mbi; + APIC::Initialize(cmdline.force_pic); + dprintln("APIX initialized"); + gdt_initialize(); + dprintln("GDT initialized"); + IDT::initialize(); + dprintln("IDT initialized"); if (!VESA::Initialize()) return; - - ParsedCommandLine cmdline; - if (mbi->flags & 0x02) - cmdline = ParseCommandLine((const char*)mbi->cmdline); - - APIC::Initialize(cmdline.force_pic); - gdt_initialize(); - IDT::initialize(); - - kmalloc_initialize(); - + TTY* tty1 = new TTY; + PIT::initialize(); if (!Input::initialize()) return; - TTY* tty1 = new TTY; - tty1->SetCursorPosition(0, 2); - ENABLE_INTERRUPTS(); kprintln("Hello from the kernel!");