UefiCpuPkg/PiSmmCpuDxeSmm: don't free page table pages that are required to handle current page fault
Reclaim may free page table pages that are required to handle current page fault. This causes a page leak, and, after sufficent number of specific page fault+reclaim pairs, we run out of reclaimable pages and hit: ASSERT (MinAcc != (UINT64)-1); To remedy, prevent pages essential to handling current page fault: (1) from being considered as reclaim candidates (first reclaim phase) (2) from being freed as part of "branch cleanup" (second reclaim phase) Signed-off-by: Damian Nikodem <damian.nikodem@intel.com> Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Krzysztof Rusocki <krzysztof.rusocki@intel.com>
This commit is contained in:
@@ -544,6 +544,11 @@ ReclaimPages (
|
|||||||
UINT64 *ReleasePageAddress;
|
UINT64 *ReleasePageAddress;
|
||||||
IA32_CR4 Cr4;
|
IA32_CR4 Cr4;
|
||||||
BOOLEAN Enable5LevelPaging;
|
BOOLEAN Enable5LevelPaging;
|
||||||
|
UINT64 PFAddress;
|
||||||
|
UINT64 PFAddressPml5Index;
|
||||||
|
UINT64 PFAddressPml4Index;
|
||||||
|
UINT64 PFAddressPdptIndex;
|
||||||
|
UINT64 PFAddressPdtIndex;
|
||||||
|
|
||||||
Pml4 = NULL;
|
Pml4 = NULL;
|
||||||
Pdpt = NULL;
|
Pdpt = NULL;
|
||||||
@@ -555,6 +560,11 @@ ReclaimPages (
|
|||||||
MinPdt = (UINTN)-1;
|
MinPdt = (UINTN)-1;
|
||||||
Acc = 0;
|
Acc = 0;
|
||||||
ReleasePageAddress = 0;
|
ReleasePageAddress = 0;
|
||||||
|
PFAddress = AsmReadCr2 ();
|
||||||
|
PFAddressPml5Index = BitFieldRead64 (PFAddress, 48, 48 + 8);
|
||||||
|
PFAddressPml4Index = BitFieldRead64 (PFAddress, 39, 39 + 8);
|
||||||
|
PFAddressPdptIndex = BitFieldRead64 (PFAddress, 30, 30 + 8);
|
||||||
|
PFAddressPdtIndex = BitFieldRead64 (PFAddress, 21, 21 + 8);
|
||||||
|
|
||||||
Cr4.UintN = AsmReadCr4 ();
|
Cr4.UintN = AsmReadCr4 ();
|
||||||
Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
|
Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
|
||||||
@@ -629,18 +639,21 @@ ReclaimPages (
|
|||||||
// we will find the entry has the smallest access record value
|
// we will find the entry has the smallest access record value
|
||||||
//
|
//
|
||||||
PDPTEIgnore = TRUE;
|
PDPTEIgnore = TRUE;
|
||||||
Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
|
if (PdtIndex != PFAddressPdtIndex || PdptIndex != PFAddressPdptIndex ||
|
||||||
if (Acc < MinAcc) {
|
Pml4Index != PFAddressPml4Index || Pml5Index != PFAddressPml5Index) {
|
||||||
//
|
Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
|
||||||
// If the PD entry has the smallest access record value,
|
if (Acc < MinAcc) {
|
||||||
// save the Page address to be released
|
//
|
||||||
//
|
// If the PD entry has the smallest access record value,
|
||||||
MinAcc = Acc;
|
// save the Page address to be released
|
||||||
MinPml5 = Pml5Index;
|
//
|
||||||
MinPml4 = Pml4Index;
|
MinAcc = Acc;
|
||||||
MinPdpt = PdptIndex;
|
MinPml5 = Pml5Index;
|
||||||
MinPdt = PdtIndex;
|
MinPml4 = Pml4Index;
|
||||||
ReleasePageAddress = Pdt + PdtIndex;
|
MinPdpt = PdptIndex;
|
||||||
|
MinPdt = PdtIndex;
|
||||||
|
ReleasePageAddress = Pdt + PdtIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,18 +662,21 @@ ReclaimPages (
|
|||||||
// If this PDPT entry has no PDT entries pointer to 4 KByte pages,
|
// If this PDPT entry has no PDT entries pointer to 4 KByte pages,
|
||||||
// it should only has the entries point to 2 MByte Pages
|
// it should only has the entries point to 2 MByte Pages
|
||||||
//
|
//
|
||||||
Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
|
if (PdptIndex != PFAddressPdptIndex || Pml4Index != PFAddressPml4Index ||
|
||||||
if (Acc < MinAcc) {
|
Pml5Index != PFAddressPml5Index) {
|
||||||
//
|
Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
|
||||||
// If the PDPT entry has the smallest access record value,
|
if (Acc < MinAcc) {
|
||||||
// save the Page address to be released
|
//
|
||||||
//
|
// If the PDPT entry has the smallest access record value,
|
||||||
MinAcc = Acc;
|
// save the Page address to be released
|
||||||
MinPml5 = Pml5Index;
|
//
|
||||||
MinPml4 = Pml4Index;
|
MinAcc = Acc;
|
||||||
MinPdpt = PdptIndex;
|
MinPml5 = Pml5Index;
|
||||||
MinPdt = (UINTN)-1;
|
MinPml4 = Pml4Index;
|
||||||
ReleasePageAddress = Pdpt + PdptIndex;
|
MinPdpt = PdptIndex;
|
||||||
|
MinPdt = (UINTN)-1;
|
||||||
|
ReleasePageAddress = Pdpt + PdptIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,18 +686,20 @@ ReclaimPages (
|
|||||||
// If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
|
// If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
|
||||||
// it should only has the entries point to 1 GByte Pages
|
// it should only has the entries point to 1 GByte Pages
|
||||||
//
|
//
|
||||||
Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
|
if (Pml4Index != PFAddressPml4Index || Pml5Index != PFAddressPml5Index) {
|
||||||
if (Acc < MinAcc) {
|
Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
|
||||||
//
|
if (Acc < MinAcc) {
|
||||||
// If the PML4 entry has the smallest access record value,
|
//
|
||||||
// save the Page address to be released
|
// If the PML4 entry has the smallest access record value,
|
||||||
//
|
// save the Page address to be released
|
||||||
MinAcc = Acc;
|
//
|
||||||
MinPml5 = Pml5Index;
|
MinAcc = Acc;
|
||||||
MinPml4 = Pml4Index;
|
MinPml5 = Pml5Index;
|
||||||
MinPdpt = (UINTN)-1;
|
MinPml4 = Pml4Index;
|
||||||
MinPdt = (UINTN)-1;
|
MinPdpt = (UINTN)-1;
|
||||||
ReleasePageAddress = Pml4 + Pml4Index;
|
MinPdt = (UINTN)-1;
|
||||||
|
ReleasePageAddress = Pml4 + Pml4Index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -709,7 +727,8 @@ ReclaimPages (
|
|||||||
Pml4 = (UINT64 *) (UINTN) (Pml5[MinPml5] & gPhyMask);
|
Pml4 = (UINT64 *) (UINTN) (Pml5[MinPml5] & gPhyMask);
|
||||||
Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask & gPhyMask);
|
Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask & gPhyMask);
|
||||||
SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);
|
SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);
|
||||||
if (SubEntriesNum == 0) {
|
if (SubEntriesNum == 0 &&
|
||||||
|
(MinPdpt != PFAddressPdptIndex || MinPml4 != PFAddressPml4Index || MinPml5 != PFAddressPml5Index)) {
|
||||||
//
|
//
|
||||||
// Release the empty Page Directory table if there was no more 4 KByte Page Table entry
|
// Release the empty Page Directory table if there was no more 4 KByte Page Table entry
|
||||||
// clear the Page directory entry
|
// clear the Page directory entry
|
||||||
@@ -725,7 +744,7 @@ ReclaimPages (
|
|||||||
//
|
//
|
||||||
// Update the sub-entries filed in PDPT entry and exit
|
// Update the sub-entries filed in PDPT entry and exit
|
||||||
//
|
//
|
||||||
SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1);
|
SetSubEntriesNum (Pdpt + MinPdpt, (SubEntriesNum - 1) & 0x1FF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (MinPdpt != (UINTN)-1) {
|
if (MinPdpt != (UINTN)-1) {
|
||||||
@@ -733,7 +752,7 @@ ReclaimPages (
|
|||||||
// One 2MB Page Table is released or Page Directory table is released, check the PML4 entry
|
// One 2MB Page Table is released or Page Directory table is released, check the PML4 entry
|
||||||
//
|
//
|
||||||
SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4);
|
SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4);
|
||||||
if (SubEntriesNum == 0) {
|
if (SubEntriesNum == 0 && (MinPml4 != PFAddressPml4Index || MinPml5 != PFAddressPml5Index)) {
|
||||||
//
|
//
|
||||||
// Release the empty PML4 table if there was no more 1G KByte Page Table entry
|
// Release the empty PML4 table if there was no more 1G KByte Page Table entry
|
||||||
// clear the Page directory entry
|
// clear the Page directory entry
|
||||||
@@ -746,7 +765,7 @@ ReclaimPages (
|
|||||||
//
|
//
|
||||||
// Update the sub-entries filed in PML4 entry and exit
|
// Update the sub-entries filed in PML4 entry and exit
|
||||||
//
|
//
|
||||||
SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1);
|
SetSubEntriesNum (Pml4 + MinPml4, (SubEntriesNum - 1) & 0x1FF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -919,7 +938,7 @@ SmiDefaultPFHandler (
|
|||||||
PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & gPhyMask & ~((1ull << EndBit) - 1)) |
|
PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & gPhyMask & ~((1ull << EndBit) - 1)) |
|
||||||
PageAttribute | IA32_PG_A | PAGE_ATTRIBUTE_BITS;
|
PageAttribute | IA32_PG_A | PAGE_ATTRIBUTE_BITS;
|
||||||
if (UpperEntry != NULL) {
|
if (UpperEntry != NULL) {
|
||||||
SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1);
|
SetSubEntriesNum (UpperEntry, (GetSubEntriesNum (UpperEntry) + 1) & 0x1FF);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Get the next page address if we need to create more page tables
|
// Get the next page address if we need to create more page tables
|
||||||
|
Reference in New Issue
Block a user