From 21b3b269a712f46927f5336b3e994b1ea5ff498a Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Thu, 12 Mar 2026 19:02:58 +0100 Subject: [PATCH] Fix critical memory corruption bug caused by overwriting active page tables marked as free memory --- boot/xtldr/arch/amd64/memory.cc | 29 ++- boot/xtldr/arch/i686/memory.cc | 51 ++++- boot/xtldr/includes/xtldr.hh | 1 + boot/xtldr/modules/xtos_o/amd64/memory.cc | 61 ++++-- boot/xtldr/modules/xtos_o/i686/memory.cc | 75 ++++--- boot/xtldr/modules/xtos_o/includes/xtos.hh | 8 +- boot/xtldr/modules/xtos_o/xtos.cc | 234 ++++++++++++--------- boot/xtldr/protocol.cc | 1 + 8 files changed, 304 insertions(+), 156 deletions(-) diff --git a/boot/xtldr/arch/amd64/memory.cc b/boot/xtldr/arch/amd64/memory.cc index 8f3659a..37ce2fe 100644 --- a/boot/xtldr/arch/amd64/memory.cc +++ b/boot/xtldr/arch/amd64/memory.cc @@ -28,13 +28,12 @@ EFI_STATUS Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, IN ULONG_PTR SelfMapAddress) { - PLIST_ENTRY ListEntry, ModulesList, ModulesListEntry; - PXTBL_MEMORY_MAPPING Mapping; + PLIST_ENTRY ModulesList, ModulesListEntry; PXTBL_MODULE_INFO ModuleInfo; EFI_PHYSICAL_ADDRESS Address; - PVOID LoaderBase; ULONGLONG LoaderSize; EFI_STATUS Status; + PVOID LoaderBase; /* Allocate pages for the Page Map */ Status = AllocatePages(AllocateAnyPages, 1, &Address); @@ -65,7 +64,7 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, } /* Map the trampoline code area */ - Status = MapVirtualMemory(PageMap, MM_TRAMPOLINE_ADDRESS,MM_TRAMPOLINE_ADDRESS, + Status = MapVirtualMemory(PageMap, MM_TRAMPOLINE_ADDRESS, MM_TRAMPOLINE_ADDRESS, 1, LoaderFirmwareTemporary); if(Status != STATUS_EFI_SUCCESS) { @@ -117,6 +116,28 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, return STATUS_EFI_PROTOCOL_ERROR; } + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * Iterates through the memory map and physically maps all virtual addresses to page tables. + * + * @param PageMap + * Supplies a pointer to the page mapping structure. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +Memory::CommitPageMap(IN PXTBL_PAGE_MAPPING PageMap) +{ + PXTBL_MEMORY_MAPPING Mapping; + PLIST_ENTRY ListEntry; + EFI_STATUS Status; + /* Iterate through and map all the mappings*/ Debug::Print(L"Mapping and dumping EFI memory:\n"); ListEntry = PageMap->MemoryMap.Flink; diff --git a/boot/xtldr/arch/i686/memory.cc b/boot/xtldr/arch/i686/memory.cc index 8250b79..3e3f62c 100644 --- a/boot/xtldr/arch/i686/memory.cc +++ b/boot/xtldr/arch/i686/memory.cc @@ -25,13 +25,12 @@ EFI_STATUS Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, IN ULONG_PTR SelfMapAddress) { - PLIST_ENTRY ListEntry, ModulesList, ModulesListEntry; EFI_PHYSICAL_ADDRESS Address, DirectoryAddress; + PLIST_ENTRY ModulesList, ModulesListEntry; PXTBL_MODULE_INFO ModuleInfo; - PXTBL_MEMORY_MAPPING Mapping; - PVOID LoaderBase; ULONGLONG LoaderSize; EFI_STATUS Status; + PVOID LoaderBase; ULONG Index; /* Check the page map level to determine which paging structure to create */ @@ -45,6 +44,14 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, return Status; } + /* Add new memory mapping for the page map itself */ + Status = MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory mapping failure */ + return Status; + } + /* Assign the allocated page to the page map and zero it out */ PageMap->PtePointer = (PVOID)(UINT_PTR)Address; RTL::Memory::ZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE); @@ -57,6 +64,14 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, return Status; } + /* Add new memory mapping for the Page Directories (PDs) */ + Status = MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, DirectoryAddress, 4, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory mapping failure */ + return Status; + } + /* Zero-fill the allocated memory for the Page Directories */ RTL::Memory::ZeroMemory((PVOID)DirectoryAddress, EFI_PAGE_SIZE * 4); @@ -79,6 +94,14 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, return Status; } + /* Add new memory mapping for the page map itself */ + Status = MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory mapping failure */ + return Status; + } + /* Assign the allocated page to the page map and zero it out */ PageMap->PtePointer = (PVOID)(UINT_PTR)Address; RTL::Memory::ZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE); @@ -144,6 +167,28 @@ Memory::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, return STATUS_EFI_PROTOCOL_ERROR; } + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +/** + * Iterates through the memory map and physically maps all virtual addresses to page tables. + * + * @param PageMap + * Supplies a pointer to the page mapping structure. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +Memory::CommitPageMap(IN PXTBL_PAGE_MAPPING PageMap) +{ + PXTBL_MEMORY_MAPPING Mapping; + PLIST_ENTRY ListEntry; + EFI_STATUS Status; + /* Iterate through and map all the mappings*/ Debug::Print(L"Mapping and dumping EFI memory:\n"); ListEntry = PageMap->MemoryMap.Flink; diff --git a/boot/xtldr/includes/xtldr.hh b/boot/xtldr/includes/xtldr.hh index bc42aab..db7e8d7 100644 --- a/boot/xtldr/includes/xtldr.hh +++ b/boot/xtldr/includes/xtldr.hh @@ -165,6 +165,7 @@ class Memory OUT PVOID *Memory); STATIC XTCDECL EFI_STATUS BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap, IN ULONG_PTR SelfMapAddress); + STATIC XTCDECL EFI_STATUS CommitPageMap(IN PXTBL_PAGE_MAPPING PageMap); STATIC XTCDECL EFI_STATUS FreePages(IN ULONGLONG NumberOfPages, IN EFI_PHYSICAL_ADDRESS Memory); STATIC XTCDECL EFI_STATUS FreePool(IN PVOID Memory); diff --git a/boot/xtldr/modules/xtos_o/amd64/memory.cc b/boot/xtldr/modules/xtos_o/amd64/memory.cc index 4ec271c..3755ff8 100644 --- a/boot/xtldr/modules/xtos_o/amd64/memory.cc +++ b/boot/xtldr/modules/xtos_o/amd64/memory.cc @@ -10,6 +10,34 @@ #include +XTCDECL +EFI_STATUS +Xtos::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap) +{ + EFI_STATUS Status; + + /* Build page map */ + Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, (PageMap->PageMapLevel > 4) ? MM_P5E_LA57_BASE : MM_PXE_BASE); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to build page map */ + XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); + return Status; + } + + /* Map memory for hardware layer */ + Status = MapHardwareMemoryPool(PageMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to map memory for hardware layer */ + XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware leyer (Status code: %zX)\n", Status); + return Status; + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + /** * Determines the appropriate EFI memory mapping strategy for the AMD64 architecture. * @@ -91,24 +119,6 @@ Xtos::EnablePaging(IN PXTBL_PAGE_MAPPING PageMap) ULONG_PTR TrampolineSize; PVOID TrampolineCode; - /* Build page map */ - Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, (PageMap->PageMapLevel > 4) ? MM_P5E_LA57_BASE : MM_PXE_BASE); - if(Status != STATUS_EFI_SUCCESS) - { - /* Failed to build page map */ - XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); - return Status; - } - - /* Map memory for hardware layer */ - Status = MapHardwareMemoryPool(PageMap); - if(Status != STATUS_EFI_SUCCESS) - { - /* Failed to map memory for hardware layer */ - XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware leyer (Status code: %zX)\n", Status); - return Status; - } - /* Check the configured page map level to set the LA57 state accordingly */ if(PageMap->PageMapLevel == 5) { @@ -188,6 +198,7 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) PHARDWARE_PTE P5eBase, PdeBase, PpeBase, PxeBase; EFI_PHYSICAL_ADDRESS Address; EFI_STATUS Status; + ULONG Index; if(PageMap->PageMapLevel == 5) { @@ -205,6 +216,9 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) return Status; } + /* Map hardware memory */ + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + /* Zero fill memory used by P5E */ XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE); @@ -239,6 +253,9 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) return Status; } + /* Map hardware memory */ + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + /* Zero fill memory used by PXE */ XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE); @@ -267,6 +284,9 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) return Status; } + /* Map hardware memory */ + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + /* Zero fill memory used by PPE */ XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE); @@ -285,7 +305,7 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) } /* Loop through 2 PDE entries */ - for(UINT Index = 0 ; Index < 2 ; Index++) + for(Index = 0 ; Index < 2 ; Index++) { /* Check if PDE entry already exists */ if(!PdeBase[((MM_HARDWARE_VA_START >> MM_PDI_SHIFT) & 0x1FF) + Index].Valid) @@ -298,6 +318,9 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) return Status; } + /* Map hardware memory */ + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + /* Zero fill memory used by PDE */ XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE); diff --git a/boot/xtldr/modules/xtos_o/i686/memory.cc b/boot/xtldr/modules/xtos_o/i686/memory.cc index e4fbdf3..b069bfd 100644 --- a/boot/xtldr/modules/xtos_o/i686/memory.cc +++ b/boot/xtldr/modules/xtos_o/i686/memory.cc @@ -9,6 +9,47 @@ #include +XTCDECL +EFI_STATUS +Xtos::BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap) +{ + ULONG_PTR SelfMapAddress; + EFI_STATUS Status; + + /* Initialize self map address */ + if(PageMap->PageMapLevel == 3) + { + /* For PML3 (PAE) use PTE base address */ + SelfMapAddress = MM_PTE_BASE; + } + else + { + /* For PML2 (PAE disabled) use legacy PDE base address */ + SelfMapAddress = MM_PDE_LEGACY_BASE; + } + + /* Build page map */ + Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, SelfMapAddress); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to build page map */ + XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); + return Status; + } + + /* Map memory for hardware layer */ + Status = MapHardwareMemoryPool(PageMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to map memory for hardware layer */ + XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware layer (Status code: %zX)\n", Status); + return Status; + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + /** * Determines the appropriate EFI memory mapping strategy for the i686 architecture. * @@ -74,37 +115,6 @@ EFI_STATUS Xtos::EnablePaging(IN PXTBL_PAGE_MAPPING PageMap) { EFI_STATUS Status; - ULONG_PTR SelfMapAddress; - - /* Initialize self map address */ - if(PageMap->PageMapLevel == 3) - { - /* For PML3 (PAE) use PTE base address */ - SelfMapAddress = MM_PTE_BASE; - } - else - { - /* For PML2 (PAE disabled) use legacy PDE base address */ - SelfMapAddress = MM_PDE_LEGACY_BASE; - } - - /* Build page map */ - Status = XtLdrProtocol->Memory.BuildPageMap(PageMap, SelfMapAddress); - if(Status != STATUS_EFI_SUCCESS) - { - /* Failed to build page map */ - XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); - return Status; - } - - /* Map memory for hardware layer */ - Status = MapHardwareMemoryPool(PageMap); - if(Status != STATUS_EFI_SUCCESS) - { - /* Failed to map memory for hardware layer */ - XtLdrProtocol->Debug.Print(L"Failed to map memory for hardware layer (Status code: %zX)\n", Status); - return Status; - } /* Exit EFI Boot Services */ XtLdrProtocol->Debug.Print(L"Exiting EFI boot services\n"); @@ -173,6 +183,9 @@ Xtos::MapHardwareMemoryPool(IN PXTBL_PAGE_MAPPING PageMap) /* Zero fill allocated memory */ XtLdrProtocol->Memory.ZeroMemory((PVOID)Address, EFI_PAGE_SIZE); + /* Map hardware memory */ + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)NULLPTR, Address, 1, LoaderMemoryData); + /* Check if PAE is enabled (3-level paging) */ if(PageMap->PageMapLevel == 3) { diff --git a/boot/xtldr/modules/xtos_o/includes/xtos.hh b/boot/xtldr/modules/xtos_o/includes/xtos.hh index 708ce14..3f21f5f 100644 --- a/boot/xtldr/modules/xtos_o/includes/xtos.hh +++ b/boot/xtldr/modules/xtos_o/includes/xtos.hh @@ -38,6 +38,7 @@ class Xtos IN PVOID PhysicalAddress, IN UINT NumberOfPages, IN LOADER_MEMORY_TYPE MemoryType); + STATIC XTCDECL EFI_STATUS BuildPageMap(IN PXTBL_PAGE_MAPPING PageMap); STATIC XTCDECL LOADER_MEMORY_TYPE ConvertEfiMemoryType(IN EFI_MEMORY_TYPE EfiMemoryType); STATIC XTCDECL BOOLEAN DetermineMappingStrategy(); STATIC XTCDECL ULONG DeterminePagingLevel(IN CONST PWCHAR Parameters); @@ -47,10 +48,13 @@ class Xtos IN PULONG_PTR FrameBufferSize, IN PXTBL_FRAMEBUFFER_MODE_INFORMATION FrameBufferModeInfo); STATIC XTCDECL EFI_STATUS GetMemoryDescriptorList(IN PXTBL_PAGE_MAPPING PageMap, - IN PVOID *VirtualAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalBase, + IN PVOID VirtualBase, OUT PLIST_ENTRY MemoryDescriptorList); STATIC XTCDECL EFI_STATUS GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, - IN PVOID *VirtualAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalBase, + IN PVOID VirtualBase, + IN PVOID FrameBufferVirtualBase, OUT PLIST_ENTRY SystemResourcesList); STATIC XTCDECL EFI_STATUS GetVirtualAddress(IN PLIST_ENTRY MemoryMappings, IN PVOID PhysicalAddress, diff --git a/boot/xtldr/modules/xtos_o/xtos.cc b/boot/xtldr/modules/xtos_o/xtos.cc index 5b2b8a0..cc24fba 100644 --- a/boot/xtldr/modules/xtos_o/xtos.cc +++ b/boot/xtldr/modules/xtos_o/xtos.cc @@ -191,38 +191,16 @@ Xtos::GetDisplayInformation(OUT PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource XTCDECL EFI_STATUS Xtos::GetMemoryDescriptorList(IN PXTBL_PAGE_MAPPING PageMap, - IN PVOID *VirtualAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalBase, + IN PVOID VirtualBase, OUT PLIST_ENTRY MemoryDescriptorList) { PLOADER_MEMORY_DESCRIPTOR Descriptor; PXTBL_MEMORY_MAPPING MemoryMapping; - EFI_PHYSICAL_ADDRESS Address; PLIST_ENTRY ListEntry; - EFI_STATUS Status; - ULONGLONG Pages; - - /* Calculate the number of pages required to store the memory descriptor array */ - Pages = (ULONGLONG)EFI_SIZE_TO_PAGES((PageMap->MapSize + 1) * sizeof(LOADER_MEMORY_DESCRIPTOR)); - - /* Allocate physical pages to hold the memory descriptor list */ - Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, Pages, &Address); - if(Status != STATUS_EFI_SUCCESS) - { - /* Page allocation failed, return the status code */ - return Status; - } - - /* Create a virtual memory mapping for the allocated descriptor buffer */ - Status = XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)*VirtualAddress, Address, Pages, LoaderMemoryData); - if(Status != STATUS_EFI_SUCCESS) - { - /* Release the allocated pages as the virtual mapping failed and return status code */ - XtLdrProtocol->Memory.FreePages(Address, Pages); - return Status; - } /* Initialize the descriptor pointer to the start of the allocated physical buffer */ - Descriptor = (PLOADER_MEMORY_DESCRIPTOR)Address; + Descriptor = (PLOADER_MEMORY_DESCRIPTOR)PhysicalBase; /* Get the first entry from the internal boot loader memory map */ ListEntry = PageMap->MemoryMap.Flink; @@ -247,17 +225,18 @@ Xtos::GetMemoryDescriptorList(IN PXTBL_PAGE_MAPPING PageMap, } /* Convert all physical link pointers in the list to their corresponding virtual addresses */ - XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, MemoryDescriptorList, (PVOID)Address, *VirtualAddress); + XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, MemoryDescriptorList, (PVOID)PhysicalBase, VirtualBase); - /* Advance the virtual address pointer to the next available free region and return success */ - *VirtualAddress = (PUINT8)*VirtualAddress + (Pages * EFI_PAGE_SIZE); + /* Return success */ return STATUS_EFI_SUCCESS; } XTCDECL EFI_STATUS Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, - IN PVOID *VirtualAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalBase, + IN PVOID VirtualBase, + IN PVOID FrameBufferVirtualBase, OUT PLIST_ENTRY SystemResourcesList) { XTSTATUS Status; @@ -268,39 +247,18 @@ Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, PXTBL_FRAMEBUFFER_PROTOCOL FrameBufProtocol; XTBL_FRAMEBUFFER_MODE_INFORMATION FbModeInfo; EFI_PHYSICAL_ADDRESS FbAddress; + EFI_PHYSICAL_ADDRESS OriginalPhysicalBase; ULONG_PTR FbSize; - UINT FrameBufferPages; PSYSTEM_RESOURCE_FRAMEBUFFER FrameBufferResource; PSYSTEM_RESOURCE_ACPI AcpiResource; - ULONGLONG Pages; - EFI_PHYSICAL_ADDRESS Address; - PVOID PhysicalBase, VirtualBase; - Pages = (ULONGLONG)EFI_SIZE_TO_PAGES(sizeof(SYSTEM_RESOURCE_ACPI) + sizeof(SYSTEM_RESOURCE_FRAMEBUFFER)); - - Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, Pages, &Address); - if(Status != STATUS_EFI_SUCCESS) - { - return Status; - } - Status = XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)*VirtualAddress, Address, Pages, LoaderFirmwarePermanent); - if(Status != STATUS_EFI_SUCCESS) - { - XtLdrProtocol->Memory.FreePages(Address, Pages); - return Status; - } - - PhysicalBase = (PVOID)Address; - VirtualBase = *VirtualAddress; - - /* Calculate next valid virtual address */ - *VirtualAddress = (PUINT8)*VirtualAddress + (Pages * EFI_PAGE_SIZE); - - AcpiResource = (PSYSTEM_RESOURCE_ACPI)Address; + /* Save original physical base */ + OriginalPhysicalBase = PhysicalBase; + AcpiResource = (PSYSTEM_RESOURCE_ACPI)PhysicalBase; XtLdrProtocol->Memory.ZeroMemory(AcpiResource, sizeof(SYSTEM_RESOURCE_ACPI)); - /* Load FrameBuffer protocol */ + /* Load ACPI protocol */ Status = XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&AcpiProtocol, &AcpiGuid); if(Status != STATUS_EFI_SUCCESS) { @@ -319,13 +277,11 @@ Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &AcpiResource->Header.ListEntry); - /* Close FrameBuffer protocol */ - XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); - - Address = Address + sizeof(SYSTEM_RESOURCE_ACPI); - - FrameBufferResource = (PSYSTEM_RESOURCE_FRAMEBUFFER)Address; + /* Close ACPI protocol */ + XtLdrProtocol->Protocol.Close(&ProtocolHandle, &AcpiGuid); + PhysicalBase = PhysicalBase + sizeof(SYSTEM_RESOURCE_ACPI); + FrameBufferResource = (PSYSTEM_RESOURCE_FRAMEBUFFER)PhysicalBase; XtLdrProtocol->Memory.ZeroMemory(FrameBufferResource, sizeof(SYSTEM_RESOURCE_FRAMEBUFFER)); /* Load FrameBuffer protocol */ @@ -346,26 +302,16 @@ Xtos::GetSystemResourcesList(IN PXTBL_PAGE_MAPPING PageMap, return Status; } - /* Calculate pages needed to map framebuffer */ - FrameBufferPages = EFI_SIZE_TO_PAGES(FbSize); - - /* Rewrite framebuffer address by using virtual address */ - FrameBufferResource->Header.VirtualAddress = *VirtualAddress; - - /* Map frame buffer memory */ - XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)FrameBufferResource->Header.VirtualAddress, - (ULONGLONG)FrameBufferResource->Header.PhysicalAddress, - FrameBufferPages, LoaderFirmwarePermanent); - - /* Close FrameBuffer protocol */ + /* Assign the pre-mapped virtual address to the resource block */ + FrameBufferResource->Header.VirtualAddress = FrameBufferVirtualBase; XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); - *VirtualAddress = (PUINT8)*VirtualAddress + (FrameBufferPages * EFI_PAGE_SIZE); - XtLdrProtocol->LinkedList.InsertTail(SystemResourcesList, &FrameBufferResource->Header.ListEntry); - XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, SystemResourcesList, PhysicalBase, VirtualBase); + /* Convert list pointers to virtual */ + XtLdrProtocol->Memory.PhysicalListToVirtual(PageMap, SystemResourcesList, (PVOID)OriginalPhysicalBase, VirtualBase); + /* Return success */ return STATUS_EFI_SUCCESS; } @@ -426,34 +372,97 @@ Xtos::InitializeApicBase(IN PXTBL_PAGE_MAPPING PageMap) XTCDECL EFI_STATUS Xtos::InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap, - IN PVOID *VirtualAddress, + IN OUT PVOID *VirtualAddress, IN PXTBL_BOOT_PARAMETERS Parameters) { + EFI_PHYSICAL_ADDRESS FbPhysicalAddress, PhysicalBlock, PhysicalDescriptor, PhysicalResources; + PVOID FbVirtualAddress, VirtualBlock, VirtualResources, VirtualDescriptor; + UINT BlockPages, DescriptorPages, FbPages, ParametersSize, ResourcesPages; + XTBL_FRAMEBUFFER_MODE_INFORMATION FbModeInfo; + PXTBL_FRAMEBUFFER_PROTOCOL FrameBufProtocol; PKERNEL_INITIALIZATION_BLOCK LoaderBlock; - EFI_PHYSICAL_ADDRESS Address; + EFI_HANDLE ProtocolHandle; EFI_STATUS Status; - UINT BlockPages; - UINT ParametersSize; + ULONG_PTR FbSize; + + EFI_GUID FrameBufGuid = XT_FRAMEBUFFER_PROTOCOL_GUID; + + /* Initialize Framebuffer information */ + FbPhysicalAddress = 0; + FbSize = 0; + FbVirtualAddress = NULLPTR; + FbPages = 0; /* Calculate size of parameters */ ParametersSize = (XtLdrProtocol->WideString.Length(Parameters->Parameters, 0) + 1) * sizeof(WCHAR); /* Calculate number of pages needed for initialization block */ BlockPages = EFI_SIZE_TO_PAGES(sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize); + ResourcesPages = EFI_SIZE_TO_PAGES(sizeof(SYSTEM_RESOURCE_ACPI) + sizeof(SYSTEM_RESOURCE_FRAMEBUFFER)); - /* Allocate memory for kernel initialization block */ - Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, BlockPages, &Address); + /* Query Framebuffer size for allocation */ + if(XtLdrProtocol->Protocol.Open(&ProtocolHandle, (PVOID*)&FrameBufProtocol, &FrameBufGuid) == STATUS_EFI_SUCCESS) + { + /* Get FrameBuffer information */ + FrameBufProtocol->GetDisplayInformation(&FbPhysicalAddress, &FbSize, &FbModeInfo); + XtLdrProtocol->Protocol.Close(&ProtocolHandle, &FrameBufGuid); + } + FbPages = EFI_SIZE_TO_PAGES(FbSize); + + /* Add padding to MapSize to account for the ledger mappings */ + DescriptorPages = EFI_SIZE_TO_PAGES((PageMap->MapSize + 16) * sizeof(LOADER_MEMORY_DESCRIPTOR)); + + /* Allocate memory for the kernel initialization block and boot parameters */ + Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, BlockPages, &PhysicalBlock); if(Status != STATUS_EFI_SUCCESS) { - /* Memory allocation failure */ + /* Memory allocation failure, return status code */ return Status; } - /* Initialize and zero-fill kernel initialization block */ - LoaderBlock = (PKERNEL_INITIALIZATION_BLOCK)(UINT_PTR)Address; - XtLdrProtocol->Memory.ZeroMemory(LoaderBlock, sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize); + /* Allocate memory for the system resources data structures */ + Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, ResourcesPages, &PhysicalResources); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure, return status code */ + return Status; + } + + /* Allocate memory for the memory descriptor list */ + Status = XtLdrProtocol->Memory.AllocatePages(AllocateAnyPages, DescriptorPages, &PhysicalDescriptor); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure, return status code */ + return Status; + } + + /* Map the Kernel Initialization Block into virtual memory and advance the virtual address pointer */ + VirtualBlock = *VirtualAddress; + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualBlock, PhysicalBlock, BlockPages, LoaderSystemBlock); + *VirtualAddress = (PUINT8)*VirtualAddress + (BlockPages * EFI_PAGE_SIZE); + + /* Map the system resources physical memory into virtual address space and update the allocation pointer */ + VirtualResources = *VirtualAddress; + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualResources, PhysicalResources, ResourcesPages, LoaderFirmwarePermanent); + *VirtualAddress = (PUINT8)*VirtualAddress + (ResourcesPages * EFI_PAGE_SIZE); + + /* Check if a framebuffer was detected and requires memory mapping */ + if(FbPages > 0) + { + /* Map the framebuffer physical memory range into virtual address space */ + FbVirtualAddress = *VirtualAddress; + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)FbVirtualAddress, FbPhysicalAddress, FbPages, LoaderFirmwarePermanent); + *VirtualAddress = (PUINT8)*VirtualAddress + (FbPages * EFI_PAGE_SIZE); + } + + /* Map the allocated physical memory for memory descriptors into the virtual address space */ + VirtualDescriptor = *VirtualAddress; + XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)VirtualDescriptor, PhysicalDescriptor, DescriptorPages, LoaderMemoryData); + *VirtualAddress = (PUINT8)*VirtualAddress + (DescriptorPages * EFI_PAGE_SIZE); /* Set basic loader block properties */ + XtLdrProtocol->Memory.ZeroMemory((PVOID)PhysicalBlock, sizeof(KERNEL_INITIALIZATION_BLOCK) + ParametersSize); + LoaderBlock = (PKERNEL_INITIALIZATION_BLOCK)PhysicalBlock; LoaderBlock->BlockSize = sizeof(KERNEL_INITIALIZATION_BLOCK); LoaderBlock->BlockVersion = INITIALIZATION_BLOCK_VERSION; LoaderBlock->ProtocolVersion = BOOT_PROTOCOL_VERSION; @@ -467,24 +476,30 @@ Xtos::InitializeLoaderBlock(IN PXTBL_PAGE_MAPPING PageMap, LoaderBlock->FirmwareInformation.EfiFirmware.EfiRuntimeServices = NULLPTR; /* Copy parameters to kernel initialization block */ - LoaderBlock->KernelParameters = (PWCHAR)((UINT_PTR)*VirtualAddress + sizeof(KERNEL_INITIALIZATION_BLOCK)); + LoaderBlock->KernelParameters = (PWCHAR)((UINT_PTR)VirtualBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)); XtLdrProtocol->Memory.CopyMemory((PVOID)((UINT_PTR)LoaderBlock + sizeof(KERNEL_INITIALIZATION_BLOCK)), - Parameters->Parameters, - ParametersSize); + Parameters->Parameters, ParametersSize); - /* Map kernel initialization block */ - XtLdrProtocol->Memory.MapVirtualMemory(PageMap, (ULONGLONG)*VirtualAddress, (ULONGLONG)LoaderBlock, - BlockPages, LoaderSystemBlock); - - /* Calculate next valid virtual address */ - *VirtualAddress = (PUINT8)*VirtualAddress + (BlockPages * EFI_PAGE_SIZE); + /* HACK: Commit page map to avoid memory leaks (AGAIN!) */ + XtLdrProtocol->Memory.CommitPageMap(PageMap); + /* Initialize system resources list */ XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->SystemResourcesListHead); - GetSystemResourcesList(PageMap, VirtualAddress, &LoaderBlock->SystemResourcesListHead); + Status = GetSystemResourcesList(PageMap, PhysicalResources, VirtualResources, FbVirtualAddress, &LoaderBlock->SystemResourcesListHead); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to initialize system resources list, return status code */ + return Status; + } /* Initialize memory descriptor list */ XtLdrProtocol->LinkedList.InitializeHead(&LoaderBlock->MemoryDescriptorListHead); - GetMemoryDescriptorList(PageMap, VirtualAddress, &LoaderBlock->MemoryDescriptorListHead); + Status = GetMemoryDescriptorList(PageMap, PhysicalDescriptor, VirtualDescriptor, &LoaderBlock->MemoryDescriptorListHead); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to initialize memory descriptor list, return status code */ + return Status; + } /* Set boot image size */ LoaderBlock->BootImageSize = (PFN_NUMBER)(((ULONGLONG)*VirtualAddress - KSEG0_BASE) / EFI_PAGE_SIZE); @@ -702,6 +717,22 @@ Xtos::RunBootSequence(IN PEFI_FILE_HANDLE BootDir, return Status; } + /* Build page map */ + Status = BuildPageMap(&PageMap); + if(Status != STATUS_EFI_SUCCESS) + { + XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); + return Status; + } + + /* Commit mappings */ + Status = XtLdrProtocol->Memory.CommitPageMap(&PageMap); + if(Status != STATUS_EFI_SUCCESS) + { + XtLdrProtocol->Debug.Print(L"Failed to commit hardware mappings (Pass 1)\n"); + return Status; + } + /* Store virtual address of kernel initialization block for future kernel call */ KernelParameters = (PKERNEL_INITIALIZATION_BLOCK)VirtualAddress; @@ -714,6 +745,15 @@ Xtos::RunBootSequence(IN PEFI_FILE_HANDLE BootDir, return Status; } + /* HACK: Commit mappings again to include the kernel initialization block */ + Status = XtLdrProtocol->Memory.CommitPageMap(&PageMap); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to build page map */ + XtLdrProtocol->Debug.Print(L"Failed to build page map (Status code: %zX)\n", Status); + return Status; + } + /* Get kernel entry point */ PeCoffProtocol->GetEntryPoint(ImageContext, (PVOID*)&KernelEntryPoint); diff --git a/boot/xtldr/protocol.cc b/boot/xtldr/protocol.cc index 6593e4a..2926a5d 100644 --- a/boot/xtldr/protocol.cc +++ b/boot/xtldr/protocol.cc @@ -1054,6 +1054,7 @@ Protocol::InstallXtLoaderProtocol() LoaderProtocol.Memory.AllocatePages = Memory::AllocatePages; LoaderProtocol.Memory.AllocatePool = Memory::AllocatePool; LoaderProtocol.Memory.BuildPageMap = Memory::BuildPageMap; + LoaderProtocol.Memory.CommitPageMap = Memory::CommitPageMap; LoaderProtocol.Memory.CompareMemory = RTL::Memory::CompareMemory; LoaderProtocol.Memory.CopyMemory = RTL::Memory::CopyMemory; LoaderProtocol.Memory.FreePages = Memory::FreePages;