feat: introduce bootloader-agnostic Boot Contract, add btlist command to list connected Bluetooth devices
This commit is contained in:
@@ -7,21 +7,21 @@
|
||||
using namespace Kt;
|
||||
|
||||
namespace Memory {
|
||||
LargestSection Scan(limine_memmap_response* mmap) {
|
||||
LargestSection Scan(const montauk::boot::MemoryMap& mmap) {
|
||||
LargestSection currentLargestSection{};
|
||||
|
||||
for (size_t i = 0; i < mmap->entry_count; i++) {
|
||||
auto entry = mmap->entries[i];
|
||||
for (size_t i = 0; i < mmap.count; i++) {
|
||||
const auto& entry = mmap.regions[i];
|
||||
|
||||
if (entry->base == 0) {
|
||||
if (entry.base == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
||||
if (entry->length > currentLargestSection.size) {
|
||||
|
||||
if (entry.kind == montauk::boot::MemoryKind::Usable) {
|
||||
if (entry.length > currentLargestSection.size) {
|
||||
currentLargestSection = {
|
||||
.address = (uint64_t)entry->base,
|
||||
.size = entry->length
|
||||
.address = entry.base,
|
||||
.size = entry.length
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,4 @@ namespace Memory {
|
||||
|
||||
return currentLargestSection;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
#include <limine.h>
|
||||
#include <Boot/BootInfo.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
using namespace std;
|
||||
#include <cstdint>
|
||||
|
||||
namespace Memory {
|
||||
// Shared
|
||||
@@ -11,5 +10,7 @@ namespace Memory {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
LargestSection Scan(limine_memmap_response* mmap);
|
||||
};
|
||||
// Scan the boot contract's physical memory map for the largest single
|
||||
// run of usable RAM (the page-frame allocator is seeded from it).
|
||||
LargestSection Scan(const montauk::boot::MemoryMap& mmap);
|
||||
};
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace Memory::VMM {
|
||||
PML4 = (PageTable*)SubHHDM((PageTable*)Memory::g_pfa->AllocateZeroed());
|
||||
}
|
||||
|
||||
void Paging::Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize, limine_memmap_response* memMap) {
|
||||
void Paging::Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize, const montauk::boot::MemoryMap& memMap,
|
||||
const montauk::boot::Framebuffer& framebuffer) {
|
||||
// Map kernel
|
||||
Kt::KernelLogStream(Kt::DEBUG, "VMM") << "Paging::Init called with kernelBaseVirt as 0x" << base::hex << kernelBaseVirt;
|
||||
|
||||
@@ -31,15 +32,31 @@ namespace Memory::VMM {
|
||||
Map(GetPhysKernelAddress(pageAddr), pageAddr);
|
||||
}
|
||||
|
||||
// Map HHDM: find the highest physical address and map everything
|
||||
// from 0 to that point. This covers gaps between memory map entries
|
||||
// (e.g. BIOS ROM at 0xE0000) that firmware may not list but the
|
||||
// kernel still needs to access via HHDM.
|
||||
|
||||
// Map HHDM: map physical memory contiguously from 0 up to the top of
|
||||
// real backing store, so the kernel can reach any RAM/firmware byte at
|
||||
// phys+hhdmBase. Mapping from 0 (rather than per-region) also covers
|
||||
// unlisted low gaps -- BIOS ROM at 0xE0000, the EBDA, etc. -- that the
|
||||
// kernel still touches through the HHDM.
|
||||
//
|
||||
// The upper bound is computed over real backing store ONLY: RAM, ACPI
|
||||
// tables, modules, the framebuffer, and so on. Reserved/Unknown
|
||||
// regions are deliberately EXCLUDED from the bound. Firmware commonly
|
||||
// reports the 64-bit PCI MMIO aperture as a Reserved region hundreds of
|
||||
// GiB above RAM (its base scales with the CPU's physical-address width);
|
||||
// letting that inflate maxPhysAddr would make this loop allocate
|
||||
// gigabytes of 4 KiB page tables and exhaust the frame allocator (OOM).
|
||||
// Such MMIO is mapped on demand via MapMMIO with the right cache
|
||||
// attributes -- never through the HHDM -- so it is correct to leave it
|
||||
// out here. Reserved regions that sit *below* the bound (e.g. low BIOS
|
||||
// areas) are still mapped by the contiguous fill.
|
||||
uint64_t maxPhysAddr = 0;
|
||||
for (size_t i = 0; i < memMap->entry_count; i++) {
|
||||
auto entry = memMap->entries[i];
|
||||
uint64_t entryEnd = entry->base + entry->length;
|
||||
for (size_t i = 0; i < memMap.count; i++) {
|
||||
const auto& entry = memMap.regions[i];
|
||||
if (entry.kind == montauk::boot::MemoryKind::Reserved
|
||||
|| entry.kind == montauk::boot::MemoryKind::Unknown) {
|
||||
continue;
|
||||
}
|
||||
uint64_t entryEnd = entry.base + entry.length;
|
||||
if (entryEnd > maxPhysAddr) maxPhysAddr = entryEnd;
|
||||
}
|
||||
maxPhysAddr = (maxPhysAddr + 0xFFF) & ~0xFFFULL;
|
||||
@@ -48,6 +65,24 @@ namespace Memory::VMM {
|
||||
Map(pageAddr, HHDM(pageAddr));
|
||||
}
|
||||
|
||||
// The linear framebuffer can sit in a PCI BAR above the RAM bound we
|
||||
// just mapped (e.g. in the 32-bit MMIO hole), and it is not guaranteed
|
||||
// to appear as a memory-map region. It MUST be reachable through the
|
||||
// HHDM before we switch to these page tables, because the very next log
|
||||
// line (and PAT setup, and Cursor init) renders to it via phys+hhdmBase.
|
||||
// Map its pages explicitly (write-back for now; Cursor upgrades them to
|
||||
// write-combining once PAT is reprogrammed).
|
||||
if (framebuffer.address != 0) {
|
||||
uint64_t fbPhys = Memory::SubHHDM(framebuffer.address);
|
||||
uint64_t fbBytes = framebuffer.height * framebuffer.pitch;
|
||||
uint64_t fbPages = (fbBytes + 0xFFF) / 0x1000;
|
||||
fbPhys &= ~0xFFFULL;
|
||||
for (uint64_t p = 0; p < fbPages; p++) {
|
||||
uint64_t phys = fbPhys + p * 0x1000;
|
||||
Map(phys, HHDM(phys));
|
||||
}
|
||||
}
|
||||
|
||||
LoadCR3(PML4);
|
||||
Kt::KernelLogStream(Kt::OK, "VMM") << "Switched CR3";
|
||||
}
|
||||
@@ -455,12 +490,12 @@ namespace Memory::VMM {
|
||||
return GetPhysAddr((std::uint64_t)PML4, virtualAddress, false);
|
||||
}
|
||||
|
||||
void Paging::MapEfiRuntime(limine_efi_memmap_response* efiMemmap) {
|
||||
if (!efiMemmap) return;
|
||||
void Paging::MapEfiRuntime(const montauk::boot::EfiInfo& efi) {
|
||||
if (efi.memoryMap == nullptr || efi.descriptorSize == 0) return;
|
||||
|
||||
auto* base = (uint8_t*)efiMemmap->memmap;
|
||||
uint64_t descSize = efiMemmap->desc_size;
|
||||
uint64_t count = efiMemmap->memmap_size / descSize;
|
||||
auto* base = (uint8_t*)efi.memoryMap;
|
||||
uint64_t descSize = efi.descriptorSize;
|
||||
uint64_t count = efi.memoryMapSize / descSize;
|
||||
|
||||
struct EfiMemDesc {
|
||||
uint32_t Type;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <limine.h>
|
||||
#include <Boot/BootInfo.hpp>
|
||||
#include <cstdint>
|
||||
#include <stddef.h>
|
||||
#include <Terminal/Terminal.hpp>
|
||||
|
||||
namespace Memory::VMM {
|
||||
@@ -87,7 +88,8 @@ public:
|
||||
PageTable* PML4{};
|
||||
|
||||
Paging();
|
||||
void Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize, limine_memmap_response* memMap);
|
||||
void Init(std::uint64_t kernelBaseVirt, std::uint64_t kernelSize, const montauk::boot::MemoryMap& memMap,
|
||||
const montauk::boot::Framebuffer& framebuffer);
|
||||
void Map(std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
||||
void MapMMIO(std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
||||
void MapWC(std::uint64_t physicalAddress, std::uint64_t virtualAddress);
|
||||
@@ -121,7 +123,7 @@ public:
|
||||
|
||||
// Identity-map EFI runtime service regions so firmware code can
|
||||
// reference its own data at physical addresses.
|
||||
void MapEfiRuntime(limine_efi_memmap_response* efiMemmap);
|
||||
void MapEfiRuntime(const montauk::boot::EfiInfo& efi);
|
||||
};
|
||||
|
||||
extern Paging* g_paging;
|
||||
|
||||
Reference in New Issue
Block a user