12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439 |
- /** @file
- Page table management support.
- Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Base.h>
- #include <Uefi.h>
- #include <Library/PeCoffGetEntryPointLib.h>
- #include <Library/SerialPortLib.h>
- #include <Library/SynchronizationLib.h>
- #include <Library/PrintLib.h>
- #include <Protocol/SmmBase2.h>
- #include <Register/Intel/Cpuid.h>
- #include <Register/Intel/Msr.h>
- #include "CpuDxe.h"
- #include "CpuPageTable.h"
- ///
- /// Page Table Entry
- ///
- #define IA32_PG_P BIT0
- #define IA32_PG_RW BIT1
- #define IA32_PG_U BIT2
- #define IA32_PG_WT BIT3
- #define IA32_PG_CD BIT4
- #define IA32_PG_A BIT5
- #define IA32_PG_D BIT6
- #define IA32_PG_PS BIT7
- #define IA32_PG_PAT_2M BIT12
- #define IA32_PG_PAT_4K IA32_PG_PS
- #define IA32_PG_PMNT BIT62
- #define IA32_PG_NX BIT63
- #define PAGE_ATTRIBUTE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_U | IA32_PG_RW | IA32_PG_P)
- #define PAGE_ATTRIBUTE_BITS_POST_SPLIT (IA32_PG_RW | IA32_PG_P)
- //
- // Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE
- // X64 PAE PDPTE does not have such restriction
- //
- #define IA32_PAE_PDPTE_ATTRIBUTE_BITS (IA32_PG_P)
- #define PAGE_PROGATE_BITS (IA32_PG_NX | PAGE_ATTRIBUTE_BITS)
- #define PAGING_4K_MASK 0xFFF
- #define PAGING_2M_MASK 0x1FFFFF
- #define PAGING_1G_MASK 0x3FFFFFFF
- #define PAGING_PAE_INDEX_MASK 0x1FF
- #define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
- #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
- #define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
- #define MAX_PF_ENTRY_COUNT 10
- #define MAX_DEBUG_MESSAGE_LENGTH 0x100
- #define IA32_PF_EC_ID BIT4
- typedef enum {
- PageNone,
- Page4K,
- Page2M,
- Page1G,
- } PAGE_ATTRIBUTE;
- typedef struct {
- PAGE_ATTRIBUTE Attribute;
- UINT64 Length;
- UINT64 AddressMask;
- } PAGE_ATTRIBUTE_TABLE;
- typedef enum {
- PageActionAssign,
- PageActionSet,
- PageActionClear,
- } PAGE_ACTION;
- PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
- { Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64 },
- { Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64 },
- { Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64 },
- };
- PAGE_TABLE_POOL *mPageTablePool = NULL;
- BOOLEAN mPageTablePoolLock = FALSE;
- PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
- EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
- //
- // Record the page fault exception count for one instruction execution.
- //
- UINTN *mPFEntryCount;
- UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
- /**
- Check if current execution environment is in SMM mode or not, via
- EFI_SMM_BASE2_PROTOCOL.
- This is necessary because of the fact that MdePkg\Library\SmmMemoryAllocationLib
- supports to free memory outside SMRAM. The library will call gBS->FreePool() or
- gBS->FreePages() and then SetMemorySpaceAttributes interface in turn to change
- memory paging attributes during free operation, if some memory related features
- are enabled (like Heap Guard).
- This means that SetMemorySpaceAttributes() has chance to run in SMM mode. This
- will cause incorrect result because SMM mode always loads its own page tables,
- which are usually different from DXE. This function can be used to detect such
- situation and help to avoid further misoperations.
- @retval TRUE In SMM mode.
- @retval FALSE Not in SMM mode.
- **/
- BOOLEAN
- IsInSmm (
- VOID
- )
- {
- BOOLEAN InSmm;
- InSmm = FALSE;
- if (mSmmBase2 == NULL) {
- gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&mSmmBase2);
- }
- if (mSmmBase2 != NULL) {
- mSmmBase2->InSmm (mSmmBase2, &InSmm);
- }
- //
- // mSmmBase2->InSmm() can only detect if the caller is running in SMRAM
- // or from SMM driver. It cannot tell if the caller is running in SMM mode.
- // Check page table base address to guarantee that because SMM mode willl
- // load its own page table.
- //
- return (InSmm &&
- mPagingContext.ContextData.X64.PageTableBase != (UINT64)AsmReadCr3 ());
- }
- /**
- Return current paging context.
- @param[in,out] PagingContext The paging context.
- **/
- VOID
- GetCurrentPagingContext (
- IN OUT PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext
- )
- {
- UINT32 RegEax;
- CPUID_EXTENDED_CPU_SIG_EDX RegEdx;
- MSR_IA32_EFER_REGISTER MsrEfer;
- IA32_CR4 Cr4;
- IA32_CR0 Cr0;
- UINT32 *Attributes;
- UINTN *PageTableBase;
- //
- // Don't retrieve current paging context from processor if in SMM mode.
- //
- if (!IsInSmm ()) {
- ZeroMem (&mPagingContext, sizeof (mPagingContext));
- if (sizeof (UINTN) == sizeof (UINT64)) {
- mPagingContext.MachineType = IMAGE_FILE_MACHINE_X64;
- } else {
- mPagingContext.MachineType = IMAGE_FILE_MACHINE_I386;
- }
- GetPagingDetails (&mPagingContext.ContextData, &PageTableBase, &Attributes);
- Cr0.UintN = AsmReadCr0 ();
- Cr4.UintN = AsmReadCr4 ();
- if (Cr0.Bits.PG != 0) {
- *PageTableBase = (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
- } else {
- *PageTableBase = 0;
- }
- if (Cr0.Bits.WP != 0) {
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE;
- }
- if (Cr4.Bits.PSE != 0) {
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE;
- }
- if (Cr4.Bits.PAE != 0) {
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE;
- }
- if (Cr4.Bits.LA57 != 0) {
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_5_LEVEL;
- }
- AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
- if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
- AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx.Uint32);
- if (RegEdx.Bits.NX != 0) {
- // XD supported
- MsrEfer.Uint64 = AsmReadMsr64 (MSR_CORE_IA32_EFER);
- if (MsrEfer.Bits.NXE != 0) {
- // XD activated
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED;
- }
- }
- if (RegEdx.Bits.Page1GB != 0) {
- *Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUPPORT;
- }
- }
- }
- //
- // This can avoid getting SMM paging context if in SMM mode. We cannot assume
- // SMM mode shares the same paging context as DXE.
- //
- CopyMem (PagingContext, &mPagingContext, sizeof (mPagingContext));
- }
- /**
- Return length according to page attributes.
- @param[in] PageAttributes The page attribute of the page entry.
- @return The length of page entry.
- **/
- UINTN
- PageAttributeToLength (
- IN PAGE_ATTRIBUTE PageAttribute
- )
- {
- UINTN Index;
- for (Index = 0; Index < sizeof (mPageAttributeTable)/sizeof (mPageAttributeTable[0]); Index++) {
- if (PageAttribute == mPageAttributeTable[Index].Attribute) {
- return (UINTN)mPageAttributeTable[Index].Length;
- }
- }
- return 0;
- }
- /**
- Return address mask according to page attributes.
- @param[in] PageAttributes The page attribute of the page entry.
- @return The address mask of page entry.
- **/
- UINTN
- PageAttributeToMask (
- IN PAGE_ATTRIBUTE PageAttribute
- )
- {
- UINTN Index;
- for (Index = 0; Index < sizeof (mPageAttributeTable)/sizeof (mPageAttributeTable[0]); Index++) {
- if (PageAttribute == mPageAttributeTable[Index].Attribute) {
- return (UINTN)mPageAttributeTable[Index].AddressMask;
- }
- }
- return 0;
- }
- /**
- Return page table entry to match the address.
- @param[in] PagingContext The paging context.
- @param[in] Address The address to be checked.
- @param[out] PageAttributes The page attribute of the page entry.
- @return The page entry.
- **/
- VOID *
- GetPageTableEntry (
- IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext,
- IN PHYSICAL_ADDRESS Address,
- OUT PAGE_ATTRIBUTE *PageAttribute
- )
- {
- UINTN Index1;
- UINTN Index2;
- UINTN Index3;
- UINTN Index4;
- UINTN Index5;
- UINT64 *L1PageTable;
- UINT64 *L2PageTable;
- UINT64 *L3PageTable;
- UINT64 *L4PageTable;
- UINT64 *L5PageTable;
- UINT64 AddressEncMask;
- ASSERT (PagingContext != NULL);
- Index5 = ((UINTN)RShiftU64 (Address, 48)) & PAGING_PAE_INDEX_MASK;
- Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
- Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
- Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
- Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
- // Make sure AddressEncMask is contained to smallest supported address field.
- //
- AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
- if (AddressEncMask == 0) {
- AddressEncMask = PcdGet64 (PcdTdxSharedBitMask) & PAGING_1G_ADDRESS_MASK_64;
- }
- if (PagingContext->MachineType == IMAGE_FILE_MACHINE_X64) {
- if ((PagingContext->ContextData.X64.Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_5_LEVEL) != 0) {
- L5PageTable = (UINT64 *)(UINTN)PagingContext->ContextData.X64.PageTableBase;
- if (L5PageTable[Index5] == 0) {
- *PageAttribute = PageNone;
- return NULL;
- }
- L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- } else {
- L4PageTable = (UINT64 *)(UINTN)PagingContext->ContextData.X64.PageTableBase;
- }
- if (L4PageTable[Index4] == 0) {
- *PageAttribute = PageNone;
- return NULL;
- }
- L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- } else {
- ASSERT ((PagingContext->ContextData.Ia32.Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) != 0);
- L3PageTable = (UINT64 *)(UINTN)PagingContext->ContextData.Ia32.PageTableBase;
- }
- if (L3PageTable[Index3] == 0) {
- *PageAttribute = PageNone;
- return NULL;
- }
- if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
- // 1G
- *PageAttribute = Page1G;
- return &L3PageTable[Index3];
- }
- L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if (L2PageTable[Index2] == 0) {
- *PageAttribute = PageNone;
- return NULL;
- }
- if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
- // 2M
- *PageAttribute = Page2M;
- return &L2PageTable[Index2];
- }
- // 4k
- L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
- if ((L1PageTable[Index1] == 0) && (Address != 0)) {
- *PageAttribute = PageNone;
- return NULL;
- }
- *PageAttribute = Page4K;
- return &L1PageTable[Index1];
- }
- /**
- Return memory attributes of page entry.
- @param[in] PageEntry The page entry.
- @return Memory attributes of page entry.
- **/
- UINT64
- GetAttributesFromPageEntry (
- IN UINT64 *PageEntry
- )
- {
- UINT64 Attributes;
- Attributes = 0;
- if ((*PageEntry & IA32_PG_P) == 0) {
- Attributes |= EFI_MEMORY_RP;
- }
- if ((*PageEntry & IA32_PG_RW) == 0) {
- Attributes |= EFI_MEMORY_RO;
- }
- if ((*PageEntry & IA32_PG_NX) != 0) {
- Attributes |= EFI_MEMORY_XP;
- }
- return Attributes;
- }
- /**
- Modify memory attributes of page entry.
- @param[in] PagingContext The paging context.
- @param[in] PageEntry The page entry.
- @param[in] Attributes The bit mask of attributes to modify for the memory region.
- @param[in] PageAction The page action.
- @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
- **/
- VOID
- ConvertPageEntryAttribute (
- IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext,
- IN UINT64 *PageEntry,
- IN UINT64 Attributes,
- IN PAGE_ACTION PageAction,
- OUT BOOLEAN *IsModified
- )
- {
- UINT64 CurrentPageEntry;
- UINT64 NewPageEntry;
- UINT32 *PageAttributes;
- CurrentPageEntry = *PageEntry;
- NewPageEntry = CurrentPageEntry;
- if ((Attributes & EFI_MEMORY_RP) != 0) {
- switch (PageAction) {
- case PageActionAssign:
- case PageActionSet:
- NewPageEntry &= ~(UINT64)IA32_PG_P;
- break;
- case PageActionClear:
- NewPageEntry |= IA32_PG_P;
- break;
- }
- } else {
- switch (PageAction) {
- case PageActionAssign:
- NewPageEntry |= IA32_PG_P;
- break;
- case PageActionSet:
- case PageActionClear:
- break;
- }
- }
- if ((Attributes & EFI_MEMORY_RO) != 0) {
- switch (PageAction) {
- case PageActionAssign:
- case PageActionSet:
- NewPageEntry &= ~(UINT64)IA32_PG_RW;
- break;
- case PageActionClear:
- NewPageEntry |= IA32_PG_RW;
- break;
- }
- } else {
- switch (PageAction) {
- case PageActionAssign:
- NewPageEntry |= IA32_PG_RW;
- break;
- case PageActionSet:
- case PageActionClear:
- break;
- }
- }
- GetPagingDetails (&PagingContext->ContextData, NULL, &PageAttributes);
- if ((*PageAttributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED) != 0) {
- if ((Attributes & EFI_MEMORY_XP) != 0) {
- switch (PageAction) {
- case PageActionAssign:
- case PageActionSet:
- NewPageEntry |= IA32_PG_NX;
- break;
- case PageActionClear:
- NewPageEntry &= ~IA32_PG_NX;
- break;
- }
- } else {
- switch (PageAction) {
- case PageActionAssign:
- NewPageEntry &= ~IA32_PG_NX;
- break;
- case PageActionSet:
- case PageActionClear:
- break;
- }
- }
- }
- *PageEntry = NewPageEntry;
- if (CurrentPageEntry != NewPageEntry) {
- *IsModified = TRUE;
- DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));
- DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
- } else {
- *IsModified = FALSE;
- }
- }
- /**
- This function returns if there is need to split page entry.
- @param[in] BaseAddress The base address to be checked.
- @param[in] Length The length to be checked.
- @param[in] PageEntry The page entry to be checked.
- @param[in] PageAttribute The page attribute of the page entry.
- @retval SplitAttributes on if there is need to split page entry.
- **/
- PAGE_ATTRIBUTE
- NeedSplitPage (
- IN PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 *PageEntry,
- IN PAGE_ATTRIBUTE PageAttribute
- )
- {
- UINT64 PageEntryLength;
- PageEntryLength = PageAttributeToLength (PageAttribute);
- if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
- return PageNone;
- }
- if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
- return Page4K;
- }
- return Page2M;
- }
- /**
- This function splits one page entry to small page entries.
- @param[in] PageEntry The page entry to be splitted.
- @param[in] PageAttribute The page attribute of the page entry.
- @param[in] SplitAttribute How to split the page entry.
- @param[in] AllocatePagesFunc If page split is needed, this function is used to allocate more pages.
- @retval RETURN_SUCCESS The page entry is splitted.
- @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
- @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
- **/
- RETURN_STATUS
- SplitPage (
- IN UINT64 *PageEntry,
- IN PAGE_ATTRIBUTE PageAttribute,
- IN PAGE_ATTRIBUTE SplitAttribute,
- IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc
- )
- {
- UINT64 BaseAddress;
- UINT64 *NewPageEntry;
- UINTN Index;
- UINT64 AddressEncMask;
- ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
- ASSERT (AllocatePagesFunc != NULL);
- // Make sure AddressEncMask is contained to smallest supported address field.
- //
- AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
- if (PageAttribute == Page2M) {
- //
- // Split 2M to 4K
- //
- ASSERT (SplitAttribute == Page4K);
- if (SplitAttribute == Page4K) {
- NewPageEntry = AllocatePagesFunc (1);
- DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
- if (NewPageEntry == NULL) {
- return RETURN_OUT_OF_RESOURCES;
- }
- BaseAddress = *PageEntry & ~AddressEncMask & PAGING_2M_ADDRESS_MASK_64;
- for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {
- NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | AddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS);
- }
- (*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask | PAGE_ATTRIBUTE_BITS_POST_SPLIT;
- return RETURN_SUCCESS;
- } else {
- return RETURN_UNSUPPORTED;
- }
- } else if (PageAttribute == Page1G) {
- //
- // Split 1G to 2M
- // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
- //
- ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
- if (((SplitAttribute == Page2M) || (SplitAttribute == Page4K))) {
- NewPageEntry = AllocatePagesFunc (1);
- DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
- if (NewPageEntry == NULL) {
- return RETURN_OUT_OF_RESOURCES;
- }
- BaseAddress = *PageEntry & ~AddressEncMask & PAGING_1G_ADDRESS_MASK_64;
- for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {
- NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | AddressEncMask | IA32_PG_PS | ((*PageEntry) & PAGE_PROGATE_BITS);
- }
- (*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask | PAGE_ATTRIBUTE_BITS_POST_SPLIT;
- return RETURN_SUCCESS;
- } else {
- return RETURN_UNSUPPORTED;
- }
- } else {
- return RETURN_UNSUPPORTED;
- }
- }
- /**
- Check the WP status in CR0 register. This bit is used to lock or unlock write
- access to pages marked as read-only.
- @retval TRUE Write protection is enabled.
- @retval FALSE Write protection is disabled.
- **/
- BOOLEAN
- IsReadOnlyPageWriteProtected (
- VOID
- )
- {
- IA32_CR0 Cr0;
- //
- // To avoid unforseen consequences, don't touch paging settings in SMM mode
- // in this driver.
- //
- if (!IsInSmm ()) {
- Cr0.UintN = AsmReadCr0 ();
- return (BOOLEAN)(Cr0.Bits.WP != 0);
- }
- return FALSE;
- }
- /**
- Disable Write Protect on pages marked as read-only.
- **/
- VOID
- DisableReadOnlyPageWriteProtect (
- VOID
- )
- {
- IA32_CR0 Cr0;
- //
- // To avoid unforseen consequences, don't touch paging settings in SMM mode
- // in this driver.
- //
- if (!IsInSmm ()) {
- Cr0.UintN = AsmReadCr0 ();
- Cr0.Bits.WP = 0;
- AsmWriteCr0 (Cr0.UintN);
- }
- }
- /**
- Enable Write Protect on pages marked as read-only.
- **/
- VOID
- EnableReadOnlyPageWriteProtect (
- VOID
- )
- {
- IA32_CR0 Cr0;
- //
- // To avoid unforseen consequences, don't touch paging settings in SMM mode
- // in this driver.
- //
- if (!IsInSmm ()) {
- Cr0.UintN = AsmReadCr0 ();
- Cr0.Bits.WP = 1;
- AsmWriteCr0 (Cr0.UintN);
- }
- }
- /**
- This function modifies the page attributes for the memory region specified by BaseAddress and
- Length from their current attributes to the attributes specified by Attributes.
- Caller should make sure BaseAddress and Length is at page boundary.
- @param[in] PagingContext The paging context. NULL means get page table from current CPU context.
- @param[in] BaseAddress The physical address that is the start address of a memory region.
- @param[in] Length The size in bytes of the memory region.
- @param[in] Attributes The bit mask of attributes to modify for the memory region.
- @param[in] PageAction The page action.
- @param[in] AllocatePagesFunc If page split is needed, this function is used to allocate more pages.
- NULL mean page split is unsupported.
- @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
- @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
- @retval RETURN_SUCCESS The attributes were modified for the memory region.
- @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval RETURN_INVALID_PARAMETER Length is zero.
- Attributes specified an illegal combination of attributes that
- cannot be set together.
- @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
- the memory resource range.
- @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
- resource range specified by BaseAddress and Length.
- The bit mask of attributes is not support for the memory resource
- range specified by BaseAddress and Length.
- **/
- RETURN_STATUS
- ConvertMemoryPageAttributes (
- IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL,
- IN PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes,
- IN PAGE_ACTION PageAction,
- IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL,
- OUT BOOLEAN *IsSplitted OPTIONAL,
- OUT BOOLEAN *IsModified OPTIONAL
- )
- {
- PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext;
- UINT64 *PageEntry;
- PAGE_ATTRIBUTE PageAttribute;
- UINTN PageEntryLength;
- PAGE_ATTRIBUTE SplitAttribute;
- RETURN_STATUS Status;
- BOOLEAN IsEntryModified;
- BOOLEAN IsWpEnabled;
- if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
- DEBUG ((DEBUG_ERROR, "BaseAddress(0x%lx) is not aligned!\n", BaseAddress));
- return EFI_UNSUPPORTED;
- }
- if ((Length & (SIZE_4KB - 1)) != 0) {
- DEBUG ((DEBUG_ERROR, "Length(0x%lx) is not aligned!\n", Length));
- return EFI_UNSUPPORTED;
- }
- if (Length == 0) {
- DEBUG ((DEBUG_ERROR, "Length is 0!\n"));
- return RETURN_INVALID_PARAMETER;
- }
- if ((Attributes & ~EFI_MEMORY_ATTRIBUTE_MASK) != 0) {
- DEBUG ((DEBUG_ERROR, "Attributes(0x%lx) has unsupported bit\n", Attributes));
- return EFI_UNSUPPORTED;
- }
- if (PagingContext == NULL) {
- GetCurrentPagingContext (&CurrentPagingContext);
- } else {
- CopyMem (&CurrentPagingContext, PagingContext, sizeof (CurrentPagingContext));
- }
- switch (CurrentPagingContext.MachineType) {
- case IMAGE_FILE_MACHINE_I386:
- if (CurrentPagingContext.ContextData.Ia32.PageTableBase == 0) {
- if (Attributes == 0) {
- return EFI_SUCCESS;
- } else {
- DEBUG ((DEBUG_ERROR, "PageTable is 0!\n"));
- return EFI_UNSUPPORTED;
- }
- }
- if ((CurrentPagingContext.ContextData.Ia32.Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) == 0) {
- DEBUG ((DEBUG_ERROR, "Non-PAE Paging!\n"));
- return EFI_UNSUPPORTED;
- }
- if ((BaseAddress + Length) > BASE_4GB) {
- DEBUG ((DEBUG_ERROR, "Beyond 4GB memory in 32-bit mode!\n"));
- return EFI_UNSUPPORTED;
- }
- break;
- case IMAGE_FILE_MACHINE_X64:
- ASSERT (CurrentPagingContext.ContextData.X64.PageTableBase != 0);
- break;
- default:
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
- break;
- }
- // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
- if (IsSplitted != NULL) {
- *IsSplitted = FALSE;
- }
- if (IsModified != NULL) {
- *IsModified = FALSE;
- }
- if (AllocatePagesFunc == NULL) {
- AllocatePagesFunc = AllocatePageTableMemory;
- }
- //
- // Make sure that the page table is changeable.
- //
- IsWpEnabled = IsReadOnlyPageWriteProtected ();
- if (IsWpEnabled) {
- DisableReadOnlyPageWriteProtect ();
- }
- //
- // Below logic is to check 2M/4K page to make sure we do not waste memory.
- //
- Status = EFI_SUCCESS;
- while (Length != 0) {
- PageEntry = GetPageTableEntry (&CurrentPagingContext, BaseAddress, &PageAttribute);
- if (PageEntry == NULL) {
- Status = RETURN_UNSUPPORTED;
- goto Done;
- }
- PageEntryLength = PageAttributeToLength (PageAttribute);
- SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);
- if (SplitAttribute == PageNone) {
- ConvertPageEntryAttribute (&CurrentPagingContext, PageEntry, Attributes, PageAction, &IsEntryModified);
- if (IsEntryModified) {
- if (IsModified != NULL) {
- *IsModified = TRUE;
- }
- }
- //
- // Convert success, move to next
- //
- BaseAddress += PageEntryLength;
- Length -= PageEntryLength;
- } else {
- if (AllocatePagesFunc == NULL) {
- Status = RETURN_UNSUPPORTED;
- goto Done;
- }
- Status = SplitPage (PageEntry, PageAttribute, SplitAttribute, AllocatePagesFunc);
- if (RETURN_ERROR (Status)) {
- Status = RETURN_UNSUPPORTED;
- goto Done;
- }
- if (IsSplitted != NULL) {
- *IsSplitted = TRUE;
- }
- if (IsModified != NULL) {
- *IsModified = TRUE;
- }
- //
- // Just split current page
- // Convert success in next around
- //
- }
- }
- Done:
- //
- // Restore page table write protection, if any.
- //
- if (IsWpEnabled) {
- EnableReadOnlyPageWriteProtect ();
- }
- return Status;
- }
- /**
- This function assigns the page attributes for the memory region specified by BaseAddress and
- Length from their current attributes to the attributes specified by Attributes.
- Caller should make sure BaseAddress and Length is at page boundary.
- Caller need guarantee the TPL <= TPL_NOTIFY, if there is split page request.
- @param[in] PagingContext The paging context. NULL means get page table from current CPU context.
- @param[in] BaseAddress The physical address that is the start address of a memory region.
- @param[in] Length The size in bytes of the memory region.
- @param[in] Attributes The bit mask of attributes to set for the memory region.
- @param[in] AllocatePagesFunc If page split is needed, this function is used to allocate more pages.
- NULL mean page split is unsupported.
- @retval RETURN_SUCCESS The attributes were cleared for the memory region.
- @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval RETURN_INVALID_PARAMETER Length is zero.
- Attributes specified an illegal combination of attributes that
- cannot be set together.
- @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
- the memory resource range.
- @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
- resource range specified by BaseAddress and Length.
- The bit mask of attributes is not support for the memory resource
- range specified by BaseAddress and Length.
- **/
- RETURN_STATUS
- EFIAPI
- AssignMemoryPageAttributes (
- IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL,
- IN PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes,
- IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL
- )
- {
- RETURN_STATUS Status;
- BOOLEAN IsModified;
- BOOLEAN IsSplitted;
- // DEBUG((DEBUG_INFO, "AssignMemoryPageAttributes: 0x%lx - 0x%lx (0x%lx)\n", BaseAddress, Length, Attributes));
- Status = ConvertMemoryPageAttributes (PagingContext, BaseAddress, Length, Attributes, PageActionAssign, AllocatePagesFunc, &IsSplitted, &IsModified);
- if (!EFI_ERROR (Status)) {
- if ((PagingContext == NULL) && IsModified) {
- //
- // Flush TLB as last step.
- //
- // Note: Since APs will always init CR3 register in HLT loop mode or do
- // TLB flush in MWAIT loop mode, there's no need to flush TLB for them
- // here.
- //
- CpuFlushTlb ();
- }
- }
- return Status;
- }
- /**
- Check if Execute Disable feature is enabled or not.
- **/
- BOOLEAN
- IsExecuteDisableEnabled (
- VOID
- )
- {
- MSR_CORE_IA32_EFER_REGISTER MsrEfer;
- MsrEfer.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
- return (MsrEfer.Bits.NXE == 1);
- }
- /**
- Update GCD memory space attributes according to current page table setup.
- **/
- VOID
- RefreshGcdMemoryAttributesFromPaging (
- VOID
- )
- {
- EFI_STATUS Status;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- PAGE_TABLE_LIB_PAGING_CONTEXT PagingContext;
- PAGE_ATTRIBUTE PageAttribute;
- UINT64 *PageEntry;
- UINT64 PageLength;
- UINT64 MemorySpaceLength;
- UINT64 Length;
- UINT64 BaseAddress;
- UINT64 PageStartAddress;
- UINT64 Attributes;
- UINT64 Capabilities;
- UINT64 NewAttributes;
- UINTN Index;
- //
- // Assuming that memory space map returned is sorted already; otherwise sort
- // them in the order of lowest address to highest address.
- //
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
- ASSERT_EFI_ERROR (Status);
- GetCurrentPagingContext (&PagingContext);
- Attributes = 0;
- NewAttributes = 0;
- BaseAddress = 0;
- PageLength = 0;
- if (IsExecuteDisableEnabled ()) {
- Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP;
- } else {
- Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP;
- }
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- continue;
- }
- //
- // Sync the actual paging related capabilities back to GCD service first.
- // As a side effect (good one), this can also help to avoid unnecessary
- // memory map entries due to the different capabilities of the same type
- // memory, such as multiple RT_CODE and RT_DATA entries in memory map,
- // which could cause boot failure of some old Linux distro (before v4.3).
- //
- Status = gDS->SetMemorySpaceCapabilities (
- MemorySpaceMap[Index].BaseAddress,
- MemorySpaceMap[Index].Length,
- MemorySpaceMap[Index].Capabilities | Capabilities
- );
- if (EFI_ERROR (Status)) {
- //
- // If we cannot update the capabilities, we cannot update its
- // attributes either. So just simply skip current block of memory.
- //
- DEBUG ((
- DEBUG_WARN,
- "Failed to update capability: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",
- (UINT64)Index,
- MemorySpaceMap[Index].BaseAddress,
- MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
- MemorySpaceMap[Index].Capabilities,
- MemorySpaceMap[Index].Capabilities | Capabilities
- ));
- continue;
- }
- if (MemorySpaceMap[Index].BaseAddress >= (BaseAddress + PageLength)) {
- //
- // Current memory space starts at a new page. Resetting PageLength will
- // trigger a retrieval of page attributes at new address.
- //
- PageLength = 0;
- } else {
- //
- // In case current memory space is not adjacent to last one
- //
- PageLength -= (MemorySpaceMap[Index].BaseAddress - BaseAddress);
- }
- //
- // Sync actual page attributes to GCD
- //
- BaseAddress = MemorySpaceMap[Index].BaseAddress;
- MemorySpaceLength = MemorySpaceMap[Index].Length;
- while (MemorySpaceLength > 0) {
- if (PageLength == 0) {
- PageEntry = GetPageTableEntry (&PagingContext, BaseAddress, &PageAttribute);
- if (PageEntry == NULL) {
- break;
- }
- //
- // Note current memory space might start in the middle of a page
- //
- PageStartAddress = (*PageEntry) & (UINT64)PageAttributeToMask (PageAttribute);
- PageLength = PageAttributeToLength (PageAttribute) - (BaseAddress - PageStartAddress);
- Attributes = GetAttributesFromPageEntry (PageEntry);
- }
- Length = MIN (PageLength, MemorySpaceLength);
- if (Attributes != (MemorySpaceMap[Index].Attributes &
- EFI_MEMORY_ATTRIBUTE_MASK))
- {
- NewAttributes = (MemorySpaceMap[Index].Attributes &
- ~EFI_MEMORY_ATTRIBUTE_MASK) | Attributes;
- Status = gDS->SetMemorySpaceAttributes (
- BaseAddress,
- Length,
- NewAttributes
- );
- ASSERT_EFI_ERROR (Status);
- DEBUG ((
- DEBUG_VERBOSE,
- "Updated memory space attribute: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",
- (UINT64)Index,
- BaseAddress,
- BaseAddress + Length - 1,
- MemorySpaceMap[Index].Attributes,
- NewAttributes
- ));
- }
- PageLength -= Length;
- MemorySpaceLength -= Length;
- BaseAddress += Length;
- }
- }
- FreePool (MemorySpaceMap);
- }
- /**
- Initialize a buffer pool for page table use only.
- To reduce the potential split operation on page table, the pages reserved for
- page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
- at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
- initialized with number of pages greater than or equal to the given PoolPages.
- Once the pages in the pool are used up, this method should be called again to
- reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't happen
- often in practice.
- @param[in] PoolPages The least page number of the pool to be created.
- @retval TRUE The pool is initialized successfully.
- @retval FALSE The memory is out of resource.
- **/
- BOOLEAN
- InitializePageTablePool (
- IN UINTN PoolPages
- )
- {
- VOID *Buffer;
- BOOLEAN IsModified;
- //
- // Do not allow re-entrance.
- //
- if (mPageTablePoolLock) {
- return FALSE;
- }
- mPageTablePoolLock = TRUE;
- IsModified = FALSE;
- //
- // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
- // header.
- //
- PoolPages += 1; // Add one page for header.
- PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
- PAGE_TABLE_POOL_UNIT_PAGES;
- Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
- if (Buffer == NULL) {
- DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
- goto Done;
- }
- DEBUG ((
- DEBUG_INFO,
- "Paging: added %lu pages to page table pool\r\n",
- (UINT64)PoolPages
- ));
- //
- // Link all pools into a list for easier track later.
- //
- if (mPageTablePool == NULL) {
- mPageTablePool = Buffer;
- mPageTablePool->NextPool = mPageTablePool;
- } else {
- ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
- mPageTablePool->NextPool = Buffer;
- mPageTablePool = Buffer;
- }
- //
- // Reserve one page for pool header.
- //
- mPageTablePool->FreePages = PoolPages - 1;
- mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
- //
- // Mark the whole pool pages as read-only.
- //
- ConvertMemoryPageAttributes (
- NULL,
- (PHYSICAL_ADDRESS)(UINTN)Buffer,
- EFI_PAGES_TO_SIZE (PoolPages),
- EFI_MEMORY_RO,
- PageActionSet,
- AllocatePageTableMemory,
- NULL,
- &IsModified
- );
- ASSERT (IsModified == TRUE);
- Done:
- mPageTablePoolLock = FALSE;
- return IsModified;
- }
- /**
- This API provides a way to allocate memory for page table.
- This API can be called more than once to allocate memory for page tables.
- Allocates the number of 4KB pages and returns a pointer to the allocated
- buffer. The buffer returned is aligned on a 4KB boundary.
- If Pages is 0, then NULL is returned.
- If there is not enough memory remaining to satisfy the request, then NULL is
- returned.
- @param Pages The number of 4 KB pages to allocate.
- @return A pointer to the allocated buffer or NULL if allocation fails.
- **/
- VOID *
- EFIAPI
- AllocatePageTableMemory (
- IN UINTN Pages
- )
- {
- VOID *Buffer;
- if (Pages == 0) {
- return NULL;
- }
- //
- // Renew the pool if necessary.
- //
- if ((mPageTablePool == NULL) ||
- (Pages > mPageTablePool->FreePages))
- {
- if (!InitializePageTablePool (Pages)) {
- return NULL;
- }
- }
- Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
- mPageTablePool->Offset += EFI_PAGES_TO_SIZE (Pages);
- mPageTablePool->FreePages -= Pages;
- return Buffer;
- }
- /**
- Special handler for #DB exception, which will restore the page attributes
- (not-present). It should work with #PF handler which will set pages to
- 'present'.
- @param ExceptionType Exception type.
- @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
- **/
- VOID
- EFIAPI
- DebugExceptionHandler (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- UINTN CpuIndex;
- UINTN PFEntry;
- BOOLEAN IsWpEnabled;
- MpInitLibWhoAmI (&CpuIndex);
- //
- // Clear last PF entries
- //
- IsWpEnabled = IsReadOnlyPageWriteProtected ();
- if (IsWpEnabled) {
- DisableReadOnlyPageWriteProtect ();
- }
- for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) {
- if (mLastPFEntryPointer[CpuIndex][PFEntry] != NULL) {
- *mLastPFEntryPointer[CpuIndex][PFEntry] &= ~(UINT64)IA32_PG_P;
- }
- }
- if (IsWpEnabled) {
- EnableReadOnlyPageWriteProtect ();
- }
- //
- // Reset page fault exception count for next page fault.
- //
- mPFEntryCount[CpuIndex] = 0;
- //
- // Flush TLB
- //
- CpuFlushTlb ();
- //
- // Clear TF in EFLAGS
- //
- if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
- SystemContext.SystemContextIa32->Eflags &= (UINT32) ~BIT8;
- } else {
- SystemContext.SystemContextX64->Rflags &= (UINT64) ~BIT8;
- }
- }
- /**
- Special handler for #PF exception, which will set the pages which caused
- #PF to be 'present'. The attribute of those pages should be restored in
- the subsequent #DB handler.
- @param ExceptionType Exception type.
- @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
- **/
- VOID
- EFIAPI
- PageFaultExceptionHandler (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- EFI_STATUS Status;
- UINT64 PFAddress;
- PAGE_TABLE_LIB_PAGING_CONTEXT PagingContext;
- PAGE_ATTRIBUTE PageAttribute;
- UINT64 Attributes;
- UINT64 *PageEntry;
- UINTN Index;
- UINTN CpuIndex;
- UINTN PageNumber;
- BOOLEAN NonStopMode;
- PFAddress = AsmReadCr2 () & ~EFI_PAGE_MASK;
- if (PFAddress < BASE_4KB) {
- NonStopMode = NULL_DETECTION_NONSTOP_MODE ? TRUE : FALSE;
- } else {
- NonStopMode = HEAP_GUARD_NONSTOP_MODE ? TRUE : FALSE;
- }
- if (NonStopMode) {
- MpInitLibWhoAmI (&CpuIndex);
- GetCurrentPagingContext (&PagingContext);
- //
- // Memory operation cross page boundary, like "rep mov" instruction, will
- // cause infinite loop between this and Debug Trap handler. We have to make
- // sure that current page and the page followed are both in PRESENT state.
- //
- PageNumber = 2;
- while (PageNumber > 0) {
- PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);
- ASSERT (PageEntry != NULL);
- if (PageEntry != NULL) {
- Attributes = GetAttributesFromPageEntry (PageEntry);
- if ((Attributes & EFI_MEMORY_RP) != 0) {
- Attributes &= ~EFI_MEMORY_RP;
- Status = AssignMemoryPageAttributes (
- &PagingContext,
- PFAddress,
- EFI_PAGE_SIZE,
- Attributes,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- Index = mPFEntryCount[CpuIndex];
- //
- // Re-retrieve page entry because above calling might update page
- // table due to table split.
- //
- PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);
- mLastPFEntryPointer[CpuIndex][Index++] = PageEntry;
- mPFEntryCount[CpuIndex] = Index;
- }
- }
- }
- PFAddress += EFI_PAGE_SIZE;
- --PageNumber;
- }
- }
- //
- // Initialize the serial port before dumping.
- //
- SerialPortInitialize ();
- //
- // Display ExceptionType, CPU information and Image information
- //
- DumpCpuContext (ExceptionType, SystemContext);
- if (NonStopMode) {
- //
- // Set TF in EFLAGS
- //
- if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
- SystemContext.SystemContextIa32->Eflags |= (UINT32)BIT8;
- } else {
- SystemContext.SystemContextX64->Rflags |= (UINT64)BIT8;
- }
- } else {
- CpuDeadLoop ();
- }
- }
- /**
- Initialize the Page Table lib.
- **/
- VOID
- InitializePageTableLib (
- VOID
- )
- {
- PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext;
- UINT32 *Attributes;
- UINTN *PageTableBase;
- GetCurrentPagingContext (&CurrentPagingContext);
- GetPagingDetails (&CurrentPagingContext.ContextData, &PageTableBase, &Attributes);
- //
- // Reserve memory of page tables for future uses, if paging is enabled.
- //
- if ((*PageTableBase != 0) &&
- ((*Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) != 0))
- {
- DisableReadOnlyPageWriteProtect ();
- InitializePageTablePool (1);
- EnableReadOnlyPageWriteProtect ();
- }
- if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {
- mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * mNumberOfProcessors);
- ASSERT (mPFEntryCount != NULL);
- mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])
- AllocateZeroPool (sizeof (mLastPFEntryPointer[0]) * mNumberOfProcessors);
- ASSERT (mLastPFEntryPointer != NULL);
- }
- DEBUG ((DEBUG_INFO, "CurrentPagingContext:\n"));
- DEBUG ((DEBUG_INFO, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
- DEBUG ((DEBUG_INFO, " PageTableBase - 0x%Lx\n", (UINT64)*PageTableBase));
- DEBUG ((DEBUG_INFO, " Attributes - 0x%x\n", *Attributes));
- return;
- }
|