]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/SmmControl2Dxe/SmiFeatures.c
OvmfPkg/SmmControl2Dxe: save fw_cfg boot script with QemuFwCfgS3Lib
[mirror_edk2.git] / OvmfPkg / SmmControl2Dxe / SmiFeatures.c
index bd257f15d955f5e72f2b53d6dfbb4c89bd72d5d0..7c2cbd86ee6284c5cc1a0beed6c59a22dcfc9388 100644 (file)
@@ -18,6 +18,7 @@
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
+#include <Library/QemuFwCfgS3Lib.h>\r
 \r
 #include "SmiFeatures.h"\r
 \r
 \r
 //\r
 // Provides a scratch buffer (allocated in EfiReservedMemoryType type memory)\r
-// for the S3 boot script fragment to write to and read from. The buffer\r
-// captures a combined fw_cfg item selection + write command using the DMA\r
-// access method. Note that we don't trust the runtime OS to preserve the\r
-// contents of the buffer, the boot script will first rewrite it.\r
+// for the S3 boot script fragment to write to and read from.\r
 //\r
 #pragma pack (1)\r
-typedef struct {\r
-  FW_CFG_DMA_ACCESS Access;\r
-  UINT64            Features;\r
+typedef union {\r
+  UINT64 Features;\r
+  UINT8  FeaturesOk;\r
 } SCRATCH_BUFFER;\r
 #pragma pack ()\r
 \r
 //\r
 // These carry the selector keys of the "etc/smi/requested-features" and\r
 // "etc/smi/features-ok" fw_cfg files from NegotiateSmiFeatures() to\r
-// SaveSmiFeatures().\r
+// AppendFwCfgBootScript().\r
 //\r
 STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem;\r
 STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem;\r
 \r
 //\r
 // Carries the negotiated SMI features from NegotiateSmiFeatures() to\r
-// SaveSmiFeatures().\r
+// AppendFwCfgBootScript().\r
 //\r
 STATIC UINT64 mSmiFeatures;\r
 \r
@@ -168,157 +166,81 @@ FatalError:
 }\r
 \r
 /**\r
-  Append a boot script fragment that will re-select the previously negotiated\r
-  SMI features during S3 resume.\r
-\r
-  @param[in] S3SaveState  The EFI_S3_SAVE_STATE_PROTOCOL instance to append to\r
-                          the S3 boot script with.\r
+  FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.\r
 **/\r
+STATIC\r
 VOID\r
-SaveSmiFeatures (\r
-  IN EFI_S3_SAVE_STATE_PROTOCOL *S3SaveState\r
+EFIAPI\r
+AppendFwCfgBootScript (\r
+  IN OUT VOID *Context,              OPTIONAL\r
+  IN OUT VOID *ExternalScratchBuffer\r
   )\r
 {\r
   SCRATCH_BUFFER *ScratchBuffer;\r
-  EFI_STATUS     Status;\r
-  UINT64         AccessAddress;\r
-  UINT32         ControlPollData;\r
-  UINT32         ControlPollMask;\r
-  UINT16         FeaturesOkItemAsUint16;\r
-  UINT8          FeaturesOkData;\r
-  UINT8          FeaturesOkMask;\r
-\r
-  ScratchBuffer = AllocateReservedPool (sizeof *ScratchBuffer);\r
-  if (ScratchBuffer == NULL) {\r
-    DEBUG ((DEBUG_ERROR, "%a: scratch buffer allocation failed\n",\r
-      __FUNCTION__));\r
-    goto FatalError;\r
-  }\r
-\r
-  //\r
-  // Populate the scratch buffer with a select + write fw_cfg DMA command that\r
-  // will write the negotiated feature bitmap into\r
-  // "etc/smi/requested-features".\r
-  //\r
-  ScratchBuffer->Access.Control = SwapBytes32 (\r
-                                    (UINT32)mRequestedFeaturesItem << 16 |\r
-                                    FW_CFG_DMA_CTL_SELECT |\r
-                                    FW_CFG_DMA_CTL_WRITE\r
-                                    );\r
-  ScratchBuffer->Access.Length = SwapBytes32 (\r
-                                   (UINT32)sizeof ScratchBuffer->Features);\r
-  ScratchBuffer->Access.Address = SwapBytes64 (\r
-                                    (UINTN)&ScratchBuffer->Features);\r
-  ScratchBuffer->Features       = mSmiFeatures;\r
+  RETURN_STATUS  Status;\r
 \r
-  //\r
-  // Copy the scratch buffer into the boot script. When replayed, this\r
-  // EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE will restore the current contents of the\r
-  // scratch buffer, in-place.\r
-  //\r
-  Status = S3SaveState->Write (\r
-                          S3SaveState,                      // This\r
-                          EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE, // OpCode\r
-                          EfiBootScriptWidthUint8,          // Width\r
-                          (UINT64)(UINTN)ScratchBuffer,     // Address\r
-                          sizeof *ScratchBuffer,            // Count\r
-                          (VOID*)ScratchBuffer              // Buffer\r
-                          );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "%a:%d: EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE: %r\n",\r
-      __FUNCTION__, __LINE__, Status));\r
-    goto FatalError;\r
-  }\r
-\r
-  //\r
-  // Append an opcode that will write the address of the scratch buffer to the\r
-  // fw_cfg DMA address register, which consists of two 32-bit IO ports. The\r
-  // second (highest address, least significant) write will start the transfer.\r
-  //\r
-  AccessAddress = SwapBytes64 ((UINTN)&ScratchBuffer->Access);\r
-  Status = S3SaveState->Write (\r
-                          S3SaveState,                     // This\r
-                          EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
-                          EfiBootScriptWidthUint32,        // Width\r
-                          (UINT64)FW_CFG_IO_DMA_ADDRESS,   // Address\r
-                          (UINTN)2,                        // Count\r
-                          &AccessAddress                   // Buffer\r
-                          );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "%a:%d: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
-      __FUNCTION__, __LINE__, Status));\r
-    goto FatalError;\r
-  }\r
+  ScratchBuffer = ExternalScratchBuffer;\r
 \r
   //\r
-  // The EFI_BOOT_SCRIPT_MEM_POLL_OPCODE will wait until the Control word reads\r
-  // as zero (transfer complete). As timeout we use MAX_UINT64 * 100ns, which\r
-  // is approximately 58494 years.\r
+  // Write the negotiated feature bitmap into "etc/smi/requested-features".\r
   //\r
-  ControlPollData = 0;\r
-  ControlPollMask = MAX_UINT32;\r
-  Status = S3SaveState->Write (\r
-                     S3SaveState,                                   // This\r
-                     EFI_BOOT_SCRIPT_MEM_POLL_OPCODE,               // OpCode\r
-                     EfiBootScriptWidthUint32,                      // Width\r
-                     (UINT64)(UINTN)&ScratchBuffer->Access.Control, // Address\r
-                     &ControlPollData,                              // Data\r
-                     &ControlPollMask,                              // DataMask\r
-                     MAX_UINT64                                     // Delay\r
-                     );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "%a:%d: EFI_BOOT_SCRIPT_MEM_POLL_OPCODE: %r\n",\r
-      __FUNCTION__, __LINE__, Status));\r
+  ScratchBuffer->Features = mSmiFeatures;\r
+  Status = QemuFwCfgS3ScriptWriteBytes (mRequestedFeaturesItem,\r
+             sizeof ScratchBuffer->Features);\r
+  if (RETURN_ERROR (Status)) {\r
     goto FatalError;\r
   }\r
 \r
   //\r
-  // Select the "etc/smi/features-ok" fw_cfg file, which invokes the feature\r
-  // validation & lockdown. (The validation succeeded at first boot.)\r
+  // Read back "etc/smi/features-ok". This invokes the feature validation &\r
+  // lockdown. (The validation succeeded at first boot.)\r
   //\r
-  FeaturesOkItemAsUint16 = (UINT16)mFeaturesOkItem;\r
-  Status = S3SaveState->Write (\r
-                          S3SaveState,                     // This\r
-                          EFI_BOOT_SCRIPT_IO_WRITE_OPCODE, // OpCode\r
-                          EfiBootScriptWidthUint16,        // Width\r
-                          (UINT64)FW_CFG_IO_SELECTOR,      // Address\r
-                          (UINTN)1,                        // Count\r
-                          &FeaturesOkItemAsUint16          // Buffer\r
-                          );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "%a:%d: EFI_BOOT_SCRIPT_IO_WRITE_OPCODE: %r\n",\r
-      __FUNCTION__, __LINE__, Status));\r
+  Status = QemuFwCfgS3ScriptReadBytes (mFeaturesOkItem,\r
+             sizeof ScratchBuffer->FeaturesOk);\r
+  if (RETURN_ERROR (Status)) {\r
     goto FatalError;\r
   }\r
 \r
   //\r
-  // Read the contents (one byte) of "etc/smi/features-ok". If the value is\r
-  // one, we're good. Otherwise, continue reading the data port: QEMU returns 0\r
-  // past the end of the fw_cfg item, so this will hang the resume process,\r
-  // which matches our intent.\r
+  // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3\r
+  // resume process.\r
   //\r
-  FeaturesOkData = 1;\r
-  FeaturesOkMask = MAX_UINT8;\r
-  Status = S3SaveState->Write (\r
-                     S3SaveState,                    // This\r
-                     EFI_BOOT_SCRIPT_IO_POLL_OPCODE, // OpCode\r
-                     EfiBootScriptWidthUint8,        // Width\r
-                     (UINT64)(UINTN)FW_CFG_IO_DATA,  // Address\r
-                     &FeaturesOkData,                // Data\r
-                     &FeaturesOkMask,                // DataMask\r
-                     MAX_UINT64                      // Delay\r
-                     );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "%a:%d: EFI_BOOT_SCRIPT_IO_POLL_OPCODE: %r\n",\r
-      __FUNCTION__, __LINE__, Status));\r
+  Status = QemuFwCfgS3ScriptCheckValue (&ScratchBuffer->FeaturesOk,\r
+             sizeof ScratchBuffer->FeaturesOk, MAX_UINT8, 1);\r
+  if (RETURN_ERROR (Status)) {\r
     goto FatalError;\r
   }\r
 \r
-  DEBUG ((DEBUG_VERBOSE, "%a: ScratchBuffer@%p\n", __FUNCTION__,\r
-    (VOID *)ScratchBuffer));\r
+  DEBUG ((DEBUG_VERBOSE, "%a: SMI feature negotiation boot script saved\n",\r
+    __FUNCTION__));\r
   return;\r
 \r
 FatalError:\r
   ASSERT (FALSE);\r
   CpuDeadLoop ();\r
 }\r
+\r
+\r
+/**\r
+  Append a boot script fragment that will re-select the previously negotiated\r
+  SMI features during S3 resume.\r
+**/\r
+VOID\r
+SaveSmiFeatures (\r
+  VOID\r
+  )\r
+{\r
+  RETURN_STATUS Status;\r
+\r
+  //\r
+  // We are already running at TPL_CALLBACK, on the stack of\r
+  // OnS3SaveStateInstalled(). But that's okay, we can easily queue more\r
+  // notification functions while executing a notification function.\r
+  //\r
+  Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript, NULL,\r
+             sizeof (SCRATCH_BUFFER));\r
+  if (RETURN_ERROR (Status)) {\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+}\r