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