exectos/xtldr/arch/amd64/memory.c
Rafal Kupiec 7128159c42
Some checks failed
Builds / ExectOS (amd64) (push) Failing after 15s
Builds / ExectOS (i686) (push) Failing after 14s
Implement BlBuildPageMap() routine
2024-01-22 15:15:21 +01:00

233 lines
6.9 KiB
C

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: xtldr/arch/amd64/memory.c
* DESCRIPTION: XT Boot Loader AMD64 specific memory management
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include <xtldr.h>
/**
* Maps boot loader related code and builds page map.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlBuildPageMap(IN PXTBL_PAGE_MAPPING PageMap)
{
PLIST_ENTRY ListEntry, ModulesList, ModulesListEntry;
PLOADER_MEMORY_MAPPING Mapping;
PXTBL_MODULE_INFO ModuleInfo;
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
/* Allocate pages for the Page Map */
Status = BlAllocateMemoryPages(1, &Address);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory allocation failure */
return Status;
}
/* Assign and zero-fill memory used by page mappings */
PageMap->PtePointer = (PVOID)(UINT_PTR)Address;
RtlZeroMemory(PageMap->PtePointer, EFI_PAGE_SIZE);
/* Add page mapping itself to memory mapping */
Status = BlMapVirtualMemory(PageMap, NULL, PageMap->PtePointer, 1, LoaderMemoryData);
if(Status != STATUS_EFI_SUCCESS)
{
/* PML mapping failed */
return Status;
}
/* Get list of XTLDR modules */
ModulesList = BlGetModulesList();
ModulesListEntry = ModulesList->Flink;
while(ModulesListEntry != ModulesList)
{
/* Get module info */
ModuleInfo = CONTAIN_RECORD(ModulesListEntry, XTBL_MODULE_INFO, Flink);
/* Map module code */
Status = BlMapVirtualMemory(PageMap, ModuleInfo->ModuleBase, ModuleInfo->ModuleBase,
EFI_SIZE_TO_PAGES(ModuleInfo->ModuleSize), LoaderFirmwareTemporary);
/* Check if mapping succeeded */
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping module code failed */
return Status;
}
/* Get next module */
ModulesListEntry = ModulesListEntry->Flink;
}
/* Make sure boot loader image base and size are set */
if(BlpStatus.LoaderBase && BlpStatus.LoaderSize)
{
/* Map boot loader code as well */
Status = BlMapVirtualMemory(PageMap, BlpStatus.LoaderBase, BlpStatus.LoaderBase,
EFI_SIZE_TO_PAGES(BlpStatus.LoaderSize), LoaderFirmwareTemporary);
if(Status != STATUS_EFI_SUCCESS)
{
/* Mapping boot loader code failed */
return Status;
}
}
else
{
/* Boot loader image information re not available */
return STATUS_EFI_PROTOCOL_ERROR;
}
/* Iterate through and map all the mappings*/
BlDebugPrint(L"Mapping and dumping EFI memory:\n");
ListEntry = PageMap->MemoryMap.Flink;
while(ListEntry != &PageMap->MemoryMap)
{
/* Take mapping from the list */
Mapping = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_MAPPING, ListEntry);
/* Check if virtual address is set */
if(Mapping->VirtualAddress)
{
/* Dump memory mapping */
BlDebugPrint(L" Type=%02lu, PhysicalBase=0x%016lx, VirtualBase=0x%016lx, Pages=%lu\n", Mapping->MemoryType,
Mapping->PhysicalAddress, Mapping->VirtualAddress, Mapping->NumberOfPages);
/* Map memory */
Status = BlMapPage(PageMap, (UINT_PTR)Mapping->VirtualAddress,
(UINT_PTR)Mapping->PhysicalAddress, Mapping->NumberOfPages);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failed */
return Status;
}
}
/* Take next element */
ListEntry = ListEntry->Flink;
}
/* Finally, map zero page */
BlMapPage(PageMap, 0, 0, 1);
/* Return success */
return STATUS_EFI_SUCCESS;
}
/**
* Does the actual virtual memory mapping.
*
* @param PageMap
* Supplies a pointer to the page mapping structure.
*
* @param VirtualAddress
* Supplies a virtual address of the mapping.
*
* @param PhysicalAddress
* Supplies a physical address of the mapping.
*
* @param NumberOfPages
* Supplies a number of the pages of the mapping.
*
* @return This routine returns a status code.
*
* @since XT 1.0
*/
XTCDECL
EFI_STATUS
BlMapPage(IN PXTBL_PAGE_MAPPING PageMap,
IN UINT_PTR VirtualAddress,
IN UINT_PTR PhysicalAddress,
IN UINT NumberOfPages)
{
SIZE_T Pml1Entry, Pml2Entry, Pml3Entry, Pml4Entry, Pml5Entry;
PHARDWARE_PTE Pml1, Pml2, Pml3, Pml4, Pml5;
SIZE_T PageFrameNumber;
EFI_STATUS Status;
/* Set the Page Frame Number (PFN) */
PageFrameNumber = PhysicalAddress >> EFI_PAGE_SHIFT;
/* Do the recursive mapping */
while(NumberOfPages > 0)
{
/* Calculate the indices in the various Page Tables from the virtual address */
Pml5Entry = (VirtualAddress & ((ULONGLONG)0x1FF << 48)) >> 48;
Pml4Entry = (VirtualAddress & ((ULONGLONG)0x1FF << 39)) >> 39;
Pml3Entry = (VirtualAddress & ((ULONGLONG)0x1FF << 30)) >> 30;
Pml2Entry = (VirtualAddress & ((ULONGLONG)0x1FF << 21)) >> 21;
Pml1Entry = (VirtualAddress & ((ULONGLONG)0x1FF << 12)) >> 12;
/* Check page map level */
if(PageMap->PageMapLevel == 5)
{
/* Five level Page Map */
Pml5 = ((PHARDWARE_PTE)(PageMap->PtePointer));
/* Get PML4 */
Status = BlpGetNextPageTable(PageMap, Pml5, Pml5Entry, &Pml4);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
}
else
{
/* Four level Page Map */
Pml4 = ((PHARDWARE_PTE)(PageMap->PtePointer));
}
/* Get PML3 */
Status = BlpGetNextPageTable(PageMap, Pml4, Pml4Entry, &Pml3);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Get PML 2 */
Status = BlpGetNextPageTable(PageMap, Pml3, Pml3Entry, &Pml2);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Get PML1 */
Status = BlpGetNextPageTable(PageMap, Pml2, Pml2Entry, &Pml1);
if(Status != STATUS_EFI_SUCCESS)
{
/* Memory mapping failure */
return Status;
}
/* Set paging entry settings */
Pml1[Pml1Entry].PageFrameNumber = PageFrameNumber;
Pml1[Pml1Entry].Valid = 1;
Pml1[Pml1Entry].Write = 1;
/* Take next virtual address and PFN */
VirtualAddress += EFI_PAGE_SIZE;
PageFrameNumber++;
/* Decrease number of pages left */
NumberOfPages--;
}
/* Return success */
return STATUS_EFI_SUCCESS;
}