2 This is an implementation of the ACPI S3 Save protocol. This is defined in
3 S3 boot path specification 0.9.
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
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
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.
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>
33 #include "AcpiS3Save.h"
36 Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
39 InstallAcpiS3SaveThunk (
44 Hook point for AcpiVariableThunkPlatform for S3Ready.
46 @param AcpiS3Context ACPI s3 context
49 S3ReadyThunkPlatform (
50 IN ACPI_S3_CONTEXT
*AcpiS3Context
53 UINTN mLegacyRegionSize
;
55 EFI_ACPI_S3_SAVE_PROTOCOL mS3Save
= {
56 LegacyGetS3MemorySize
,
60 EFI_GUID mAcpiS3IdtrProfileGuid
= {
61 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
65 Allocate memory below 4G memory address.
67 This function allocates memory below 4G memory address.
69 @param MemoryType Memory type of memory to allocate.
70 @param Size Size of memory to allocate.
72 @return Allocated address for output.
76 AllocateMemoryBelow4G (
82 EFI_PHYSICAL_ADDRESS Address
;
86 Pages
= EFI_SIZE_TO_PAGES (Size
);
89 Status
= gBS
->AllocatePages (
95 ASSERT_EFI_ERROR (Status
);
97 Buffer
= (VOID
*) (UINTN
) Address
;
98 ZeroMem (Buffer
, Size
);
105 This function scan ACPI table in RSDT.
107 @param Rsdt ACPI RSDT
108 @param Signature ACPI table signature
115 IN EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
,
122 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
128 EntryCount
= (Rsdt
->Length
- sizeof (EFI_ACPI_DESCRIPTION_HEADER
)) / sizeof(UINT32
);
130 EntryPtr
= (UINT32
*)(Rsdt
+ 1);
131 for (Index
= 0; Index
< EntryCount
; Index
++, EntryPtr
++) {
132 Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)((UINTN
)(*EntryPtr
));
133 if (Table
->Signature
== Signature
) {
143 This function scan ACPI table in XSDT.
145 @param Xsdt ACPI XSDT
146 @param Signature ACPI table signature
153 IN EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
,
161 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
167 EntryCount
= (Xsdt
->Length
- sizeof (EFI_ACPI_DESCRIPTION_HEADER
)) / sizeof(UINT64
);
169 BasePtr
= (UINTN
)(Xsdt
+ 1);
170 for (Index
= 0; Index
< EntryCount
; Index
++) {
171 CopyMem (&EntryPtr
, (VOID
*)(BasePtr
+ Index
* sizeof(UINT64
)), sizeof(UINT64
));
172 Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)((UINTN
)(EntryPtr
));
173 if (Table
->Signature
== Signature
) {
182 To find Facs in FADT.
184 @param Fadt FADT table pointer
186 @return Facs table pointer.
188 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*
189 FindAcpiFacsFromFadt (
190 IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
*Fadt
193 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
200 if (Fadt
->Header
.Revision
< EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
) {
201 Facs
= (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*)(UINTN
)Fadt
->FirmwareCtrl
;
203 if (Fadt
->FirmwareCtrl
!= 0) {
204 Facs
= (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*)(UINTN
)Fadt
->FirmwareCtrl
;
206 CopyMem (&Data64
, &Fadt
->XFirmwareCtrl
, sizeof(UINT64
));
207 Facs
= (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*)(UINTN
)Data64
;
214 To find Facs in Acpi tables.
216 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
219 @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
221 @return Facs table pointer.
223 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*
224 FindAcpiFacsTableByAcpiGuid (
225 IN EFI_GUID
*AcpiTableGuid
228 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
229 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
230 EFI_ACPI_DESCRIPTION_HEADER
*Xsdt
;
231 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
*Fadt
;
232 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
237 // found ACPI table RSD_PTR from system table
239 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
240 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), AcpiTableGuid
)) {
242 // A match was found.
244 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
256 if (Rsdp
->Revision
>= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION
) {
257 Xsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
) Rsdp
->XsdtAddress
;
258 Fadt
= ScanTableInXSDT (Xsdt
, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
);
260 Facs
= FindAcpiFacsFromFadt (Fadt
);
270 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
) Rsdp
->RsdtAddress
;
271 Fadt
= ScanTableInRSDT (Rsdt
, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
);
273 Facs
= FindAcpiFacsFromFadt (Fadt
);
283 To find Facs in Acpi tables.
285 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
288 @return Facs table pointer.
290 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*
295 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
297 Facs
= FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid
);
302 return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid
);
306 Allocates and fills in the Page Directory and Page Table Entries to
307 establish a 1:1 Virtual to Physical mapping.
308 If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
309 virtual to physical mapping page table.
310 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
312 @return the 1:1 Virtual to Physical identity mapping page table base address.
316 S3CreateIdentityMappingPageTables (
320 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
323 UINT8 PhysicalAddressBits
;
324 UINT32 NumberOfPml4EntriesNeeded
;
325 UINT32 NumberOfPdpEntriesNeeded
;
326 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress
;
327 UINTN TotalPageTableSize
;
329 BOOLEAN Page1GSupport
;
331 Page1GSupport
= FALSE
;
332 if (PcdGetBool(PcdUse1GPageTable
)) {
333 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
334 if (RegEax
>= 0x80000001) {
335 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
336 if ((RegEdx
& BIT26
) != 0) {
337 Page1GSupport
= TRUE
;
343 // Get physical address bits supported.
345 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
347 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
349 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
350 if (RegEax
>= 0x80000008) {
351 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
352 PhysicalAddressBits
= (UINT8
) RegEax
;
354 PhysicalAddressBits
= 36;
359 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
361 ASSERT (PhysicalAddressBits
<= 52);
362 if (PhysicalAddressBits
> 48) {
363 PhysicalAddressBits
= 48;
367 // Calculate the table entries needed.
369 if (PhysicalAddressBits
<= 39 ) {
370 NumberOfPml4EntriesNeeded
= 1;
371 NumberOfPdpEntriesNeeded
= (UINT32
)LShiftU64 (1, (PhysicalAddressBits
- 30));
373 NumberOfPml4EntriesNeeded
= (UINT32
)LShiftU64 (1, (PhysicalAddressBits
- 39));
374 NumberOfPdpEntriesNeeded
= 512;
378 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
380 if (!Page1GSupport
) {
381 TotalPageTableSize
= (UINTN
)(1 + NumberOfPml4EntriesNeeded
+ NumberOfPml4EntriesNeeded
* NumberOfPdpEntriesNeeded
);
383 TotalPageTableSize
= (UINTN
)(1 + NumberOfPml4EntriesNeeded
);
385 DEBUG ((EFI_D_ERROR
, "TotalPageTableSize - %x pages\n", TotalPageTableSize
));
388 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
390 S3NvsPageTableAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, EFI_PAGES_TO_SIZE(TotalPageTableSize
));
391 ASSERT (S3NvsPageTableAddress
!= 0);
392 return S3NvsPageTableAddress
;
395 // If DXE is running 32-bit mode, no need to establish page table.
397 return (EFI_PHYSICAL_ADDRESS
) 0;
402 Gets the buffer of legacy memory below 1 MB
403 This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
405 @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
406 @param Size The returned size of legacy memory below 1 MB.
408 @retval EFI_SUCCESS Size is successfully returned.
409 @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
414 LegacyGetS3MemorySize (
415 IN EFI_ACPI_S3_SAVE_PROTOCOL
*This
,
420 return EFI_INVALID_PARAMETER
;
423 *Size
= mLegacyRegionSize
;
428 Prepares all information that is needed in the S3 resume boot path.
430 Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
432 @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
433 @param LegacyMemoryAddress The base address of legacy memory.
435 @retval EFI_NOT_FOUND Some necessary information cannot be found.
436 @retval EFI_SUCCESS All information was saved successfully.
437 @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information.
438 @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
444 IN EFI_ACPI_S3_SAVE_PROTOCOL
*This
,
445 IN VOID
*LegacyMemoryAddress
449 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer
;
450 ACPI_S3_CONTEXT
*AcpiS3Context
;
451 STATIC BOOLEAN AlreadyEntered
;
452 IA32_DESCRIPTOR
*Idtr
;
453 IA32_IDT_GATE_DESCRIPTOR
*IdtGate
;
455 DEBUG ((EFI_D_INFO
, "S3Ready!\n"));
458 // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
459 // So if 2nd S3Save() is triggered later, we need ignore it.
461 if (AlreadyEntered
) {
464 AlreadyEntered
= TRUE
;
466 AcpiS3Context
= AllocateMemoryBelow4G (EfiReservedMemoryType
, sizeof(*AcpiS3Context
));
467 ASSERT (AcpiS3Context
!= NULL
);
468 AcpiS3ContextBuffer
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AcpiS3Context
;
471 // Get ACPI Table because we will save its position to variable
473 AcpiS3Context
->AcpiFacsTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)FindAcpiFacsTable ();
474 ASSERT (AcpiS3Context
->AcpiFacsTable
!= 0);
476 IdtGate
= AllocateMemoryBelow4G (EfiReservedMemoryType
, sizeof(IA32_IDT_GATE_DESCRIPTOR
) * 0x100 + sizeof(IA32_DESCRIPTOR
));
477 Idtr
= (IA32_DESCRIPTOR
*)(IdtGate
+ 0x100);
478 Idtr
->Base
= (UINTN
)IdtGate
;
479 Idtr
->Limit
= (UINT16
)(sizeof(IA32_IDT_GATE_DESCRIPTOR
) * 0x100 - 1);
480 AcpiS3Context
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Idtr
;
482 Status
= SaveLockBox (
483 &mAcpiS3IdtrProfileGuid
,
485 (UINTN
)sizeof(IA32_DESCRIPTOR
)
487 ASSERT_EFI_ERROR (Status
);
489 Status
= SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
490 ASSERT_EFI_ERROR (Status
);
493 // Allocate page table
495 AcpiS3Context
->S3NvsPageTableAddress
= S3CreateIdentityMappingPageTables ();
500 AcpiS3Context
->BootScriptStackSize
= PcdGet32 (PcdS3BootScriptStackSize
);
501 AcpiS3Context
->BootScriptStackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, PcdGet32 (PcdS3BootScriptStackSize
));
502 ASSERT (AcpiS3Context
->BootScriptStackBase
!= 0);
505 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
507 AcpiS3Context
->S3DebugBufferAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, EFI_PAGE_SIZE
);
508 SetMem ((VOID
*)(UINTN
)AcpiS3Context
->S3DebugBufferAddress
, EFI_PAGE_SIZE
, 0xff);
510 DEBUG((EFI_D_INFO
, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context
->AcpiFacsTable
));
511 DEBUG((EFI_D_INFO
, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context
->IdtrProfile
));
512 DEBUG((EFI_D_INFO
, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context
->S3NvsPageTableAddress
));
513 DEBUG((EFI_D_INFO
, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context
->S3DebugBufferAddress
));
515 Status
= SaveLockBox (
516 &gEfiAcpiVariableGuid
,
517 &AcpiS3ContextBuffer
,
518 sizeof(AcpiS3ContextBuffer
)
520 ASSERT_EFI_ERROR (Status
);
522 Status
= SaveLockBox (
523 &gEfiAcpiS3ContextGuid
,
524 (VOID
*)(UINTN
)AcpiS3Context
,
525 (UINTN
)sizeof(*AcpiS3Context
)
527 ASSERT_EFI_ERROR (Status
);
529 Status
= SetLockBoxAttributes (&gEfiAcpiS3ContextGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
530 ASSERT_EFI_ERROR (Status
);
532 if (FeaturePcdGet(PcdFrameworkCompatibilitySupport
)) {
533 S3ReadyThunkPlatform (AcpiS3Context
);
540 The Driver Entry Point.
542 The function is the driver Entry point which will produce AcpiS3SaveProtocol.
544 @param ImageHandle A handle for the image that is initializing this driver
545 @param SystemTable A pointer to the EFI system table
547 @retval EFI_SUCCESS: Driver initialized successfully
548 @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
549 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
555 IN EFI_HANDLE ImageHandle
,
556 IN EFI_SYSTEM_TABLE
*SystemTable
561 if (!FeaturePcdGet(PcdPlatformCsmSupport
)) {
563 // More memory for no CSM tip, because GDT need relocation
565 mLegacyRegionSize
= 0x250;
567 mLegacyRegionSize
= 0x100;
570 if (FeaturePcdGet(PcdFrameworkCompatibilitySupport
)) {
571 InstallAcpiS3SaveThunk ();
574 Status
= gBS
->InstallProtocolInterface (
576 &gEfiAcpiS3SaveProtocolGuid
,
577 EFI_NATIVE_INTERFACE
,
580 ASSERT_EFI_ERROR (Status
);