EFI_MEMORY_RO \\r
)\r
\r
+#define HEAP_GUARD_NONSTOP_MODE \\r
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT6|BIT1|BIT0)) > BIT6)\r
+\r
+#define NULL_DETECTION_NONSTOP_MODE \\r
+ ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT6|BIT0)) > BIT6)\r
+\r
/**\r
Flush CPU data cache. If the instruction cache is fully coherent\r
with all DMA operations then function can just return EFI_SUCCESS.\r
VOID\r
);\r
\r
+/**\r
+ Special handler for #DB exception, which will restore the page attributes\r
+ (not-present). It should work with #PF handler which will set pages to\r
+ 'present'.\r
+\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
+/**\r
+ Special handler for #PF exception, which will set the pages which caused\r
+ #PF to be 'present'. The attribute of those pages should be restored in\r
+ the subsequent #DB handler.\r
+\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PageFaultExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
extern BOOLEAN mIsAllocatingPageTable;\r
+extern UINTN mNumberOfProcessors;\r
\r
#endif\r
\r
UINT8 *GdtBuffer;\r
UINT8 *StackTop;\r
\r
- if (!PcdGetBool (PcdCpuStackGuard)) {\r
- return;\r
- }\r
-\r
ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);\r
NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;\r
\r
}\r
}\r
\r
+/**\r
+ Initializes MP exceptions handlers for special features, such as Heap Guard\r
+ and Stack Guard.\r
+**/\r
+VOID\r
+InitializeMpExceptionHandlers (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Enable non-stop mode for #PF triggered by Heap Guard or NULL Pointer\r
+ // Detection.\r
+ //\r
+ if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {\r
+ RegisterCpuInterruptHandler (EXCEPT_IA32_DEBUG, DebugExceptionHandler);\r
+ RegisterCpuInterruptHandler (EXCEPT_IA32_PAGE_FAULT, PageFaultExceptionHandler);\r
+ }\r
+\r
+ //\r
+ // Setup stack switch for Stack Guard feature.\r
+ //\r
+ if (PcdGetBool (PcdCpuStackGuard)) {\r
+ InitializeMpExceptionStackSwitchHandlers ();\r
+ }\r
+}\r
+\r
/**\r
Initialize Multi-processor support.\r
\r
DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));\r
\r
//\r
- // Initialize exception stack switch handlers for each logic processor.\r
+ // Initialize special exception handlers for each logic processor.\r
//\r
- InitializeMpExceptionStackSwitchHandlers ();\r
+ InitializeMpExceptionHandlers ();\r
\r
//\r
// Update CPU healthy information from Guided HOB\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/PrintLib.h>\r
#include <Protocol/MpService.h>\r
#include <Protocol/SmmBase2.h>\r
#include <Register/Cpuid.h>\r
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull\r
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
\r
+#define MAX_PF_ENTRY_COUNT 10\r
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100\r
+#define IA32_PF_EC_ID BIT4\r
+\r
typedef enum {\r
PageNone,\r
Page4K,\r
PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;\r
EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;\r
\r
+//\r
+// Record the page fault exception count for one instruction execution.\r
+//\r
+UINTN *mPFEntryCount;\r
+UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];\r
+\r
/**\r
Check if current execution environment is in SMM mode or not, via\r
EFI_SMM_BASE2_PROTOCOL.\r
return Buffer;\r
}\r
\r
+/**\r
+ Special handler for #DB exception, which will restore the page attributes\r
+ (not-present). It should work with #PF handler which will set pages to\r
+ 'present'.\r
+\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ UINTN CpuIndex;\r
+ UINTN PFEntry;\r
+ BOOLEAN IsWpEnabled;\r
+\r
+ MpInitLibWhoAmI (&CpuIndex);\r
+\r
+ //\r
+ // Clear last PF entries\r
+ //\r
+ IsWpEnabled = IsReadOnlyPageWriteProtected ();\r
+ if (IsWpEnabled) {\r
+ DisableReadOnlyPageWriteProtect ();\r
+ }\r
+\r
+ for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) {\r
+ if (mLastPFEntryPointer[CpuIndex][PFEntry] != NULL) {\r
+ *mLastPFEntryPointer[CpuIndex][PFEntry] &= ~IA32_PG_P;\r
+ }\r
+ }\r
+\r
+ if (IsWpEnabled) {\r
+ EnableReadOnlyPageWriteProtect ();\r
+ }\r
+\r
+ //\r
+ // Reset page fault exception count for next page fault.\r
+ //\r
+ mPFEntryCount[CpuIndex] = 0;\r
+\r
+ //\r
+ // Flush TLB\r
+ //\r
+ CpuFlushTlb ();\r
+\r
+ //\r
+ // Clear TF in EFLAGS\r
+ //\r
+ if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {\r
+ SystemContext.SystemContextIa32->Eflags &= (UINT32)~BIT8;\r
+ } else {\r
+ SystemContext.SystemContextX64->Rflags &= (UINT64)~BIT8;\r
+ }\r
+}\r
+\r
+/**\r
+ Special handler for #PF exception, which will set the pages which caused\r
+ #PF to be 'present'. The attribute of those pages should be restored in\r
+ the subsequent #DB handler.\r
+\r
+ @param ExceptionType Exception type.\r
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PageFaultExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 PFAddress;\r
+ PAGE_TABLE_LIB_PAGING_CONTEXT PagingContext;\r
+ PAGE_ATTRIBUTE PageAttribute;\r
+ UINT64 Attributes;\r
+ UINT64 *PageEntry;\r
+ UINTN Index;\r
+ UINTN CpuIndex;\r
+ UINTN PageNumber;\r
+ BOOLEAN NonStopMode;\r
+\r
+ PFAddress = AsmReadCr2 () & ~EFI_PAGE_MASK;\r
+ if (PFAddress < BASE_4KB) {\r
+ NonStopMode = NULL_DETECTION_NONSTOP_MODE ? TRUE : FALSE;\r
+ } else {\r
+ NonStopMode = HEAP_GUARD_NONSTOP_MODE ? TRUE : FALSE;\r
+ }\r
+\r
+ if (NonStopMode) {\r
+ MpInitLibWhoAmI (&CpuIndex);\r
+ GetCurrentPagingContext (&PagingContext);\r
+ //\r
+ // Memory operation cross page boundary, like "rep mov" instruction, will\r
+ // cause infinite loop between this and Debug Trap handler. We have to make\r
+ // sure that current page and the page followed are both in PRESENT state.\r
+ //\r
+ PageNumber = 2;\r
+ while (PageNumber > 0) {\r
+ PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);\r
+ ASSERT(PageEntry != NULL);\r
+\r
+ if (PageEntry != NULL) {\r
+ Attributes = GetAttributesFromPageEntry (PageEntry);\r
+ if ((Attributes & EFI_MEMORY_RP) != 0) {\r
+ Attributes &= ~EFI_MEMORY_RP;\r
+ Status = AssignMemoryPageAttributes (&PagingContext, PFAddress,\r
+ EFI_PAGE_SIZE, Attributes, NULL);\r
+ if (!EFI_ERROR(Status)) {\r
+ Index = mPFEntryCount[CpuIndex];\r
+ //\r
+ // Re-retrieve page entry because above calling might update page\r
+ // table due to table split.\r
+ //\r
+ PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);\r
+ mLastPFEntryPointer[CpuIndex][Index++] = PageEntry;\r
+ mPFEntryCount[CpuIndex] = Index;\r
+ }\r
+ }\r
+ }\r
+\r
+ PFAddress += EFI_PAGE_SIZE;\r
+ --PageNumber;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize the serial port before dumping.\r
+ //\r
+ SerialPortInitialize ();\r
+ //\r
+ // Display ExceptionType, CPU information and Image information\r
+ //\r
+ DumpCpuContext (ExceptionType, SystemContext);\r
+ if (!NonStopMode) {\r
+ CpuDeadLoop ();\r
+ }\r
+}\r
+\r
/**\r
Initialize the Page Table lib.\r
**/\r
EnableReadOnlyPageWriteProtect ();\r
}\r
\r
+ if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {\r
+ mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * mNumberOfProcessors);\r
+ ASSERT (mPFEntryCount != NULL);\r
+\r
+ mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])\r
+ AllocateZeroPool (sizeof (mLastPFEntryPointer[0]) * mNumberOfProcessors);\r
+ ASSERT (mLastPFEntryPointer != NULL);\r
+ }\r
+\r
DEBUG ((DEBUG_INFO, "CurrentPagingContext:\n", CurrentPagingContext.MachineType));\r
DEBUG ((DEBUG_INFO, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));\r
DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));\r