/** * 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 */ #include /** * 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; PXTBL_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, XTBL_MEMORY_MAPPING, ListEntry); /* Check if virtual address is set */ if(Mapping->VirtualAddress) { /* Dump memory mapping */ BlDebugPrint(L" Type=%02lu, PhysicalBase=%.16P, VirtualBase=%.16P, 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; } /* 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].Writable = 1; /* Take next virtual address and PFN */ VirtualAddress += EFI_PAGE_SIZE; PageFrameNumber++; /* Decrease number of pages left */ NumberOfPages--; } /* Return success */ return STATUS_EFI_SUCCESS; }