Home | History | Annotate | Download | only in AcpiS3SaveDxe
      1 /** @file
      2   This is an implementation of the ACPI S3 Save protocol.  This is defined in
      3   S3 boot path specification 0.9.
      4 
      5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions
      9 of the BSD License which accompanies this distribution.  The
     10 full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <PiDxe.h>
     19 #include <Library/BaseLib.h>
     20 #include <Library/BaseMemoryLib.h>
     21 #include <Library/UefiBootServicesTableLib.h>
     22 #include <Library/UefiRuntimeServicesTableLib.h>
     23 #include <Library/HobLib.h>
     24 #include <Library/LockBoxLib.h>
     25 #include <Library/PcdLib.h>
     26 #include <Library/DebugLib.h>
     27 #include <Guid/AcpiVariableCompatibility.h>
     28 #include <Guid/AcpiS3Context.h>
     29 #include <Guid/Acpi.h>
     30 #include <Protocol/AcpiS3Save.h>
     31 #include <IndustryStandard/Acpi.h>
     32 
     33 #include "AcpiS3Save.h"
     34 
     35 //
     36 // 8 extra pages for PF handler.
     37 //
     38 #define EXTRA_PAGE_TABLE_PAGES   8
     39 
     40 /**
     41   Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
     42 **/
     43 VOID
     44 InstallAcpiS3SaveThunk (
     45   VOID
     46   );
     47 
     48 /**
     49   Hook point for AcpiVariableThunkPlatform for S3Ready.
     50 
     51   @param AcpiS3Context   ACPI s3 context
     52 **/
     53 VOID
     54 S3ReadyThunkPlatform (
     55   IN ACPI_S3_CONTEXT      *AcpiS3Context
     56   );
     57 
     58 UINTN     mLegacyRegionSize;
     59 
     60 EFI_ACPI_S3_SAVE_PROTOCOL mS3Save = {
     61   LegacyGetS3MemorySize,
     62   S3Ready,
     63 };
     64 
     65 EFI_GUID              mAcpiS3IdtrProfileGuid = {
     66   0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
     67 };
     68 
     69 /**
     70   Allocate memory below 4G memory address.
     71 
     72   This function allocates memory below 4G memory address.
     73 
     74   @param  MemoryType   Memory type of memory to allocate.
     75   @param  Size         Size of memory to allocate.
     76 
     77   @return Allocated address for output.
     78 
     79 **/
     80 VOID*
     81 AllocateMemoryBelow4G (
     82   IN EFI_MEMORY_TYPE    MemoryType,
     83   IN UINTN              Size
     84   )
     85 {
     86   UINTN                 Pages;
     87   EFI_PHYSICAL_ADDRESS  Address;
     88   EFI_STATUS            Status;
     89   VOID*                 Buffer;
     90 
     91   Pages = EFI_SIZE_TO_PAGES (Size);
     92   Address = 0xffffffff;
     93 
     94   Status  = gBS->AllocatePages (
     95                    AllocateMaxAddress,
     96                    MemoryType,
     97                    Pages,
     98                    &Address
     99                    );
    100   ASSERT_EFI_ERROR (Status);
    101 
    102   Buffer = (VOID *) (UINTN) Address;
    103   ZeroMem (Buffer, Size);
    104 
    105   return Buffer;
    106 }
    107 
    108 /**
    109 
    110   This function scan ACPI table in RSDT.
    111 
    112   @param Rsdt      ACPI RSDT
    113   @param Signature ACPI table signature
    114 
    115   @return ACPI table
    116 
    117 **/
    118 VOID *
    119 ScanTableInRSDT (
    120   IN EFI_ACPI_DESCRIPTION_HEADER    *Rsdt,
    121   IN UINT32                         Signature
    122   )
    123 {
    124   UINTN                              Index;
    125   UINT32                             EntryCount;
    126   UINT32                             *EntryPtr;
    127   EFI_ACPI_DESCRIPTION_HEADER        *Table;
    128 
    129   if (Rsdt == NULL) {
    130     return NULL;
    131   }
    132 
    133   EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
    134 
    135   EntryPtr = (UINT32 *)(Rsdt + 1);
    136   for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
    137     Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
    138     if (Table->Signature == Signature) {
    139       return Table;
    140     }
    141   }
    142 
    143   return NULL;
    144 }
    145 
    146 /**
    147 
    148   This function scan ACPI table in XSDT.
    149 
    150   @param Xsdt      ACPI XSDT
    151   @param Signature ACPI table signature
    152 
    153   @return ACPI table
    154 
    155 **/
    156 VOID *
    157 ScanTableInXSDT (
    158   IN EFI_ACPI_DESCRIPTION_HEADER    *Xsdt,
    159   IN UINT32                         Signature
    160   )
    161 {
    162   UINTN                          Index;
    163   UINT32                         EntryCount;
    164   UINT64                         EntryPtr;
    165   UINTN                          BasePtr;
    166   EFI_ACPI_DESCRIPTION_HEADER    *Table;
    167 
    168   if (Xsdt == NULL) {
    169     return NULL;
    170   }
    171 
    172   EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
    173 
    174   BasePtr = (UINTN)(Xsdt + 1);
    175   for (Index = 0; Index < EntryCount; Index ++) {
    176     CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
    177     Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
    178     if (Table->Signature == Signature) {
    179       return Table;
    180     }
    181   }
    182 
    183   return NULL;
    184 }
    185 
    186 /**
    187   To find Facs in FADT.
    188 
    189   @param Fadt   FADT table pointer
    190 
    191   @return  Facs table pointer.
    192 **/
    193 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
    194 FindAcpiFacsFromFadt (
    195   IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt
    196   )
    197 {
    198   EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
    199   UINT64                                        Data64;
    200 
    201   if (Fadt == NULL) {
    202     return NULL;
    203   }
    204 
    205   if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
    206     Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
    207   } else {
    208     if (Fadt->FirmwareCtrl != 0) {
    209       Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
    210     } else {
    211       CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
    212       Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
    213     }
    214   }
    215   return Facs;
    216 }
    217 
    218 /**
    219   To find Facs in Acpi tables.
    220 
    221   To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
    222   in the table.
    223 
    224   @param AcpiTableGuid   The guid used to find ACPI table in UEFI ConfigurationTable.
    225 
    226   @return  Facs table pointer.
    227 **/
    228 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
    229 FindAcpiFacsTableByAcpiGuid (
    230   IN EFI_GUID  *AcpiTableGuid
    231   )
    232 {
    233   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;
    234   EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;
    235   EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
    236   EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;
    237   EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
    238   UINTN                                         Index;
    239 
    240   Rsdp  = NULL;
    241   //
    242   // found ACPI table RSD_PTR from system table
    243   //
    244   for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    245     if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
    246       //
    247       // A match was found.
    248       //
    249       Rsdp = gST->ConfigurationTable[Index].VendorTable;
    250       break;
    251     }
    252   }
    253 
    254   if (Rsdp == NULL) {
    255     return NULL;
    256   }
    257 
    258   //
    259   // Search XSDT
    260   //
    261   if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
    262     Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
    263     Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
    264     if (Fadt != NULL) {
    265       Facs = FindAcpiFacsFromFadt (Fadt);
    266       if (Facs != NULL) {
    267         return Facs;
    268       }
    269     }
    270   }
    271 
    272   //
    273   // Search RSDT
    274   //
    275   Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
    276   Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
    277   if (Fadt != NULL) {
    278     Facs = FindAcpiFacsFromFadt (Fadt);
    279     if (Facs != NULL) {
    280       return Facs;
    281     }
    282   }
    283 
    284   return NULL;
    285 }
    286 
    287 /**
    288   To find Facs in Acpi tables.
    289 
    290   To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
    291   in the table.
    292 
    293   @return  Facs table pointer.
    294 **/
    295 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
    296 FindAcpiFacsTable (
    297   VOID
    298   )
    299 {
    300   EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
    301 
    302   Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);
    303   if (Facs != NULL) {
    304     return Facs;
    305   }
    306 
    307   return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);
    308 }
    309 
    310 /**
    311   The function will check if long mode waking vector is supported.
    312 
    313   @param[in] Facs   Pointer to FACS table.
    314 
    315   @retval TRUE   Long mode waking vector is supported.
    316   @retval FALSE  Long mode waking vector is not supported.
    317 
    318 **/
    319 BOOLEAN
    320 IsLongModeWakingVectorSupport (
    321   IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs
    322   )
    323 {
    324   if ((Facs == NULL) ||
    325       (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ) {
    326     //
    327     // Something wrong with FACS.
    328     //
    329     return FALSE;
    330   }
    331   if (Facs->XFirmwareWakingVector != 0) {
    332     if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
    333         ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0)) {
    334       //
    335       // BIOS supports 64bit waking vector.
    336       //
    337       if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    338         return TRUE;
    339       }
    340     }
    341   }
    342   return FALSE;
    343 }
    344 
    345 /**
    346   Allocates page table buffer.
    347 
    348   @param[in] LongModeWakingVectorSupport    Support long mode waking vector or not.
    349 
    350   If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
    351   virtual to physical mapping page table when long mode waking vector is supported, otherwise
    352   create 4G page table when long mode waking vector is not supported and let PF handler to
    353   handle > 4G request.
    354   If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
    355 
    356   @return Page table base address.
    357 
    358 **/
    359 EFI_PHYSICAL_ADDRESS
    360 S3AllocatePageTablesBuffer (
    361   IN BOOLEAN    LongModeWakingVectorSupport
    362   )
    363 {
    364   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
    365     UINTN                                         ExtraPageTablePages;
    366     UINT32                                        RegEax;
    367     UINT32                                        RegEdx;
    368     UINT8                                         PhysicalAddressBits;
    369     UINT32                                        NumberOfPml4EntriesNeeded;
    370     UINT32                                        NumberOfPdpEntriesNeeded;
    371     EFI_PHYSICAL_ADDRESS                          S3NvsPageTableAddress;
    372     UINTN                                         TotalPageTableSize;
    373     VOID                                          *Hob;
    374     BOOLEAN                                       Page1GSupport;
    375 
    376     Page1GSupport = FALSE;
    377     if (PcdGetBool(PcdUse1GPageTable)) {
    378       AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    379       if (RegEax >= 0x80000001) {
    380         AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
    381         if ((RegEdx & BIT26) != 0) {
    382           Page1GSupport = TRUE;
    383         }
    384       }
    385     }
    386 
    387     //
    388     // Get physical address bits supported.
    389     //
    390     Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
    391     if (Hob != NULL) {
    392       PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
    393     } else {
    394       AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    395       if (RegEax >= 0x80000008) {
    396         AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
    397         PhysicalAddressBits = (UINT8) RegEax;
    398       } else {
    399         PhysicalAddressBits = 36;
    400       }
    401     }
    402 
    403     //
    404     // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
    405     //
    406     ASSERT (PhysicalAddressBits <= 52);
    407     if (PhysicalAddressBits > 48) {
    408       PhysicalAddressBits = 48;
    409     }
    410 
    411     ExtraPageTablePages = 0;
    412     if (!LongModeWakingVectorSupport) {
    413       //
    414       // Create 4G page table when BIOS does not support long mode waking vector,
    415       // and let PF handler to handle > 4G request.
    416       //
    417       PhysicalAddressBits = 32;
    418       ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
    419     }
    420 
    421     //
    422     // Calculate the table entries needed.
    423     //
    424     if (PhysicalAddressBits <= 39 ) {
    425       NumberOfPml4EntriesNeeded = 1;
    426       NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
    427     } else {
    428       NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
    429       NumberOfPdpEntriesNeeded = 512;
    430     }
    431 
    432     //
    433     // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
    434     //
    435     if (!Page1GSupport) {
    436       TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);
    437     } else {
    438       TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded);
    439     }
    440 
    441     TotalPageTableSize += ExtraPageTablePages;
    442     DEBUG ((EFI_D_ERROR, "AcpiS3Save TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));
    443 
    444     //
    445     // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
    446     //
    447     S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
    448     ASSERT (S3NvsPageTableAddress != 0);
    449     return S3NvsPageTableAddress;
    450   } else {
    451     //
    452     // If DXE is running 32-bit mode, no need to establish page table.
    453     //
    454     return  (EFI_PHYSICAL_ADDRESS) 0;
    455   }
    456 }
    457 
    458 /**
    459   Gets the buffer of legacy memory below 1 MB
    460   This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
    461 
    462   @param This           A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
    463   @param Size           The returned size of legacy memory below 1 MB.
    464 
    465   @retval EFI_SUCCESS           Size is successfully returned.
    466   @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
    467 
    468 **/
    469 EFI_STATUS
    470 EFIAPI
    471 LegacyGetS3MemorySize (
    472   IN  EFI_ACPI_S3_SAVE_PROTOCOL   *This,
    473   OUT UINTN                       *Size
    474   )
    475 {
    476   if (Size == NULL) {
    477     return EFI_INVALID_PARAMETER;
    478   }
    479 
    480   *Size = mLegacyRegionSize;
    481   return EFI_SUCCESS;
    482 }
    483 
    484 /**
    485   Prepares all information that is needed in the S3 resume boot path.
    486 
    487   Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
    488 
    489   @param This                 A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
    490   @param LegacyMemoryAddress  The base address of legacy memory.
    491 
    492   @retval EFI_NOT_FOUND         Some necessary information cannot be found.
    493   @retval EFI_SUCCESS           All information was saved successfully.
    494   @retval EFI_OUT_OF_RESOURCES  Resources were insufficient to save all the information.
    495   @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
    496 
    497 **/
    498 EFI_STATUS
    499 EFIAPI
    500 S3Ready (
    501   IN EFI_ACPI_S3_SAVE_PROTOCOL    *This,
    502   IN VOID                         *LegacyMemoryAddress
    503   )
    504 {
    505   EFI_STATUS                                    Status;
    506   EFI_PHYSICAL_ADDRESS                          AcpiS3ContextBuffer;
    507   ACPI_S3_CONTEXT                               *AcpiS3Context;
    508   STATIC BOOLEAN                                AlreadyEntered;
    509   IA32_DESCRIPTOR                               *Idtr;
    510   IA32_IDT_GATE_DESCRIPTOR                      *IdtGate;
    511   EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
    512 
    513   DEBUG ((EFI_D_INFO, "S3Ready!\n"));
    514 
    515   //
    516   // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
    517   // So if 2nd S3Save() is triggered later, we need ignore it.
    518   //
    519   if (AlreadyEntered) {
    520     return EFI_SUCCESS;
    521   }
    522   AlreadyEntered = TRUE;
    523 
    524   AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
    525   ASSERT (AcpiS3Context != NULL);
    526   AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
    527 
    528   //
    529   // Get ACPI Table because we will save its position to variable
    530   //
    531   Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) FindAcpiFacsTable ();
    532   AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS) (UINTN) Facs;
    533   ASSERT (AcpiS3Context->AcpiFacsTable != 0);
    534 
    535   IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));
    536   Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
    537   Idtr->Base  = (UINTN)IdtGate;
    538   Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
    539   AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
    540 
    541   Status = SaveLockBox (
    542              &mAcpiS3IdtrProfileGuid,
    543              (VOID *)(UINTN)Idtr,
    544              (UINTN)sizeof(IA32_DESCRIPTOR)
    545              );
    546   ASSERT_EFI_ERROR (Status);
    547 
    548   Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
    549   ASSERT_EFI_ERROR (Status);
    550 
    551   //
    552   // Allocate page table
    553   //
    554   AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));
    555 
    556   //
    557   // Allocate stack
    558   //
    559   AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
    560   AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
    561   ASSERT (AcpiS3Context->BootScriptStackBase != 0);
    562 
    563   //
    564   // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
    565   //
    566   AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
    567   SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
    568 
    569   DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));
    570   DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));
    571   DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));
    572   DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));
    573   DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));
    574   DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));
    575 
    576   Status = SaveLockBox (
    577              &gEfiAcpiVariableGuid,
    578              &AcpiS3ContextBuffer,
    579              sizeof(AcpiS3ContextBuffer)
    580              );
    581   ASSERT_EFI_ERROR (Status);
    582 
    583   Status = SaveLockBox (
    584              &gEfiAcpiS3ContextGuid,
    585              (VOID *)(UINTN)AcpiS3Context,
    586              (UINTN)sizeof(*AcpiS3Context)
    587              );
    588   ASSERT_EFI_ERROR (Status);
    589 
    590   Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
    591   ASSERT_EFI_ERROR (Status);
    592 
    593   if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
    594     S3ReadyThunkPlatform (AcpiS3Context);
    595   }
    596 
    597   return EFI_SUCCESS;
    598 }
    599 
    600 /**
    601   The Driver Entry Point.
    602 
    603   The function is the driver Entry point which will produce AcpiS3SaveProtocol.
    604 
    605   @param ImageHandle   A handle for the image that is initializing this driver
    606   @param SystemTable   A pointer to the EFI system table
    607 
    608   @retval EFI_SUCCESS:              Driver initialized successfully
    609   @retval EFI_LOAD_ERROR:           Failed to Initialize or has been loaded
    610   @retval EFI_OUT_OF_RESOURCES      Could not allocate needed resources
    611 
    612 **/
    613 EFI_STATUS
    614 EFIAPI
    615 InstallAcpiS3Save (
    616   IN EFI_HANDLE           ImageHandle,
    617   IN EFI_SYSTEM_TABLE     *SystemTable
    618   )
    619 {
    620   EFI_STATUS        Status;
    621 
    622   if (!FeaturePcdGet(PcdPlatformCsmSupport)) {
    623     //
    624     // More memory for no CSM tip, because GDT need relocation
    625     //
    626     mLegacyRegionSize = 0x250;
    627   } else {
    628     mLegacyRegionSize = 0x100;
    629   }
    630 
    631   if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
    632     InstallAcpiS3SaveThunk ();
    633   }
    634 
    635   Status = gBS->InstallProtocolInterface (
    636                   &ImageHandle,
    637                   &gEfiAcpiS3SaveProtocolGuid,
    638                   EFI_NATIVE_INTERFACE,
    639                   &mS3Save
    640                   );
    641   ASSERT_EFI_ERROR (Status);
    642   return Status;
    643 }
    644