// boot/main.c - UEFI bootloader // // Responsibilities (see design ยง5.2): // 1. Parse boot.ini // 2. Read drivers/drivers.ini // 3. Load PE images (kernel.exe, hal.dll, syscall.dll, win32.dll, *.sys) // 4. Validate PE checksums // 5. Map images into the upper half of a new PML4 // 6. Map all RAM as direct physical window at 0xFFFF880000000000 // 7. Convert EFI memory map -> MEMORY_MAP // 8. ExitBootServices // 9. Set up minimal GDT/IDT, enable NXE, set CR3 // 10. Fill BOOT_INFO and jump to KernelMain // #include #include #include #include #include #include #include #pragma intrinsic(_disable) int _fltused = 0; #define KERNEL_VIRT_BASE 0xFFFF800000000000ULL #define PHYS_MAP_BASE 0xFFFF880000000000ULL #define PAGE_SIZE 4096ULL static int AsciiStrToUnicodeStrS(const char* Source, uint16_t* Dest, size_t DestMax) { if (!Source || !Dest || !DestMax) return -1; for (size_t i = 0; i < DestMax; i++) { if ((Dest[i] = (unsigned char)Source[i]) == '\0') return 0; } Dest[DestMax - 1] = '\0'; return -1; // Buffer too small } int AsciiStrCpyS(char* Dest, size_t DestMax, const char* Source) { if (!Dest || !Source || !DestMax) return -1; for (size_t i = 0; i < DestMax; i++) { if ((Dest[i] = Source[i]) == '\0') return 0; } Dest[DestMax - 1] = '\0'; // Ensure termination on truncation return -1; } int UnicodeStrToAsciiStrS(const uint16_t* Source, char* Dest, size_t DestMax) { if (!Source || !Dest || !DestMax) return -1; for (size_t i = 0; i < DestMax; i++) { // Narrowing: only taking the lower 8 bits Dest[i] = (char)(Source[i] & 0xFF); if (Source[i] == 0) return 0; } Dest[DestMax - 1] = '\0'; return -1; } // --------------------------------------------------------------------------- // PE32+ checksum validation // --------------------------------------------------------------------------- static UINT32 ComputePeChecksum(const UINT8* buf, UINTN size) { UINT64 checksum = 0; const UINT16* words = (const UINT16 *)buf; UINTN wordCount = size / 2; // Locate and zero the CheckSum field in the optional header. UINT32 peOff = *(UINT32 *)(buf + 0x3C); UINTN cksumOff = peOff + 4 + 20 + 64; // COFF hdr + optional hdr offset to CheckSum UINT16 savedLo = words[cksumOff / 2]; UINT16 savedHi = words[cksumOff / 2 + 1]; ((UINT16 *)buf)[cksumOff / 2] = 0; ((UINT16 *)buf)[cksumOff / 2 + 1] = 0; for (UINTN i = 0; i < wordCount; i++) { checksum += words[i]; if (checksum > 0xFFFF) checksum = (checksum & 0xFFFF) + (checksum >> 16); } if (size & 1) { checksum += buf[size - 1]; } checksum = (checksum & 0xFFFF) + (checksum >> 16); checksum += (UINT64)size; // Restore. ((UINT16 *)buf)[cksumOff / 2] = savedLo; ((UINT16 *)buf)[cksumOff / 2 + 1] = savedHi; return (UINT32)checksum; } // --------------------------------------------------------------------------- // Page table helpers // --------------------------------------------------------------------------- static UINT64* AllocPage(EFI_PHYSICAL_ADDRESS* physOut) { VOID* mem = NULL; gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, (EFI_PHYSICAL_ADDRESS *)&mem); gBS->SetMem(mem, PAGE_SIZE, 0); if (physOut) *physOut = (EFI_PHYSICAL_ADDRESS)mem; // identity-mapped in UEFI return (UINT64 *)mem; } #define PML4_IDX(va) (((va) >> 39) & 0x1FF) #define PDPT_IDX(va) (((va) >> 30) & 0x1FF) #define PDT_IDX(va) (((va) >> 21) & 0x1FF) #define PT_IDX(va) (((va) >> 12) & 0x1FF) #define PAGE_2M (2ULL * 1024ULL * 1024ULL) #define PAGE_1G (1024ULL * 1024ULL * 1024ULL) static UINT64* gPml4; static UINT64* EnsureTable(UINT64* parent, UINTN index) { UINT64* entry = &parent[index]; if (!(*entry & 1)) { EFI_PHYSICAL_ADDRESS p; UINT64* child = AllocPage(&p); *entry = p | 3; return child; } return (UINT64 *)(*entry & ~0xFFFULL); } static void Map4K(UINT64 virt, UINT64 phys, UINT64 flags) { UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt)); UINT64* pdt = EnsureTable(pdpt, PDPT_IDX(virt)); UINT64* pt = EnsureTable(pdt, PDT_IDX(virt)); pt[PT_IDX(virt)] = phys | flags; } static void Map2M(UINT64 virt, UINT64 phys, UINT64 flags) { UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt)); UINT64* pdt = EnsureTable(pdpt, PDPT_IDX(virt)); pdt[PDT_IDX(virt)] = phys | flags | 0x80ULL; // PS bit } static void Map1G(UINT64 virt, UINT64 phys, UINT64 flags) { UINT64* pdpt = EnsureTable(gPml4, PML4_IDX(virt)); pdpt[PDPT_IDX(virt)] = phys | flags | 0x80ULL; // PS bit } static void MapRangeSmart(UINT64 virt, UINT64 phys, UINT64 size, UINT64 flags) { while (size) { if ((virt & (PAGE_1G - 1)) == 0 && (phys & (PAGE_1G - 1)) == 0 && size >= PAGE_1G) { Map1G(virt, phys, flags); virt += PAGE_1G; phys += PAGE_1G; size -= PAGE_1G; } else if ((virt & (PAGE_2M - 1)) == 0 && (phys & (PAGE_2M - 1)) == 0 && size >= PAGE_2M) { Map2M(virt, phys, flags); virt += PAGE_2M; phys += PAGE_2M; size -= PAGE_2M; } else { Map4K(virt, phys, flags); virt += PAGE_SIZE; phys += PAGE_SIZE; size -= PAGE_SIZE; } } } static void MapRangeSkipping(UINT64 virt, UINT64 phys, UINT64 size, UINT64 flags, const UINT64* holes, UINTN holeCount) { UINT64 curVirt = virt; UINT64 curPhys = phys; UINT64 end = virt + size; for (UINTN i = 0; i < holeCount; i++) { UINT64 hStart = holes[i * 2 + 0]; UINT64 hEnd = holes[i * 2 + 1]; if (hEnd <= curVirt || hStart >= end) continue; if (curVirt < hStart) { UINT64 prefixSize = hStart - curVirt; MapRangeSmart(curVirt, curPhys, prefixSize, flags); curPhys += prefixSize; curVirt += prefixSize; } if (curVirt < hEnd) { UINT64 skip = hEnd - curVirt; curVirt += skip; curPhys += skip; } } if (curVirt < end) { MapRangeSmart(curVirt, curPhys, end - curVirt, flags); } } // --------------------------------------------------------------------------- // File loading // --------------------------------------------------------------------------- static EFI_FILE_PROTOCOL* gRoot; static UINT8* LoadFile(CHAR16* path, UINTN* sizeOut) { EFI_STATUS Status; EFI_FILE_PROTOCOL* fh; // Open the file Status = gRoot->Open(gRoot, &fh, path, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) return NULL; // Get the correct buffer size for EFI_FILE_INFO EFI_FILE_INFO* info; UINTN infoSz = 0; // This first call will fail but will return the required size in infoSz fh->GetInfo(fh, &gEfiFileInfoGuid, &infoSz, NULL); // Allocate the buffer for the info struct info = AllocatePool(infoSz); if (info == NULL) { fh->Close(fh); return NULL; } // Now actually get the info Status = fh->GetInfo(fh, &gEfiFileInfoGuid, &infoSz, info); if (EFI_ERROR(Status)) { FreePool(info); fh->Close(fh); return NULL; } // Allocate buffer for file content UINTN sz = (UINTN)info->FileSize; FreePool(info); // Don't need this anymore UINT8* buf = AllocatePool(sz); if (buf == NULL) { fh->Close(fh); return NULL; } // Read the file into the buffer Status = fh->Read(fh, &sz, buf); fh->Close(fh); if (EFI_ERROR(Status)) { FreePool(buf); return NULL; } if (sizeOut) *sizeOut = sz; return buf; } // --------------------------------------------------------------------------- // INI parsing state // --------------------------------------------------------------------------- typedef struct { BOOT_INFO* bi; CHAR16 drivers[32][64]; int driverCount; int debug; char commandLine[64]; } PARSE_STATE; static int ParseBootIniInteger(const char* val) { int out = 0; if (!val) return 0; while (*val == ' ' || *val == '\t') val++; int base = 10; if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) { base = 16; val += 2; } while (*val) { char c = *val++; int digit; if (c >= '0' && c <= '9') digit = c - '0'; else if (c >= 'a' && c <= 'f') digit = 10 + c - 'a'; else if (c >= 'A' && c <= 'F') digit = 10 + c - 'A'; else break; if (digit >= base) break; out = out * base + digit; } return out; } static void BootIniCb(const char* section, const char* key, const char* val, void* ud) { PARSE_STATE* s = (PARSE_STATE *)ud; // [kernel] debug = bitmask: 1=console, 2=selftests, 4=file log if (!AsciiStrCmp(section, "kernel") && !AsciiStrCmp(key, "debug")) s->debug = ParseBootIniInteger(val); // [init] commandline = hello.exe else if (!AsciiStrCmp(section, "init") && !AsciiStrCmp(key, "commandline")) AsciiStrCpyS(s->commandLine, 64, val); } static void DriversIniCb(const char* section, const char* key, const char* val, void* ud) { (void)val; PARSE_STATE* s = (PARSE_STATE *)ud; if (!AsciiStrCmp(section, "boot") && s->driverCount < 32) { AsciiStrToUnicodeStrS(key, s->drivers[s->driverCount], 64); s->driverCount++; } } // --------------------------------------------------------------------------- // EFI Memory Map -> MEMORY_MAP conversion // --------------------------------------------------------------------------- static EFI_PHYSICAL_ADDRESS AllocateApTrampolinePageBelow1M(void) { // AP startup via SIPI requires the first instruction page to live below // 1 MiB. Some real UEFI firmware exposes no ConventionalMemory below // 640 KiB after ExitBootServices, so reserve a loader-data page here while // boot services can still satisfy AllocateMaxAddress. EFI_PHYSICAL_ADDRESS phys = 0x0009F000ULL; EFI_STATUS st = gBS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1, &phys); if (EFI_ERROR(st) || phys == 0 || phys >= 0x000A0000ULL || (phys & 0xFFFULL)) { return 0; } gBS->SetMem((VOID*)phys, PAGE_SIZE, 0); return phys; } static void ConvertMemoryMap(MEMORY_MAP* out) { UINTN mapSize = 0, descSz = 0, mapKey; UINT32 descVer; gBS->GetMemoryMap(&mapSize, NULL, &mapKey, &descSz, &descVer); mapSize += 8 * descSz; EFI_MEMORY_DESCRIPTOR* efiMap = AllocatePool(mapSize); gBS->GetMemoryMap(&mapSize, efiMap, &mapKey, &descSz, &descVer); out->Magic = MEMORY_MAP_MAGIC; out->RegionCount = 0; EFI_MEMORY_DESCRIPTOR* desc = efiMap; for (UINTN i = 0; i < mapSize / descSz && out->RegionCount < MEMORY_MAX_REGIONS; i++) { MEMORY_TYPE type; switch (desc->Type) { case EfiConventionalMemory: type = MemoryUsable; break; case EfiMemoryMappedIO: case EfiMemoryMappedIOPortSpace: type = MemoryMappedIO; break; case EfiLoaderCode: case EfiLoaderData: type = MemoryBootloader; break; case EfiRuntimeServicesCode: case EfiRuntimeServicesData: default: type = MemoryReserved; break; } MEMORY_REGION* r = &out->Regions[out->RegionCount++]; r->Base = desc->PhysicalStart; r->Length = desc->NumberOfPages * PAGE_SIZE; r->Type = type; r->_pad = 0; desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + descSz); } FreePool(efiMap); } #pragma pack(push, 1) typedef struct { UINT32 Characteristics; UINT32 TimeDateStamp; UINT16 MajorVersion; UINT16 MinorVersion; UINT32 Name; UINT32 Base; UINT32 NumberOfFunctions; UINT32 NumberOfNames; UINT32 AddressOfFunctions; // RVA to array of RVAs UINT32 AddressOfNames; // RVA to array of RVAs UINT32 AddressOfNameOrdinals; // RVA to array of UINT16 } IMAGE_EXPORT_DIRECTORY; typedef struct { union { UINT32 Characteristics; UINT32 OriginalFirstThunk; // RVA to Import Lookup Table } DUMMYUNIONNAME; UINT32 TimeDateStamp; UINT32 ForwarderChain; UINT32 Name; // RVA to DLL Name UINT32 FirstThunk; // RVA to IAT (Import Address Table) } IMAGE_IMPORT_DESCRIPTOR; typedef struct { union { UINT64 ForwarderString; UINT64 Function; UINT64 Ordinal; UINT64 AddressOfData; // RVA to IMAGE_IMPORT_BY_NAME } u1; } IMAGE_THUNK_DATA64; typedef struct { UINT16 Hint; CHAR8 Name[1]; } IMAGE_IMPORT_BY_NAME; #pragma pack(pop) #define IMAGE_ORDINAL_FLAG64 0x8000000000000000ULL // --- Essential PE Structures (if not in your headers) --- #pragma pack(push, 1) typedef struct { UINT32 VirtualAddress; UINT32 Size; } IMAGE_DATA_DIRECTORY; typedef struct { UINT32 VirtualAddress; UINT32 SizeOfBlock; } IMAGE_BASE_RELOCATION; typedef struct { UINT8 Name[8]; UINT32 VirtualSize; UINT32 VirtualAddress; UINT32 SizeOfRawData; UINT32 PointerToRawData; UINT32 PointerToRelocations; UINT32 PointerToLinenumbers; UINT16 NumberOfRelocations; UINT16 NumberOfLinenumbers; UINT32 Characteristics; } IMAGE_SECTION_HEADER; #pragma pack(pop) // --- The PE Loader --- EFI_STATUS LoadPeImage(UINT8* rawFile, UINT64 virtDest, EFI_PHYSICAL_ADDRESS* outPhys) { UINT32 peOff = *(UINT32*)(rawFile + 0x3C); UINT8* ntHeaders = rawFile + peOff; // Validate Signature if (*(UINT32*)ntHeaders != 0x00004550) { Print(L"Signature mismatch\n"); return EFI_INVALID_PARAMETER; } // "PE\0\0" UINT16 sizeOfOptHeader = *(UINT16*)(ntHeaders + 20); UINT16 numSections = *(UINT16*)(ntHeaders + 6); // Offsets for PE32+ (64-bit) UINT64 imageBase = *(UINT64*)(ntHeaders + 24 + 24); UINT32 sizeOfImage = *(UINT32*)(ntHeaders + 24 + 56); UINT32 sizeOfHeaders = *(UINT32*)(ntHeaders + 24 + 60); IMAGE_DATA_DIRECTORY* dataDirs = (IMAGE_DATA_DIRECTORY*)(ntHeaders + 24 + 112); IMAGE_DATA_DIRECTORY* relocDir = &dataDirs[5]; //IMAGE_DATA_DIRECTORY* importDir = &dataDirs[1]; // Allocate Physical Memory for the mapped image UINTN pages = (sizeOfImage + PAGE_SIZE - 1) / PAGE_SIZE; EFI_PHYSICAL_ADDRESS physBase; gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, &physBase); gBS->SetMem((VOID*)physBase, pages * PAGE_SIZE, 0); // Copy Headers gBS->CopyMem((VOID*)physBase, rawFile, sizeOfHeaders); // Map Sections to their RVAs IMAGE_SECTION_HEADER* sections = (IMAGE_SECTION_HEADER*)(ntHeaders + 24 + sizeOfOptHeader); for (int i = 0; i < numSections; i++) { if (sections[i].SizeOfRawData > 0) { UINT8* dest = (UINT8*)physBase + sections[i].VirtualAddress; UINT8* src = rawFile + sections[i].PointerToRawData; gBS->CopyMem(dest, src, sections[i].SizeOfRawData); } } // Apply Base Relocations (.reloc) // We calculate the delta between where it wants to be (ImageBase) // and where it will actually be (virtDest). UINT64 delta = virtDest - imageBase; if (delta != 0 && relocDir->Size > 0) { IMAGE_BASE_RELOCATION* reloc = (IMAGE_BASE_RELOCATION*)((UINT8*)physBase + relocDir->VirtualAddress); UINTN endOfRelocs = (UINTN)reloc + relocDir->Size; while ((UINTN)reloc < endOfRelocs && reloc->SizeOfBlock > 0) { UINTN count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(UINT16); UINT16* entries = (UINT16*)(reloc + 1); for (UINTN i = 0; i < count; i++) { UINT16 type = entries[i] >> 12; UINT16 offset = entries[i] & 0x0FFF; if (type == 10) { // IMAGE_REL_BASED_DIR64 UINT64* patchAddr = (UINT64*)((UINT8*)physBase + reloc->VirtualAddress + offset); *patchAddr += delta; } } reloc = (IMAGE_BASE_RELOCATION*)((UINT8*)reloc + reloc->SizeOfBlock); } } *outPhys = physBase; return EFI_SUCCESS; } static UINT32 GetExportRva(UINT8* providerPhys, const char* funcName) { UINT32 peOff = *(UINT32*)(providerPhys + 0x3C); UINT8* ntHeaders = providerPhys + peOff; // Export Dir is index 0 in the DataDirectory array UINT32 exportDirRva = *(UINT32*)(ntHeaders + 24 + 112); if (!exportDirRva) return 0; // No exports! IMAGE_EXPORT_DIRECTORY* exports = (IMAGE_EXPORT_DIRECTORY*)(providerPhys + exportDirRva); UINT32* addrOfFunctions = (UINT32*)(providerPhys + exports->AddressOfFunctions); UINT32* addrOfNames = (UINT32*)(providerPhys + exports->AddressOfNames); UINT16* addrOfOrdinals = (UINT16*)(providerPhys + exports->AddressOfNameOrdinals); // Binary search is faster, but linear is fine for a bootloader for (UINT32 i = 0; i < exports->NumberOfNames; i++) { char* name = (char*)(providerPhys + addrOfNames[i]); if (AsciiStrCmp(name, funcName) == 0) { UINT16 ordinal = addrOfOrdinals[i]; return addrOfFunctions[ordinal]; } } return 0; // Function not found } EFI_STATUS ResolveImports(UINT8* consumerPhys, UINT8* providerPhys, UINT64 providerVirt) { UINT32 peOff = *(UINT32*)(consumerPhys + 0x3C); UINT8* ntHeaders = consumerPhys + peOff; // Import Dir is index 1 in the DataDirectory array UINT32 importDirRva = *(UINT32*)(ntHeaders + 24 + 112 + 8); if (!importDirRva) return EFI_SUCCESS; // No imports to resolve IMAGE_IMPORT_DESCRIPTOR* importDesc = (IMAGE_IMPORT_DESCRIPTOR*)(consumerPhys + importDirRva); // Iterate through all imported DLLs while (importDesc->Name != 0) { char* dllName = (char*)(consumerPhys + importDesc->Name); // In a full OS, you'd loop through all loaded modules here. // For now, we assume we are resolving hal.dll. // Convert to lowercase or do a case-insensitive check if needed! if (AsciiStrCmp(dllName, "hal.dll") == 0) { IMAGE_THUNK_DATA64* origFirstThunk = (IMAGE_THUNK_DATA64*)(consumerPhys + importDesc->DUMMYUNIONNAME.OriginalFirstThunk); IMAGE_THUNK_DATA64* firstThunk = (IMAGE_THUNK_DATA64*)(consumerPhys + importDesc->FirstThunk); if (!importDesc->DUMMYUNIONNAME.OriginalFirstThunk) { origFirstThunk = firstThunk; // Some compilers omit OriginalFirstThunk } int i = 0; while (origFirstThunk[i].u1.Function != 0) { if (origFirstThunk[i].u1.Ordinal & IMAGE_ORDINAL_FLAG64) { // Import by Ordinal (Usually you don't do this in modern kernels, but good to handle) Print(L"Error: Ordinal imports not supported in basic loader.\n"); return EFI_UNSUPPORTED; } else { // Import by Name IMAGE_IMPORT_BY_NAME* importByName = (IMAGE_IMPORT_BY_NAME*)(consumerPhys + origFirstThunk[i].u1.AddressOfData); char* funcName = (char*)importByName->Name; UINT32 funcRva = GetExportRva(providerPhys, funcName); if (funcRva == 0) { Print(L"FATAL: Unresolved import: %a\n", funcName); return EFI_NOT_FOUND; } // PATCH THE IAT! // We write the final Virtual Address (Provider Base + Target RVA) // into the physical memory of the consumer's IAT. firstThunk[i].u1.Function = providerVirt + funcRva; } i++; } } importDesc++; } return EFI_SUCCESS; } // --------------------------------------------------------------------------- // UefiMain // --------------------------------------------------------------------------- EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) { InitializeLib(ImageHandle, SystemTable); // Open root filesystem on the device we actually booted from EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* fs; // Get the LoadedImage protocol for this application EFI_STATUS Status = gBS->HandleProtocol( ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage ); if (EFI_ERROR(Status)) { Print(L"Failed to get LoadedImage protocol\n"); return Status; } // Get the SimpleFileSystem protocol for the device we were loaded from Status = gBS->HandleProtocol( LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&fs ); if (EFI_ERROR(Status)) { Print(L"Failed to get SimpleFileSystem protocol on boot device\n"); return Status; } // Open the volume Status = fs->OpenVolume(fs, &gRoot); if (EFI_ERROR(Status)) { Print(L"Failed to open root volume\n"); return Status; } //Print(L"1\n"); // --- Parse boot.ini --- UINTN sz; UINT8* bootIniRaw = LoadFile(L"boot.ini", &sz); PARSE_STATE ps = {0}; if (bootIniRaw) { char* txt = (char *)bootIniRaw; txt[sz] = '\0'; IniParse(txt, BootIniCb, &ps); FreePool(bootIniRaw); } //Print(L"2\n"); // --- Parse drivers/drivers.ini --- UINT8* drvIniRaw = LoadFile(L"drivers\\drivers.ini", &sz); if (drvIniRaw) { char* txt = (char *)drvIniRaw; txt[sz] = '\0'; IniParse(txt, DriversIniCb, &ps); FreePool(drvIniRaw); } //Print(L"3\n"); BOOT_INFO* bi = AllocateZeroPool(sizeof(BOOT_INFO)); bi->Magic = BOOT_INFO_MAGIC; AsciiStrCpyS(bi->CommandLine, 64, ps.commandLine); EFI_TIME fwTime; if (!EFI_ERROR(gRT->GetTime(&fwTime, NULL)) && fwTime.Year >= 1970 && fwTime.Month >= 1 && fwTime.Month <= 12 && fwTime.Day >= 1 && fwTime.Day <= 31 && fwTime.Hour <= 23 && fwTime.Minute <= 59 && fwTime.Second <= 59 && fwTime.Nanosecond < 1000000000U) { bi->BootTime.Year = fwTime.Year; bi->BootTime.Month = fwTime.Month; bi->BootTime.Day = fwTime.Day; bi->BootTime.Hour = fwTime.Hour; bi->BootTime.Minute = fwTime.Minute; bi->BootTime.Second = fwTime.Second; bi->BootTime.Daylight = fwTime.Daylight; bi->BootTime.Nanosecond = fwTime.Nanosecond; bi->BootTime.TimeZoneMinutes = fwTime.TimeZone; bi->BootTime.Flags = BOOT_TIME_FLAG_VALID | BOOT_TIME_FLAG_UEFI; if (fwTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) bi->BootTime.Flags |= BOOT_TIME_FLAG_TZ_KNOWN; } // Build PML4. gPml4 = AllocPage(NULL); // Current mapping cursor for upper half. UINT64 virtCursor = KERNEL_VIRT_BASE; //Print(L"4\n"); // --- Load and validate PE images --- typedef struct { CHAR16* path; char name[32]; UINT8* physBase; // Temporary storage for import resolution UINT64 virtBase; } MODULE_LOAD_INFO; MODULE_LOAD_INFO core[] = { { L"system\\colonel.exe", "kernel.exe", NULL, KERNEL_VIRT_BASE }, { L"system\\hal.dll", "hal.dll", NULL, 0 /* Calculated dynamically */ }, }; for (int i = 0; i < 2; i++) { //Print(L"Loading %s...\n", core[i].path); UINTN rawSize; UINT8* rawBuf = LoadFile(core[i].path, &rawSize); if (!rawBuf) { Print(L"MISSING: %s\n", core[i].path); while(true); return EFI_NOT_FOUND; } // Map sections and apply base relocations EFI_PHYSICAL_ADDRESS physBase; EFI_STATUS status = LoadPeImage(rawBuf, virtCursor, &physBase); if (EFI_ERROR(status)) { Print(L"PE Load Error: %r\n", status); while(true); return status; } // Store locations for the Import Resolver core[i].physBase = (UINT8*)physBase; core[i].virtBase = virtCursor; // Map the pages into the new PML4 // We need the SizeOfImage from the mapped headers UINT32 peOff = *(UINT32*)(rawBuf + 0x3C); UINT32 imgLen = *(UINT32*)(rawBuf + peOff + 4 + 20 + 56); // SizeOfImage imgLen = (imgLen + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); for (UINT64 off = 0; off < imgLen; off += PAGE_SIZE) { Map4K(virtCursor + off, physBase + off, 0x03 /* P|W */); } // Fill BOOT_INFO AsciiStrCpyS(bi->Modules[bi->ModuleCount].Name, 32, core[i].name); bi->Modules[bi->ModuleCount].VirtBase = virtCursor; bi->Modules[bi->ModuleCount].ImageSize = imgLen; bi->ModuleCount++; // Increment cursor (1MB alignment for safety) virtCursor = (virtCursor + imgLen + 0xFFFFF) & ~0xFFFFF; // We can free the raw file buffer now; sections are in physBase FreePool(rawBuf); } if (EFI_ERROR(ResolveImports(core[0].physBase, core[1].physBase, core[1].virtBase))) { Print(L"Failed to resolve imports.\n"); while(true); } //Print(L"5\n"); // Load driver .sys files into raw buffers for (int i = 0; i < ps.driverCount; i++) { CHAR16 path[128]; UnicodeSPrint(path, sizeof(path), L"drivers\\%s", ps.drivers[i]); UINTN imgSz; UINT8* buf = LoadFile(path, &imgSz); if (!buf) { Print(L"Driver not found: %s\n", ps.drivers[i]); continue; } // Store file info for the kernel to process later char name[32]; UnicodeStrToAsciiStrS(ps.drivers[i], name, 32); BOOT_MODULE* mod = &bi->Modules[bi->ModuleCount++]; AsciiStrCpyS(mod->Name, 32, name); mod->PhysBase = (uintptr_t)buf; // Raw physical buffer from LoadFile mod->ImageSize = (size_t)imgSz; mod->VirtBase = 0; // Kernel will map this later } //Print(L"6\n"); // Query GOP FIRST, before the GetMemoryMap loop EFI_GRAPHICS_OUTPUT_PROTOCOL* gop; UINT64 fbBase = 0; UINT64 fbBytes = 0; if (!EFI_ERROR(gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&gop))) { bi->FramebufferBase = gop->Mode->FrameBufferBase; bi->FramebufferWidth = gop->Mode->Info->HorizontalResolution; bi->FramebufferHeight = gop->Mode->Info->VerticalResolution; bi->FramebufferStride = gop->Mode->Info->PixelsPerScanLine; // FrameBufferSize is a lie - EFI reports it as Width*Height*4. // The ACTUAL consumed bytes are Stride*Height*4. // Add one extra page as a safety margin. fbBase = gop->Mode->FrameBufferBase; fbBytes = (UINT64)gop->Mode->Info->PixelsPerScanLine * (UINT64)gop->Mode->Info->VerticalResolution * 4 + PAGE_SIZE; fbBytes = (fbBytes + PAGE_SIZE - 1) & ~(UINT64)(PAGE_SIZE - 1); for (UINT64 i = 0; i < fbBytes; i += PAGE_SIZE) { UINT64 phys = gop->Mode->FrameBufferBase + i; Map4K(PHYS_MAP_BASE + phys, phys, 0x13); // P|W|PCD (write-combined MMIO) Map4K(phys, phys, 0x13); } } //Print(L"7\n"); bi->ApTrampolinePhys = (uintptr_t)AllocateApTrampolinePageBelow1M(); // --- Map physical RAM as direct window AND identity map --- UINTN mapSize = 0, descSz = 0, mapKey; UINT32 descVer; gBS->GetMemoryMap(&mapSize, NULL, &mapKey, &descSz, &descVer); mapSize += 8 * descSz; EFI_MEMORY_DESCRIPTOR* efiMap = AllocatePool(mapSize); gBS->GetMemoryMap(&mapSize, efiMap, &mapKey, &descSz, &descVer); { UINT64 idHoles[8]; UINT64 winHoles[8]; UINTN idHoleCount = 0; UINTN winHoleCount = 0; // Leave virtual page zero genuinely unmapped. Mapping it supervisor/NX // still hides null pointer bugs from the page-fault path and makes // diagnostics worse. The physical-window alias for frame zero remains // available at PHYS_MAP_BASE if low physical memory is ever needed. idHoles[idHoleCount * 2 + 0] = 0; idHoles[idHoleCount * 2 + 1] = PAGE_SIZE; idHoleCount++; if (fbBytes) { idHoles[idHoleCount * 2 + 0] = fbBase; idHoles[idHoleCount * 2 + 1] = fbBase + fbBytes; idHoleCount++; winHoles[winHoleCount * 2 + 0] = PHYS_MAP_BASE + fbBase; winHoles[winHoleCount * 2 + 1] = PHYS_MAP_BASE + fbBase + fbBytes; winHoleCount++; } idHoles[idHoleCount * 2 + 0] = 0xFEC00000ULL; idHoles[idHoleCount * 2 + 1] = 0xFEE01000ULL; idHoleCount++; winHoles[winHoleCount * 2 + 0] = PHYS_MAP_BASE + 0xFEC00000ULL; winHoles[winHoleCount * 2 + 1] = PHYS_MAP_BASE + 0xFEE01000ULL; winHoleCount++; for (UINTN pass = 0; pass < idHoleCount; pass++) { for (UINTN i = 1; i < idHoleCount; i++) { if (idHoles[i * 2] < idHoles[(i - 1) * 2]) { UINT64 s0 = idHoles[(i - 1) * 2 + 0]; UINT64 e0 = idHoles[(i - 1) * 2 + 1]; idHoles[(i - 1) * 2 + 0] = idHoles[i * 2 + 0]; idHoles[(i - 1) * 2 + 1] = idHoles[i * 2 + 1]; idHoles[i * 2 + 0] = s0; idHoles[i * 2 + 1] = e0; } } } for (UINTN pass = 0; pass < winHoleCount; pass++) { for (UINTN i = 1; i < winHoleCount; i++) { if (winHoles[i * 2] < winHoles[(i - 1) * 2]) { UINT64 s0 = winHoles[(i - 1) * 2 + 0]; UINT64 e0 = winHoles[(i - 1) * 2 + 1]; winHoles[(i - 1) * 2 + 0] = winHoles[i * 2 + 0]; winHoles[(i - 1) * 2 + 1] = winHoles[i * 2 + 1]; winHoles[i * 2 + 0] = s0; winHoles[i * 2 + 1] = e0; } } } for (UINTN i = 0; i < mapSize / descSz; i++) { EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)efiMap + i * descSz); // Map normal firmware-described regions into the physical window. // PCI/firmware MMIO is mapped explicitly by the owning driver. if (desc->Type != EfiUnusableMemory && desc->Type != EfiMemoryMappedIO && desc->Type != EfiMemoryMappedIOPortSpace) { UINT64 start = desc->PhysicalStart; UINT64 end = start + (desc->NumberOfPages * PAGE_SIZE); // Add 2 pages (8KB) of padding to the end of the region. // This catches ACPI tables that cross page boundaries into unmapped // memory because of buggy UEFI size reporting. end += 2 * PAGE_SIZE; MapRangeSkipping(start, start, end - start, 0x03, idHoles, idHoleCount); MapRangeSkipping(PHYS_MAP_BASE + start, start, end - start, 0x03, winHoles, winHoleCount); } } } FreePool(efiMap); // ------------------------------------------------------------------------- // Explicitly Map Standard Architectural MMIO // ------------------------------------------------------------------------- // Motherboards frequently omit the APIC/IOAPIC/HPET from the UEFI memory map. // We explicitly map the region from 0xFEC00000 up through 0xFEE00FFF // to guarantee the HAL can access them via the physical window. for (UINT64 phys = 0xFEC00000; phys < 0xFEE01000; phys += PAGE_SIZE) { Map4K(phys, phys, 0x13); // Identity Map, P|W|PCD Map4K(PHYS_MAP_BASE + phys, phys, 0x13); // Physical Window Map, P|W|PCD } //Print(L"8\n"); // --- Convert EFI memory map -> MEMORY_MAP --- ConvertMemoryMap(&bi->MemoryMap); // --- Locate ACPI RSDP --- // Define the standard UEFI ACPI GUIDs EFI_GUID acpi2Guid = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} }; EFI_GUID acpi1Guid = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }; bi->RsdpPhysical = 0; void* acpi1Table = NULL; // Search the UEFI Configuration Table for (UINTN i = 0; i < SystemTable->NumberOfTableEntries; i++) { EFI_GUID* vendorGuid = &SystemTable->ConfigurationTable[i].VendorGuid; // Check for ACPI 2.0 (Preferred) if (vendorGuid->Data1 == acpi2Guid.Data1 && vendorGuid->Data2 == acpi2Guid.Data2 && vendorGuid->Data3 == acpi2Guid.Data3 && vendorGuid->Data4[0] == acpi2Guid.Data4[0] && vendorGuid->Data4[7] == acpi2Guid.Data4[7]) { bi->RsdpPhysical = (UINT64)SystemTable->ConfigurationTable[i].VendorTable; break; // Found the best one, stop searching } // Check for ACPI 1.0 (Fallback) if (vendorGuid->Data1 == acpi1Guid.Data1 && vendorGuid->Data2 == acpi1Guid.Data2 && vendorGuid->Data3 == acpi1Guid.Data3 && vendorGuid->Data4[0] == acpi1Guid.Data4[0] && vendorGuid->Data4[7] == acpi1Guid.Data4[7]) { acpi1Table = SystemTable->ConfigurationTable[i].VendorTable; } } // Fallback to ACPI 1.0 if ACPI 2.0 wasn't found if (bi->RsdpPhysical == 0 && acpi1Table != NULL) { bi->RsdpPhysical = (UINT64)acpi1Table; } // Print it out to verify the bootloader actually found it before launching the kernel //Print(L"Found RSDP at: 0x%016llX\n", bi->RsdpPhysical); bi->PhysicalMapBase = PHYS_MAP_BASE; bi->Debug = (UINT32)ps.debug; //Print(L"9\n"); // --- ExitBootServices --- gBS->GetMemoryMap(&mapSize, NULL, &mapKey, &descSz, &descVer); gBS->ExitBootServices(ImageHandle, mapKey); // --- Load minimal GDT / IDT, enable NXE, set CR3 --- // (These are inline since we have no runtime services after ExitBootServices.) // GDT is set up by the kernel's KeInitializeGdt; we just need a valid one to // reach KernelMain. The bootloader installed a flat 64-bit GDT earlier via // EDK2, which is fine for the jump. // Enable NXE bit in EFER. UINT64 efer = __readmsr(0xC0000080); __writemsr(0xC0000080, efer | (1ULL << 11)); // Switch to our new PML4. __writecr3((UINT64)gPml4); // --- Jump to KernelMain --- typedef void (*KERNEL_ENTRY)(BOOT_INFO *); KERNEL_ENTRY KernelMain = (KERNEL_ENTRY)bi->Modules[0].VirtBase; // The PE entry point is at VirtBase + AddressOfEntryPoint. UINT32 epOff = *(UINT32 *)(bi->Modules[0].VirtBase + *(UINT32 *)(bi->Modules[0].VirtBase + 0x3C) + 4 + 20 + 16); KernelMain = (KERNEL_ENTRY)(bi->Modules[0].VirtBase + epOff); KernelMain(bi); // Never returns. _disable(); while (true) __halt(); }