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