• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
AllocateMemoryBelow4G(IN EFI_MEMORY_TYPE MemoryType,IN UINTN Size)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 *
ScanTableInRSDT(IN EFI_ACPI_DESCRIPTION_HEADER * Rsdt,IN UINT32 Signature)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 *
ScanTableInXSDT(IN EFI_ACPI_DESCRIPTION_HEADER * Xsdt,IN UINT32 Signature)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  *
FindAcpiFacsFromFadt(IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * Fadt)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  *
FindAcpiFacsTableByAcpiGuid(IN EFI_GUID * AcpiTableGuid)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  *
FindAcpiFacsTable(VOID)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
IsLongModeWakingVectorSupport(IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE * Facs)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
S3AllocatePageTablesBuffer(IN BOOLEAN LongModeWakingVectorSupport)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
LegacyGetS3MemorySize(IN EFI_ACPI_S3_SAVE_PROTOCOL * This,OUT UINTN * Size)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
S3Ready(IN EFI_ACPI_S3_SAVE_PROTOCOL * This,IN VOID * LegacyMemoryAddress)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
InstallAcpiS3Save(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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