]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/PiSmmCpuDxeSmm: don't free page table pages that are required to handle...
authorDamian Nikodem <damian.nikodem@intel.com>
Mon, 19 Aug 2019 17:48:45 +0000 (01:48 +0800)
committerRay Ni <ray.ni@intel.com>
Tue, 20 Aug 2019 18:44:48 +0000 (02:44 +0800)
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>
UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c

index d7af3b6d7941891afd119bae59260a341886934c..d60c404a3df5e120e46ce066b442638a4ed222ed 100644 (file)
@@ -544,6 +544,11 @@ ReclaimPages (
   UINT64                       *ReleasePageAddress;\r
   IA32_CR4                     Cr4;\r
   BOOLEAN                      Enable5LevelPaging;\r
+  UINT64                       PFAddress;\r
+  UINT64                       PFAddressPml5Index;\r
+  UINT64                       PFAddressPml4Index;\r
+  UINT64                       PFAddressPdptIndex;\r
+  UINT64                       PFAddressPdtIndex;\r
 \r
   Pml4 = NULL;\r
   Pdpt = NULL;\r
@@ -555,6 +560,11 @@ ReclaimPages (
   MinPdt  = (UINTN)-1;\r
   Acc     = 0;\r
   ReleasePageAddress = 0;\r
+  PFAddress = AsmReadCr2 ();\r
+  PFAddressPml5Index = BitFieldRead64 (PFAddress, 48, 48 + 8);\r
+  PFAddressPml4Index = BitFieldRead64 (PFAddress, 39, 39 + 8);\r
+  PFAddressPdptIndex = BitFieldRead64 (PFAddress, 30, 30 + 8);\r
+  PFAddressPdtIndex = BitFieldRead64 (PFAddress, 21, 21 + 8);\r
 \r
   Cr4.UintN = AsmReadCr4 ();\r
   Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);\r
@@ -629,40 +639,46 @@ ReclaimPages (
               // we will find the entry has the smallest access record value\r
               //\r
               PDPTEIgnore = TRUE;\r
-              Acc = GetAndUpdateAccNum (Pdt + PdtIndex);\r
+              if (PdtIndex != PFAddressPdtIndex || PdptIndex != PFAddressPdptIndex ||\r
+                  Pml4Index != PFAddressPml4Index || Pml5Index != PFAddressPml5Index) {\r
+                Acc = GetAndUpdateAccNum (Pdt + PdtIndex);\r
+                if (Acc < MinAcc) {\r
+                  //\r
+                  // If the PD entry has the smallest access record value,\r
+                  // save the Page address to be released\r
+                  //\r
+                  MinAcc  = Acc;\r
+                  MinPml5 = Pml5Index;\r
+                  MinPml4 = Pml4Index;\r
+                  MinPdpt = PdptIndex;\r
+                  MinPdt  = PdtIndex;\r
+                  ReleasePageAddress = Pdt + PdtIndex;\r
+                }\r
+              }\r
+            }\r
+          }\r
+          if (!PDPTEIgnore) {\r
+            //\r
+            // If this PDPT entry has no PDT entries pointer to 4 KByte pages,\r
+            // it should only has the entries point to 2 MByte Pages\r
+            //\r
+            if (PdptIndex != PFAddressPdptIndex || Pml4Index != PFAddressPml4Index ||\r
+                Pml5Index != PFAddressPml5Index) {\r
+              Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);\r
               if (Acc < MinAcc) {\r
                 //\r
-                // If the PD entry has the smallest access record value,\r
+                // If the PDPT entry has the smallest access record value,\r
                 // save the Page address to be released\r
                 //\r
                 MinAcc  = Acc;\r
                 MinPml5 = Pml5Index;\r
                 MinPml4 = Pml4Index;\r
                 MinPdpt = PdptIndex;\r
-                MinPdt  = PdtIndex;\r
-                ReleasePageAddress = Pdt + PdtIndex;\r
+                MinPdt  = (UINTN)-1;\r
+                ReleasePageAddress = Pdpt + PdptIndex;\r
               }\r
             }\r
           }\r
-          if (!PDPTEIgnore) {\r
-            //\r
-            // If this PDPT entry has no PDT entries pointer to 4 KByte pages,\r
-            // it should only has the entries point to 2 MByte Pages\r
-            //\r
-            Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);\r
-            if (Acc < MinAcc) {\r
-              //\r
-              // If the PDPT entry has the smallest access record value,\r
-              // save the Page address to be released\r
-              //\r
-              MinAcc  = Acc;\r
-              MinPml5 = Pml5Index;\r
-              MinPml4 = Pml4Index;\r
-              MinPdpt = PdptIndex;\r
-              MinPdt  = (UINTN)-1;\r
-              ReleasePageAddress = Pdpt + PdptIndex;\r
-            }\r
-          }\r
         }\r
       }\r
       if (!PML4EIgnore) {\r
@@ -670,18 +686,20 @@ ReclaimPages (
         // If PML4 entry has no the PDPT entry pointer to 2 MByte pages,\r
         // it should only has the entries point to 1 GByte Pages\r
         //\r
-        Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);\r
-        if (Acc < MinAcc) {\r
-          //\r
-          // If the PML4 entry has the smallest access record value,\r
-          // save the Page address to be released\r
-          //\r
-          MinAcc  = Acc;\r
-          MinPml5 = Pml5Index;\r
-          MinPml4 = Pml4Index;\r
-          MinPdpt = (UINTN)-1;\r
-          MinPdt  = (UINTN)-1;\r
-          ReleasePageAddress = Pml4 + Pml4Index;\r
+        if (Pml4Index != PFAddressPml4Index || Pml5Index != PFAddressPml5Index) {\r
+          Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);\r
+          if (Acc < MinAcc) {\r
+            //\r
+            // If the PML4 entry has the smallest access record value,\r
+            // save the Page address to be released\r
+            //\r
+            MinAcc  = Acc;\r
+            MinPml5 = Pml5Index;\r
+            MinPml4 = Pml4Index;\r
+            MinPdpt = (UINTN)-1;\r
+            MinPdt  = (UINTN)-1;\r
+            ReleasePageAddress = Pml4 + Pml4Index;\r
+          }\r
         }\r
       }\r
     }\r
@@ -709,7 +727,8 @@ ReclaimPages (
       Pml4 = (UINT64 *) (UINTN) (Pml5[MinPml5] & gPhyMask);\r
       Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask & gPhyMask);\r
       SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);\r
-      if (SubEntriesNum == 0) {\r
+      if (SubEntriesNum == 0 &&\r
+          (MinPdpt != PFAddressPdptIndex || MinPml4 != PFAddressPml4Index || MinPml5 != PFAddressPml5Index)) {\r
         //\r
         // Release the empty Page Directory table if there was no more 4 KByte Page Table entry\r
         // clear the Page directory entry\r
@@ -725,7 +744,7 @@ ReclaimPages (
       //\r
       // Update the sub-entries filed in PDPT entry and exit\r
       //\r
-      SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1);\r
+      SetSubEntriesNum (Pdpt + MinPdpt, (SubEntriesNum - 1) & 0x1FF);\r
       break;\r
     }\r
     if (MinPdpt != (UINTN)-1) {\r
@@ -733,7 +752,7 @@ ReclaimPages (
       // One 2MB Page Table is released or Page Directory table is released, check the PML4 entry\r
       //\r
       SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4);\r
-      if (SubEntriesNum == 0) {\r
+      if (SubEntriesNum == 0 && (MinPml4 != PFAddressPml4Index || MinPml5 != PFAddressPml5Index)) {\r
         //\r
         // Release the empty PML4 table if there was no more 1G KByte Page Table entry\r
         // clear the Page directory entry\r
@@ -746,7 +765,7 @@ ReclaimPages (
       //\r
       // Update the sub-entries filed in PML4 entry and exit\r
       //\r
-      SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1);\r
+      SetSubEntriesNum (Pml4 + MinPml4, (SubEntriesNum - 1) & 0x1FF);\r
       break;\r
     }\r
     //\r
@@ -919,7 +938,7 @@ SmiDefaultPFHandler (
     PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & gPhyMask & ~((1ull << EndBit) - 1)) |\r
                          PageAttribute | IA32_PG_A | PAGE_ATTRIBUTE_BITS;\r
     if (UpperEntry != NULL) {\r
-      SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1);\r
+      SetSubEntriesNum (UpperEntry, (GetSubEntriesNum (UpperEntry) + 1) & 0x1FF);\r
     }\r
     //\r
     // Get the next page address if we need to create more page tables\r