Add support for multiboot2

This commit is contained in:
Alex 2023-05-10 21:50:11 +03:00
parent 79c6a5096d
commit f1dc3868ca
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
11 changed files with 343 additions and 97 deletions

View File

@ -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"
]
}

View File

@ -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:

View File

@ -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
}
}
}

View File

@ -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() {}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <memory.hpp>
#include <debug.h>
#ifdef DEBUG
#include <uart.hpp>
#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
}
}

View File

@ -25,6 +25,105 @@
namespace SymbolResolver
{
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
{
Symbols::SymbolTable Result{0, (char *)"<unknown>"};
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 *)"<unknown>"};
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++;
}
}

View File

@ -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);

View File

@ -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 := \

View File

@ -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

View File

@ -468,6 +468,8 @@ namespace Memory
uint64_t PageBitmapIndex = 0;
Bitmap PageBitmap;
void ReserveEssentials();
public:
Bitmap GetPageBitmap() { return PageBitmap; }

View File

@ -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();
};
}