From 149d8ba79013c7aa8ee7eb90d1f00ce23e8bfdd0 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 11 May 2023 18:34:21 +0300 Subject: [PATCH] Make kernel to boot in x32 --- .../amd64/Bootstrap/Multiboot/2/Multiboot.cpp | 2 +- .../amd64/Memory/VirtualMemoryManager.cpp | 294 ++++++++++++++++ .../i386/Bootstrap/Multiboot/2/Multiboot.cpp | 8 +- .../Multiboot/2/Multiboot_PageTable.asm | 24 +- .../Multiboot/2/Multiboot_PageTable.s_fixme | 47 --- .../i386/Bootstrap/Multiboot/2/Start.s_fixme | 97 ------ .../i386/Memory/VirtualMemoryManager.cpp | 197 +++++++++++ .../i386/cpu/SymmetricMultiprocessing.cpp | 22 +- Core/Crash/CrashDetails.cpp | 2 + Core/Crash/CrashHandler.cpp | 2 + Core/Crash/UserHandler.cpp | 2 + Core/Memory/Memory.cpp | 23 +- Core/Memory/PageMapIndexer.cpp | 2 - Core/Memory/ReserveEssentials.cpp | 8 + Core/Memory/VirtualMemoryManager.cpp | 270 --------------- Core/Video/Display.cpp | 5 +- Tests/MemoryAllocation.cpp | 3 + include/display.hpp | 2 +- include/memory.hpp | 323 +++++++++++++----- 19 files changed, 803 insertions(+), 530 deletions(-) create mode 100644 Architecture/amd64/Memory/VirtualMemoryManager.cpp create mode 100644 Architecture/i386/Memory/VirtualMemoryManager.cpp diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp index 37eb70a8..536be89c 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp @@ -23,7 +23,7 @@ #include "multiboot2.h" #include "../../../../../kernel.h" -EXTERNC void multiboot_main(uint64_t Magic, uint64_t Info) +EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info) { if (Info == NULL || Magic == NULL) { diff --git a/Architecture/amd64/Memory/VirtualMemoryManager.cpp b/Architecture/amd64/Memory/VirtualMemoryManager.cpp new file mode 100644 index 00000000..4b757c5e --- /dev/null +++ b/Architecture/amd64/Memory/VirtualMemoryManager.cpp @@ -0,0 +1,294 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include + +namespace Memory +{ + bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFFFFFFFFFF000; + + PageMapIndexer Index = PageMapIndexer(Address); + PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; + + PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; + PageDirectoryEntryPtr *PDE = nullptr; + PageTableEntryPtr *PTE = nullptr; + + if ((PML4.raw & Flag) > 0) + { + PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); + if (PDPTE) + { + if ((PDPTE->Entries[Index.PDPTEIndex].Present)) + { + if (Type == MapType::OneGB && PDPTE->Entries[Index.PDPTEIndex].PageSize) + return true; + + PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); + if (PDE) + { + if (Type == MapType::TwoMB && PDE->Entries[Index.PDEIndex].PageSize) + return true; + + if ((PDE->Entries[Index.PDEIndex].Present)) + { + PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); + if (PTE) + { + if ((PTE->Entries[Index.PTEIndex].Present)) + return true; + } + } + } + } + } + } + return false; + } + + void *Virtual::GetPhysical(void *VirtualAddress) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFFFFFFFFFF000; + + PageMapIndexer Index = PageMapIndexer(Address); + PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; + + PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; + PageDirectoryEntryPtr *PDE = nullptr; + PageTableEntryPtr *PTE = nullptr; + + if (PML4.Present) + { + PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); + if (PDPTE) + { + if (PDPTE->Entries[Index.PDPTEIndex].Present) + { + if (PDPTE->Entries[Index.PDPTEIndex].PageSize) + return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); + + PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); + if (PDE) + { + if (PDE->Entries[Index.PDEIndex].Present) + { + if (PDE->Entries[Index.PDEIndex].PageSize) + return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); + + PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); + if (PTE) + { + if (PTE->Entries[Index.PTEIndex].Present) + return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); + } + } + } + } + } + } + return nullptr; + } + + void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) + { + SmartLock(this->MemoryLock); + if (unlikely(!this->Table)) + { + error("No page table"); + return; + } + + Flags |= PTFlag::P; + + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only + uint64_t DirectoryFlags = Flags & 0x3F; + + PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; + if (!PML4->Present) + { + PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1)); + memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr)); + PML4->Present = true; + PML4->SetAddress((uintptr_t)PDPTEPtr >> 12); + } + else + PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12); + PML4->raw |= DirectoryFlags; + + PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; + if (Type == MapType::OneGB) + { + PDPTE->raw |= Flags; + PDPTE->PageSize = true; + PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12); + debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress); + return; + } + + PageDirectoryEntryPtr *PDEPtr = nullptr; + if (!PDPTE->Present) + { + PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1)); + memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr)); + PDPTE->Present = true; + PDPTE->SetAddress((uintptr_t)PDEPtr >> 12); + } + else + PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); + PDPTE->raw |= DirectoryFlags; + + PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; + if (Type == MapType::TwoMB) + { + PDE->raw |= Flags; + PDE->PageSize = true; + PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); + debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress); + return; + } + + PageTableEntryPtr *PTEPtr = nullptr; + if (!PDE->Present) + { + PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); + memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); + PDE->Present = true; + PDE->SetAddress((uintptr_t)PTEPtr >> 12); + } + else + PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); + PDE->raw |= DirectoryFlags; + + PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; + PTE->Present = true; + PTE->raw |= Flags; + PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); + +#if defined(a64) + CPU::x64::invlpg(VirtualAddress); +#elif defined(a32) + CPU::x32::invlpg(VirtualAddress); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(VirtualAddress) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif + +#ifdef DEBUG +/* https://stackoverflow.com/a/3208376/9352057 */ +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + + if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails + warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); +#endif + } + + void Virtual::Unmap(void *VirtualAddress, MapType Type) + { + SmartLock(this->MemoryLock); + if (!this->Table) + { + error("No page table"); + return; + } + + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + if (!PML4->Present) + { + error("Page %#lx not present", PML4->GetAddress()); + return; + } + + PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); + PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; + if (!PDPTE->Present) + { + error("Page %#lx not present", PDPTE->GetAddress()); + return; + } + + if (Type == MapType::OneGB && PDPTE->PageSize) + { + PDPTE->Present = false; + return; + } + + PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12); + PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; + if (!PDE->Present) + { + error("Page %#lx not present", PDE->GetAddress()); + return; + } + + if (Type == MapType::TwoMB && PDE->PageSize) + { + PDE->Present = false; + return; + } + + PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); + PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; + if (!PTE.Present) + { + error("Page %#lx not present", PTE.GetAddress()); + return; + } + + PTE.Present = false; + PTEPtr->Entries[Index.PTEIndex] = PTE; + +#if defined(a64) + CPU::x64::invlpg(VirtualAddress); +#elif defined(a32) + CPU::x32::invlpg(VirtualAddress); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(VirtualAddress) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif + } +} diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot.cpp b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot.cpp index 2f82a1c3..536be89c 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot.cpp +++ b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot.cpp @@ -23,7 +23,7 @@ #include "multiboot2.h" #include "../../../../../kernel.h" -EXTERNC void multiboot_main(uint32_t Magic, uint32_t Info) +EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info) { if (Info == NULL || Magic == NULL) { @@ -217,8 +217,10 @@ EXTERNC void multiboot_main(uint32_t Magic, uint32_t Info) case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: { multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag; - fixme("elf_sections->[num=%d, size=%d, entsize=%d, shndx=%d]", - elf->num, elf->size, elf->entsize, elf->shndx); + mb2binfo.Kernel.Symbols.Num = elf->num; + mb2binfo.Kernel.Symbols.EntSize = elf->entsize; + mb2binfo.Kernel.Symbols.Shndx = elf->shndx; + mb2binfo.Kernel.Symbols.Sections = (uintptr_t)&elf->sections; break; } case MULTIBOOT_TAG_TYPE_APM: diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm index 46b0e896..1fefe1fb 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm +++ b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm @@ -23,8 +23,24 @@ align 0x1000 global BootPageTable BootPageTable: dd 0x00000083 + dd 0x00400083 + dd 0x00800083 + dd 0x00C00083 + dd 0x01000083 + dd 0x01400083 + dd 0x01800083 + dd 0x01C00083 + dd 0x02000083 + dd 0x02400083 + times (KERNEL_PAGE_NUMBER - 10) dd 0 dd 0x00000083 - times (KERNEL_PAGE_NUMBER - 2) dd 0 - dd 0x00000083 - dd 0x00000083 - times (1024 - KERNEL_PAGE_NUMBER - 2) dd 0 + dd 0x00400083 + dd 0x00800083 + dd 0x00C00083 + dd 0x01000083 + dd 0x01400083 + dd 0x01800083 + dd 0x01C00083 + dd 0x02000083 + dd 0x02400083 + times (1024 - KERNEL_PAGE_NUMBER - 10) dd 0 diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme index 6922f1bb..8d58c66d 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme +++ b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme @@ -18,50 +18,3 @@ .intel_syntax noprefix .code32 - -.equ PAGE_TABLE_SIZE, 0x4 - -.section .bootstrap.data -.align 0x1000 -.global BootPageTable -BootPageTable: - .rept 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */ - .long 0 - .endr - -.section .bootstrap.text -.global UpdatePageTable -UpdatePageTable: - mov edi, (BootPageTable + 0x0000) /* First PML4E */ - mov eax, (BootPageTable + 0x1000) /* First PDPTE */ - or eax, 0b11 /* Bitwise OR on rax (PDPTE) with 11b (Present, Write) */ - mov dword [edi], eax /* Write 11b to PML4E */ - - mov edi, (BootPageTable + 0x1000) /* First PDPTE */ - mov eax, (BootPageTable + 0x2000) /* First PDE */ - or eax, 0b11 /* Bitwise OR on rax (PDE) with 11b (Present, Write) */ - - mov ecx, PAGE_TABLE_SIZE /* For loop instruction */ - mov ebx, 0x0 /* Value to store in the next 4 bytes */ - .FillPageTableLevel3: - mov dword [edi], eax /* Store modified PDE in PDPTE */ - mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */ - add eax, 0x1000 /* Increment (page size) */ - adc ebx, 0 /* Add 0 to carry flag */ - add edi, 8 /* Add 8 to rdi (next PDE) */ - loop .FillPageTableLevel3 /* Loop until rcx is 0 */ - - mov edi, (BootPageTable + 0x2000) /* First PDE */ - mov eax, 0b10000011 /* Present, Write, Large Page */ - - mov ecx, (512 * PAGE_TABLE_SIZE) /* For loop instruction */ - mov ebx, 0x0 /* Value to store in the next 4 bytes */ - .FillPageTableLevel2: - mov dword [edi], eax /* Store modified PDE in PDPTE */ - mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */ - add eax, 1 << 21 /* Increment (page size) */ - adc ebx, 0 /* Add 0 (carry flag) to rbx to increment if there was a carry */ - add edi, 8 /* Add 8 to rdi (next PDE) */ - loop .FillPageTableLevel2 /* Loop until rcx is 0 */ - - ret diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme b/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme index 8076319c..8d58c66d 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme +++ b/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme @@ -18,100 +18,3 @@ .intel_syntax noprefix .code32 -.equ KERNEL_STACK_SIZE, 0x4000 /* 16KB */ - -.extern DetectCPUID -.extern Detect64Bit -.extern DetectPSE -.extern DetectPAE -.extern multiboot_main -.extern LoadGDT32 -.extern BootPageTable -.extern UpdatePageTable -.extern GDT64.Ptr -.extern GDT64.Code -.extern GDT64.Data - -.section .bootstrap.data -MB_HeaderMagic: - .quad 0 - -MB_HeaderInfo: - .quad 0 - -.section .bootstrap.text - -.global Multiboot2_start -Multiboot2_start: - cli - - mov [MB_HeaderMagic], eax - mov [MB_HeaderInfo], ebx - - call DetectCPUID - cmp eax, 0 - je $ - - call Detect64Bit - cmp eax, 0 - je $ - - call DetectPSE - cmp eax, 0 - je $ - - call DetectPAE - cmp eax, 0 - je $ - - mov ecx, cr4 - or ecx, 0x00000010 /* Set PSE in CR4 */ - or ecx, 0x00000020 /* Set PAE in CR4 */ - mov cr4, ecx - - call LoadGDT32 - call UpdatePageTable - - mov ecx, BootPageTable - mov cr3, ecx - - mov ecx, 0xC0000080 /* EFER */ - rdmsr - or eax, 0x800 | 0x100 | 0x1 /* Set LME, LMA, SCE */ - wrmsr - - mov ecx, cr0 - or ecx, 0x80000001 /* Set PG and PE in CR0 */ - mov cr0, ecx - - lgdt [GDT64.Ptr] - jmp GDT64.Code:HigherHalfStart - -.extern UpdatePageTable64 - -.code64 -HigherHalfStart: - mov ax, GDT64.Data - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - call UpdatePageTable64 - - mov rsp, KernelStack + KERNEL_STACK_SIZE - mov rbp, 0 - mov rdi, [MB_HeaderMagic] - mov rsi, [MB_HeaderInfo] - push rsi - push rdi - call multiboot_main -.Hang: - hlt - jmp .Hang - -.section .bootstrap.bss -.align 16 -KernelStack: - .space KERNEL_STACK_SIZE diff --git a/Architecture/i386/Memory/VirtualMemoryManager.cpp b/Architecture/i386/Memory/VirtualMemoryManager.cpp new file mode 100644 index 00000000..dcec06b6 --- /dev/null +++ b/Architecture/i386/Memory/VirtualMemoryManager.cpp @@ -0,0 +1,197 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include + +namespace Memory +{ + bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFFFFFFFFFF000; + + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry PDE = this->Table->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTE = nullptr; + + if ((PDE.raw & Flag) > 0) + { + if (Type == MapType::FourMB && PDE.PageSize) + return true; + + PTE = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12); + if (PTE) + { + if ((PTE->Entries[Index.PTEIndex].Present)) + return true; + } + } + return false; + } + + void *Virtual::GetPhysical(void *VirtualAddress) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFFFFFFFFFF000; + + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry PDE = this->Table->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTE = nullptr; + + if (PDE.Present) + { + if (PDE.PageSize) + return (void *)((uintptr_t)PDE.GetAddress() << 12); + + PTE = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12); + if (PTE) + { + if (PTE->Entries[Index.PTEIndex].Present) + return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); + } + } + return nullptr; + } + + void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) + { + SmartLock(this->MemoryLock); + if (unlikely(!this->Table)) + { + error("No page table"); + return; + } + + Flags |= PTFlag::P; + + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only + uint64_t DirectoryFlags = Flags & 0x3F; + + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (Type == MapType::FourMB) + { + PDE->raw |= Flags; + PDE->PageSize = true; + PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); + debug("Mapped 4MB page at %p to %p", VirtualAddress, PhysicalAddress); + return; + } + + PageTableEntryPtr *PTEPtr = nullptr; + if (!PDE->Present) + { + PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); + memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); + PDE->Present = true; + PDE->SetAddress((uintptr_t)PTEPtr >> 12); + } + else + PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); + PDE->raw |= DirectoryFlags; + + PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; + PTE->Present = true; + PTE->raw |= Flags; + PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); + +#if defined(a64) + CPU::x64::invlpg(VirtualAddress); +#elif defined(a32) + CPU::x32::invlpg(VirtualAddress); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(VirtualAddress) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif + +#ifdef DEBUG +/* https://stackoverflow.com/a/3208376/9352057 */ +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + + if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails + warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); +#endif + } + + void Virtual::Unmap(void *VirtualAddress, MapType Type) + { + SmartLock(this->MemoryLock); + if (!this->Table) + { + error("No page table"); + return; + } + + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (!PDE->Present) + { + error("Page %#lx not present", PDE->GetAddress()); + return; + } + + if (Type == MapType::FourMB && PDE->PageSize) + { + PDE->Present = false; + return; + } + + PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); + PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; + if (!PTE.Present) + { + error("Page %#lx not present", PTE.GetAddress()); + return; + } + + PTE.Present = false; + PTEPtr->Entries[Index.PTEIndex] = PTE; + +#if defined(a64) + CPU::x64::invlpg(VirtualAddress); +#elif defined(a32) + CPU::x32::invlpg(VirtualAddress); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(VirtualAddress) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif + } +} diff --git a/Architecture/i386/cpu/SymmetricMultiprocessing.cpp b/Architecture/i386/cpu/SymmetricMultiprocessing.cpp index a60692f2..2bec9ff3 100644 --- a/Architecture/i386/cpu/SymmetricMultiprocessing.cpp +++ b/Architecture/i386/cpu/SymmetricMultiprocessing.cpp @@ -17,26 +17,38 @@ #include -#include #include +#include #include #include +#include #include "../../../kernel.h" -volatile bool CPUEnabled = false; +enum SMPTrampolineAddress +{ + PAGE_TABLE = 0x500, + START_ADDR = 0x520, + STACK = 0x570, + GDT = 0x580, + IDT = 0x590, + CORE = 0x600, + TRAMPOLINE_START = 0x2000 +}; + +std::atomic_bool CPUEnabled = false; #pragma GCC diagnostic ignored "-Wmissing-field-initializers" static __aligned(0x1000) CPUData CPUs[MAX_CPU] = {0}; -CPUData *GetCPU(uint64_t id) { return &CPUs[id]; } +SafeFunction CPUData *GetCPU(uint64_t id) { return &CPUs[id]; } -CPUData *GetCurrentCPU() +SafeFunction CPUData *GetCurrentCPU() { uint64_t ret = 0; if (!(&CPUs[ret])->IsActive) { - error("CPU %d is not active!", ret); + // error("CPU %d is not active!", ret); FIXME return &CPUs[0]; } assert((&CPUs[ret])->Checksum == CPU_DATA_CHECKSUM); diff --git a/Core/Crash/CrashDetails.cpp b/Core/Crash/CrashDetails.cpp index e9144dab..0730d51a 100644 --- a/Core/Crash/CrashDetails.cpp +++ b/Core/Crash/CrashDetails.cpp @@ -227,6 +227,7 @@ SafeFunction void PageFaultExceptionHandler(CHArchTrapFrame *Frame) if (Present) { +#if defined(a64) uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress; CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000; debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress); @@ -298,6 +299,7 @@ SafeFunction void PageFaultExceptionHandler(CHArchTrapFrame *Frame) PTE->Entries[Index.PTEIndex].ProtectionKey, PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0", PTE->Entries[Index.PTEIndex].GetAddress() << 12); +#endif } } #endif diff --git a/Core/Crash/CrashHandler.cpp b/Core/Crash/CrashHandler.cpp index 30473186..db216c8a 100644 --- a/Core/Crash/CrashHandler.cpp +++ b/Core/Crash/CrashHandler.cpp @@ -435,6 +435,7 @@ namespace CrashHandler { for (int PMLIndex = 0; PMLIndex < 512; PMLIndex++) { +#if defined(a64) Memory::PageMapLevel4 PML4 = BasePageTable->Entries[PMLIndex]; EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n", PMLIndex, 0, 0, 0, @@ -514,6 +515,7 @@ namespace CrashHandler } } } +#endif } } } diff --git a/Core/Crash/UserHandler.cpp b/Core/Crash/UserHandler.cpp index 89e3958a..009c79c8 100644 --- a/Core/Crash/UserHandler.cpp +++ b/Core/Crash/UserHandler.cpp @@ -281,6 +281,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame) if (Present) { +#if defined(a64) uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress; CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000; debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress); @@ -345,6 +346,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame) PTE->Entries[Index.PTEIndex].ProtectionKey, PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0", PTE->Entries[Index.PTEIndex].GetAddress() << 12); +#endif } } } diff --git a/Core/Memory/Memory.cpp b/Core/Memory/Memory.cpp index 22dede76..282f46e3 100644 --- a/Core/Memory/Memory.cpp +++ b/Core/Memory/Memory.cpp @@ -287,6 +287,7 @@ NIF void MapKernel(PageTable *PT) NIF void InitializeMemoryManagement() { #ifdef DEBUG +#ifndef a32 for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) { uintptr_t Base = r_cst(uintptr_t, bInfo.Memory.Entry[i].BaseAddress); @@ -330,7 +331,8 @@ NIF void InitializeMemoryManagement() End, Type); } -#endif +#endif // a32 +#endif // DEBUG trace("Initializing Physical Memory Manager"); // KernelAllocator = Physical(); <- Already called in the constructor KernelAllocator.Init(); @@ -364,14 +366,13 @@ NIF void InitializeMemoryManagement() } else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) { - CPU::x86::Intel::CPUID0x80000001 cpuid; + CPU::x86::Intel::CPUID0x00000001 cpuid; cpuid.Get(); - fixme("Intel PSE support"); + PSESupport = cpuid.EDX.PSE; } - if (Page1GBSupport && PSESupport) + if (PSESupport) { - debug("1GB Page Support Enabled"); #if defined(a64) CPU::x64::CR4 cr4 = CPU::x64::readcr4(); cr4.PSE = 1; @@ -382,8 +383,14 @@ NIF void InitializeMemoryManagement() CPU::x32::writecr4(cr4); #elif defined(aa64) #endif + trace("PSE Support Enabled"); } +#ifdef DEBUG + if (Page1GBSupport) + debug("1GB Page Support Enabled"); +#endif + MapFromZero(KernelPageTable); MapFramebuffer(KernelPageTable); MapKernel(KernelPageTable); @@ -615,7 +622,7 @@ void free(void *Address) #endif } -void *operator new(size_t Size) +void *operator new(std::size_t Size) { #ifdef DEBUG_ALLOCATIONS_SL SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown")); @@ -646,7 +653,7 @@ void *operator new(size_t Size) return ret; } -void *operator new[](size_t Size) +void *operator new[](std::size_t Size) { #ifdef DEBUG_ALLOCATIONS_SL SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown")); @@ -677,7 +684,7 @@ void *operator new[](size_t Size) return ret; } -void *operator new(unsigned long Size, std::align_val_t Alignment) +void *operator new(std::size_t Size, std::align_val_t Alignment) { #ifdef DEBUG_ALLOCATIONS_SL SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown")); diff --git a/Core/Memory/PageMapIndexer.cpp b/Core/Memory/PageMapIndexer.cpp index 76bec314..ccf7f906 100644 --- a/Core/Memory/PageMapIndexer.cpp +++ b/Core/Memory/PageMapIndexer.cpp @@ -37,8 +37,6 @@ namespace Memory this->PTEIndex = Address & 0x3FF; Address >>= 10; this->PDEIndex = Address & 0x3FF; - Address >>= 10; - this->PDPTEIndex = Address & 0x3FF; #elif defined(aa64) #endif } diff --git a/Core/Memory/ReserveEssentials.cpp b/Core/Memory/ReserveEssentials.cpp index 71d00fb6..d4d142a1 100644 --- a/Core/Memory/ReserveEssentials.cpp +++ b/Core/Memory/ReserveEssentials.cpp @@ -101,6 +101,14 @@ namespace Memory debug("Reserving RSDT..."); this->ReservePages((void *)bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo))); +#if defined(a32) + if ((uintptr_t)ACPIPtr > 0x2800000) /* FIXME */ + { + error("ACPI table is located above 0x2800000, which is not mapped."); + return; + } +#endif + size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4)); debug("Reserving %d ACPI tables...", TableSize); diff --git a/Core/Memory/VirtualMemoryManager.cpp b/Core/Memory/VirtualMemoryManager.cpp index eff29b19..61b5e111 100644 --- a/Core/Memory/VirtualMemoryManager.cpp +++ b/Core/Memory/VirtualMemoryManager.cpp @@ -22,276 +22,6 @@ namespace Memory { - bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) - { - // 0x1000 aligned - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFFFFFFFFFF000; - - PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; - - PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; - PageDirectoryEntryPtr *PDE = nullptr; - PageTableEntryPtr *PTE = nullptr; - - if ((PML4.raw & Flag) > 0) - { - PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); - if (PDPTE) - { - if ((PDPTE->Entries[Index.PDPTEIndex].Present)) - { - if (Type == MapType::OneGB && PDPTE->Entries[Index.PDPTEIndex].PageSize) - return true; - - PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); - if (PDE) - { - if (Type == MapType::TwoMB && PDE->Entries[Index.PDEIndex].PageSize) - return true; - - if ((PDE->Entries[Index.PDEIndex].Present)) - { - PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); - if (PTE) - { - if ((PTE->Entries[Index.PTEIndex].Present)) - return true; - } - } - } - } - } - } - return false; - } - - void *Virtual::GetPhysical(void *VirtualAddress) - { - // 0x1000 aligned - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFFFFFFFFFF000; - - PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex]; - - PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; - PageDirectoryEntryPtr *PDE = nullptr; - PageTableEntryPtr *PTE = nullptr; - - if (PML4.Present) - { - PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); - if (PDPTE) - { - if (PDPTE->Entries[Index.PDPTEIndex].Present) - { - if (PDPTE->Entries[Index.PDPTEIndex].PageSize) - return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); - - PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); - if (PDE) - { - if (PDE->Entries[Index.PDEIndex].Present) - { - if (PDE->Entries[Index.PDEIndex].PageSize) - return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); - - PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); - if (PTE) - { - if (PTE->Entries[Index.PTEIndex].Present) - return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); - } - } - } - } - } - } - return nullptr; - } - - void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) - { - SmartLock(this->MemoryLock); - if (unlikely(!this->Table)) - { - error("No page table"); - return; - } - - Flags |= PTFlag::P; - - PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); - // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only - uint64_t DirectoryFlags = Flags & 0x3F; - - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; - PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; - if (!PML4->Present) - { - PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1)); - memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr)); - PML4->Present = true; - PML4->SetAddress((uintptr_t)PDPTEPtr >> 12); - } - else - PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12); - PML4->raw |= DirectoryFlags; - - PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; - if (Type == MapType::OneGB) - { - PDPTE->raw |= Flags; - PDPTE->PageSize = true; - PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12); - debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress); - return; - } - - PageDirectoryEntryPtr *PDEPtr = nullptr; - if (!PDPTE->Present) - { - PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1)); - memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr)); - PDPTE->Present = true; - PDPTE->SetAddress((uintptr_t)PDEPtr >> 12); - } - else - PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); - PDPTE->raw |= DirectoryFlags; - - PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; - if (Type == MapType::TwoMB) - { - PDE->raw |= Flags; - PDE->PageSize = true; - PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); - debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress); - return; - } - - PageTableEntryPtr *PTEPtr = nullptr; - if (!PDE->Present) - { - PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); - memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); - PDE->Present = true; - PDE->SetAddress((uintptr_t)PTEPtr >> 12); - } - else - PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); - PDE->raw |= DirectoryFlags; - - PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; - PTE->Present = true; - PTE->raw |= Flags; - PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); - -#if defined(a64) - CPU::x64::invlpg(VirtualAddress); -#elif defined(a32) - CPU::x32::invlpg(VirtualAddress); -#elif defined(aa64) - asmv("dsb sy"); - asmv("tlbi vae1is, %0" - : - : "r"(VirtualAddress) - : "memory"); - asmv("dsb sy"); - asmv("isb"); -#endif - -#ifdef DEBUG -/* https://stackoverflow.com/a/3208376/9352057 */ -#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" -#define BYTE_TO_BINARY(byte) \ - (byte & 0x80 ? '1' : '0'), \ - (byte & 0x40 ? '1' : '0'), \ - (byte & 0x20 ? '1' : '0'), \ - (byte & 0x10 ? '1' : '0'), \ - (byte & 0x08 ? '1' : '0'), \ - (byte & 0x04 ? '1' : '0'), \ - (byte & 0x02 ? '1' : '0'), \ - (byte & 0x01 ? '1' : '0') - - if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails - warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); -#endif - } - - void Virtual::Unmap(void *VirtualAddress, MapType Type) - { - SmartLock(this->MemoryLock); - if (!this->Table) - { - error("No page table"); - return; - } - - PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; - if (!PML4->Present) - { - error("Page %#lx not present", PML4->GetAddress()); - return; - } - - PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); - PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; - if (!PDPTE->Present) - { - error("Page %#lx not present", PDPTE->GetAddress()); - return; - } - - if (Type == MapType::OneGB && PDPTE->PageSize) - { - PDPTE->Present = false; - return; - } - - PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12); - PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; - if (!PDE->Present) - { - error("Page %#lx not present", PDE->GetAddress()); - return; - } - - if (Type == MapType::TwoMB && PDE->PageSize) - { - PDE->Present = false; - return; - } - - PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); - PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; - if (!PTE.Present) - { - error("Page %#lx not present", PTE.GetAddress()); - return; - } - - PTE.Present = false; - PTEPtr->Entries[Index.PTEIndex] = PTE; - -#if defined(a64) - CPU::x64::invlpg(VirtualAddress); -#elif defined(a32) - CPU::x32::invlpg(VirtualAddress); -#elif defined(aa64) - asmv("dsb sy"); - asmv("tlbi vae1is, %0" - : - : "r"(VirtualAddress) - : "memory"); - asmv("dsb sy"); - asmv("isb"); -#endif - } - Virtual::Virtual(PageTable *Table) { if (Table) diff --git a/Core/Video/Display.cpp b/Core/Video/Display.cpp index c3462929..98b43353 100644 --- a/Core/Video/Display.cpp +++ b/Core/Video/Display.cpp @@ -232,7 +232,10 @@ namespace Video this->Buffers[Index].DoNotScroll = Value; } - char Display::Print(char Char, int Index, bool WriteToUART) +#if defined(a32) + __no_sanitize("undefined") +#endif + char Display::Print(char Char, int Index, bool WriteToUART) { if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) return 0; diff --git a/Tests/MemoryAllocation.cpp b/Tests/MemoryAllocation.cpp index 3e410bf2..b423183c 100644 --- a/Tests/MemoryAllocation.cpp +++ b/Tests/MemoryAllocation.cpp @@ -49,6 +49,9 @@ extern bool DebuggerIsAttached; void TestMemoryAllocation() { +#ifdef a32 + return; /* Not really for now. */ +#endif if (EnableExternalMemoryTracer || DebuggerIsAttached) { debug("The test is disabled when the external memory tracer or a debugger is enabled."); diff --git a/include/display.hpp b/include/display.hpp index 64c0b71c..a8dc8d49 100644 --- a/include/display.hpp +++ b/include/display.hpp @@ -102,7 +102,7 @@ namespace Video uint32_t CursorX, CursorY; char Brightness; bool DoNotScroll; - long Checksum; + long long Checksum; }; class Display diff --git a/include/memory.hpp b/include/memory.hpp index b01e520f..e502ac3a 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #endif // __cplusplus #include @@ -177,28 +178,44 @@ namespace Memory XD = (uint64_t)1 << 63 }; - /* 2.2 Paging in IA-32e Mode - https://composter.com.ua/documents/TLBs_Paging-Structure_Caches_and_Their_Invalidation.pdf */ - union __packed PageTableEntry { +#if defined(a64) struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Dirty : 1; // 6 - uint64_t PageAttributeTable : 1; // 7 - uint64_t Global : 1; // 8 - uint64_t Available0 : 3; // 9-11 - uint64_t Address : 40; // 12-51 - uint64_t Available1 : 7; // 52-58 - uint64_t ProtectionKey : 4; // 59-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Dirty : 1; // 6 + uintptr_t PageAttributeTable : 1; // 7 + uintptr_t Global : 1; // 8 + uintptr_t Available0 : 3; // 9-11 + uintptr_t Address : 40; // 12-51 + uintptr_t Available1 : 7; // 52-58 + uintptr_t ProtectionKey : 4; // 59-62 + uintptr_t ExecuteDisable : 1; // 63 }; - uint64_t raw; +#elif defined(a32) + struct + { + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Dirty : 1; // 6 + uintptr_t PageAttributeTable : 1; // 7 + uintptr_t Global : 1; // 8 + uintptr_t Available0 : 3; // 9-11 + uintptr_t Address : 20; // 12-31 + }; +#elif defined(aa64) +#endif + uintptr_t raw; /** @brief Set Address */ void SetAddress(uintptr_t _Address) @@ -233,48 +250,87 @@ namespace Memory struct __packed PageTableEntryPtr { +#if defined(a64) PageTableEntry Entries[512]; +#elif defined(a32) + PageTableEntry Entries[1024]; +#elif defined(aa64) +#endif }; union __packed PageDirectoryEntry { +#if defined(a64) struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Available0 : 1; // 6 - uint64_t PageSize : 1; // 7 - uint64_t Available1 : 4; // 8-11 - uint64_t Address : 40; // 12-51 - uint64_t Available2 : 11; // 52-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Available0 : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Available1 : 4; // 8-11 + uintptr_t Address : 40; // 12-51 + uintptr_t Available2 : 11; // 52-62 + uintptr_t ExecuteDisable : 1; // 63 }; struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Dirty : 1; // 6 - uint64_t PageSize : 1; // 7 - uint64_t Global : 1; // 8 - uint64_t Available0 : 3; // 9-11 - uint64_t PageAttributeTable : 1; // 12 - uint64_t Reserved0 : 8; // 13-20 - uint64_t Address : 31; // 21-51 - uint64_t Available1 : 7; // 52-58 - uint64_t ProtectionKey : 4; // 59-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Dirty : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Global : 1; // 8 + uintptr_t Available0 : 3; // 9-11 + uintptr_t PageAttributeTable : 1; // 12 + uintptr_t Reserved0 : 8; // 13-20 + uintptr_t Address : 31; // 21-51 + uintptr_t Available1 : 7; // 52-58 + uintptr_t ProtectionKey : 4; // 59-62 + uintptr_t ExecuteDisable : 1; // 63 } TwoMB; +#elif defined(a32) + struct + { + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Available0 : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Available1 : 4; // 8-11 + uintptr_t Address : 20; // 12-31 + }; - uint64_t raw; + struct + { + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Dirty : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Global : 1; // 8 + uintptr_t Available0 : 3; // 9-11 + uintptr_t PageAttributeTable : 1; // 12 + uintptr_t Address0 : 8; // 13-20 + uintptr_t Reserved0 : 1; // 21 + uintptr_t Address1 : 10; // 22-31 + } FourMB; +#elif defined(aa64) +#endif + uintptr_t raw; /** @brief Set PageTableEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -316,41 +372,41 @@ namespace Memory { struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Available0 : 1; // 6 - uint64_t PageSize : 1; // 7 - uint64_t Available1 : 4; // 8-11 - uint64_t Address : 40; // 12-51 - uint64_t Available2 : 11; // 52-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Available0 : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Available1 : 4; // 8-11 + uintptr_t Address : 40; // 12-51 + uintptr_t Available2 : 11; // 52-62 + uintptr_t ExecuteDisable : 1; // 63 }; struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Dirty : 1; // 6 - uint64_t PageSize : 1; // 7 - uint64_t Global : 1; // 8 - uint64_t Available0 : 3; // 9-11 - uint64_t PageAttributeTable : 1; // 12 - uint64_t Reserved0 : 17; // 13-29 - uint64_t Address : 22; // 30-51 - uint64_t Available1 : 7; // 52-58 - uint64_t ProtectionKey : 4; // 59-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Dirty : 1; // 6 + uintptr_t PageSize : 1; // 7 + uintptr_t Global : 1; // 8 + uintptr_t Available0 : 3; // 9-11 + uintptr_t PageAttributeTable : 1; // 12 + uintptr_t Reserved0 : 17; // 13-29 + uintptr_t Address : 22; // 30-51 + uintptr_t Available1 : 7; // 52-58 + uintptr_t ProtectionKey : 4; // 59-62 + uintptr_t ExecuteDisable : 1; // 63 } OneGB; - uint64_t raw; + uintptr_t raw; /** @brief Set PageDirectoryEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -392,20 +448,20 @@ namespace Memory { struct { - uint64_t Present : 1; // 0 - uint64_t ReadWrite : 1; // 1 - uint64_t UserSupervisor : 1; // 2 - uint64_t WriteThrough : 1; // 3 - uint64_t CacheDisable : 1; // 4 - uint64_t Accessed : 1; // 5 - uint64_t Available0 : 1; // 6 - uint64_t Reserved0 : 1; // 7 - uint64_t Available1 : 4; // 8-11 - uint64_t Address : 40; // 12-51 - uint64_t Available2 : 11; // 52-62 - uint64_t ExecuteDisable : 1; // 63 + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Available0 : 1; // 6 + uintptr_t Reserved0 : 1; // 7 + uintptr_t Available1 : 4; // 8-11 + uintptr_t Address : 40; // 12-51 + uintptr_t Available2 : 11; // 52-62 + uintptr_t ExecuteDisable : 1; // 63 }; - uint64_t raw; + uintptr_t raw; /** @brief Set PageDirectoryPointerTableEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -438,10 +494,70 @@ namespace Memory } }; + struct __packed PageMapLevel4Ptr + { + PageMapLevel4 Entries[512]; + }; + + union __packed PageMapLevel5 + { + struct + { + uintptr_t Present : 1; // 0 + uintptr_t ReadWrite : 1; // 1 + uintptr_t UserSupervisor : 1; // 2 + uintptr_t WriteThrough : 1; // 3 + uintptr_t CacheDisable : 1; // 4 + uintptr_t Accessed : 1; // 5 + uintptr_t Available0 : 1; // 6 + uintptr_t Reserved0 : 1; // 7 + uintptr_t Available1 : 4; // 8-11 + uintptr_t Address : 40; // 12-51 + uintptr_t Available2 : 11; // 52-62 + uintptr_t ExecuteDisable : 1; // 63 + }; + uintptr_t raw; + + /** @brief Set PageMapLevel4Ptr address */ + void SetAddress(uintptr_t _Address) + { +#if defined(a64) + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); +#elif defined(a32) + _Address &= 0x000FFFFF; + this->raw &= 0xFFC00003; + this->raw |= (_Address << 12); +#elif defined(aa64) + _Address &= 0x000000FFFFFFFFFF; + this->raw &= 0xFFF0000000000FFF; + this->raw |= (_Address << 12); +#endif + } + + /** @brief Get PageMapLevel4Ptr address */ + uintptr_t GetAddress() + { +#if defined(a64) + return (this->raw & 0x000FFFFFFFFFF000) >> 12; +#elif defined(a32) + return (this->raw & 0x003FFFFF000) >> 12; +#elif defined(aa64) + return (this->raw & 0x000FFFFFFFFFF000) >> 12; +#endif + } + }; + class PageTable { public: +#if defined(a64) PageMapLevel4 Entries[512]; +#elif defined(a32) + PageDirectoryEntry Entries[1024]; +#elif defined(aa64) +#endif /** * @brief Update CR3 with this PageTable @@ -611,14 +727,17 @@ namespace Memory NoMapType, FourKB, TwoMB, + FourMB, OneGB }; class PageMapIndexer { public: +#if defined(a64) uintptr_t PMLIndex = 0; uintptr_t PDPTEIndex = 0; +#endif uintptr_t PDEIndex = 0; uintptr_t PTEIndex = 0; PageMapIndexer(uintptr_t VirtualAddress); @@ -667,6 +786,8 @@ namespace Memory if (Type == MapType::TwoMB) PageSize = PAGE_SIZE_2M; + else if (Type == MapType::FourMB) + PageSize = PAGE_SIZE_4M; else if (Type == MapType::OneGB) PageSize = PAGE_SIZE_1G; @@ -701,6 +822,14 @@ namespace Memory Length -= PAGE_SIZE_1G; } + while (Length >= PAGE_SIZE_4M) + { + this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Virtual::MapType::FourMB); + VirtualAddress = (void *)((uintptr_t)VirtualAddress + PAGE_SIZE_4M); + PhysicalAddress = (void *)((uintptr_t)PhysicalAddress + PAGE_SIZE_4M); + Length -= PAGE_SIZE_4M; + } + while (Length >= PAGE_SIZE_2M) { this->Map(VirtualAddress, PhysicalAddress, Length, Flags, Virtual::MapType::TwoMB); @@ -732,6 +861,16 @@ namespace Memory return Virtual::MapType::NoMapType; } } + else if (Length >= PAGE_SIZE_4M) + { + Type = Virtual::MapType::FourMB; + if (Length % PAGE_SIZE_4M != 0) + { + warn("Length is not a multiple of 4MB."); + if (FailOnModulo) + return Virtual::MapType::NoMapType; + } + } else if (Length >= PAGE_SIZE_2M) { Type = Virtual::MapType::TwoMB; @@ -768,6 +907,8 @@ namespace Memory if (Type == MapType::TwoMB) PageSize = PAGE_SIZE_2M; + else if (Type == MapType::FourMB) + PageSize = PAGE_SIZE_4M; else if (Type == MapType::OneGB) PageSize = PAGE_SIZE_1G; @@ -909,9 +1050,9 @@ namespace Memory void InitializeMemoryManagement(); -void *operator new(size_t Size); -void *operator new[](size_t Size); -void *operator new(size_t Size, std::align_val_t Alignment); +void *operator new(std::size_t Size); +void *operator new[](std::size_t Size); +void *operator new(std::size_t Size, std::align_val_t Alignment); void operator delete(void *Pointer); void operator delete[](void *Pointer); void operator delete(void *Pointer, long unsigned int Size);