Create 4G page table by default, and using PF to handle >4G MMIO access, to improve S3 performance.
signed-off-by: jiewen.yao@intel.com reviewed-by: rui.sun@intel.com git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13631 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -33,6 +33,63 @@ typedef struct {
|
||||
#define INTERRUPT_GATE_ATTRIBUTE 0x8e00
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define IA32_PG_P BIT0
|
||||
#define IA32_PG_RW BIT1
|
||||
#define IA32_PG_PS BIT7
|
||||
|
||||
UINT64 mPhyMask;
|
||||
BOOLEAN mPage1GSupport;
|
||||
VOID *mOriginalHandler;
|
||||
UINTN mS3NvsPageTableAddress;
|
||||
|
||||
VOID
|
||||
EFIAPI
|
||||
PageFaultHandlerHook (
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
HookPageFaultHandler (
|
||||
IN INTERRUPT_GATE_DESCRIPTOR *IdtEntry
|
||||
)
|
||||
{
|
||||
UINT32 RegEax;
|
||||
UINT32 RegEdx;
|
||||
|
||||
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
|
||||
mPhyMask = LShiftU64 (1, (UINT8)RegEax) - 1;
|
||||
mPhyMask &= (1ull << 48) - SIZE_4KB;
|
||||
|
||||
mPage1GSupport = FALSE;
|
||||
if (PcdGetBool(PcdUse1GPageTable)) {
|
||||
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
||||
if (RegEax >= 0x80000001) {
|
||||
AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
|
||||
if ((RegEdx & BIT26) != 0) {
|
||||
mPage1GSupport = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Set Page Fault entry to catch >4G access
|
||||
//
|
||||
mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Offset63To32, 32) + IdtEntry->Offset15To0 + (IdtEntry->Offset31To16 << 16));
|
||||
IdtEntry->Offset15To0 = (UINT16)((UINTN)PageFaultHandlerHook);
|
||||
IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();
|
||||
IdtEntry->Attributes = (UINT16)INTERRUPT_GATE_ATTRIBUTE;
|
||||
IdtEntry->Offset31To16 = (UINT16)((UINTN)PageFaultHandlerHook >> 16);
|
||||
IdtEntry->Offset63To32 = (UINT32)((UINTN)PageFaultHandlerHook >> 32);
|
||||
IdtEntry->Reserved = 0;
|
||||
|
||||
if (mPage1GSupport) {
|
||||
mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
|
||||
}else {
|
||||
mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set a IDT entry for interrupt vector 3 for debug purpose.
|
||||
|
||||
@@ -66,11 +123,69 @@ SetIdtEntry (
|
||||
S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
|
||||
|
||||
IdtEntry->Offset15To0 = (UINT16)S3DebugBuffer;
|
||||
IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();;
|
||||
IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();
|
||||
IdtEntry->Attributes = (UINT16)INTERRUPT_GATE_ATTRIBUTE;
|
||||
IdtEntry->Offset31To16 = (UINT16)(S3DebugBuffer >> 16);
|
||||
IdtEntry->Offset63To32 = (UINT32)(S3DebugBuffer >> 32);
|
||||
IdtEntry->Reserved = 0;
|
||||
|
||||
IdtEntry = (INTERRUPT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (INTERRUPT_GATE_DESCRIPTOR)));
|
||||
HookPageFaultHandler (IdtEntry);
|
||||
|
||||
AsmWriteIdtr (IdtDescriptor);
|
||||
}
|
||||
|
||||
UINTN
|
||||
GetNewPage (
|
||||
IN UINTN PageNum
|
||||
)
|
||||
{
|
||||
UINTN NewPage;
|
||||
NewPage = mS3NvsPageTableAddress;
|
||||
ZeroMem ((VOID *)NewPage, EFI_PAGES_TO_SIZE(PageNum));
|
||||
mS3NvsPageTableAddress += EFI_PAGES_TO_SIZE(PageNum);
|
||||
return NewPage;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
PageFaultHandler (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT64 *PageTable;
|
||||
UINT64 PFAddress;
|
||||
UINTN PTIndex;
|
||||
|
||||
PFAddress = AsmReadCr2 ();
|
||||
DEBUG ((EFI_D_ERROR, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
|
||||
|
||||
if (PFAddress >= mPhyMask + SIZE_4KB) {
|
||||
return FALSE;
|
||||
}
|
||||
PFAddress &= mPhyMask;
|
||||
|
||||
PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
|
||||
|
||||
PTIndex = BitFieldRead64 (PFAddress, 39, 47);
|
||||
// PML4E
|
||||
if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
|
||||
PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
|
||||
}
|
||||
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
|
||||
PTIndex = BitFieldRead64 (PFAddress, 30, 38);
|
||||
// PDPTE
|
||||
if (mPage1GSupport) {
|
||||
PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
|
||||
} else {
|
||||
if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
|
||||
PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
|
||||
}
|
||||
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
|
||||
PTIndex = BitFieldRead64 (PFAddress, 21, 29);
|
||||
// PD
|
||||
PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user