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