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