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