/* * main.cpp * Kernel entry point * Copyright (c) 2025 Daniel Hammer. * Further copyright information and third party notices can be found at https://montaukos.org/license.txt. */ #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](); } if (!montauk::boot::Initialize()) { Arch::HaltForever(); } 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 ); Arch::EarlyInitialize(); 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(); Arch::InitializeTraps(); 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); Arch::InitializeMemoryAttributes(); Graphics::Framebuffer::Initialize(framebuffer); Graphics::Framebuffer::MapWriteCombining(); Hal::ACPI g_acpi((Hal::ACPI::XSDP*)Memory::HHDM(boot.rsdpPhysical)); Drivers::Serial::InitializeConsole(g_acpi.GetXSDT()); if (g_acpi.GetXSDT() != nullptr) { Hal::AcpiShutdown::Initialize(g_acpi.GetXSDT()); // The EC is the transport behind battery (and most thermal) methods, so // it has to be latched before anything evaluates them. Hal::EmbeddedController::Initialize(g_acpi.GetXSDT()); Hal::Battery::Initialize(); // Interrupt controllers, this CPU's per-CPU data, idle and power // management. Arch::InitializeInterrupts(g_acpi.GetXSDT()); Arch::EnableInterrupts(); Hal::AcpiEvents::Initialize(g_acpi.GetXSDT()); Pci::Initialize(g_acpi.GetXSDT()); // _REG and _INI, once the EC and PCI config space (ECAM, for the // extended registers PCI_Config regions reach) are both available: // firmware settles which OS it is talking to here, and gates device // power control on the answer. Hal::AML::InitializeNamespaceObjects(); Pci::AssignInterruptLines(); Drivers::ProbeEarly(); Drivers::InitializeGraphics(); Timekeeping::TimerInitialize(); Arch::InitializePlatformDevices(); // Hybrid graphics: switch off a discrete GPU nothing drives before // the normal probe can claim its USB-C/audio functions. Drivers::PowerDownUnusedGpus(); Drivers::ProbeNormal(); Drivers::InitializeNetwork(); Drivers::InitializeStorage(); Drivers::InitializeAudio(); } // 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); Arch::PrepareUserMode(); montauk::abi::InitializeSyscalls(); Sched::Initialize(); Memory::InitUserRange(); Fs::LogProtectedPaths(); Ipc::Initialize(); Smp::BootAPs(boot.smp); Arch::LateInitialize(); // Without a root nothing can start; say so instead of idling silently. if (!Fs::Vfs::IsDriveRegistered(0)) { Panic("No root filesystem (0:/): cannot start 0:/os/init.elf", nullptr); } Kt::SuppressKernelLog(); Sched::Spawn("0:/os/init.elf"); Timekeeping::EnableSchedulerTick(); for (;;) { Timekeeping::IdleOnce(); } }