/* * main.cpp * Kernel entry point * Copyright (c) 2025 Daniel Hammer, Limine Contributors (via Limine C++ example) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kt; namespace Memory { HeapAllocator* g_heap; PageFrameAllocator* g_pfa; uint64_t HHDMBase; }; KernelOutStream kout{}; KernelErrorStream kerr{}; // Extern declarations for global constructors array. extern void (*__init_array[])(); extern void (*__init_array_end[])(); extern "C" uint64_t KernelStartSymbol; extern "C" uint64_t KernelEndSymbol; extern "C" void kmain() { // Call global constructors. for (std::size_t i = 0; &__init_array[i] != __init_array_end; i++) { __init_array[i](); } // Acquire the boot environment through the Montauk Boot Contract. The // active bootloader adapter (see Boot/Protocols/) translates its native // handoff into this bootloader-agnostic structure. A false return means // we cannot even bring up a console (unsupported loader, no HHDM, or no // framebuffer) -- there is nothing to do but halt. if (!montauk::boot::Initialize()) { Hal::Halt(); } const montauk::boot::BootInfo& boot = montauk::boot::Info(); const montauk::boot::Framebuffer& framebuffer = boot.framebuffer; Kt::Initialize( (uint32_t*)framebuffer.address, framebuffer.width, framebuffer.height, framebuffer.pitch, framebuffer.redMaskSize, framebuffer.redMaskShift, framebuffer.greenMaskSize, framebuffer.greenMaskShift, framebuffer.blueMaskSize, framebuffer.blueMaskShift ); #if defined (__x86_64__) Hal::PrepareGDT(); Hal::BridgeLoadGDT(); Hal::EnableSSE(); #endif Memory::HHDMBase = boot.hhdmBase; if (boot.memoryMap.regions == nullptr || boot.memoryMap.count == 0) { Panic("System memory map missing!", nullptr); } Kt::KernelLogStream(OK, "Mem") << "Creating PageFrameAllocator"; Memory::PageFrameAllocator pmm(Memory::Scan(boot.memoryMap)); Memory::g_pfa = &pmm; Kt::KernelLogStream(OK, "Mem") << "Creating HeapAllocator"; Memory::HeapAllocator heap{}; Memory::g_heap = &heap; heap.Walk(); #if defined (__x86_64__) Hal::IDTInitialize(); Memory::VMM::Paging g_paging{}; Memory::VMM::g_paging = &g_paging; g_paging.Init((uint64_t)&KernelStartSymbol, ((uint64_t)&KernelEndSymbol - (uint64_t)&KernelStartSymbol), boot.memoryMap, framebuffer); // Reprogram PAT so entry 1 = Write-Combining (default is Write-Through). // Must be done after paging init and before any WC mappings. Hal::InitializePAT(); Kt::KernelLogStream(OK, "Hal") << "PAT reprogrammed (entry 1 = WC)"; #endif // Initialize the framebuffer early so we can WC-map it before // the bulk of boot logging begins (ACPI, PCI, drivers, etc.) Graphics::Framebuffer::Initialize(framebuffer); #if defined (__x86_64__) // Map framebuffer as Write-Combining immediately for faster screen writes. // All subsequent log output benefits from WC burst transfers. Graphics::Framebuffer::MapWriteCombining(); #endif Hal::ACPI g_acpi((Hal::ACPI::XSDP*)Memory::HHDM(boot.rsdpPhysical)); #if defined (__x86_64__) if (g_acpi.GetXSDT() != nullptr) { Hal::AcpiShutdown::Initialize(g_acpi.GetXSDT()); Hal::CpuIdle::Initialize(g_acpi.GetXSDT()); Hal::ApicInitialize(g_acpi.GetXSDT()); // Set up BSP per-CPU data (GS base) before enabling interrupts. // ISR stubs use SWAPGS which requires GS base to point to CpuData. Smp::InitBsp(); // Enable hardware P-state scaling and the thermal governor. // Needs GS base (per-CPU data) set up, and must run before the // APs boot so they inherit the shared policy in ApEntry. Hal::CpuPower::InitializeBsp(); // Now safe to enable interrupts (SWAPGS-aware ISR stubs are installed) asm volatile("sti"); // Initialize ACPI events (SCI, power button) after APIC is ready Hal::AcpiEvents::Initialize(g_acpi.GetXSDT()); Pci::Initialize(g_acpi.GetXSDT()); Drivers::ProbeEarly(); Drivers::InitializeGraphics(); Timekeeping::ApicTimerInitialize(); Drivers::PS2::Initialize(); Drivers::PS2::Keyboard::Initialize(); Drivers::PS2::Mouse::Initialize(); Drivers::ProbeNormal(); Drivers::InitializeNetwork(); Drivers::InitializeStorage(); Drivers::InitializeAudio(); } #endif // UEFI runtime services are optional (absent on legacy-BIOS boots). if (boot.has(montauk::boot::FeatureEfiSystemTable)) { Efi::SystemTable* ST = (Efi::SystemTable*)Memory::HHDM(boot.efi.systemTablePhysical); Efi::Init(ST, boot.efi); } Fs::InitializeBootFilesystems(boot.modules); Hal::LoadTSS(); montauk::abi::InitializeSyscalls(); Sched::Initialize(); Ipc::Initialize(); // Boot Application Processors (all subsystems ready, APs can schedule) Smp::BootAPs(boot.smp); // Flush any stale PS/2 mouse bytes that accumulated during boot // (edge-triggered IRQs can be lost while spinlocks disable interrupts) Drivers::PS2::Mouse::FlushState(); Kt::SuppressKernelLog(); Sched::Spawn("0:/os/init.elf"); // Enable preemptive scheduling via the APIC timer Timekeeping::EnableSchedulerTick(); // Main loop: idle until next interrupt. // Use MWAIT for deeper C-states if available, otherwise HLT. auto* bspCpu = Smp::GetCpuData(0); if (bspCpu && bspCpu->hasMwait) { static volatile uint64_t s_bspIdleMonitor = 0; for (;;) { Timekeeping::IdleOnce(true, &s_bspIdleMonitor); } } else { for (;;) { Timekeeping::IdleOnce(false); } } }