Add support for multiboot2

This commit is contained in:
Alex
2023-05-10 21:50:11 +03:00
parent 79c6a5096d
commit f1dc3868ca
11 changed files with 343 additions and 97 deletions

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