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