]> git.proxmox.com Git - mirror_edk2.git/commitdiff
IntelFrameworkModulePkg: Add AcpiS3SaveDxe driver
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 31 Aug 2011 18:57:46 +0000 (18:57 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 31 Aug 2011 18:57:46 +0000 (18:57 +0000)
Signed-off-by: jljusten
Reviewed-by: rsun3
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12246 6f19259b-4bc3-4df7-8a09-765794883524

IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf [new file with mode: 0644]
IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c [new file with mode: 0644]

index 39a6adda960dfdd6d0179f88aa29b60659105d6e..bd26806d21508d81da28c7e19064bbd7761e9d01 100644 (file)
@@ -81,6 +81,9 @@
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf\r
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
 \r
+[LibraryClasses.common.DXE_DRIVER]\r
+  LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r
+\r
 [LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER]\r
   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
   IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf\r
   IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf\r
 \r
+[Components.IA32,Components.X64]\r
+  IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf\r
+\r
 [Components.IA32,Components.X64,Components.IPF]\r
   IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf\r
   \r
diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c
new file mode 100644 (file)
index 0000000..73074a2
--- /dev/null
@@ -0,0 +1,485 @@
+/** @file\r
+  This is an implementation of the ACPI S3 Save protocol.  This is defined in\r
+  S3 boot path specification 0.9.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Guid/AcpiVariableCompatibility.h>\r
+#include <Guid/AcpiS3Context.h>\r
+#include <Guid/Acpi.h>\r
+#include <Protocol/AcpiS3Save.h>\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+#include "AcpiS3Save.h"\r
+\r
+/**\r
+  Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.\r
+**/\r
+VOID\r
+InstallAcpiS3SaveThunk (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Hook point for AcpiVariableThunkPlatform for S3Ready.\r
+\r
+  @param AcpiS3Context   ACPI s3 context\r
+**/\r
+VOID\r
+S3ReadyThunkPlatform (\r
+  IN ACPI_S3_CONTEXT      *AcpiS3Context\r
+  );\r
+\r
+UINTN     mLegacyRegionSize;\r
+\r
+EFI_ACPI_S3_SAVE_PROTOCOL mS3Save = {\r
+  LegacyGetS3MemorySize,\r
+  S3Ready,\r
+};\r
+\r
+EFI_GUID              mAcpiS3IdtrProfileGuid = {\r
+  0xdea652b0, 0xd587, 0x4c54, 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d\r
+};\r
+\r
+/**\r
+  Allocate EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  @param  Size         Size of memory to allocate.\r
+  \r
+  @return Allocated address for output.\r
+\r
+**/\r
+VOID*\r
+AllocateAcpiNvsMemoryBelow4G (\r
+  IN   UINTN   Size\r
+  )\r
+{\r
+  UINTN                 Pages;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  EFI_STATUS            Status;\r
+  VOID*                 Buffer;\r
+\r
+  Pages = EFI_SIZE_TO_PAGES (Size);\r
+  Address = 0xffffffff;\r
+\r
+  Status  = gBS->AllocatePages (\r
+                   AllocateMaxAddress,\r
+                   EfiACPIMemoryNVS,\r
+                   Pages,\r
+                   &Address\r
+                   );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Buffer = (VOID *) (UINTN) Address;\r
+  ZeroMem (Buffer, Size);\r
+\r
+  return Buffer;\r
+}\r
+\r
+/**\r
+  To find Facs in Acpi tables.\r
\r
+  To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored \r
+  in the table.\r
+\r
+  @param AcpiTableGuid   The guid used to find ACPI table in UEFI ConfigurationTable.\r
+  \r
+  @return  Facs table pointer.\r
+**/\r
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *\r
+FindAcpiFacsTableByAcpiGuid (\r
+  IN EFI_GUID  *AcpiTableGuid\r
+  )\r
+{\r
+  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;\r
+  EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;\r
+  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;\r
+  UINTN                                         Index;\r
+  UINT32                                        Data32;\r
+  Rsdp  = NULL;\r
+  Rsdt  = NULL;\r
+  Fadt  = NULL;\r
+  //\r
+  // found ACPI table RSD_PTR from system table\r
+  //\r
+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+    if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {\r
+      //\r
+      // A match was found.\r
+      //\r
+      Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Rsdp == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;\r
+  if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) {\r
+\r
+    Data32  = *(UINT32 *) ((UINT8 *) Rsdt + Index);\r
+    Fadt    = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32;\r
+    if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+\r
+  Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;\r
+\r
+  return Facs;\r
+}\r
+\r
+/**\r
+  To find Facs in Acpi tables.\r
\r
+  To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored \r
+  in the table.\r
+  \r
+  @return  Facs table pointer.\r
+**/\r
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *\r
+FindAcpiFacsTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
+\r
+  Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);\r
+  if (Facs != NULL) {\r
+    return Facs;\r
+  }\r
+\r
+  return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);\r
+}\r
+\r
+/**\r
+  Allocates and fills in the Page Directory and Page Table Entries to\r
+  establish a 1:1 Virtual to Physical mapping.\r
+  If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1 \r
+  virtual to physical mapping page table.\r
+  If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. \r
+  \r
+  @return  the 1:1 Virtual to Physical identity mapping page table base address. \r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+S3CreateIdentityMappingPageTables (\r
+  VOID\r
+  )\r
+{  \r
+  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+    UINT32                                        RegEax;\r
+    UINT8                                         PhysicalAddressBits;\r
+    EFI_PHYSICAL_ADDRESS                          PageAddress;\r
+    UINTN                                         IndexOfPml4Entries;\r
+    UINTN                                         IndexOfPdpEntries;\r
+    UINTN                                         IndexOfPageDirectoryEntries;\r
+    UINTN                                         NumberOfPml4EntriesNeeded;\r
+    UINTN                                         NumberOfPdpEntriesNeeded;\r
+    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel4Entry;\r
+    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;\r
+    PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;\r
+    PAGE_TABLE_ENTRY                              *PageDirectoryEntry;\r
+    EFI_PHYSICAL_ADDRESS                          S3NvsPageTableAddress;\r
+    UINTN                                         TotalPageTableSize;\r
+\r
+    //\r
+    // Get physical address bits supported.\r
+    //\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000008) {\r
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+      PhysicalAddressBits = (UINT8) RegEax;\r
+    } else {\r
+      PhysicalAddressBits = 36;\r
+    }\r
+    \r
+    //\r
+    // Calculate the table entries needed.\r
+    //\r
+    if (PhysicalAddressBits <= 39 ) {\r
+      NumberOfPml4EntriesNeeded = 1;\r
+      NumberOfPdpEntriesNeeded = (UINTN)LShiftU64 (1, (PhysicalAddressBits - 30));\r
+    } else {\r
+      NumberOfPml4EntriesNeeded = (UINTN)LShiftU64 (1, (PhysicalAddressBits - 39));\r
+      NumberOfPdpEntriesNeeded = 512;\r
+    }\r
+\r
+    //\r
+    // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.\r
+    //\r
+    TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);\r
+    DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %x pages\n", TotalPageTableSize));\r
+\r
+    //\r
+    // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.\r
+    //\r
+    S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE(TotalPageTableSize));\r
+    ASSERT (S3NvsPageTableAddress != 0);\r
+    PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN)S3NvsPageTableAddress;\r
+    S3NvsPageTableAddress += SIZE_4KB;\r
+\r
+    PageMapLevel4Entry = PageMap;\r
+    PageAddress        = 0;\r
+    for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+      //\r
+      // Each PML4 entry points to a page of Page Directory Pointer entires.\r
+      // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.\r
+      //\r
+      PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN)S3NvsPageTableAddress;\r
+      S3NvsPageTableAddress += SIZE_4KB;\r
+      //\r
+      // Make a PML4 Entry\r
+      //\r
+      PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;\r
+      PageMapLevel4Entry->Bits.ReadWrite = 1;\r
+      PageMapLevel4Entry->Bits.Present = 1;\r
+    \r
+      for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+        //\r
+        // Each Directory Pointer entries points to a page of Page Directory entires.\r
+        // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
+        //       \r
+        PageDirectoryEntry = (PAGE_TABLE_ENTRY *)(UINTN)S3NvsPageTableAddress;\r
+        S3NvsPageTableAddress += SIZE_4KB;\r
+    \r
+        //\r
+        // Fill in a Page Directory Pointer Entries\r
+        //\r
+        PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;\r
+        PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
+        PageDirectoryPointerEntry->Bits.Present = 1;\r
+    \r
+        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += 0x200000) {\r
+          //\r
+          // Fill in the Page Directory entries\r
+          //\r
+          PageDirectoryEntry->Uint64 = (UINT64)PageAddress;\r
+          PageDirectoryEntry->Bits.ReadWrite = 1;\r
+          PageDirectoryEntry->Bits.Present = 1;\r
+          PageDirectoryEntry->Bits.MustBe1 = 1;\r
+        }\r
+      }\r
+    }\r
+    return (EFI_PHYSICAL_ADDRESS) (UINTN) PageMap;\r
+  } else {\r
+    //\r
+    // If DXE is running 32-bit mode, no need to establish page table.\r
+    //\r
+    return  (EFI_PHYSICAL_ADDRESS) 0;  \r
+  }\r
+}\r
+\r
+/**\r
+  Gets the buffer of legacy memory below 1 MB \r
+  This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.\r
+\r
+  @param This           A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.\r
+  @param Size           The returned size of legacy memory below 1 MB.\r
+\r
+  @retval EFI_SUCCESS           Size is successfully returned.\r
+  @retval EFI_INVALID_PARAMETER The pointer Size is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyGetS3MemorySize (\r
+  IN  EFI_ACPI_S3_SAVE_PROTOCOL   *This,\r
+  OUT UINTN                       *Size\r
+  )\r
+{\r
+  if (Size == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Size = mLegacyRegionSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Prepares all information that is needed in the S3 resume boot path.\r
+  \r
+  Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path  \r
+  \r
+  @param This                 A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.\r
+  @param LegacyMemoryAddress  The base address of legacy memory.\r
+\r
+  @retval EFI_NOT_FOUND         Some necessary information cannot be found.\r
+  @retval EFI_SUCCESS           All information was saved successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Resources were insufficient to save all the information.\r
+  @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+S3Ready (\r
+  IN EFI_ACPI_S3_SAVE_PROTOCOL    *This,\r
+  IN VOID                         *LegacyMemoryAddress\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_PHYSICAL_ADDRESS                          AcpiS3ContextBuffer;\r
+  ACPI_S3_CONTEXT                               *AcpiS3Context;\r
+  STATIC BOOLEAN                                AlreadyEntered;\r
+  IA32_DESCRIPTOR                               *Idtr;\r
+  IA32_IDT_GATE_DESCRIPTOR                      *IdtGate;\r
+\r
+  DEBUG ((EFI_D_INFO, "S3Ready!\n"));\r
+\r
+  //\r
+  // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.\r
+  // So if 2nd S3Save() is triggered later, we need ignore it.\r
+  //\r
+  if (AlreadyEntered) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  AlreadyEntered = TRUE;\r
+\r
+  AcpiS3Context = AllocateAcpiNvsMemoryBelow4G (sizeof(*AcpiS3Context));\r
+  ASSERT (AcpiS3Context != NULL);\r
+  AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
+\r
+  //\r
+  // Get ACPI Table because we will save its position to variable\r
+  //\r
+  AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable ();\r
+  ASSERT (AcpiS3Context->AcpiFacsTable != 0);\r
+\r
+  IdtGate = AllocateAcpiNvsMemoryBelow4G (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));\r
+  Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);\r
+  Idtr->Base  = (UINTN)IdtGate;\r
+  Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);\r
+  AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;\r
+\r
+  Status = SaveLockBox (\r
+             &mAcpiS3IdtrProfileGuid,\r
+             (VOID *)(UINTN)Idtr,\r
+             (UINTN)sizeof(IA32_DESCRIPTOR)\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Allocate page table\r
+  //\r
+  AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables ();\r
+\r
+  //\r
+  // Allocate stack\r
+  //\r
+  AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);\r
+  AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3BootScriptStackSize));\r
+  ASSERT (AcpiS3Context->BootScriptStackBase != 0);\r
+\r
+  //\r
+  // Allocate a code buffer < 4G for S3 debug to load external code\r
+  //\r
+  AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGE_SIZE);\r
+\r
+  DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));\r
+  DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));\r
+  DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));\r
+  DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));\r
+\r
+  Status = SaveLockBox (\r
+             &gEfiAcpiVariableGuid,\r
+             &AcpiS3ContextBuffer,\r
+             sizeof(AcpiS3ContextBuffer)\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SaveLockBox (\r
+             &gEfiAcpiS3ContextGuid,\r
+             (VOID *)(UINTN)AcpiS3Context,\r
+             (UINTN)sizeof(*AcpiS3Context)\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {\r
+    S3ReadyThunkPlatform (AcpiS3Context);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The Driver Entry Point.\r
+  \r
+  The function is the driver Entry point which will produce AcpiS3SaveProtocol.\r
+  \r
+  @param ImageHandle   A handle for the image that is initializing this driver\r
+  @param SystemTable   A pointer to the EFI system table\r
+\r
+  @retval EFI_SUCCESS:              Driver initialized successfully\r
+  @retval EFI_LOAD_ERROR:           Failed to Initialize or has been loaded\r
+  @retval EFI_OUT_OF_RESOURCES      Could not allocate needed resources\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InstallAcpiS3Save (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+\r
+  if (!FeaturePcdGet(PcdPlatformCsmSupport)) {\r
+    //\r
+    // More memory for no CSM tip, because GDT need relocation\r
+    //\r
+    mLegacyRegionSize = 0x250;\r
+  } else {\r
+    mLegacyRegionSize = 0x100;\r
+  }\r
+\r
+  if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {\r
+    InstallAcpiS3SaveThunk ();\r
+  }\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &ImageHandle,\r
+                  &gEfiAcpiS3SaveProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mS3Save\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  return Status;\r
+}\r
diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h
new file mode 100644 (file)
index 0000000..d9bbe93
--- /dev/null
@@ -0,0 +1,135 @@
+/** @file\r
+  This is an implementation of the ACPI S3 Save protocol.  This is defined in \r
+  S3 boot path specification 0.9.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _ACPI_S3_SAVE_H_\r
+#define _ACPI_S3_SAVE_H_\r
+\r
+#pragma pack(push, 1)\r
+\r
+typedef union {\r
+  struct {\r
+    UINT32  LimitLow    : 16;\r
+    UINT32  BaseLow     : 16;\r
+    UINT32  BaseMid     : 8;\r
+    UINT32  Type        : 4;\r
+    UINT32  System      : 1;\r
+    UINT32  Dpl         : 2;\r
+    UINT32  Present     : 1;\r
+    UINT32  LimitHigh   : 4;\r
+    UINT32  Software    : 1;\r
+    UINT32  Reserved    : 1;\r
+    UINT32  DefaultSize : 1;\r
+    UINT32  Granularity : 1;\r
+    UINT32  BaseHigh    : 8;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} IA32_GDT;\r
+\r
+typedef struct {\r
+  IA32_IDT_GATE_DESCRIPTOR  Ia32IdtEntry;\r
+  UINT32                    Offset32To63;\r
+  UINT32                    Reserved;\r
+} X64_IDT_GATE_DESCRIPTOR;\r
+\r
+//\r
+// Page-Map Level-4 Offset (PML4) and\r
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB\r
+//\r
+\r
+typedef union {\r
+  struct {\r
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory\r
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write\r
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User\r
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching\r
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached\r
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)\r
+    UINT64  Reserved:1;               // Reserved\r
+    UINT64  MustBeZero:2;             // Must Be Zero\r
+    UINT64  Available:3;              // Available for use by system software\r
+    UINT64  PageTableBaseAddress:40;  // Page Table Base Address\r
+    UINT64  AvabilableHigh:11;        // Available for use by system software\r
+    UINT64  Nx:1;                     // No Execute bit\r
+  } Bits;\r
+  UINT64    Uint64;\r
+} PAGE_MAP_AND_DIRECTORY_POINTER;\r
+\r
+//\r
+// Page Table Entry 2MB\r
+//\r
+typedef union {\r
+  struct {\r
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory\r
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write\r
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User\r
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching\r
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached\r
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)\r
+    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page\r
+    UINT64  MustBe1:1;                // Must be 1 \r
+    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write\r
+    UINT64  Available:3;              // Available for use by system software\r
+    UINT64  PAT:1;                    //\r
+    UINT64  MustBeZero:8;             // Must be zero;\r
+    UINT64  PageTableBaseAddress:31;  // Page Table Base Address\r
+    UINT64  AvabilableHigh:11;        // Available for use by system software\r
+    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution\r
+  } Bits;\r
+  UINT64    Uint64;\r
+} PAGE_TABLE_ENTRY;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+  Gets the buffer of legacy memory below 1 MB \r
+  This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.\r
+\r
+  @param This           A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.\r
+  @param Size           The returned size of legacy memory below 1 MB.\r
+\r
+  @retval EFI_SUCCESS           Size is successfully returned.\r
+  @retval EFI_INVALID_PARAMETER The pointer Size is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyGetS3MemorySize (\r
+  IN  EFI_ACPI_S3_SAVE_PROTOCOL    * This,\r
+  OUT UINTN                        * Size\r
+  );\r
+\r
+/**\r
+  Prepares all information that is needed in the S3 resume boot path.\r
+  \r
+  Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path  \r
+  \r
+  @param This                 A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.\r
+  @param LegacyMemoryAddress  The base address of legacy memory.\r
+\r
+  @retval EFI_NOT_FOUND         Some necessary information cannot be found.\r
+  @retval EFI_SUCCESS           All information was saved successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Resources were insufficient to save all the information.\r
+  @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+S3Ready (\r
+  IN EFI_ACPI_S3_SAVE_PROTOCOL     *This,\r
+  IN VOID                          *LegacyMemoryAddress   \r
+  );\r
+#endif\r
diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
new file mode 100644 (file)
index 0000000..24a526d
--- /dev/null
@@ -0,0 +1,83 @@
+## @file\r
+# Component description file for AcpiS3Save module.\r
+#\r
+# This is an implementation of the ACPI S3 Save protocol.\r
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are\r
+# licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = AcpiS3SaveDxe\r
+  FILE_GUID                      = 2BDED685-F733-455f-A840-43A22B791FB3\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InstallAcpiS3Save\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  AcpiS3Save.h\r
+  AcpiS3Save.c\r
+  AcpiVariableThunkPlatform.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  PcdLib\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  HobLib\r
+  UefiLib\r
+  LockBoxLib\r
+  DebugLib\r
+  DxeServicesLib\r
+\r
+[Guids]\r
+  gEfiAcpiVariableGuid                          # ALWAYS_CONSUMED\r
+  gEfiAcpiS3ContextGuid                         # ALWAYS_CONSUMED\r
+  gEfiAcpiVariableCompatiblityGuid              # SOMETIME_CONSUMED L"AcpiGlobalVariable"\r
+  gEfiAcpi20TableGuid                           # ALWAYS_CONSUMED  System Table\r
+  gEfiAcpi10TableGuid                           # ALWAYS_CONSUMED  System Table\r
+\r
+[Protocols]\r
+  gEfiAcpiS3SaveProtocolGuid                    # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiLegacyBiosProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiLegacyRegion2ProtocolGuid                 # PROTOCOL SOMETIMES_CONSUMED\r
+  gFrameworkEfiMpServiceProtocolGuid            # PROTOCOL SOMETIMES_CONSUMED\r
+\r
+[FeaturePcd]\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport          ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport          ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode\r
+\r
+[Pcd]\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3AcpiReservedMemorySize    ## CONSUMES\r
+  gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize       ## CONSUMES\r
+\r
+[Depex]\r
+  #\r
+  # Note: the extra dependency of gEfiMpServiceProtocolGuid is to ensure that ACPI variable is set by MpDxe driver before\r
+  # AcpiS3SaveDxe module is executed. \r
+  #\r
+  gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid AND gEfiMpServiceProtocolGuid\r
+  \r
diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c
new file mode 100644 (file)
index 0000000..883b790
--- /dev/null
@@ -0,0 +1,166 @@
+/** @file\r
+  This is an implementation of the AcpiVariable platform field for ECP platform.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+==\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS  AcpiReservedMemoryBase;  <<===\r
+  UINT32                AcpiReservedMemorySize;  <<===\r
+  EFI_PHYSICAL_ADDRESS  S3ReservedLowMemoryBase;\r
+  EFI_PHYSICAL_ADDRESS  AcpiBootScriptTable;\r
+  EFI_PHYSICAL_ADDRESS  RuntimeScriptTableBase;\r
+  EFI_PHYSICAL_ADDRESS  AcpiFacsTable;\r
+  UINT64                SystemMemoryLength;      <<===\r
+  ACPI_CPU_DATA_COMPATIBILITY         AcpiCpuData;\r
+  EFI_PHYSICAL_ADDRESS  VideoOpromAddress;\r
+  UINT32                VideoOpromSize;\r
+  EFI_PHYSICAL_ADDRESS  S3DebugBufferAddress; \r
+  EFI_PHYSICAL_ADDRESS  S3ResumeNvsEntryPoint;    \r
+} ACPI_VARIABLE_SET_COMPATIBILITY;\r
+\r
+**/\r
+\r
+#include <FrameworkDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Protocol/FrameworkMpService.h>\r
+#include <Guid/AcpiVariableCompatibility.h>\r
+#include <Guid/AcpiS3Context.h>\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+ACPI_VARIABLE_SET_COMPATIBILITY               *mAcpiVariableSetCompatibility = NULL;\r
+\r
+/**\r
+  Allocate EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  @param  Size         Size of memory to allocate.\r
+  \r
+  @return Allocated address for output.\r
+\r
+**/\r
+VOID*\r
+AllocateAcpiNvsMemoryBelow4G (\r
+  IN   UINTN   Size\r
+  );\r
+\r
+/**\r
+  Hook point for AcpiVariableThunkPlatform for S3Ready.\r
+\r
+  @param AcpiS3Context   ACPI s3 context\r
+**/\r
+VOID\r
+S3ReadyThunkPlatform (\r
+  IN ACPI_S3_CONTEXT      *AcpiS3Context\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS                          AcpiMemoryBase;\r
+  UINT32                                        AcpiMemorySize;\r
+  EFI_PEI_HOB_POINTERS                          Hob;\r
+  UINT64                                        MemoryLength;\r
+\r
+  DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n"));\r
+\r
+  //\r
+  // Allocate ACPI reserved memory under 4G\r
+  //\r
+  AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize));\r
+  ASSERT (AcpiMemoryBase != 0);\r
+  AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);\r
+\r
+  //\r
+  // Calculate the system memory length by memory hobs\r
+  //\r
+  MemoryLength  = 0x100000;\r
+  Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
+  ASSERT (Hob.Raw != NULL);\r
+  while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {\r
+    if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+      //\r
+      // Skip the memory region below 1MB\r
+      //\r
+      if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {\r
+        MemoryLength += Hob.ResourceDescriptor->ResourceLength;\r
+      }\r
+    }\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
+  }\r
+\r
+  mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase;\r
+  mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize;\r
+  mAcpiVariableSetCompatibility->SystemMemoryLength     = MemoryLength;\r
+\r
+  DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase));\r
+  DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize));\r
+  DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength));\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.\r
+**/\r
+VOID\r
+InstallAcpiS3SaveThunk (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  FRAMEWORK_EFI_MP_SERVICES_PROTOCOL   *FrameworkMpService;\r
+  UINTN                                VarSize;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gFrameworkEfiMpServiceProtocolGuid,\r
+                  NULL,\r
+                  (VOID**) &FrameworkMpService\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set \r
+    // should be produced by CPU driver. \r
+    //\r
+    VarSize = sizeof (mAcpiVariableSetCompatibility);\r
+    Status = gRT->GetVariable (\r
+                    ACPI_GLOBAL_VARIABLE,\r
+                    &gEfiAcpiVariableCompatiblityGuid,\r
+                    NULL,\r
+                    &VarSize,\r
+                    &mAcpiVariableSetCompatibility\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    //\r
+    // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform \r
+    // driver need this variable\r
+    //\r
+    mAcpiVariableSetCompatibility = AllocateAcpiNvsMemoryBelow4G (sizeof(ACPI_VARIABLE_SET_COMPATIBILITY));\r
+    Status = gRT->SetVariable (\r
+                    ACPI_GLOBAL_VARIABLE,\r
+                    &gEfiAcpiVariableCompatiblityGuid,\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                    sizeof(mAcpiVariableSetCompatibility),\r
+                    &mAcpiVariableSetCompatibility\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility));\r
+}\r