OVMF's PlatformPei module discovers and installs permanent memory:

InitializePlatform [OvmfPkg/PlatformPei/Platform.c]
  PublishPeiMemory() for Xen | MemDetect() otherwise
    PublishSystemMemory() [MdePkg/.../PeiResourcePublicationLib.c]
      PeiServicesInstallPeiMemory() [MdePkg/.../PeiServicesLib.c]
        PeiInstallPeiMemory() [MdeModulePkg/Core/Pei/.../MemoryServices.c]

This enables PeiDispatcher()
[MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c] via the private
"SwitchStackSignal" flag to migrate the PEI phase's temporary stack and
heap to the permanent memory just discovered.

(OVMF implements said migration in TemporaryRamMigration()
[OvmfPkg/Sec/SecMain.c], exposed through the (optional)
EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI interface.)

The ever-current stack is exposed to the rest of the system through a
memory allocation HOB that is named with a special GUID. The PEI
dispatcher installs this HOB right before migrating the stack / heap from
temporary RAM to permanent RAM:

PeiDispatcher() [MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c]
  BuildStackHob() [MdePkg/Library/PeiHobLib/HobLib.c]
  TemporaryRamMigration() [OvmfPkg/Sec/SecMain.c]

Per default, BuildStackHob() describes the PEI stack/heap as
EfiBootServicesData. It makes sense because the PEI stack and heap are
usually not needed to survive into (or even after) runtime.

However, in OVMF we rewrite the area during S3 Resume (when we repeat the
same temporary RAM migration), hence we must prevent the OS from
repurposing it. Let's look up the HOB and flip the described memory type
to ACPI NVS in TemporaryRamMigration().

(Note that refreshing the preinstalled stack allocation HOB is permitted,
the DXE IPL does it too when not on the S3 resume path):

HandOffToDxeCore()
  UpdateStackHob()

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 OvmfPkg/Sec/SecMain.inf |  4 ++++
 OvmfPkg/Sec/SecMain.c   | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 91d0a44..d0f9455 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -59,6 +59,7 @@
   PeCoffGetEntryPointLib
   PeCoffExtraActionLib
   ExtractGuidedSectionLib
+  HobLib
 
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
@@ -66,3 +67,6 @@
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfMemFvBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfMemFvSize
+
+[Guids]
+  gEfiHobMemoryAllocStackGuid
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 3882dad..77aeffa 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -28,9 +28,12 @@
 #include <Library/PeCoffGetEntryPointLib.h>
 #include <Library/PeCoffExtraActionLib.h>
 #include <Library/ExtractGuidedSectionLib.h>
+#include <Library/HobLib.h>
 
 #include <Ppi/TemporaryRamSupport.h>
 
+#include <Guid/MemoryAllocationHob.h>
+
 #define SEC_IDT_ENTRY_COUNT  34
 
 typedef struct _SEC_IDT_TABLE {
@@ -695,6 +698,31 @@ SecStartupPhase2(
   CpuDeadLoop ();
 }
 
+/**
+  Expand the lifetime of the migrated PEI stack / heap area by changing its
+  allocation type to ACPI NVS.
+**/
+VOID
+EFIAPI
+ReservePermanentFromOs (
+  VOID
+  )
+{
+  EFI_HOB_MEMORY_ALLOCATION *MemHob;
+
+  for (MemHob = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); MemHob != NULL;
+       MemHob = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION,
+                    GET_NEXT_HOB (MemHob))) {
+    if (CompareGuid (&gEfiHobMemoryAllocStackGuid,
+          &MemHob->AllocDescriptor.Name)) {
+      break;
+    }
+  }
+  ASSERT (MemHob != NULL);
+  ASSERT (MemHob->AllocDescriptor.MemoryType == EfiBootServicesData);
+  MemHob->AllocDescriptor.MemoryType = EfiACPIMemoryNVS;
+}
+
 EFI_STATUS
 EFIAPI
 TemporaryRamMigration (
@@ -715,6 +743,13 @@ TemporaryRamMigration (
   
   DEBUG ((EFI_D_ERROR, "TemporaryRamMigration(0x%x, 0x%x, 0x%x)\n", 
(UINTN)TemporaryMemoryBase, (UINTN)PermanentMemoryBase, CopySize));
   
+  //
+  // This pokes into a HOB that's currently in temporary memory itself. Update
+  // it before it is migrated to permanent memory, with the rest of temporary
+  // memory.
+  //
+  ReservePermanentFromOs ();
+
   OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
   NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
   
-- 
1.8.3.1



------------------------------------------------------------------------------
Sponsored by Intel(R) XDK 
Develop, test and display web and hybrid apps with a single code base.
Download it for free now!
http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to