Vlv2TbltDevicePkg/PlatformInitPei: Better SMRAM size alignment
authorMichael Kinney <michael.d.kinney@intel.com>
Fri, 2 Dec 2016 16:40:20 +0000 (08:40 -0800)
committerMichael Kinney <michael.d.kinney@intel.com>
Wed, 7 Dec 2016 16:57:06 +0000 (08:57 -0800)
https://bugzilla.tianocore.org/show_bug.cgi?id=260

Update workaround to be more generic.

* Search for the largest region between 1MB and 4GB
* Find all adjacent regions to compute total size
* Minimum aligned size if 4KB
* Mark extended region to align size as EFI_ALLOCATED
* If an adjacent EFI_ALLOCATED region is present, then
  increase the size of the adjacent region.
* If adjacent EFI_ALLOCATED region is not present, then
  allocate a new HOB with one extra entry to describe
  the extended region to align the total size.  Preserve
  the last entry in the descriptor list for compatibility.

This is a workaround until the binary module that produces the
gEfiSmmPeiSmramMemoryReserveGuid HOB is updated

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: David Wei <david.wei@intel.com>
Cc: Mang Guo <mang.guo@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Michael Kinney <michael.d.kinney@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Vlv2TbltDevicePkg/PlatformInitPei/PlatformEarlyInit.c

index f8ea09a..0db940c 100644 (file)
@@ -821,17 +821,156 @@ PlatformEarlyInitEntry (
   EFI_PEI_HOB_POINTERS        Hob;\r
   EFI_PLATFORM_CPU_INFO       PlatformCpuInfo;\r
   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *DescriptorBlock;\r
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *NewDescriptorBlock;\r
+  UINTN                           Index;\r
+  UINTN                           MaxIndex;\r
+  UINT64                          Base;\r
   UINT64                          Size;\r
+  UINT64                          NewSize;\r
 \r
   //\r
-  // Make sure last SMRAM region is aligned\r
+  // Make sure base and size of the SMRAM region is aligned\r
   //\r
   Hob.Raw = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
   if (Hob.Raw != NULL) {\r
     DescriptorBlock = GET_GUID_HOB_DATA (Hob.Raw);\r
-    Size = DescriptorBlock->Descriptor[DescriptorBlock->NumberOfSmmReservedRegions - 1].PhysicalSize;\r
-    Size = LShiftU64 (1, HighBitSet64 (Size - 1) + 1);\r
-    DescriptorBlock->Descriptor[DescriptorBlock->NumberOfSmmReservedRegions - 1].PhysicalSize = Size;\r
+    DEBUG ((DEBUG_INFO, "SMM PEI SMRAM Memory Reserved HOB\n"));\r
+    for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+      DEBUG((DEBUG_INFO, "  SMRAM Descriptor[%02x]: Start=%016lx  Size=%016lx  State=%02x\n",\r
+        Index,\r
+        DescriptorBlock->Descriptor[Index].PhysicalStart,\r
+        DescriptorBlock->Descriptor[Index].PhysicalSize,\r
+        DescriptorBlock->Descriptor[Index].RegionState\r
+        ));\r
+    }\r
+\r
+    //\r
+    // Find the largest usable range of SMRAM between 1MB and 4GB\r
+    //\r
+    for (Index = 0, MaxIndex = 0, Size = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+      //\r
+      // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
+      //\r
+      if ((DescriptorBlock->Descriptor[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
+        continue;\r
+      }\r
+      //\r
+      // Skip any SMRAM region below 1MB\r
+      //\r
+      if (DescriptorBlock->Descriptor[Index].CpuStart < BASE_1MB) {\r
+        continue;\r
+      }\r
+      //\r
+      // Skip any SMRAM region that is above 4GB or crosses the 4GB boundary\r
+      //\r
+      if ((DescriptorBlock->Descriptor[Index].CpuStart + DescriptorBlock->Descriptor[Index].PhysicalSize) >= BASE_4GB) {\r
+        continue;\r
+      }\r
+      //\r
+      // Cache the largest SMRAM region index\r
+      //\r
+      if (DescriptorBlock->Descriptor[Index].PhysicalSize >= DescriptorBlock->Descriptor[MaxIndex].PhysicalSize) {\r
+        MaxIndex = Index;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Find the extent of the contiguous SMRAM region that surrounds the largest usable SMRAM range\r
+    //\r
+    Base = DescriptorBlock->Descriptor[MaxIndex].CpuStart;\r
+    Size = DescriptorBlock->Descriptor[MaxIndex].PhysicalSize;\r
+    for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+      if (DescriptorBlock->Descriptor[Index].CpuStart < Base &&\r
+          Base == (DescriptorBlock->Descriptor[Index].CpuStart + DescriptorBlock->Descriptor[Index].PhysicalSize)) {\r
+        Base  = DescriptorBlock->Descriptor[Index].CpuStart;\r
+        Size += DescriptorBlock->Descriptor[Index].PhysicalSize;\r
+      } else if ((Base + Size) == DescriptorBlock->Descriptor[Index].CpuStart) {\r
+        Size += DescriptorBlock->Descriptor[Index].PhysicalSize;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Round SMRAM region up to nearest power of 2 that is at least 4KB\r
+    //\r
+    NewSize = MAX (LShiftU64 (1, HighBitSet64 (Size - 1) + 1), SIZE_4KB);\r
+    if ((Base & ~(NewSize - 1)) != Base) {\r
+      //\r
+      // SMRAM region Base Address has smaller alignment than SMRAM region Size\r
+      // This is not compatible with SMRR settings\r
+      //\r
+      DEBUG((DEBUG_ERROR, "ERROR: SMRAM Region Size has larger alignment than SMRAM Region Base\n"));\r
+      DEBUG((DEBUG_ERROR, "  SMRAM Region Base=%016lx  Size=%016lx\n", Base, NewSize));\r
+      ASSERT (FALSE);\r
+    } else if (Size != NewSize) {\r
+      //\r
+      // See if the size difference can be added to an adjacent descriptor that is already allocated\r
+      //\r
+      for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+        if ((DescriptorBlock->Descriptor[Index].CpuStart + DescriptorBlock->Descriptor[Index].PhysicalSize) == (Base + Size)) {\r
+          if (((DescriptorBlock->Descriptor[Index].RegionState) & EFI_ALLOCATED) != 0) {\r
+            DescriptorBlock->Descriptor[Index].PhysicalSize += (NewSize - Size);\r
+            Size = NewSize;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+\r
+      if (Size != NewSize) {\r
+        //\r
+        // Add an allocated descriptor to the SMM PEI SMRAM Memory Reserved HOB to accomodate the larger size.\r
+        //\r
+        Index = DescriptorBlock->NumberOfSmmReservedRegions;\r
+        NewDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)BuildGuidHob (\r
+          &gEfiSmmPeiSmramMemoryReserveGuid,\r
+          sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + ((Index + 1) * sizeof (EFI_SMRAM_DESCRIPTOR))\r
+          );\r
+        ASSERT (NewDescriptorBlock != NULL);\r
+\r
+        //\r
+        // Copy old EFI_SMRAM_HOB_DESCRIPTOR_BLOCK to new allocated region\r
+        //\r
+        CopyMem (\r
+          NewDescriptorBlock,\r
+          DescriptorBlock,\r
+          sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + (Index * sizeof (EFI_SMRAM_DESCRIPTOR))\r
+          );\r
+\r
+        //\r
+        // Make sure last descriptor in NewDescriptorBlock contains last descriptor from DescriptorBlock\r
+        //\r
+        CopyMem (\r
+          &NewDescriptorBlock->Descriptor[Index],\r
+          &NewDescriptorBlock->Descriptor[Index - 1],\r
+          sizeof (EFI_SMRAM_DESCRIPTOR)\r
+          );\r
+\r
+        //\r
+        // Fill next to last descriptor with an allocated descriptor that aligns the total size of SMRAM\r
+        //\r
+        NewDescriptorBlock->Descriptor[Index - 1].CpuStart      = Base + Size;\r
+        NewDescriptorBlock->Descriptor[Index - 1].PhysicalStart = Base + Size;\r
+        NewDescriptorBlock->Descriptor[Index - 1].PhysicalSize  = NewSize - Size;\r
+        NewDescriptorBlock->Descriptor[Index - 1].RegionState   = DescriptorBlock->Descriptor[MaxIndex].RegionState | EFI_ALLOCATED;\r
+        NewDescriptorBlock->NumberOfSmmReservedRegions++;\r
+\r
+        //\r
+        // Invalidate the original gEfiSmmPeiSmramMemoryReserveGuid HOB\r
+        //\r
+        ZeroMem (&Hob.Guid->Name, sizeof (&Hob.Guid->Name));\r
+      }\r
+\r
+      Hob.Raw = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
+      DescriptorBlock = GET_GUID_HOB_DATA (Hob.Raw);\r
+      DEBUG ((DEBUG_INFO, "SMM PEI SMRAM Memory Reserved HOB - Updated\n"));\r
+      for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+        DEBUG((DEBUG_INFO, "  SMRAM Descriptor[%02x]: Start=%016lx  Size=%016lx  State=%02x\n",\r
+          Index,\r
+          DescriptorBlock->Descriptor[Index].PhysicalStart,\r
+          DescriptorBlock->Descriptor[Index].PhysicalSize,\r
+          DescriptorBlock->Descriptor[Index].RegionState\r
+          ));\r
+      }\r
+    }\r
   }\r
 \r
   //\r