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
);
104 To find Facs in Acpi tables.
106 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
109 @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
111 @return Facs table pointer.
113 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*
114 FindAcpiFacsTableByAcpiGuid (
115 IN EFI_GUID
*AcpiTableGuid
118 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER
*Rsdp
;
119 EFI_ACPI_DESCRIPTION_HEADER
*Rsdt
;
120 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
*Fadt
;
121 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
128 // found ACPI table RSD_PTR from system table
130 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
131 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), AcpiTableGuid
)) {
133 // A match was found.
135 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
144 Rsdt
= (EFI_ACPI_DESCRIPTION_HEADER
*)(UINTN
) Rsdp
->RsdtAddress
;
145 if (Rsdt
== NULL
|| Rsdt
->Signature
!= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
) {
149 for (Index
= sizeof (EFI_ACPI_DESCRIPTION_HEADER
); Index
< Rsdt
->Length
; Index
= Index
+ sizeof (UINT32
)) {
151 Data32
= *(UINT32
*) ((UINT8
*) Rsdt
+ Index
);
152 Fadt
= (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE
*) (UINT32
*) (UINTN
) Data32
;
153 if (Fadt
->Header
.Signature
== EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
) {
158 if (Fadt
== NULL
|| Fadt
->Header
.Signature
!= EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
) {
162 Facs
= (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*)(UINTN
)Fadt
->FirmwareCtrl
;
168 To find Facs in Acpi tables.
170 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
173 @return Facs table pointer.
175 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*
180 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
182 Facs
= FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid
);
187 return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid
);
191 Allocates and fills in the Page Directory and Page Table Entries to
192 establish a 1:1 Virtual to Physical mapping.
193 If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
194 virtual to physical mapping page table.
195 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
197 @return the 1:1 Virtual to Physical identity mapping page table base address.
201 S3CreateIdentityMappingPageTables (
205 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
208 UINT8 PhysicalAddressBits
;
209 UINT32 NumberOfPml4EntriesNeeded
;
210 UINT32 NumberOfPdpEntriesNeeded
;
211 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress
;
212 UINTN TotalPageTableSize
;
214 BOOLEAN Page1GSupport
;
216 Page1GSupport
= FALSE
;
217 if (PcdGetBool(PcdUse1GPageTable
)) {
218 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
219 if (RegEax
>= 0x80000001) {
220 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
221 if ((RegEdx
& BIT26
) != 0) {
222 Page1GSupport
= TRUE
;
228 // Get physical address bits supported.
230 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
232 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
234 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
235 if (RegEax
>= 0x80000008) {
236 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
237 PhysicalAddressBits
= (UINT8
) RegEax
;
239 PhysicalAddressBits
= 36;
244 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
246 ASSERT (PhysicalAddressBits
<= 52);
247 if (PhysicalAddressBits
> 48) {
248 PhysicalAddressBits
= 48;
252 // Calculate the table entries needed.
254 if (PhysicalAddressBits
<= 39 ) {
255 NumberOfPml4EntriesNeeded
= 1;
256 NumberOfPdpEntriesNeeded
= (UINT32
)LShiftU64 (1, (PhysicalAddressBits
- 30));
258 NumberOfPml4EntriesNeeded
= (UINT32
)LShiftU64 (1, (PhysicalAddressBits
- 39));
259 NumberOfPdpEntriesNeeded
= 512;
263 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
265 if (!Page1GSupport
) {
266 TotalPageTableSize
= (UINTN
)(1 + NumberOfPml4EntriesNeeded
+ NumberOfPml4EntriesNeeded
* NumberOfPdpEntriesNeeded
);
268 TotalPageTableSize
= (UINTN
)(1 + NumberOfPml4EntriesNeeded
);
270 DEBUG ((EFI_D_ERROR
, "TotalPageTableSize - %x pages\n", TotalPageTableSize
));
273 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
275 S3NvsPageTableAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, EFI_PAGES_TO_SIZE(TotalPageTableSize
));
276 ASSERT (S3NvsPageTableAddress
!= 0);
277 return S3NvsPageTableAddress
;
280 // If DXE is running 32-bit mode, no need to establish page table.
282 return (EFI_PHYSICAL_ADDRESS
) 0;
287 Gets the buffer of legacy memory below 1 MB
288 This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
290 @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
291 @param Size The returned size of legacy memory below 1 MB.
293 @retval EFI_SUCCESS Size is successfully returned.
294 @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
299 LegacyGetS3MemorySize (
300 IN EFI_ACPI_S3_SAVE_PROTOCOL
*This
,
305 return EFI_INVALID_PARAMETER
;
308 *Size
= mLegacyRegionSize
;
313 Prepares all information that is needed in the S3 resume boot path.
315 Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
317 @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
318 @param LegacyMemoryAddress The base address of legacy memory.
320 @retval EFI_NOT_FOUND Some necessary information cannot be found.
321 @retval EFI_SUCCESS All information was saved successfully.
322 @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information.
323 @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
329 IN EFI_ACPI_S3_SAVE_PROTOCOL
*This
,
330 IN VOID
*LegacyMemoryAddress
334 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer
;
335 ACPI_S3_CONTEXT
*AcpiS3Context
;
336 STATIC BOOLEAN AlreadyEntered
;
337 IA32_DESCRIPTOR
*Idtr
;
338 IA32_IDT_GATE_DESCRIPTOR
*IdtGate
;
340 DEBUG ((EFI_D_INFO
, "S3Ready!\n"));
343 // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
344 // So if 2nd S3Save() is triggered later, we need ignore it.
346 if (AlreadyEntered
) {
349 AlreadyEntered
= TRUE
;
351 AcpiS3Context
= AllocateMemoryBelow4G (EfiReservedMemoryType
, sizeof(*AcpiS3Context
));
352 ASSERT (AcpiS3Context
!= NULL
);
353 AcpiS3ContextBuffer
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AcpiS3Context
;
356 // Get ACPI Table because we will save its position to variable
358 AcpiS3Context
->AcpiFacsTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)FindAcpiFacsTable ();
359 ASSERT (AcpiS3Context
->AcpiFacsTable
!= 0);
361 IdtGate
= AllocateMemoryBelow4G (EfiReservedMemoryType
, sizeof(IA32_IDT_GATE_DESCRIPTOR
) * 0x100 + sizeof(IA32_DESCRIPTOR
));
362 Idtr
= (IA32_DESCRIPTOR
*)(IdtGate
+ 0x100);
363 Idtr
->Base
= (UINTN
)IdtGate
;
364 Idtr
->Limit
= (UINT16
)(sizeof(IA32_IDT_GATE_DESCRIPTOR
) * 0x100 - 1);
365 AcpiS3Context
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Idtr
;
367 Status
= SaveLockBox (
368 &mAcpiS3IdtrProfileGuid
,
370 (UINTN
)sizeof(IA32_DESCRIPTOR
)
372 ASSERT_EFI_ERROR (Status
);
374 Status
= SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
375 ASSERT_EFI_ERROR (Status
);
378 // Allocate page table
380 AcpiS3Context
->S3NvsPageTableAddress
= S3CreateIdentityMappingPageTables ();
385 AcpiS3Context
->BootScriptStackSize
= PcdGet32 (PcdS3BootScriptStackSize
);
386 AcpiS3Context
->BootScriptStackBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, PcdGet32 (PcdS3BootScriptStackSize
));
387 ASSERT (AcpiS3Context
->BootScriptStackBase
!= 0);
390 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
392 AcpiS3Context
->S3DebugBufferAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateMemoryBelow4G (EfiReservedMemoryType
, EFI_PAGE_SIZE
);
393 SetMem ((VOID
*)(UINTN
)AcpiS3Context
->S3DebugBufferAddress
, EFI_PAGE_SIZE
, 0xff);
395 DEBUG((EFI_D_INFO
, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context
->AcpiFacsTable
));
396 DEBUG((EFI_D_INFO
, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context
->IdtrProfile
));
397 DEBUG((EFI_D_INFO
, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context
->S3NvsPageTableAddress
));
398 DEBUG((EFI_D_INFO
, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context
->S3DebugBufferAddress
));
400 Status
= SaveLockBox (
401 &gEfiAcpiVariableGuid
,
402 &AcpiS3ContextBuffer
,
403 sizeof(AcpiS3ContextBuffer
)
405 ASSERT_EFI_ERROR (Status
);
407 Status
= SaveLockBox (
408 &gEfiAcpiS3ContextGuid
,
409 (VOID
*)(UINTN
)AcpiS3Context
,
410 (UINTN
)sizeof(*AcpiS3Context
)
412 ASSERT_EFI_ERROR (Status
);
414 Status
= SetLockBoxAttributes (&gEfiAcpiS3ContextGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
415 ASSERT_EFI_ERROR (Status
);
417 if (FeaturePcdGet(PcdFrameworkCompatibilitySupport
)) {
418 S3ReadyThunkPlatform (AcpiS3Context
);
425 The Driver Entry Point.
427 The function is the driver Entry point which will produce AcpiS3SaveProtocol.
429 @param ImageHandle A handle for the image that is initializing this driver
430 @param SystemTable A pointer to the EFI system table
432 @retval EFI_SUCCESS: Driver initialized successfully
433 @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
434 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
440 IN EFI_HANDLE ImageHandle
,
441 IN EFI_SYSTEM_TABLE
*SystemTable
446 if (!FeaturePcdGet(PcdPlatformCsmSupport
)) {
448 // More memory for no CSM tip, because GDT need relocation
450 mLegacyRegionSize
= 0x250;
452 mLegacyRegionSize
= 0x100;
455 if (FeaturePcdGet(PcdFrameworkCompatibilitySupport
)) {
456 InstallAcpiS3SaveThunk ();
459 Status
= gBS
->InstallProtocolInterface (
461 &gEfiAcpiS3SaveProtocolGuid
,
462 EFI_NATIVE_INTERFACE
,
465 ASSERT_EFI_ERROR (Status
);