]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c
OvmfPkg: AcpiS3SaveDxe: drop EFI_ACPI_S3_SAVE_PROTOCOL
[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
364 DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %x pages\n", TotalPageTableSize));\r
365\r
366 //\r
367 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
368 //\r
369 S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));\r
370 ASSERT (S3NvsPageTableAddress != 0);\r
371 return S3NvsPageTableAddress;\r
372 } else {\r
373 //\r
374 // If DXE is running 32-bit mode, no need to establish page table.\r
375 //\r
376 return (EFI_PHYSICAL_ADDRESS) 0; \r
377 }\r
378}\r
379\r
600c74bc
LE
380/**\r
381 Prepares all information that is needed in the S3 resume boot path.\r
382 \r
383 Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path \r
384 \r
600c74bc 385 @retval EFI_SUCCESS All information was saved successfully.\r
600c74bc 386**/\r
ca82d563 387STATIC\r
600c74bc
LE
388EFI_STATUS\r
389EFIAPI\r
390S3Ready (\r
ca82d563 391 VOID\r
600c74bc
LE
392 )\r
393{\r
394 EFI_STATUS Status;\r
395 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;\r
396 ACPI_S3_CONTEXT *AcpiS3Context;\r
397 STATIC BOOLEAN AlreadyEntered;\r
398 IA32_DESCRIPTOR *Idtr;\r
399 IA32_IDT_GATE_DESCRIPTOR *IdtGate;\r
400\r
401 DEBUG ((EFI_D_INFO, "S3Ready!\n"));\r
402\r
ca82d563 403 ASSERT (!AlreadyEntered);\r
600c74bc
LE
404 if (AlreadyEntered) {\r
405 return EFI_SUCCESS;\r
406 }\r
407 AlreadyEntered = TRUE;\r
408\r
409 AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));\r
410 ASSERT (AcpiS3Context != NULL);\r
411 AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
412\r
413 //\r
414 // Get ACPI Table because we will save its position to variable\r
415 //\r
416 AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable ();\r
417 ASSERT (AcpiS3Context->AcpiFacsTable != 0);\r
418\r
419 IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));\r
420 Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);\r
421 Idtr->Base = (UINTN)IdtGate;\r
422 Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);\r
423 AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;\r
424\r
425 Status = SaveLockBox (\r
426 &mAcpiS3IdtrProfileGuid,\r
427 (VOID *)(UINTN)Idtr,\r
428 (UINTN)sizeof(IA32_DESCRIPTOR)\r
429 );\r
430 ASSERT_EFI_ERROR (Status);\r
431\r
432 Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
433 ASSERT_EFI_ERROR (Status);\r
434\r
435 //\r
436 // Allocate page table\r
437 //\r
438 AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables ();\r
439\r
440 //\r
441 // Allocate stack\r
442 //\r
443 AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);\r
444 AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));\r
445 ASSERT (AcpiS3Context->BootScriptStackBase != 0);\r
446\r
447 //\r
448 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.\r
449 //\r
450 AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);\r
451 SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);\r
452\r
453 DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));\r
454 DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));\r
455 DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));\r
456 DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));\r
457\r
458 Status = SaveLockBox (\r
459 &gEfiAcpiVariableGuid,\r
460 &AcpiS3ContextBuffer,\r
461 sizeof(AcpiS3ContextBuffer)\r
462 );\r
463 ASSERT_EFI_ERROR (Status);\r
464\r
465 Status = SaveLockBox (\r
466 &gEfiAcpiS3ContextGuid,\r
467 (VOID *)(UINTN)AcpiS3Context,\r
468 (UINTN)sizeof(*AcpiS3Context)\r
469 );\r
470 ASSERT_EFI_ERROR (Status);\r
471\r
472 Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
473 ASSERT_EFI_ERROR (Status);\r
474\r
475 return EFI_SUCCESS;\r
476}\r
477\r
b88ac532
LE
478/**\r
479 Callback function executed when the EndOfDxe event group is signaled.\r
480\r
481 @param[in] Event Event whose notification function is being invoked.\r
482 @param[in] Context The pointer to the notification function's context, which\r
483 is implementation-dependent.\r
484**/\r
485VOID\r
486EFIAPI\r
487OnEndOfDxe (\r
488 IN EFI_EVENT Event,\r
489 IN VOID *Context\r
490 )\r
491{\r
492 EFI_STATUS Status;\r
493\r
494 //\r
ca82d563 495 // Our S3Ready() function always succeeds.\r
b88ac532 496 //\r
ca82d563 497 Status = S3Ready ();\r
b88ac532
LE
498 ASSERT_EFI_ERROR (Status);\r
499\r
500 //\r
501 // Close the event, deregistering the callback and freeing resources.\r
502 //\r
503 Status = gBS->CloseEvent (Event);\r
504 ASSERT_EFI_ERROR (Status);\r
505}\r
506\r
507\r
600c74bc
LE
508/**\r
509 The Driver Entry Point.\r
510 \r
ca82d563
LE
511 The function is the driver Entry point that will register the End-of-Dxe\r
512 callback.\r
513\r
600c74bc
LE
514 @param ImageHandle A handle for the image that is initializing this driver\r
515 @param SystemTable A pointer to the EFI system table\r
516\r
517 @retval EFI_SUCCESS: Driver initialized successfully\r
518 @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded\r
519 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources\r
520\r
521**/\r
522EFI_STATUS\r
523EFIAPI\r
ca82d563 524InstallEndOfDxeCallback (\r
600c74bc
LE
525 IN EFI_HANDLE ImageHandle,\r
526 IN EFI_SYSTEM_TABLE *SystemTable\r
527 )\r
528{\r
529 EFI_STATUS Status;\r
b88ac532 530 EFI_EVENT EndOfDxeEvent;\r
600c74bc 531\r
209c3922
LE
532 if (!QemuFwCfgS3Enabled()) {\r
533 return EFI_LOAD_ERROR;\r
534 }\r
535\r
d4ba06df 536 Status = gBS->InstallMultipleProtocolInterfaces (\r
600c74bc 537 &ImageHandle,\r
d4ba06df
LE
538 &gEfiLockBoxProtocolGuid, NULL,\r
539 NULL\r
600c74bc
LE
540 );\r
541 ASSERT_EFI_ERROR (Status);\r
b88ac532
LE
542\r
543 Status = gBS->CreateEventEx (\r
544 EVT_NOTIFY_SIGNAL,\r
545 TPL_CALLBACK,\r
546 OnEndOfDxe,\r
547 NULL, /* NotifyContext */\r
548 &gEfiEndOfDxeEventGroupGuid,\r
549 &EndOfDxeEvent\r
550 );\r
551 ASSERT_EFI_ERROR (Status);\r
600c74bc
LE
552 return Status;\r
553}\r