From 13d4af68f83c39993b90c0f4d251c4312a0ddc9a Mon Sep 17 00:00:00 2001 From: jljusten Date: Wed, 31 Aug 2011 18:57:46 +0000 Subject: [PATCH] IntelFrameworkModulePkg: Add AcpiS3SaveDxe driver Signed-off-by: jljusten Reviewed-by: rsun3 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12246 6f19259b-4bc3-4df7-8a09-765794883524 --- .../IntelFrameworkModulePkg.dsc | 6 + .../Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c | 485 ++++++++++++++++++ .../Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h | 135 +++++ .../Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf | 83 +++ .../AcpiS3SaveDxe/AcpiVariableThunkPlatform.c | 166 ++++++ 5 files changed, 875 insertions(+) create mode 100644 IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c create mode 100644 IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h create mode 100644 IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf create mode 100644 IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc index 39a6adda96..bd26806d21 100644 --- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc +++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc @@ -81,6 +81,9 @@ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf +[LibraryClasses.common.DXE_DRIVER] + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf + [LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf @@ -160,6 +163,9 @@ IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf +[Components.IA32,Components.X64] + IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf + [Components.IA32,Components.X64,Components.IPF] IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c new file mode 100644 index 0000000000..73074a2684 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c @@ -0,0 +1,485 @@ +/** @file + This is an implementation of the ACPI S3 Save protocol. This is defined in + S3 boot path specification 0.9. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AcpiS3Save.h" + +/** + Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. +**/ +VOID +InstallAcpiS3SaveThunk ( + VOID + ); + +/** + Hook point for AcpiVariableThunkPlatform for S3Ready. + + @param AcpiS3Context ACPI s3 context +**/ +VOID +S3ReadyThunkPlatform ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ); + +UINTN mLegacyRegionSize; + +EFI_ACPI_S3_SAVE_PROTOCOL mS3Save = { + LegacyGetS3MemorySize, + S3Ready, +}; + +EFI_GUID mAcpiS3IdtrProfileGuid = { + 0xdea652b0, 0xd587, 0x4c54, 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d +}; + +/** + Allocate EfiACPIMemoryNVS below 4G memory address. + + This function allocates EfiACPIMemoryNVS below 4G memory address. + + @param Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID* +AllocateAcpiNvsMemoryBelow4G ( + IN UINTN Size + ) +{ + UINTN Pages; + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID* Buffer; + + Pages = EFI_SIZE_TO_PAGES (Size); + Address = 0xffffffff; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + Pages, + &Address + ); + ASSERT_EFI_ERROR (Status); + + Buffer = (VOID *) (UINTN) Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + To find Facs in Acpi tables. + + To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored + in the table. + + @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable. + + @return Facs table pointer. +**/ +EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE * +FindAcpiFacsTableByAcpiGuid ( + IN EFI_GUID *AcpiTableGuid + ) +{ + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; + EFI_ACPI_DESCRIPTION_HEADER *Rsdt; + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + UINTN Index; + UINT32 Data32; + Rsdp = NULL; + Rsdt = NULL; + Fadt = NULL; + // + // found ACPI table RSD_PTR from system table + // + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) { + // + // A match was found. + // + Rsdp = gST->ConfigurationTable[Index].VendorTable; + break; + } + } + + if (Rsdp == NULL) { + return NULL; + } + + Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress; + if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + return NULL; + } + + for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) { + + Data32 = *(UINT32 *) ((UINT8 *) Rsdt + Index); + Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32; + if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + break; + } + } + + if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) { + return NULL; + } + + Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl; + + return Facs; +} + +/** + To find Facs in Acpi tables. + + To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored + in the table. + + @return Facs table pointer. +**/ +EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE * +FindAcpiFacsTable ( + VOID + ) +{ + EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + + Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid); + if (Facs != NULL) { + return Facs; + } + + return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid); +} + +/** + Allocates and fills in the Page Directory and Page Table Entries to + establish a 1:1 Virtual to Physical mapping. + If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1 + virtual to physical mapping page table. + If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. + + @return the 1:1 Virtual to Physical identity mapping page table base address. + +**/ +EFI_PHYSICAL_ADDRESS +S3CreateIdentityMappingPageTables ( + VOID + ) +{ + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { + UINT32 RegEax; + UINT8 PhysicalAddressBits; + EFI_PHYSICAL_ADDRESS PageAddress; + UINTN IndexOfPml4Entries; + UINTN IndexOfPdpEntries; + UINTN IndexOfPageDirectoryEntries; + UINTN NumberOfPml4EntriesNeeded; + UINTN NumberOfPdpEntriesNeeded; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMap; + PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; + PAGE_TABLE_ENTRY *PageDirectoryEntry; + EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress; + UINTN TotalPageTableSize; + + // + // Get physical address bits supported. + // + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + + // + // Calculate the table entries needed. + // + if (PhysicalAddressBits <= 39 ) { + NumberOfPml4EntriesNeeded = 1; + NumberOfPdpEntriesNeeded = (UINTN)LShiftU64 (1, (PhysicalAddressBits - 30)); + } else { + NumberOfPml4EntriesNeeded = (UINTN)LShiftU64 (1, (PhysicalAddressBits - 39)); + NumberOfPdpEntriesNeeded = 512; + } + + // + // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs. + // + TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded); + DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %x pages\n", TotalPageTableSize)); + + // + // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it. + // + S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE(TotalPageTableSize)); + ASSERT (S3NvsPageTableAddress != 0); + PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + PageMapLevel4Entry = PageMap; + PageAddress = 0; + for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) { + // + // Each PML4 entry points to a page of Page Directory Pointer entires. + // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop. + // + PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)(UINTN)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + // + // Make a PML4 Entry + // + PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry; + PageMapLevel4Entry->Bits.ReadWrite = 1; + PageMapLevel4Entry->Bits.Present = 1; + + for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { + // + // Each Directory Pointer entries points to a page of Page Directory entires. + // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop. + // + PageDirectoryEntry = (PAGE_TABLE_ENTRY *)(UINTN)S3NvsPageTableAddress; + S3NvsPageTableAddress += SIZE_4KB; + + // + // Fill in a Page Directory Pointer Entries + // + PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry; + PageDirectoryPointerEntry->Bits.ReadWrite = 1; + PageDirectoryPointerEntry->Bits.Present = 1; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += 0x200000) { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry->Uint64 = (UINT64)PageAddress; + PageDirectoryEntry->Bits.ReadWrite = 1; + PageDirectoryEntry->Bits.Present = 1; + PageDirectoryEntry->Bits.MustBe1 = 1; + } + } + } + return (EFI_PHYSICAL_ADDRESS) (UINTN) PageMap; + } else { + // + // If DXE is running 32-bit mode, no need to establish page table. + // + return (EFI_PHYSICAL_ADDRESS) 0; + } +} + +/** + Gets the buffer of legacy memory below 1 MB + This function is to get the buffer in legacy memory below 1MB that is required during S3 resume. + + @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance. + @param Size The returned size of legacy memory below 1 MB. + + @retval EFI_SUCCESS Size is successfully returned. + @retval EFI_INVALID_PARAMETER The pointer Size is NULL. + +**/ +EFI_STATUS +EFIAPI +LegacyGetS3MemorySize ( + IN EFI_ACPI_S3_SAVE_PROTOCOL *This, + OUT UINTN *Size + ) +{ + if (Size == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Size = mLegacyRegionSize; + return EFI_SUCCESS; +} + +/** + Prepares all information that is needed in the S3 resume boot path. + + Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path + + @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance. + @param LegacyMemoryAddress The base address of legacy memory. + + @retval EFI_NOT_FOUND Some necessary information cannot be found. + @retval EFI_SUCCESS All information was saved successfully. + @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information. + @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB. + +**/ +EFI_STATUS +EFIAPI +S3Ready ( + IN EFI_ACPI_S3_SAVE_PROTOCOL *This, + IN VOID *LegacyMemoryAddress + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer; + ACPI_S3_CONTEXT *AcpiS3Context; + STATIC BOOLEAN AlreadyEntered; + IA32_DESCRIPTOR *Idtr; + IA32_IDT_GATE_DESCRIPTOR *IdtGate; + + DEBUG ((EFI_D_INFO, "S3Ready!\n")); + + // + // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again. + // So if 2nd S3Save() is triggered later, we need ignore it. + // + if (AlreadyEntered) { + return EFI_SUCCESS; + } + AlreadyEntered = TRUE; + + AcpiS3Context = AllocateAcpiNvsMemoryBelow4G (sizeof(*AcpiS3Context)); + ASSERT (AcpiS3Context != NULL); + AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context; + + // + // Get ACPI Table because we will save its position to variable + // + AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable (); + ASSERT (AcpiS3Context->AcpiFacsTable != 0); + + IdtGate = AllocateAcpiNvsMemoryBelow4G (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR)); + Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100); + Idtr->Base = (UINTN)IdtGate; + Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1); + AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr; + + Status = SaveLockBox ( + &mAcpiS3IdtrProfileGuid, + (VOID *)(UINTN)Idtr, + (UINTN)sizeof(IA32_DESCRIPTOR) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + // + // Allocate page table + // + AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables (); + + // + // Allocate stack + // + AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize); + AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3BootScriptStackSize)); + ASSERT (AcpiS3Context->BootScriptStackBase != 0); + + // + // Allocate a code buffer < 4G for S3 debug to load external code + // + AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGE_SIZE); + + DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable)); + DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile)); + DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress)); + DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress)); + + Status = SaveLockBox ( + &gEfiAcpiVariableGuid, + &AcpiS3ContextBuffer, + sizeof(AcpiS3ContextBuffer) + ); + ASSERT_EFI_ERROR (Status); + + Status = SaveLockBox ( + &gEfiAcpiS3ContextGuid, + (VOID *)(UINTN)AcpiS3Context, + (UINTN)sizeof(*AcpiS3Context) + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); + ASSERT_EFI_ERROR (Status); + + if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + S3ReadyThunkPlatform (AcpiS3Context); + } + + return EFI_SUCCESS; +} + +/** + The Driver Entry Point. + + The function is the driver Entry point which will produce AcpiS3SaveProtocol. + + @param ImageHandle A handle for the image that is initializing this driver + @param SystemTable A pointer to the EFI system table + + @retval EFI_SUCCESS: Driver initialized successfully + @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + +**/ +EFI_STATUS +EFIAPI +InstallAcpiS3Save ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (!FeaturePcdGet(PcdPlatformCsmSupport)) { + // + // More memory for no CSM tip, because GDT need relocation + // + mLegacyRegionSize = 0x250; + } else { + mLegacyRegionSize = 0x100; + } + + if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { + InstallAcpiS3SaveThunk (); + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiAcpiS3SaveProtocolGuid, + EFI_NATIVE_INTERFACE, + &mS3Save + ); + ASSERT_EFI_ERROR (Status); + return Status; +} diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h new file mode 100644 index 0000000000..d9bbe932d8 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h @@ -0,0 +1,135 @@ +/** @file + This is an implementation of the ACPI S3 Save protocol. This is defined in + S3 boot path specification 0.9. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ACPI_S3_SAVE_H_ +#define _ACPI_S3_SAVE_H_ + +#pragma pack(push, 1) + +typedef union { + struct { + UINT32 LimitLow : 16; + UINT32 BaseLow : 16; + UINT32 BaseMid : 8; + UINT32 Type : 4; + UINT32 System : 1; + UINT32 Dpl : 2; + UINT32 Present : 1; + UINT32 LimitHigh : 4; + UINT32 Software : 1; + UINT32 Reserved : 1; + UINT32 DefaultSize : 1; + UINT32 Granularity : 1; + UINT32 BaseHigh : 8; + } Bits; + UINT64 Uint64; +} IA32_GDT; + +typedef struct { + IA32_IDT_GATE_DESCRIPTOR Ia32IdtEntry; + UINT32 Offset32To63; + UINT32 Reserved; +} X64_IDT_GATE_DESCRIPTOR; + +// +// Page-Map Level-4 Offset (PML4) and +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB +// + +typedef union { + struct { + UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User + UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Reserved:1; // Reserved + UINT64 MustBeZero:2; // Must Be Zero + UINT64 Available:3; // Available for use by system software + UINT64 PageTableBaseAddress:40; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system software + UINT64 Nx:1; // No Execute bit + } Bits; + UINT64 Uint64; +} PAGE_MAP_AND_DIRECTORY_POINTER; + +// +// Page Table Entry 2MB +// +typedef union { + struct { + UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User + UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU) + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page + UINT64 MustBe1:1; // Must be 1 + UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system software + UINT64 PAT:1; // + UINT64 MustBeZero:8; // Must be zero; + UINT64 PageTableBaseAddress:31; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system software + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution + } Bits; + UINT64 Uint64; +} PAGE_TABLE_ENTRY; + +#pragma pack() + +/** + Gets the buffer of legacy memory below 1 MB + This function is to get the buffer in legacy memory below 1MB that is required during S3 resume. + + @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance. + @param Size The returned size of legacy memory below 1 MB. + + @retval EFI_SUCCESS Size is successfully returned. + @retval EFI_INVALID_PARAMETER The pointer Size is NULL. + +**/ +EFI_STATUS +EFIAPI +LegacyGetS3MemorySize ( + IN EFI_ACPI_S3_SAVE_PROTOCOL * This, + OUT UINTN * Size + ); + +/** + Prepares all information that is needed in the S3 resume boot path. + + Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path + + @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance. + @param LegacyMemoryAddress The base address of legacy memory. + + @retval EFI_NOT_FOUND Some necessary information cannot be found. + @retval EFI_SUCCESS All information was saved successfully. + @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information. + @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB. + +**/ +EFI_STATUS +EFIAPI +S3Ready ( + IN EFI_ACPI_S3_SAVE_PROTOCOL *This, + IN VOID *LegacyMemoryAddress + ); +#endif diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf new file mode 100644 index 0000000000..24a526d963 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf @@ -0,0 +1,83 @@ +## @file +# Component description file for AcpiS3Save module. +# +# This is an implementation of the ACPI S3 Save protocol. +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are +# licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiS3SaveDxe + FILE_GUID = 2BDED685-F733-455f-A840-43A22B791FB3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InstallAcpiS3Save + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + AcpiS3Save.h + AcpiS3Save.c + AcpiVariableThunkPlatform.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + PcdLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + HobLib + UefiLib + LockBoxLib + DebugLib + DxeServicesLib + +[Guids] + gEfiAcpiVariableGuid # ALWAYS_CONSUMED + gEfiAcpiS3ContextGuid # ALWAYS_CONSUMED + gEfiAcpiVariableCompatiblityGuid # SOMETIME_CONSUMED L"AcpiGlobalVariable" + gEfiAcpi20TableGuid # ALWAYS_CONSUMED System Table + gEfiAcpi10TableGuid # ALWAYS_CONSUMED System Table + +[Protocols] + gEfiAcpiS3SaveProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiLegacyRegion2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gFrameworkEfiMpServiceProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + +[FeaturePcd] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode + +[Pcd] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3AcpiReservedMemorySize ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize ## CONSUMES + +[Depex] + # + # Note: the extra dependency of gEfiMpServiceProtocolGuid is to ensure that ACPI variable is set by MpDxe driver before + # AcpiS3SaveDxe module is executed. + # + gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid AND gEfiMpServiceProtocolGuid + diff --git a/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c new file mode 100644 index 0000000000..883b79035f --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c @@ -0,0 +1,166 @@ +/** @file + This is an implementation of the AcpiVariable platform field for ECP platform. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the BSD License which accompanies this distribution. The +full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +== + +typedef struct { + EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase; <<=== + UINT32 AcpiReservedMemorySize; <<=== + EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase; + EFI_PHYSICAL_ADDRESS AcpiBootScriptTable; + EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase; + EFI_PHYSICAL_ADDRESS AcpiFacsTable; + UINT64 SystemMemoryLength; <<=== + ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData; + EFI_PHYSICAL_ADDRESS VideoOpromAddress; + UINT32 VideoOpromSize; + EFI_PHYSICAL_ADDRESS S3DebugBufferAddress; + EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint; +} ACPI_VARIABLE_SET_COMPATIBILITY; + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED +ACPI_VARIABLE_SET_COMPATIBILITY *mAcpiVariableSetCompatibility = NULL; + +/** + Allocate EfiACPIMemoryNVS below 4G memory address. + + This function allocates EfiACPIMemoryNVS below 4G memory address. + + @param Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID* +AllocateAcpiNvsMemoryBelow4G ( + IN UINTN Size + ); + +/** + Hook point for AcpiVariableThunkPlatform for S3Ready. + + @param AcpiS3Context ACPI s3 context +**/ +VOID +S3ReadyThunkPlatform ( + IN ACPI_S3_CONTEXT *AcpiS3Context + ) +{ + EFI_PHYSICAL_ADDRESS AcpiMemoryBase; + UINT32 AcpiMemorySize; + EFI_PEI_HOB_POINTERS Hob; + UINT64 MemoryLength; + + DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n")); + + // + // Allocate ACPI reserved memory under 4G + // + AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize)); + ASSERT (AcpiMemoryBase != 0); + AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); + + // + // Calculate the system memory length by memory hobs + // + MemoryLength = 0x100000; + Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); + ASSERT (Hob.Raw != NULL); + while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { + if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + // + // Skip the memory region below 1MB + // + if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { + MemoryLength += Hob.ResourceDescriptor->ResourceLength; + } + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); + } + + mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase; + mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize; + mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength; + + DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase)); + DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize)); + DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength)); + + return ; +} + +/** + Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. +**/ +VOID +InstallAcpiS3SaveThunk ( + VOID + ) +{ + EFI_STATUS Status; + FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService; + UINTN VarSize; + + Status = gBS->LocateProtocol ( + &gFrameworkEfiMpServiceProtocolGuid, + NULL, + (VOID**) &FrameworkMpService + ); + if (!EFI_ERROR (Status)) { + // + // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set + // should be produced by CPU driver. + // + VarSize = sizeof (mAcpiVariableSetCompatibility); + Status = gRT->GetVariable ( + ACPI_GLOBAL_VARIABLE, + &gEfiAcpiVariableCompatiblityGuid, + NULL, + &VarSize, + &mAcpiVariableSetCompatibility + ); + ASSERT_EFI_ERROR (Status); + } else { + // + // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform + // driver need this variable + // + mAcpiVariableSetCompatibility = AllocateAcpiNvsMemoryBelow4G (sizeof(ACPI_VARIABLE_SET_COMPATIBILITY)); + Status = gRT->SetVariable ( + ACPI_GLOBAL_VARIABLE, + &gEfiAcpiVariableCompatiblityGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof(mAcpiVariableSetCompatibility), + &mAcpiVariableSetCompatibility + ); + ASSERT_EFI_ERROR (Status); + } + + DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility)); +}