Currently we have the following call chain in OVMF:

  BdsLibBootViaBootOption()
                 [IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c]
    //
    // calls, via AcpiS3Save->S3Save():
    //
    S3Ready()                         [OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c]
      //
      // 1. saves S3 state, then calls:
      //
      SaveS3BootScript()              [OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c]
        //
        // 2. saves INFO opcode in S3 boot script
        // 3. installs DxeSmmReadyToLockProtocol
        //

This call chain was introduced in git commit 5a217a06 (SVN r15305,
"OvmfPkg: S3 Suspend: save boot script after ACPI context"). That patch
was necessary because there was no other way, due to GenericBdsLib calling
S3Save() from BdsLibBootViaBootOption(), to perform the necessary steps in
the right order:
- save S3 system information,
- save a final (well, only) boot script opcode,
- signal DxeSmmReadyToLock, closing the boot script, and locking down
  LockBox and SMM.

This GenericBdsLib bug is going to be fixed in the next patch -- the call
in BdsLibBootViaBootOption() will be eliminated. Also, following Yao
Jiewen's idea, AcpiS3SaveDxe now saves S3 system state on End-of-Dxe as
well (which OVMF's BDS doesn't signal yet).

Therefore, reorganize the call tree as follows:

  PlatformBdsPolicyBehavior()
                            [OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c]
    //
    // signals End-of-Dxe
    //
    OnEndOfDxe()                      [OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c]
      S3Ready()                       [OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c]
        //
        // 1. saves S3 state
        //

    SaveS3BootScript()      [OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c]
      //
      // 2. saves INFO opcode in S3 boot script
      // 3. installs DxeSmmReadyToLockProtocol
      //

The installation of DxeSmmReadyToLockProtocol belongs with Platform BDS,
not AcpiS3SaveDxe, and we can now undo the hack in SVN r15305, without
upsetting the relative order of the steps.

Plus, after the patch OVMF's BDS signals End-of-Dxe (in the right place),
which has additional benefits: variable reclaim, and the splitting of the
memory regions that is part of the recently added UEFI 2.5 properties
table feature.

Note that after the patch, both the new and the old calls to S3Ready()
occur. (The old call will be removed in the next patch.) Luckily, that
function has always been protected against second and later calls with a
static variable.

This patch has been regression tested for S3 suspend and resume, with
Fedora and Windows Server 2012 R2 guests.

Cc: Jordan Justen <jordan.l.jus...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 OvmfPkg/AcpiS3SaveDxe/AcpiS3SaveDxe.inf           |  4 +-
 OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf |  4 +
 OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h      |  4 +
 OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c                | 49 -----------
 OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c      | 86 ++++++++++++++++++++
 5 files changed, 95 insertions(+), 52 deletions(-)

diff --git a/OvmfPkg/AcpiS3SaveDxe/AcpiS3SaveDxe.inf 
b/OvmfPkg/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
index 81da2fb..e657bbe 100644
--- a/OvmfPkg/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
+++ b/OvmfPkg/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
@@ -66,8 +66,6 @@ [Protocols]
   gEfiLegacyBiosProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED
   gEfiLegacyRegion2ProtocolGuid                 # PROTOCOL SOMETIMES_CONSUMED
   gFrameworkEfiMpServiceProtocolGuid            # PROTOCOL SOMETIMES_CONSUMED
-  gEfiS3SaveStateProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED
-  gEfiDxeSmmReadyToLockProtocolGuid             # PROTOCOL ALWAYS_PRODUCED
 
 [FeaturePcd]
   gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport          ## 
CONSUMES
@@ -79,4 +77,4 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
 
 [Depex]
-  gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid AND 
gEfiS3SaveStateProtocolGuid
+  gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
diff --git a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf 
b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
index 5a28d78..f66f51c 100644
--- a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
+++ b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
@@ -64,4 +64,8 @@ [Pcd.IA32, Pcd.X64]
 
 [Protocols]
   gEfiDecompressProtocolGuid
+  gEfiS3SaveStateProtocolGuid                   # PROTOCOL SOMETIMES_CONSUMED
+  gEfiDxeSmmReadyToLockProtocolGuid             # PROTOCOL SOMETIMES_PRODUCED
 
+[Guids]
+  gEfiEndOfDxeEventGroupGuid
diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h 
b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h
index 7006fb3..f451e7e 100644
--- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h
+++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.h
@@ -47,17 +47,21 @@ Abstract:
 #include <Library/DevicePathLib.h>
 #include <Library/IoLib.h>
 #include <Library/NvVarsFileLib.h>
+#include <Library/QemuFwCfgLib.h>
 
 #include <Protocol/Decompress.h>
 #include <Protocol/PciIo.h>
 #include <Protocol/FirmwareVolume2.h>
 #include <Protocol/SimpleFileSystem.h>
+#include <Protocol/S3SaveState.h>
+#include <Protocol/DxeSmmReadyToLock.h>
 
 #include <Guid/Acpi.h>
 #include <Guid/SmBios.h>
 #include <Guid/Mps.h>
 #include <Guid/HobList.h>
 #include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
 
 #include <OvmfPlatforms.h>
 
diff --git a/OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c 
b/OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c
index 5eb33e0..8372db8 100644
--- a/OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c
+++ b/OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c
@@ -31,8 +31,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #include <Guid/Acpi.h>
 #include <Guid/EventGroup.h>
 #include <Protocol/AcpiS3Save.h>
-#include <Protocol/S3SaveState.h>
-#include <Protocol/DxeSmmReadyToLock.h>
 #include <Protocol/LockBox.h>
 #include <IndustryStandard/Acpi.h>
 
@@ -415,48 +413,6 @@ LegacyGetS3MemorySize (
 }
 
 /**
-  Save the S3 boot script.
-
-  Note that we trigger DxeSmmReadyToLock here -- otherwise the script wouldn't
-  be saved actually. Triggering this protocol installation event in turn locks
-  down SMM, so no further changes to LockBoxes or SMRAM are possible
-  afterwards.
-**/
-STATIC
-VOID
-EFIAPI
-SaveS3BootScript (
-  VOID
-  )
-{
-  EFI_STATUS                 Status;
-  EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
-  EFI_HANDLE                 Handle;
-  STATIC CONST UINT8         Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
-
-  Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
-                  (VOID **) &BootScript);
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Despite the opcode documentation in the PI spec, the protocol
-  // implementation embeds a deep copy of the info in the boot script, rather
-  // than storing just a pointer to runtime or NVS storage.
-  //
-  Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
-                         (UINT32) sizeof Info,
-                         (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
-  ASSERT_EFI_ERROR (Status);
-
-  Handle = NULL;
-  Status = gBS->InstallProtocolInterface (&Handle,
-                  &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
-                  NULL);
-  ASSERT_EFI_ERROR (Status);
-}
-
-
-/**
   Prepares all information that is needed in the S3 resume boot path.
   
   Allocate the resources or prepare informations and save in ACPI variable set 
for S3 resume boot path  
@@ -563,11 +519,6 @@ S3Ready (
   Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, 
LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
   ASSERT_EFI_ERROR (Status);
 
-  //
-  // Save the boot script too. Note that this requires/includes emitting the
-  // DxeSmmReadyToLock event, which in turn locks down SMM.
-  //
-  SaveS3BootScript ();
   return EFI_SUCCESS;
 }
 
diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c 
b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
index 1eb2a8b..7440380 100644
--- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
+++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
@@ -1152,6 +1152,68 @@ Returns:
 }
 
 
+/**
+  Empty callback function executed when the EndOfDxe event group is signaled.
+
+  We only need this function because we'd like to signal EndOfDxe, and for that
+  we need to create an event, with a callback function.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  The pointer to the notification function's context, which
+                      is implementation-dependent.
+**/
+STATIC
+VOID
+EFIAPI
+OnEndOfDxe (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+}
+
+
+/**
+  Save the S3 boot script.
+
+  Note that we trigger DxeSmmReadyToLock here -- otherwise the script wouldn't
+  be saved actually. Triggering this protocol installation event in turn locks
+  down SMM, so no further changes to LockBoxes or SMRAM are possible
+  afterwards.
+**/
+STATIC
+VOID
+SaveS3BootScript (
+  VOID
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
+  EFI_HANDLE                 Handle;
+  STATIC CONST UINT8         Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
+
+  Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
+                  (VOID **) &BootScript);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Despite the opcode documentation in the PI spec, the protocol
+  // implementation embeds a deep copy of the info in the boot script, rather
+  // than storing just a pointer to runtime or NVS storage.
+  //
+  Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
+                         (UINT32) sizeof Info,
+                         (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
+  ASSERT_EFI_ERROR (Status);
+
+  Handle = NULL;
+  Status = gBS->InstallProtocolInterface (&Handle,
+                  &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
+                  NULL);
+  ASSERT_EFI_ERROR (Status);
+}
+
+
 VOID
 EFIAPI
 PlatformBdsPolicyBehavior (
@@ -1186,11 +1248,35 @@ Returns:
 {
   EFI_STATUS                         Status;
   EFI_BOOT_MODE                      BootMode;
+  EFI_EVENT                          EndOfDxeEvent;
 
   DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));
 
   ConnectRootBridge ();
 
+  //
+  // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
+  // the preparation of S3 system information. That logic has a hard dependency
+  // on the presence of the FACS ACPI table. Since our ACPI tables are only
+  // installed after PCI enumeration completes, we must not trigger the S3 save
+  // earlier, hence we can't signal End-of-Dxe earlier.
+  //
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, OnEndOfDxe,
+                  NULL /* NotifyContext */, &gEfiEndOfDxeEventGroupGuid,
+                  &EndOfDxeEvent);
+  if (!EFI_ERROR (Status)) {
+    gBS->SignalEvent (EndOfDxeEvent);
+    gBS->CloseEvent (EndOfDxeEvent);
+  }
+
+  if (QemuFwCfgS3Enabled ()) {
+    //
+    // Save the boot script too. Note that this requires/includes emitting the
+    // DxeSmmReadyToLock event, which in turn locks down SMM.
+    //
+    SaveS3BootScript ();
+  }
+
   if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
     DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
       "from disk since flash variables appear to be supported.\n"));
-- 
1.8.3.1



------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors 
network devices and physical & virtual servers, alerts via email & sms 
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to