#include <Library/DebugLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Protocol/MpService.h>\r
+\r
+#include "CpuDxe.h"\r
#include "CpuPageTable.h"\r
\r
///\r
AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
if ((RegEdx & BIT20) != 0) {\r
// XD supported\r
- if ((AsmReadMsr64 (0x000001A0) & BIT34) == 0) {\r
- // XD enabled\r
- if ((AsmReadMsr64 (0xC0000080) & BIT11) != 0) {\r
- // XD activated\r
- PagingContext->ContextData.Ia32.Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED;\r
- }\r
+ if ((AsmReadMsr64 (0xC0000080) & BIT11) != 0) {\r
+ // XD activated\r
+ PagingContext->ContextData.Ia32.Attributes |= PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED;\r
}\r
}\r
if ((RegEdx & BIT26) != 0) {\r
*PageEntry = NewPageEntry;\r
if (CurrentPageEntry != NewPageEntry) {\r
*IsModified = TRUE;\r
- DEBUG ((DEBUG_INFO, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
- DEBUG ((DEBUG_INFO, "->0x%lx\n", NewPageEntry));\r
+ DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));\r
+ DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));\r
} else {\r
*IsModified = FALSE;\r
}\r
switch(CurrentPagingContext.MachineType) {\r
case IMAGE_FILE_MACHINE_I386:\r
if (CurrentPagingContext.ContextData.Ia32.PageTableBase == 0) {\r
- DEBUG ((DEBUG_ERROR, "PageTable is 0!\n"));\r
if (Attributes == 0) {\r
return EFI_SUCCESS;\r
} else {\r
+ DEBUG ((DEBUG_ERROR, "PageTable is 0!\n"));\r
return EFI_UNSUPPORTED;\r
}\r
}\r
return Status;\r
}\r
\r
+/**\r
+ Check if Execute Disable feature is enabled or not.\r
+**/\r
+BOOLEAN\r
+IsExecuteDisableEnabled (\r
+ VOID\r
+ )\r
+{\r
+ MSR_CORE_IA32_EFER_REGISTER MsrEfer;\r
+\r
+ MsrEfer.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
+ return (MsrEfer.Bits.NXE == 1);\r
+}\r
+\r
+/**\r
+ Update GCD memory space attributes according to current page table setup.\r
+**/\r
+VOID\r
+RefreshGcdMemoryAttributesFromPaging (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NumberOfDescriptors;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
+ PAGE_TABLE_LIB_PAGING_CONTEXT PagingContext;\r
+ PAGE_ATTRIBUTE PageAttribute;\r
+ UINT64 *PageEntry;\r
+ UINT64 PageLength;\r
+ UINT64 MemorySpaceLength;\r
+ UINT64 Length;\r
+ UINT64 BaseAddress;\r
+ UINT64 PageStartAddress;\r
+ UINT64 Attributes;\r
+ UINT64 Capabilities;\r
+ UINT64 NewAttributes;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Assuming that memory space map returned is sorted already; otherwise sort\r
+ // them in the order of lowest address to highest address.\r
+ //\r
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ GetCurrentPagingContext (&PagingContext);\r
+\r
+ Attributes = 0;\r
+ NewAttributes = 0;\r
+ BaseAddress = 0;\r
+ PageLength = 0;\r
+\r
+ if (IsExecuteDisableEnabled ()) {\r
+ Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP;\r
+ } else {\r
+ Capabilities = EFI_MEMORY_RO | EFI_MEMORY_RP;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Sync the actual paging related capabilities back to GCD service first.\r
+ // As a side effect (good one), this can also help to avoid unnecessary\r
+ // memory map entries due to the different capabilities of the same type\r
+ // memory, such as multiple RT_CODE and RT_DATA entries in memory map,\r
+ // which could cause boot failure of some old Linux distro (before v4.3).\r
+ //\r
+ Status = gDS->SetMemorySpaceCapabilities (\r
+ MemorySpaceMap[Index].BaseAddress,\r
+ MemorySpaceMap[Index].Length,\r
+ MemorySpaceMap[Index].Capabilities | Capabilities\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If we cannot udpate the capabilities, we cannot update its\r
+ // attributes either. So just simply skip current block of memory.\r
+ //\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "Failed to update capability: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",\r
+ (UINT64)Index, MemorySpaceMap[Index].BaseAddress,\r
+ MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,\r
+ MemorySpaceMap[Index].Capabilities,\r
+ MemorySpaceMap[Index].Capabilities | Capabilities\r
+ ));\r
+ continue;\r
+ }\r
+\r
+ if (MemorySpaceMap[Index].BaseAddress >= (BaseAddress + PageLength)) {\r
+ //\r
+ // Current memory space starts at a new page. Resetting PageLength will\r
+ // trigger a retrieval of page attributes at new address.\r
+ //\r
+ PageLength = 0;\r
+ } else {\r
+ //\r
+ // In case current memory space is not adjacent to last one\r
+ //\r
+ PageLength -= (MemorySpaceMap[Index].BaseAddress - BaseAddress);\r
+ }\r
+\r
+ //\r
+ // Sync actual page attributes to GCD\r
+ //\r
+ BaseAddress = MemorySpaceMap[Index].BaseAddress;\r
+ MemorySpaceLength = MemorySpaceMap[Index].Length;\r
+ while (MemorySpaceLength > 0) {\r
+ if (PageLength == 0) {\r
+ PageEntry = GetPageTableEntry (&PagingContext, BaseAddress, &PageAttribute);\r
+ if (PageEntry == NULL) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Note current memory space might start in the middle of a page\r
+ //\r
+ PageStartAddress = (*PageEntry) & (UINT64)PageAttributeToMask(PageAttribute);\r
+ PageLength = PageAttributeToLength (PageAttribute) - (BaseAddress - PageStartAddress);\r
+ Attributes = GetAttributesFromPageEntry (PageEntry);\r
+ }\r
+\r
+ Length = MIN (PageLength, MemorySpaceLength);\r
+ if (Attributes != (MemorySpaceMap[Index].Attributes &\r
+ EFI_MEMORY_PAGETYPE_MASK)) {\r
+ NewAttributes = (MemorySpaceMap[Index].Attributes &\r
+ ~EFI_MEMORY_PAGETYPE_MASK) | Attributes;\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ BaseAddress,\r
+ Length,\r
+ NewAttributes\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Updated memory space attribute: [%lu] %016lx - %016lx (%016lx -> %016lx)\r\n",\r
+ (UINT64)Index, BaseAddress, BaseAddress + Length - 1,\r
+ MemorySpaceMap[Index].Attributes,\r
+ NewAttributes\r
+ ));\r
+ }\r
+\r
+ PageLength -= Length;\r
+ MemorySpaceLength -= Length;\r
+ BaseAddress += Length;\r
+ }\r
+ }\r
+\r
+ FreePool (MemorySpaceMap);\r
+}\r
+\r
/**\r
Initialize the Page Table lib.\r
**/\r