From f1dc3868cac36c4eefbad941ac82be9456e6b0ac Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 10 May 2023 21:50:11 +0300 Subject: [PATCH] Add support for multiboot2 --- .vscode/extensions.json | 13 -- .../amd64/Bootstrap/Multiboot/2/Multiboot.cpp | 6 +- Core/Memory/PageMapIndexer.cpp | 38 +++--- Core/Memory/PhysicalMemoryManager.cpp | 107 ++++++++++----- Core/Memory/ReserveEssentials.cpp | 122 +++++++++++++++++ Core/Symbols.cpp | 125 ++++++++++++++---- Kernel.cpp | 9 ++ Makefile | 2 +- include/boot/binfo.h | 8 ++ include/memory.hpp | 2 + include/symbols.hpp | 8 +- 11 files changed, 343 insertions(+), 97 deletions(-) delete mode 100644 .vscode/extensions.json create mode 100644 Core/Memory/ReserveEssentials.cpp diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 42ea9d0..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "recommendations": [ - "ms-vscode.cpptools", - "wayou.vscode-todo-highlight", - "gruntfuggly.todo-tree", - "13xforever.language-x86-64-assembly", - "webfreak.debug", - "zixuanwang.linkerscript", - "maziac.hex-hover-converter", - "cschlosser.doxdocgen", - "streetsidesoftware.code-spell-checker" - ] -} \ No newline at end of file diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp index 8167f5f..37eb70a 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot.cpp @@ -217,8 +217,10 @@ EXTERNC void multiboot_main(uint64_t Magic, uint64_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/Core/Memory/PageMapIndexer.cpp b/Core/Memory/PageMapIndexer.cpp index d16212e..76bec31 100644 --- a/Core/Memory/PageMapIndexer.cpp +++ b/Core/Memory/PageMapIndexer.cpp @@ -19,27 +19,27 @@ namespace Memory { - Virtual::PageMapIndexer::PageMapIndexer(uintptr_t VirtualAddress) - { + Virtual::PageMapIndexer::PageMapIndexer(uintptr_t VirtualAddress) + { #if defined(a64) - uintptr_t Address = VirtualAddress; - Address >>= 12; - this->PTEIndex = Address & 0x1FF; - Address >>= 9; - this->PDEIndex = Address & 0x1FF; - Address >>= 9; - this->PDPTEIndex = Address & 0x1FF; - Address >>= 9; - this->PMLIndex = Address & 0x1FF; + uintptr_t Address = VirtualAddress; + Address >>= 12; + this->PTEIndex = Address & 0x1FF; + Address >>= 9; + this->PDEIndex = Address & 0x1FF; + Address >>= 9; + this->PDPTEIndex = Address & 0x1FF; + Address >>= 9; + this->PMLIndex = Address & 0x1FF; #elif defined(a32) - uintptr_t Address = VirtualAddress; - Address >>= 12; - this->PTEIndex = Address & 0x3FF; - Address >>= 10; - this->PDEIndex = Address & 0x3FF; - Address >>= 10; - this->PDPTEIndex = Address & 0x3FF; + uintptr_t Address = VirtualAddress; + Address >>= 12; + 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/PhysicalMemoryManager.cpp b/Core/Memory/PhysicalMemoryManager.cpp index b9a0cfc..d7c93cc 100644 --- a/Core/Memory/PhysicalMemoryManager.cpp +++ b/Core/Memory/PhysicalMemoryManager.cpp @@ -377,63 +377,100 @@ namespace Memory TotalMemory = MemorySize; FreeMemory = MemorySize; - void *LargestFreeMemorySegment = nullptr; - uint64_t LargestFreeMemorySegmentSize = 0; + size_t BitmapSize = (MemorySize / PAGE_SIZE) / 8 + 1; + uintptr_t BitmapAddress = 0x0; + size_t BitmapAddressSize = 0; + + uintptr_t KernelStart = (uintptr_t)bInfo.Kernel.PhysicalBase; + uintptr_t KernelEnd = (uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size; for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) { if (bInfo.Memory.Entry[i].Type == Usable) { - if (bInfo.Memory.Entry[i].Length > LargestFreeMemorySegmentSize) + uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress; + uintptr_t RegionSize = bInfo.Memory.Entry[i].Length; + + /* We don't want to use 0 as a memory address. */ + if (RegionAddress == 0x0) + continue; + + if ((BitmapSize + 0x100) > RegionSize) { - /* We don't want to use 0 as a memory address. */ - if (bInfo.Memory.Entry[i].BaseAddress == 0x0) - continue; - - LargestFreeMemorySegment = (void *)bInfo.Memory.Entry[i].BaseAddress; - LargestFreeMemorySegmentSize = bInfo.Memory.Entry[i].Length; - - debug("Largest free memory segment: %llp (%lldMB)", - (void *)bInfo.Memory.Entry[i].BaseAddress, - TO_MB(bInfo.Memory.Entry[i].Length)); + debug("Region %p-%p (%dMB) is too small for bitmap.", + (void *)RegionAddress, + (void *)(RegionAddress + RegionSize), + TO_MB(RegionSize)); + continue; } + + BitmapAddress = RegionAddress; + BitmapAddressSize = RegionSize; + + if (RegionAddress >= KernelStart && KernelEnd <= (RegionAddress + RegionSize)) + { + BitmapAddress = KernelEnd; + BitmapAddressSize = RegionSize - (KernelEnd - RegionAddress); + } + + if ((BitmapSize + 0x100) > BitmapAddressSize) + { + debug("Region %p-%p (%dMB) is too small for bitmap.", + (void *)RegionAddress, + (void *)(RegionAddress + BitmapAddressSize), + TO_MB(BitmapAddressSize)); + continue; + } + + for (size_t i = 0; i < MAX_MODULES; i++) + { + uintptr_t ModuleStart = (uintptr_t)bInfo.Modules[i].Address; + uintptr_t ModuleEnd = (uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size; + + if (ModuleStart == 0x0) + break; + + if (RegionAddress >= ModuleStart && ModuleEnd <= (RegionAddress + RegionSize)) + { + BitmapAddress = ModuleEnd; + BitmapAddressSize = RegionSize - (ModuleEnd - RegionAddress); + } + } + + if ((BitmapSize + 0x100) > BitmapAddressSize) + { + debug("Region %p-%p (%dMB) is too small for bitmap.", + (void *)BitmapAddress, + (void *)(BitmapAddress + BitmapAddressSize), + TO_MB(BitmapAddressSize)); + continue; + } + + debug("Found free memory for bitmap: %p (%dMB)", + (void *)BitmapAddress, + TO_MB(BitmapAddressSize)); + break; } } - if (LargestFreeMemorySegment == nullptr) + if (BitmapAddress == 0x0) { error("No free memory found!"); CPU::Stop(); } /* TODO: Read swap config and make the configure the bitmap size correctly */ - size_t BitmapSize = (MemorySize / PAGE_SIZE) / 8 + 1; - debug("Initializing Bitmap at %llp-%llp (%lld Bytes)", - LargestFreeMemorySegment, - (void *)((uintptr_t)LargestFreeMemorySegment + BitmapSize), + debug("Initializing Bitmap at %p-%p (%d Bytes)", + BitmapAddress, + (void *)(BitmapAddress + BitmapSize), BitmapSize); PageBitmap.Size = BitmapSize; - PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegment; + PageBitmap.Buffer = (uint8_t *)BitmapAddress; for (size_t i = 0; i < BitmapSize; i++) *(uint8_t *)(PageBitmap.Buffer + i) = 0; - debug("Reserving pages..."); - this->ReservePages(0, TO_PAGES(bInfo.Memory.Size)); - debug("Unreserving usable pages..."); - - for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) - { - if (bInfo.Memory.Entry[i].Type == Usable) - this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress, TO_PAGES(bInfo.Memory.Entry[i].Length)); - } - - debug("Reserving pages for SMP..."); - this->ReservePage((void *)0x0); /* Trampoline stack, gdt, idt, etc... */ - this->ReservePages((void *)0x2000, 4); /* TRAMPOLINE_START */ - - debug("Reserving bitmap pages..."); - this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size)); + ReserveEssentials(); } Physical::Physical() {} diff --git a/Core/Memory/ReserveEssentials.cpp b/Core/Memory/ReserveEssentials.cpp new file mode 100644 index 0000000..71d00fb --- /dev/null +++ b/Core/Memory/ReserveEssentials.cpp @@ -0,0 +1,122 @@ +/* + 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 +#ifdef DEBUG +#include +#endif + +#if defined(a64) +#include "../../Architecture/amd64/acpi.hpp" +#elif defined(a32) +#include "../../Architecture/i386/acpi.hpp" +#elif defined(aa64) +#endif + +#include "../../kernel.h" + +namespace Memory +{ + __no_sanitize("alignment") void Physical::ReserveEssentials() + { + debug("Reserving pages..."); + /* The bootloader won't give us the entire mapping, so we + reserve everything and then unreserve the usable pages. */ + this->ReservePages(0, TO_PAGES(bInfo.Memory.Size)); + debug("Unreserving usable pages..."); + + for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) + { + if (bInfo.Memory.Entry[i].Type == Usable) + this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress, TO_PAGES(bInfo.Memory.Entry[i].Length)); + } + + debug("Reserving 0x0-0xFFFFF range..."); + // this->ReservePage((void *)0x0); /* Trampoline stack, gdt, idt, etc... */ + // this->ReservePages((void *)0x2000, 4); /* TRAMPOLINE_START */ + + /* Reserve the lower part of memory. (0x0-0xFFFFF) + This includes: BIOS, EBDA, VGA, SMP, etc... + https://wiki.osdev.org/Memory_Map_(x86) + */ + this->ReservePages((void *)0x0, TO_PAGES(0xFFFFF)); + + debug("Reserving bitmap region %#lx-%#lx...", PageBitmap.Buffer, (void *)((uintptr_t)PageBitmap.Buffer + PageBitmap.Size)); + this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size)); + + debug("Reserving kernel physical region %#lx-%#lx...", bInfo.Kernel.PhysicalBase, (void *)((uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size)); + this->ReservePages(bInfo.Kernel.PhysicalBase, TO_PAGES(bInfo.Kernel.Size)); + + debug("Reserving kernel file and symbols..."); + if (bInfo.Kernel.FileBase) + this->ReservePages(bInfo.Kernel.FileBase, TO_PAGES(bInfo.Kernel.Size)); + + if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx) + this->ReservePages((void *)bInfo.Kernel.Symbols.Sections, TO_PAGES(bInfo.Kernel.Symbols.Num * bInfo.Kernel.Symbols.EntSize)); + + debug("Reserving kernel modules..."); + + for (uint64_t i = 0; i < MAX_MODULES; i++) + { + if (bInfo.Modules[i].Address == 0x0) + continue; + + debug("Reserving module %s (%#lx-%#lx)...", bInfo.Modules[i].CommandLine, + bInfo.Modules[i].Address, (void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size)); + + this->ReservePages((void *)bInfo.Modules[i].Address, TO_PAGES(bInfo.Modules[i].Size)); + } + +#if defined(a86) + debug("Reserving RSDT region %#lx-%#lx...", bInfo.RSDP, (void *)((uintptr_t)bInfo.RSDP + sizeof(BootInfo::RSDPInfo))); + this->ReservePages(bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo))); + + ACPI::ACPI::ACPIHeader *ACPIPtr = nullptr; + bool XSDT = false; + + if (bInfo.RSDP->Revision >= 2 && bInfo.RSDP->XSDTAddress) + { + ACPIPtr = (ACPI::ACPI::ACPIHeader *)(bInfo.RSDP->XSDTAddress); + XSDT = true; + } + else + ACPIPtr = (ACPI::ACPI::ACPIHeader *)(uintptr_t)bInfo.RSDP->RSDTAddress; + + debug("Reserving RSDT..."); + this->ReservePages((void *)bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo))); + + size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4)); + debug("Reserving %d ACPI tables...", TableSize); + + for (size_t t = 0; t < TableSize; t++) + { + // TODO: Should I be concerned about unaligned memory access? + ACPI::ACPI::ACPIHeader *SDTHdr = nullptr; + if (XSDT) + SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 8))); + else + SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 4))); + + this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length)); + } + +#elif defined(aa64) +#endif + } +} diff --git a/Core/Symbols.cpp b/Core/Symbols.cpp index 089b23c..2dd0cb0 100644 --- a/Core/Symbols.cpp +++ b/Core/Symbols.cpp @@ -25,6 +25,105 @@ namespace SymbolResolver { + const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address) + { + Symbols::SymbolTable Result{0, (char *)""}; + for (int64_t i = 0; i < this->TotalEntries; i++) + if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address) + Result = this->SymTable[i]; + return Result.FunctionName; + } + + void Symbols::AddSymbol(uintptr_t Address, const char *Name) + { + if (this->TotalEntries >= 0x10000) + { + error("Symbol table is full"); + return; + } + + this->SymTable[this->TotalEntries].Address = Address; + strcpy(this->SymTable[this->TotalEntries].FunctionName, Name); + this->TotalEntries++; + } + + __no_sanitize("alignment") void Symbols::AddBySymbolInfo(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections) + { + if (this->TotalEntries >= 0x10000) + { + error("Symbol table is full"); + return; + } + + Elf64_Shdr *ElfSections = (Elf64_Shdr *)(Sections); + Elf64_Sym *ElfSymbols = nullptr; + char *strtab = nullptr; + + for (uint64_t i = 0; i < Num; i++) + switch (ElfSections[i].sh_type) + { + case SHT_SYMTAB: + ElfSymbols = (Elf64_Sym *)(Sections + ElfSections[i].sh_offset); + this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym); + if (this->TotalEntries >= 0x10000) + this->TotalEntries = 0x10000 - 1; + + debug("Symbol table found, %d entries", this->TotalEntries); + break; + case SHT_STRTAB: + if (Shndx == i) + { + debug("String table found, %d entries", ElfSections[i].sh_size); + } + else + { + strtab = (char *)(Sections + ElfSections[i].sh_offset); + debug("String table found, %d entries", ElfSections[i].sh_size); + } + break; + default: + break; + } + + if (ElfSymbols != nullptr && strtab != nullptr) + { + int64_t Index, MinimumIndex; + for (int64_t i = 0; i < this->TotalEntries - 1; i++) + { + MinimumIndex = i; + for (Index = i + 1; Index < this->TotalEntries; Index++) + if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value) + MinimumIndex = Index; + Elf64_Sym tmp = ElfSymbols[MinimumIndex]; + ElfSymbols[MinimumIndex] = ElfSymbols[i]; + ElfSymbols[i] = tmp; + } + + while (ElfSymbols[0].st_value == 0) + { + if (this->TotalEntries <= 0) + break; + ElfSymbols++; + this->TotalEntries--; + } + + if (this->TotalEntries <= 0) + { + error("Symbol table is empty"); + return; + } + + trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable))); + for (uintptr_t i = 0, g = this->TotalEntries; i < g; i++) + { + this->SymTable[i].Address = ElfSymbols[i].st_value; + this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name]; + + // debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName); + } + } + } + Symbols::Symbols(uintptr_t ImageAddress) { if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false) @@ -76,8 +175,8 @@ namespace SymbolResolver if (ElfSymbols != nullptr && strtab != nullptr) { - uintptr_t Index, MinimumIndex; - for (uintptr_t i = 0; i < this->TotalEntries - 1; i++) + int64_t Index, MinimumIndex; + for (int64_t i = 0; i < this->TotalEntries - 1; i++) { MinimumIndex = i; for (Index = i + 1; Index < this->TotalEntries; Index++) @@ -106,26 +205,4 @@ namespace SymbolResolver } Symbols::~Symbols() {} - - const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address) - { - Symbols::SymbolTable Result{0, (char *)""}; - for (uintptr_t i = 0; i < this->TotalEntries; i++) - if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address) - Result = this->SymTable[i]; - return Result.FunctionName; - } - - NIF void Symbols::AddSymbol(uintptr_t Address, const char *Name) - { - if (this->TotalEntries >= 0x10000) - { - error("Symbol table is full"); - return; - } - - this->SymTable[this->TotalEntries].Address = Address; - strcpy(this->SymTable[this->TotalEntries].FunctionName, Name); - this->TotalEntries++; - } } diff --git a/Kernel.cpp b/Kernel.cpp index d769410..ba7df81 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -271,6 +271,15 @@ EXTERNC NIF void Main() KPrint("Loading Kernel Symbols"); KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)bInfo.Kernel.FileBase); + if (KernelSymbolTable->GetTotalEntries() == 0 && + bInfo.Kernel.Symbols.Num && + bInfo.Kernel.Symbols.EntSize && + bInfo.Kernel.Symbols.Shndx) + KernelSymbolTable->AddBySymbolInfo(bInfo.Kernel.Symbols.Num, + bInfo.Kernel.Symbols.EntSize, + bInfo.Kernel.Symbols.Shndx, + bInfo.Kernel.Symbols.Sections); + KPrint("Reading Kernel Parameters"); ParseConfig((char *)bInfo.Kernel.CommandLine, &Config); diff --git a/Makefile b/Makefile index 6c30374..9a52f10 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ LDFLAGS := -Wl,-Map kernel.map -shared -nostdlib -nodefaultlibs -nolibc WARNCFLAG = -Wall -Wextra \ -Wfloat-equal -Wpointer-arith -Wcast-align \ -Wredundant-decls -Winit-self -Wswitch-default \ - -Wstrict-overflow=5 -Wconversion -w + -Wstrict-overflow=5 -Wconversion # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html CFLAGS := \ diff --git a/include/boot/binfo.h b/include/boot/binfo.h index 9b32263..5985df2 100644 --- a/include/boot/binfo.h +++ b/include/boot/binfo.h @@ -133,6 +133,14 @@ struct BootInfo void *FileBase; char CommandLine[256]; __UINT64_TYPE__ Size; + + struct KernelSymbolInfo + { + __UINT32_TYPE__ Num; + __UINT32_TYPE__ EntSize; + __UINT32_TYPE__ Shndx; + __UINTPTR_TYPE__ Sections; + } Symbols; } Kernel; struct BootloaderInfo diff --git a/include/memory.hpp b/include/memory.hpp index c6874de..b01e520 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -468,6 +468,8 @@ namespace Memory uint64_t PageBitmapIndex = 0; Bitmap PageBitmap; + void ReserveEssentials(); + public: Bitmap GetPageBitmap() { return PageBitmap; } diff --git a/include/symbols.hpp b/include/symbols.hpp index 6214a7a..e580f37 100644 --- a/include/symbols.hpp +++ b/include/symbols.hpp @@ -30,14 +30,16 @@ namespace SymbolResolver }; SymbolTable SymTable[0x10000]; - uintptr_t TotalEntries = 0; + int64_t TotalEntries = 0; void *Image; public: + size_t GetTotalEntries() { return this->TotalEntries; } void *GetImage() { return this->Image; } - Symbols(uintptr_t ImageAddress); - ~Symbols(); const char *GetSymbolFromAddress(uintptr_t Address); void AddSymbol(uintptr_t Address, const char *Name); + void AddBySymbolInfo(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections); + Symbols(uintptr_t ImageAddress); + ~Symbols(); }; }