summaryrefslogtreecommitdiff
path: root/Core/MdeModulePkg/Universal/Acpi
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2017-04-27 11:05:07 +0800
committerGuo Mang <mang.guo@intel.com>2017-04-27 11:05:07 +0800
commitc23f114d3cfbb29b8734b87213d1ec0de404197b (patch)
tree4f3612573be055139a88213559212a40b7862fee /Core/MdeModulePkg/Universal/Acpi
parent001e57a103fce87245bfb7ae9c32ffb499a64135 (diff)
downloadedk2-platforms-c23f114d3cfbb29b8734b87213d1ec0de404197b.tar.xz
MdeModulePkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core/MdeModulePkg/Universal/Acpi')
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c260
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni22
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf56
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c1059
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h586
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c90
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h240
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf84
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c1856
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c302
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c280
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c614
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c452
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c545
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c465
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf62
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni22
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf95
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni23
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S66
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm71
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm68
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c62
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c489
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h96
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S130
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm135
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm136
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c267
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c909
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf92
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni24
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c207
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf76
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni27
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c336
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf72
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni23
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c532
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h178
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c935
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf77
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni22
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni20
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h161
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c920
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf62
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni22
-rw-r--r--Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni20
57 files changed, 13508 insertions, 0 deletions
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c
new file mode 100644
index 0000000000..44bdd94fa8
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c
@@ -0,0 +1,260 @@
+/** @file
+ Sample ACPI Platform Driver
+
+ Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
+ 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 <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/FirmwareVolume2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Acpi.h>
+
+/**
+ Locate the first instance of a protocol. If the protocol requested is an
+ FV protocol, then it will return the first FV that contains the ACPI table
+ storage file.
+
+ @param Instance Return pointer to the first instance of the protocol
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_NOT_FOUND The protocol could not be located.
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
+
+**/
+EFI_STATUS
+LocateFvInstanceWithTables (
+ OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+
+ FvStatus = 0;
+
+ //
+ // Locate protocol.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Defined errors at this time are not found and out of resources.
+ //
+ return Status;
+ }
+
+
+
+ //
+ // Looking for FV with ACPI storage file
+ //
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ //
+ // Get the protocol on this handle
+ // This should not fail because of LocateHandleBuffer
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID**) &FvInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // See if it has the ACPI storage file
+ //
+ Status = FvInstance->ReadFile (
+ FvInstance,
+ (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ //
+ // If we found it, then we are done
+ //
+ if (Status == EFI_SUCCESS) {
+ *Instance = FvInstance;
+ break;
+ }
+ }
+
+ //
+ // Our exit status is determined by the success of the previous operations
+ // If the protocol was found, Instance already points to it.
+ //
+
+ //
+ // Free any allocated buffers
+ //
+ gBS->FreePool (HandleBuffer);
+
+ return Status;
+}
+
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+
+**/
+VOID
+AcpiPlatformChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
+
+ //
+ // Set checksum to 0 first
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
+}
+
+
+/**
+ Entrypoint of Acpi Platform driver.
+
+ @param ImageHandle
+ @param SystemTable
+
+ @return EFI_SUCCESS
+ @return EFI_LOAD_ERROR
+ @return EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+EFIAPI
+AcpiPlatformEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ UINTN TableHandle;
+ UINT32 FvStatus;
+ UINTN TableSize;
+ UINTN Size;
+
+ Instance = 0;
+ CurrentTable = NULL;
+ TableHandle = 0;
+
+ //
+ // Find the AcpiTable protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Locate the firmware volume protocol
+ //
+ Status = LocateFvInstanceWithTables (&FwVol);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read tables from the storage file.
+ //
+ while (Status == EFI_SUCCESS) {
+
+ Status = FwVol->ReadSection (
+ FwVol,
+ (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile),
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID**) &CurrentTable,
+ &Size,
+ &FvStatus
+ );
+ if (!EFI_ERROR(Status)) {
+ //
+ // Add the table
+ //
+ TableHandle = 0;
+
+ TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length;
+ ASSERT (Size >= TableSize);
+
+ //
+ // Checksum ACPI table
+ //
+ AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize);
+
+ //
+ // Install ACPI table
+ //
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ CurrentTable,
+ TableSize,
+ &TableHandle
+ );
+
+ //
+ // Free memory allocated by ReadSection
+ //
+ gBS->FreePool (CurrentTable);
+
+ if (EFI_ERROR(Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Increment the instance
+ //
+ Instance++;
+ CurrentTable = NULL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni
new file mode 100644
index 0000000000..68b3e48e20
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Sample ACPI Platform Driver
+//
+// Sample ACPI Platform Driver
+//
+// Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Sample ACPI Platform Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Sample ACPI Platform Driver"
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
new file mode 100644
index 0000000000..34b1600171
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# Sample ACPI Platform Driver
+#
+# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+# 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 = AcpiPlatform
+ MODULE_UNI_FILE = AcpiPlatform.uni
+ FILE_GUID = cb933912-df8f-4305-b1f9-7b44fa11395c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = AcpiPlatformEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ AcpiPlatform.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ DxeServicesLib
+ PcdLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile ## CONSUMES
+
+[Depex]
+ gEfiAcpiTableProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiPlatformExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni
new file mode 100644
index 0000000000..e976c59983
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// AcpiPlatform Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Platform Sample DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
new file mode 100644
index 0000000000..2b3bb35625
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
@@ -0,0 +1,1059 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved. <BR>
+ 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.
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = {
+ EFI_ACPI_TABLE_VERSION_NONE,
+ GetAcpiTable2,
+ RegisterNotify,
+ Open,
+ OpenSdt,
+ Close,
+ GetChild,
+ GetOption,
+ SetOption,
+ FindPath
+};
+
+/**
+ This function returns ACPI Table instance.
+
+ @return AcpiTableInstance
+**/
+EFI_ACPI_TABLE_INSTANCE *
+SdtGetAcpiTableInstance (
+ VOID
+ )
+{
+ return mPrivateData;
+}
+
+/**
+ This function finds the table specified by the buffer.
+
+ @param[in] Buffer Table buffer to find.
+
+ @return ACPI table list.
+**/
+EFI_ACPI_TABLE_LIST *
+FindTableByBuffer (
+ IN VOID *Buffer
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ LIST_ENTRY *CurrentLink;
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->TableList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) &&
+ ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) {
+ //
+ // Good! Found Table.
+ //
+ return CurrentTableList;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return NULL;
+}
+
+/**
+ This function updates AML table checksum.
+ It will search the ACPI table installed by ACPI_TABLE protocol.
+
+ @param[in] Buffer A piece of AML code buffer pointer.
+
+ @retval EFI_SUCCESS The table holds the AML buffer is found, and checksum is updated.
+ @retval EFI_NOT_FOUND The table holds the AML buffer is not found.
+**/
+EFI_STATUS
+SdtUpdateAmlChecksum (
+ IN VOID *Buffer
+ )
+{
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+
+ CurrentTableList = FindTableByBuffer (Buffer);
+ if (CurrentTableList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ AcpiPlatformChecksum (
+ (VOID *)CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ This function finds MAX AML buffer size.
+ It will search the ACPI table installed by ACPI_TABLE protocol.
+
+ @param[in] Buffer A piece of AML code buffer pointer.
+ @param[out] MaxSize On return it holds the MAX size of buffer.
+
+ @retval EFI_SUCCESS The table holds the AML buffer is found, and MAX size if returned.
+ @retval EFI_NOT_FOUND The table holds the AML buffer is not found.
+**/
+EFI_STATUS
+SdtGetMaxAmlBufferSize (
+ IN VOID *Buffer,
+ OUT UINTN *MaxSize
+ )
+{
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+
+ CurrentTableList = FindTableByBuffer (Buffer);
+ if (CurrentTableList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function invokes ACPI notification.
+
+ @param[in] AcpiTableInstance Instance to AcpiTable
+ @param[in] Version Version(s) to set.
+ @param[in] Handle Handle of the table.
+**/
+VOID
+SdtNotifyAcpiList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ )
+{
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_STATUS Status;
+
+ //
+ // We should not use Table buffer, because it is user input buffer.
+ //
+ Status = FindTableByHandle (
+ Handle,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->NotifyList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
+
+ //
+ // Inovke notification
+ //
+ CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle);
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return ;
+}
+
+/**
+ Returns a requested ACPI table.
+
+ The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated
+ with the Index that was input. The following structures are not considered elements in the list of
+ ACPI tables:
+ - Root System Description Pointer (RSD_PTR)
+ - Root System Description Table (RSDT)
+ - Extended System Description Table (XSDT)
+ Version is updated with a bit map containing all the versions of ACPI of which the table is a
+ member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,
+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.
+
+ @param[in] Index The zero-based index of the table to retrieve.
+ @param[out] Table Pointer for returning the table buffer.
+ @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type
+ EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the
+ EFI_ACPI_SDT_PROTOCOL.
+ @param[out] TableKey On return, points to the table key for the specified ACPI system definition table.
+ This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.
+ The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()
+ to uninstall the table.
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The requested index is too large and a table was not found.
+**/
+EFI_STATUS
+EFIAPI
+GetAcpiTable2 (
+ IN UINTN Index,
+ OUT EFI_ACPI_SDT_HEADER **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *TableKey
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ UINTN TableIndex;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_ACPI_TABLE_LIST *CurrentTable;
+
+ ASSERT (Table != NULL);
+ ASSERT (Version != NULL);
+ ASSERT (TableKey != NULL);
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the table
+ //
+ StartLink = &AcpiTableInstance->TableList;
+ CurrentLink = StartLink->ForwardLink;
+ TableIndex = 0;
+
+ while (CurrentLink != StartLink) {
+ if (TableIndex == Index) {
+ break;
+ }
+ //
+ // Next one
+ //
+ CurrentLink = CurrentLink->ForwardLink;
+ TableIndex ++;
+ }
+
+ if ((TableIndex != Index) || (CurrentLink == StartLink)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get handle and version
+ //
+ CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ *TableKey = CurrentTable->Handle;
+ *Version = CurrentTable->Version;
+ *Table = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register a callback when an ACPI table is installed.
+
+ This function registers a function which will be called whenever a new ACPI table is installed.
+
+ @param[in] Notification Points to the callback function to be registered
+**/
+VOID
+SdtRegisterNotify (
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Create a new list entry
+ //
+ CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST));
+ ASSERT (CurrentNotifyList != NULL);
+
+ //
+ // Initialize the table contents
+ //
+ CurrentNotifyList->Signature = EFI_ACPI_NOTIFY_LIST_SIGNATURE;
+ CurrentNotifyList->Notification = Notification;
+
+ //
+ // Add the table to the current list of tables
+ //
+ InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link);
+
+ return ;
+}
+
+/**
+ Unregister a callback when an ACPI table is installed.
+
+ This function unregisters a function which will be called whenever a new ACPI table is installed.
+
+ @param[in] Notification Points to the callback function to be unregistered.
+
+ @retval EFI_SUCCESS Callback successfully unregistered.
+ @retval EFI_INVALID_PARAMETER Notification does not match a known registration function.
+**/
+EFI_STATUS
+SdtUnregisterNotify (
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_ACPI_NOTIFY_LIST *CurrentNotifyList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the notify
+ //
+ StartLink = &AcpiTableInstance->NotifyList;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
+ if (CurrentNotifyList->Notification == Notification) {
+ //
+ // Good! Found notification.
+ //
+ // Remove it from list and free the node.
+ //
+ RemoveEntryList (&(CurrentNotifyList->Link));
+ FreePool (CurrentNotifyList);
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Not found!
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Register or unregister a callback when an ACPI table is installed.
+
+ This function registers or unregisters a function which will be called whenever a new ACPI table is
+ installed.
+
+ @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified
+ function will be unregistered.
+ @param[in] Notification Points to the callback function to be registered or unregistered.
+
+ @retval EFI_SUCCESS Callback successfully registered or unregistered.
+ @retval EFI_INVALID_PARAMETER Notification is NULL
+ @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterNotify (
+ IN BOOLEAN Register,
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ )
+{
+ //
+ // Check for invalid input parameters
+ //
+ if (Notification == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Register) {
+ //
+ // Register a new notify
+ //
+ SdtRegisterNotify (Notification);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Unregister an old notify
+ //
+ return SdtUnregisterNotify (Notification);
+ }
+}
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+SdtOpenSdtTable (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_AML_HANDLE *AmlHandle;
+
+ //
+ // Get the instance of the ACPI Table
+ //
+ AcpiTableInstance = SdtGetAcpiTableInstance ();
+
+ //
+ // Find the table
+ //
+ Status = FindTableByHandle (
+ TableKey,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ AmlHandle = AllocatePool (sizeof(*AmlHandle));
+ ASSERT (AmlHandle != NULL);
+ AmlHandle->Signature = EFI_AML_ROOT_HANDLE_SIGNATURE;
+ AmlHandle->Buffer = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER));
+ AmlHandle->Size = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER);
+ AmlHandle->AmlByteEncoding = NULL;
+ AmlHandle->Modified = FALSE;
+
+ //
+ // return the ACPI handle
+ //
+ *Handle = (EFI_ACPI_HANDLE)AmlHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+EFIAPI
+OpenSdt (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SdtOpenSdtTable (TableKey, Handle);
+}
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[in] BufferSize Max buffer size.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+SdtOpenEx (
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_AML_HANDLE *AmlHandle;
+
+ AmlByteEncoding = AmlSearchByOpByte (Buffer);
+ if (AmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Do not open NameString as handle
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Good, find it
+ //
+ AmlHandle = AllocatePool (sizeof(*AmlHandle));
+ ASSERT (AmlHandle != NULL);
+
+ AmlHandle->Signature = EFI_AML_HANDLE_SIGNATURE;
+ AmlHandle->Buffer = Buffer;
+ AmlHandle->AmlByteEncoding = AmlByteEncoding;
+ AmlHandle->Modified = FALSE;
+
+ AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize);
+ if (AmlHandle->Size == 0) {
+ FreePool (AmlHandle);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Handle = (EFI_ACPI_HANDLE)AmlHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+EFIAPI
+Open (
+ IN VOID *Buffer,
+ OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxSize;
+
+ MaxSize = 0;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Buffer == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SdtOpenEx (Buffer, MaxSize, Handle);
+}
+
+/**
+ Close an ACPI handle.
+
+ @param[in] Handle Returns the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_ACPI_HANDLE Handle
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) &&
+ (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update Checksum only if modified
+ //
+ if (AmlHandle->Modified) {
+ Status = SdtUpdateAmlChecksum (AmlHandle->Buffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ FreePool (AmlHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT CONST VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_STATUS Status;
+
+ ASSERT (DataType != NULL);
+ ASSERT (Data != NULL);
+ ASSERT (DataSize != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ //
+ // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
+ //
+ if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+ if (Index > AmlByteEncoding->MaxIndex) {
+ *DataType = EFI_ACPI_DATA_TYPE_NONE;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse option
+ //
+ Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Change information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[in] Data Points to the data.
+ @param[in] DataSize The size of the Data.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+ @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by
+ the option.
+
+**/
+EFI_STATUS
+EFIAPI
+SetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ EFI_STATUS Status;
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *OrgData;
+ UINTN OrgDataSize;
+
+ ASSERT (Data != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)Handle;
+ //
+ // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
+ //
+ if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+
+ if (Index > AmlByteEncoding->MaxIndex) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Parse option
+ //
+ Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataType == EFI_ACPI_DATA_TYPE_NONE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize > OrgDataSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // Update
+ //
+ CopyMem (OrgData, Data, DataSize);
+ AmlHandle->Modified = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child ACPI objects.
+
+ @param[in] ParentHandle Parent handle.
+ @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first
+ handle. On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetChild (
+ IN EFI_ACPI_HANDLE ParentHandle,
+ IN OUT EFI_ACPI_HANDLE *Handle
+ )
+{
+ EFI_AML_HANDLE *AmlParentHandle;
+ EFI_AML_HANDLE *AmlHandle;
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ ASSERT (Handle != NULL);
+
+ //
+ // Check for invalid input parameters
+ //
+ if (ParentHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = *Handle;
+ if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle;
+ if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
+ //
+ // Root handle
+ //
+ Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer);
+ } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
+ //
+ // Non-root handle
+ //
+ Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer);
+ } else {
+ //
+ // Invalid
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Buffer == NULL) {
+ *Handle = NULL;
+ return EFI_SUCCESS;
+ }
+ return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle);
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the AML path.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+SdtFindPathFromNonRoot (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN UINT8 *AmlPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Buffer = NULL;
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // For non-root handle, we need search from THIS node instead of ROOT.
+ //
+ Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Buffer == NULL) {
+ *HandleOut = NULL;
+ return EFI_SUCCESS;
+ }
+ return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
+}
+
+/**
+ Duplicate AML handle.
+
+ @param[in] AmlHandle Handle to be duplicated.
+
+ @return Duplicated AML handle.
+**/
+EFI_AML_HANDLE *
+SdtDuplicateHandle (
+ IN EFI_AML_HANDLE *AmlHandle
+ )
+{
+ EFI_AML_HANDLE *DstAmlHandle;
+
+ DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle));
+ ASSERT (DstAmlHandle != NULL);
+ CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle));
+
+ return DstAmlHandle;
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the AML path.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+SdtFindPathFromRoot (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN UINT8 *AmlPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_ACPI_HANDLE ChildHandle;
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+ VOID *Buffer;
+
+ Buffer = NULL;
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // Handle case that AcpiPath is Root
+ //
+ if (AmlIsRootPath (AmlPath)) {
+ //
+ // Duplicate RootHandle
+ //
+ *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Let children find it.
+ //
+ ChildHandle = NULL;
+ while (TRUE) {
+ Status = GetChild (HandleIn, &ChildHandle);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChildHandle == NULL) {
+ //
+ // Not found
+ //
+ *HandleOut = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // More child
+ //
+ AmlHandle = (EFI_AML_HANDLE *)ChildHandle;
+ Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer != NULL) {
+ //
+ // Great! Find it, open
+ //
+ Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Not success, try next one
+ //
+ }
+ }
+
+ //
+ // Should not run here
+ //
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+FindPath (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN VOID *AcpiPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ )
+{
+ EFI_AML_HANDLE *AmlHandle;
+ EFI_STATUS Status;
+ UINT8 *AmlPath;
+
+ //
+ // Check for invalid input parameters
+ //
+ if (HandleIn == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AmlHandle = (EFI_AML_HANDLE *)HandleIn;
+
+ //
+ // Convert ASL path to AML path
+ //
+ AmlPath = AmlNameFromAslName (AcpiPath);
+ if (AmlPath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - "));
+ AmlPrintNameString (AmlPath);
+ DEBUG ((EFI_D_ERROR, "\n"));
+ DEBUG_CODE_END ();
+
+ if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
+ //
+ // Root Handle
+ //
+ Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut);
+ } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
+ //
+ // Non-Root handle
+ //
+ Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut);
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (AmlPath);
+
+ return Status;
+}
+
+/**
+ This function initializes AcpiSdt protocol in ACPI table instance.
+
+ @param[in] AcpiTableInstance Instance to construct
+**/
+VOID
+SdtAcpiTableAcpiSdtConstructor (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+
+ InitializeListHead (&AcpiTableInstance->NotifyList);
+ CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));
+ AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions);
+
+ return ;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h
new file mode 100644
index 0000000000..f11bdee9ac
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.h
@@ -0,0 +1,586 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved. <BR>
+ 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_SDT_H_
+#define _ACPI_SDT_H_
+
+//
+// Privacy data structure
+//
+
+//
+// ACPI Notify Linked List Signature.
+//
+#define EFI_ACPI_NOTIFY_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'N', 'L')
+
+//
+// ACPI Notify List Entry definition.
+//
+// Signature must be set to EFI_ACPI_NOTIFY_LIST_SIGNATURE
+// Link is the linked list data.
+// Notification is the callback function.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_ACPI_NOTIFICATION_FN Notification;
+} EFI_ACPI_NOTIFY_LIST;
+
+//
+// Containment record for ACPI Notify linked list.
+//
+#define EFI_ACPI_NOTIFY_LIST_FROM_LINK(_link) CR (_link, EFI_ACPI_NOTIFY_LIST, Link, EFI_ACPI_NOTIFY_LIST_SIGNATURE)
+
+typedef struct _AML_BYTE_ENCODING AML_BYTE_ENCODING;
+typedef struct _EFI_AML_NODE_LIST EFI_AML_NODE_LIST;
+
+//
+// AML Node Linked List Signature.
+//
+#define EFI_AML_NODE_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'M', 'L')
+
+//
+// AML Node Linked List Entry definition.
+//
+// Signature must be set to EFI_AML_NODE_LIST_SIGNATURE
+// Link is the linked list data.
+// Name is the ACPI node name.
+// This is listed for PATH finding.
+// Buffer is the ACPI node buffer pointer, the first/second bytes are opcode.
+// This buffer should not be freed.
+// Size is the total size of this ACPI node buffer.
+// Children is the children linked list of this node.
+//
+#define AML_NAME_SEG_SIZE 4
+
+struct _EFI_AML_NODE_LIST {
+ UINT32 Signature;
+ UINT8 Name[AML_NAME_SEG_SIZE];
+ UINT8 *Buffer;
+ UINTN Size;
+ LIST_ENTRY Link;
+ LIST_ENTRY Children;
+ EFI_AML_NODE_LIST *Parent;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+};
+
+//
+// Containment record for AML Node linked list.
+//
+#define EFI_AML_NODE_LIST_FROM_LINK(_link) CR (_link, EFI_AML_NODE_LIST, Link, EFI_AML_NODE_LIST_SIGNATURE)
+
+//
+// AML Handle Signature.
+//
+#define EFI_AML_HANDLE_SIGNATURE SIGNATURE_32 ('E', 'A', 'H', 'S')
+#define EFI_AML_ROOT_HANDLE_SIGNATURE SIGNATURE_32 ('E', 'A', 'R', 'H')
+
+//
+// AML Handle Entry definition.
+//
+// Signature must be set to EFI_AML_HANDLE_SIGNATURE or EFI_AML_ROOT_HANDLE_SIGNATURE
+// Buffer is the ACPI node buffer pointer, the first/second bytes are opcode.
+// This buffer should not be freed.
+// Size is the total size of this ACPI node buffer.
+//
+typedef struct {
+ UINT32 Signature;
+ UINT8 *Buffer;
+ UINTN Size;
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ BOOLEAN Modified;
+} EFI_AML_HANDLE;
+
+typedef UINT32 AML_OP_PARSE_INDEX;
+
+#define AML_OP_PARSE_INDEX_GET_OPCODE 0
+#define AML_OP_PARSE_INDEX_GET_TERM1 1
+#define AML_OP_PARSE_INDEX_GET_TERM2 2
+#define AML_OP_PARSE_INDEX_GET_TERM3 3
+#define AML_OP_PARSE_INDEX_GET_TERM4 4
+#define AML_OP_PARSE_INDEX_GET_TERM5 5
+#define AML_OP_PARSE_INDEX_GET_TERM6 6
+#define AML_OP_PARSE_INDEX_GET_SIZE (AML_OP_PARSE_INDEX)-1
+
+typedef UINT32 AML_OP_PARSE_FORMAT;
+#define AML_NONE 0
+#define AML_OPCODE 1
+#define AML_UINT8 2
+#define AML_UINT16 3
+#define AML_UINT32 4
+#define AML_UINT64 5
+#define AML_NAME 6
+#define AML_STRING 7
+#define AML_OBJECT 8
+
+typedef UINT32 AML_OP_ATTRIBUTE;
+#define AML_HAS_PKG_LENGTH 0x1 // It is ACPI attribute - if OpCode has PkgLength
+#define AML_IS_NAME_CHAR 0x2 // It is ACPI attribute - if this is NameChar
+#define AML_HAS_CHILD_OBJ 0x4 // it is ACPI attribute - if OpCode has Child Object.
+#define AML_IN_NAMESPACE 0x10000 // It is UEFI SDT attribute - if OpCode will be in NameSpace
+ // NOTE; Not all OBJECT will be in NameSpace
+ // For example, BankField | CreateBitField | CreateByteField | CreateDWordField |
+ // CreateField | CreateQWordField | CreateWordField | Field | IndexField.
+
+struct _AML_BYTE_ENCODING {
+ UINT8 OpCode;
+ UINT8 SubOpCode;
+ AML_OP_PARSE_INDEX MaxIndex;
+ AML_OP_PARSE_FORMAT Format[6];
+ AML_OP_ATTRIBUTE Attribute;
+};
+
+//
+// AcpiSdt protocol declaration
+//
+
+/**
+ Returns a requested ACPI table.
+
+ The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated
+ with the Index that was input. The following structures are not considered elements in the list of
+ ACPI tables:
+ - Root System Description Pointer (RSD_PTR)
+ - Root System Description Table (RSDT)
+ - Extended System Description Table (XSDT)
+ Version is updated with a bit map containing all the versions of ACPI of which the table is a
+ member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,
+ the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.
+
+ @param[in] Index The zero-based index of the table to retrieve.
+ @param[out] Table Pointer for returning the table buffer.
+ @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type
+ EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the
+ EFI_ACPI_SDT_PROTOCOL.
+ @param[out] TableKey On return, points to the table key for the specified ACPI system definition table.
+ This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.
+ The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()
+ to uninstall the table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The requested index is too large and a table was not found.
+**/
+EFI_STATUS
+EFIAPI
+GetAcpiTable2 (
+ IN UINTN Index,
+ OUT EFI_ACPI_SDT_HEADER **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *TableKey
+ );
+
+/**
+ Register or unregister a callback when an ACPI table is installed.
+
+ This function registers or unregisters a function which will be called whenever a new ACPI table is
+ installed.
+
+ @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified
+ function will be unregistered.
+ @param[in] Notification Points to the callback function to be registered or unregistered.
+
+ @retval EFI_SUCCESS Callback successfully registered or unregistered.
+ @retval EFI_INVALID_PARAMETER Notification is NULL
+ @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.
+**/
+EFI_STATUS
+EFIAPI
+RegisterNotify (
+ IN BOOLEAN Register,
+ IN EFI_ACPI_NOTIFICATION_FN Notification
+ );
+
+/**
+ Create a handle for the first ACPI opcode in an ACPI system description table.
+
+ @param[in] TableKey The table key for the ACPI table, as returned by GetTable().
+ @param[out] Handle On return, points to the newly created ACPI handle.
+
+ @retval EFI_SUCCESS Handle created successfully.
+ @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table.
+**/
+EFI_STATUS
+EFIAPI
+OpenSdt (
+ IN UINTN TableKey,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+EFIAPI
+Open (
+ IN VOID *Buffer,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Close an ACPI handle.
+
+ @param[in] Handle Returns the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_ACPI_HANDLE Handle
+ );
+
+/**
+ Retrieve information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT CONST VOID **Data,
+ OUT UINTN *DataSize
+ );
+
+/**
+ Change information about an ACPI object.
+
+ @param[in] Handle ACPI object handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[in] Data Points to the data.
+ @param[in] DataSize The size of the Data.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
+ @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by
+ the option.
+
+**/
+EFI_STATUS
+EFIAPI
+SetOption (
+ IN EFI_ACPI_HANDLE Handle,
+ IN UINTN Index,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ );
+
+/**
+ Return the child ACPI objects.
+
+ @param[in] ParentHandle Parent handle.
+ @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first
+ handle. On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+GetChild (
+ IN EFI_ACPI_HANDLE ParentHandle,
+ IN OUT EFI_ACPI_HANDLE *Handle
+ );
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI path
+
+ @param[in] HandleIn Points to the handle of the object representing the starting point for the path search.
+ @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format.
+ @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+EFIAPI
+FindPath (
+ IN EFI_ACPI_HANDLE HandleIn,
+ IN VOID *AcpiPath,
+ OUT EFI_ACPI_HANDLE *HandleOut
+ );
+
+//
+// ACPI SDT function
+//
+
+/**
+ Create a handle from an ACPI opcode
+
+ @param[in] Buffer Points to the ACPI opcode.
+ @param[in] BufferSize Max buffer size.
+ @param[out] Handle Upon return, holds the handle.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an
+ invalid opcode.
+
+**/
+EFI_STATUS
+SdtOpenEx (
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT EFI_ACPI_HANDLE *Handle
+ );
+
+//
+// AML support function
+//
+
+/**
+ Get AML NameString size.
+
+ @param[in] Buffer AML NameString.
+ @param[out] BufferSize AML NameString size
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
+**/
+EFI_STATUS
+AmlGetNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *BufferSize
+ );
+
+/**
+ This function retuns package length from the buffer.
+
+ @param[in] Buffer AML buffer
+ @param[out] PkgLength The total length of package.
+
+ @return The byte data count to present the package length.
+**/
+UINTN
+AmlGetPkgLength (
+ IN UINT8 *Buffer,
+ OUT UINTN *PkgLength
+ );
+
+/**
+ This function returns AcpiDataType according to AmlType.
+
+ @param[in] AmlType AML Type.
+
+ @return AcpiDataType
+**/
+EFI_ACPI_DATA_TYPE
+AmlTypeToAcpiType (
+ IN AML_OP_PARSE_FORMAT AmlType
+ );
+
+/**
+ This function returns AmlByteEncoding according to OpCode Byte.
+
+ @param[in] OpByteBuffer OpCode byte buffer.
+
+ @return AmlByteEncoding
+**/
+AML_BYTE_ENCODING *
+AmlSearchByOpByte (
+ IN UINT8 *OpByteBuffer
+ );
+
+/**
+ Return object size.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML object buffer.
+ @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
+
+ @return Size of the object.
+**/
+UINTN
+AmlGetObjectSize (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize
+ );
+
+/**
+ Return object name.
+
+ @param[in] AmlHandle AML handle.
+
+ @return Name of the object.
+**/
+CHAR8 *
+AmlGetObjectName (
+ IN EFI_AML_HANDLE *AmlHandle
+ );
+
+/**
+ Retrieve information according to AmlHandle
+
+ @param[in] AmlHandle AML handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionHandleCommon (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ );
+
+/**
+ Return offset of last option.
+
+ @param[in] AmlHandle AML Handle.
+ @param[out] Buffer Upon return, points to the offset after last option.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetOffsetAfterLastOption (
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT UINT8 **Buffer
+ );
+
+/**
+ Return the child ACPI objects from Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ );
+
+/**
+ Return the child ACPI objects from Non-Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Non-Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromNonRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ );
+
+/**
+ Return AML name according to ASL name.
+ The caller need free the AmlName returned.
+
+ @param[in] AslPath ASL name.
+
+ @return AmlName
+**/
+UINT8 *
+AmlNameFromAslName (
+ IN UINT8 *AslPath
+ );
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI AML path
+
+ @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the ACPI AML path.
+ @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+ @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
+ FALSE means to find AML path from this Node (The HandleIn).
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlFindPath (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN UINT8 *AmlPath,
+ OUT VOID **Buffer,
+ IN BOOLEAN FromRoot
+ );
+
+/**
+ Print AML NameString.
+
+ @param[in] Buffer AML NameString.
+**/
+VOID
+AmlPrintNameString (
+ IN UINT8 *Buffer
+ );
+
+/**
+ Print AML NameSeg.
+
+ @param[in] Buffer AML NameSeg.
+**/
+VOID
+AmlPrintNameSeg (
+ IN UINT8 *Buffer
+ );
+
+/**
+ Check if it is AML Root name
+
+ @param[in] Buffer AML path.
+
+ @retval TRUE AML path is root.
+ @retval FALSE AML path is not root.
+**/
+BOOLEAN
+AmlIsRootPath (
+ IN UINT8 *Buffer
+ );
+
+#endif
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c
new file mode 100644
index 0000000000..f39de844e0
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.c
@@ -0,0 +1,90 @@
+/** @file
+ ACPI Table Protocol Driver
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ 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.
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+
+//
+// Handle to install ACPI Table Protocol
+//
+EFI_HANDLE mHandle = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_TABLE_INSTANCE *mPrivateData = NULL;
+
+/**
+ Entry point of the ACPI table driver.
+ Creates and initializes an instance of the ACPI Table
+ Protocol and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver.
+ @param SystemTable A pointer to the EFI system table.
+
+ @return EFI_SUCCESS Driver initialized successfully.
+ @return EFI_LOAD_ERROR Failed to Initialize or has been loaded.
+ @return EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeAcpiTableDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_INSTANCE *PrivateData;
+
+ //
+ // Initialize our protocol
+ //
+ PrivateData = AllocateZeroPool (sizeof (EFI_ACPI_TABLE_INSTANCE));
+ ASSERT (PrivateData);
+ PrivateData->Signature = EFI_ACPI_TABLE_SIGNATURE;
+
+ //
+ // Call all constructors per produced protocols
+ //
+ Status = AcpiTableAcpiTableConstructor (PrivateData);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrivateData);
+ return EFI_LOAD_ERROR;
+ }
+
+ //
+ // Install ACPI Table protocol
+ //
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ mPrivateData = PrivateData;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ &gEfiAcpiSdtProtocolGuid,
+ &mPrivateData->AcpiSdtProtocol,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ NULL
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
new file mode 100644
index 0000000000..d6d81ae04d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
@@ -0,0 +1,240 @@
+/** @file
+ ACPI Table Protocol Driver
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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_TABLE_H_
+#define _ACPI_TABLE_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Guid/Acpi.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Statements that include other files
+//
+#include <IndustryStandard/Acpi.h>
+
+#include "AcpiSdt.h"
+
+//
+// Great than or equal to 2.0.
+//
+#define ACPI_TABLE_VERSION_GTE_2_0 (EFI_ACPI_TABLE_VERSION_2_0 | \
+ EFI_ACPI_TABLE_VERSION_3_0 | \
+ EFI_ACPI_TABLE_VERSION_4_0 | \
+ EFI_ACPI_TABLE_VERSION_5_0)
+
+//
+// Private Driver Data
+//
+//
+// ACPI Table Linked List Signature.
+//
+#define EFI_ACPI_TABLE_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'T', 'L')
+
+//
+// ACPI Table Linked List Entry definition.
+//
+// Signature must be set to EFI_ACPI_TABLE_LIST_SIGNATURE
+// Link is the linked list data.
+// Version is the versions of the ACPI tables that this table belongs in.
+// Table is a pointer to the table.
+// PageAddress is the address of the pages allocated for the table.
+// NumberOfPages is the number of pages allocated at PageAddress.
+// Handle is used to identify a particular table.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_COMMON_HEADER *Table;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ UINTN NumberOfPages;
+ UINTN Handle;
+} EFI_ACPI_TABLE_LIST;
+
+//
+// Containment record for ACPI Table linked list.
+//
+#define EFI_ACPI_TABLE_LIST_FROM_LINK(_link) CR (_link, EFI_ACPI_TABLE_LIST, Link, EFI_ACPI_TABLE_LIST_SIGNATURE)
+
+//
+// The maximum number of tables this driver supports
+//
+#define EFI_ACPI_MAX_NUM_TABLES 20
+
+//
+// Protocol private structure definition
+//
+//
+// ACPI support protocol instance signature definition.
+//
+#define EFI_ACPI_TABLE_SIGNATURE SIGNATURE_32 ('S', 'T', 'A', 'E')
+
+//
+// ACPI support protocol instance data structure
+//
+typedef struct {
+ UINTN Signature;
+ EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp1; // Pointer to RSD_PTR structure
+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp3; // Pointer to RSD_PTR structure
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt1; // Pointer to RSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt3; // Pointer to RSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Xsdt; // Pointer to XSDT table header
+ EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt1; // Pointer to FADT table header
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt3; // Pointer to FADT table header
+ EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs1; // Pointer to FACS table header
+ EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs3; // Pointer to FACS table header
+ EFI_ACPI_DESCRIPTION_HEADER *Dsdt1; // Pointer to DSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Dsdt3; // Pointer to DSDT table header
+ LIST_ENTRY TableList;
+ UINTN NumberOfTableEntries1; // Number of ACPI 1.0 tables
+ UINTN NumberOfTableEntries3; // Number of ACPI 3.0 tables
+ UINTN CurrentHandle;
+ EFI_ACPI_TABLE_PROTOCOL AcpiTableProtocol;
+ EFI_ACPI_SDT_PROTOCOL AcpiSdtProtocol;
+ LIST_ENTRY NotifyList;
+} EFI_ACPI_TABLE_INSTANCE;
+
+//
+// ACPI table protocol instance containing record macro
+//
+#define EFI_ACPI_TABLE_INSTANCE_FROM_THIS(a) \
+ CR (a, \
+ EFI_ACPI_TABLE_INSTANCE, \
+ AcpiTableProtocol, \
+ EFI_ACPI_TABLE_SIGNATURE \
+ )
+
+//
+// Protocol Constructor functions
+//
+
+/**
+ Constructor for the ACPI support protocol. Initializes instance
+ data.
+
+ @param AcpiTableInstance Instance to construct
+
+ @return EFI_SUCCESS Instance initialized.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+AcpiTableAcpiTableConstructor (
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+
+/**
+ Entry point of the ACPI table driver.
+ Creates and initializes an instance of the ACPI Table
+ Protocol and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @return EFI_SUCCESS Driver initialized successfully
+ @return EFI_LOAD_ERROR Failed to Initialize or has been loaded
+ @return EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeAcpiTableDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ This function finds the table specified by the handle and returns a pointer to it.
+ If the handle is not found, EFI_NOT_FOUND is returned and the contents of Table are
+ undefined.
+
+ @param[in] Handle Table to find.
+ @param[in] TableList Table list to search
+ @param[out] Table Pointer to table found.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND No table found matching the handle specified.
+
+**/
+EFI_STATUS
+FindTableByHandle (
+ IN UINTN Handle,
+ IN LIST_ENTRY *TableList,
+ OUT EFI_ACPI_TABLE_LIST **Table
+ );
+
+/**
+
+ This function calculates and updates an UINT8 checksum.
+
+ @param[in] Buffer Pointer to buffer to checksum
+ @param[in] Size Number of bytes to checksum
+ @param[in] ChecksumOffset Offset to place the checksum result in
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ );
+
+/**
+ This function invokes ACPI notification.
+
+ @param[in] AcpiTableInstance Instance to AcpiTable
+ @param[in] Version Version(s) to set.
+ @param[in] Handle Handle of the table.
+**/
+VOID
+SdtNotifyAcpiList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ );
+
+/**
+ This function initializes AcpiSdt protocol in ACPI table instance.
+
+ @param[in] AcpiTableInstance Instance to construct
+**/
+VOID
+SdtAcpiTableAcpiSdtConstructor (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+//
+// export PrivateData symbol, because we need that in AcpiSdtProtol implementation
+//
+extern EFI_HANDLE mHandle;
+extern EFI_ACPI_TABLE_INSTANCE *mPrivateData;
+
+#endif
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
new file mode 100644
index 0000000000..ffb8d08f98
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@@ -0,0 +1,84 @@
+## @file
+# ACPI Table Protocol Driver
+#
+# This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces UEFI/PI
+# services to install/uninstall/manage ACPI tables.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+# 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 = AcpiTableDxe
+ MODULE_UNI_FILE = AcpiTableDxe.uni
+ FILE_GUID = 9622E42C-8E38-4a08-9E8F-54F784652F6B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeAcpiTableDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ AcpiTableProtocol.c
+ AcpiTable.h
+ AcpiTable.c
+ AcpiSdt.h
+ AcpiSdt.c
+ Aml.c
+ AmlString.c
+ AmlOption.c
+ AmlChild.c
+ AmlNamespace.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ BaseLib
+ PcdLib
+
+[Guids]
+ gEfiAcpi10TableGuid ## PRODUCES ## SystemTable
+ gEfiAcpiTableGuid ## PRODUCES ## SystemTable
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions ## CONSUMES
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## PRODUCES
+ gEfiAcpiSdtProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiTableDxeExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni
new file mode 100644
index 0000000000..b8d82f30fe
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// AcpiTableDxe Module Localized Abstract and Description Content
+//
+// Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ACPI Table Protocol Driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver initializes ACPI tables (Rsdp, Rsdt and Xsdt) and produces UEFI/PI services to install/uninstall/manage ACPI tables."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni
new file mode 100644
index 0000000000..ea2b025a9d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// AcpiTableDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Table DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
new file mode 100644
index 0000000000..05340f80db
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
@@ -0,0 +1,1856 @@
+/** @file
+ ACPI Table Protocol Implementation
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+ 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.
+
+**/
+
+//
+// Includes
+//
+#include "AcpiTable.h"
+//
+// The maximum number of tables that pre-allocated.
+//
+UINTN mEfiAcpiMaxNumTables = EFI_ACPI_MAX_NUM_TABLES;
+
+//
+// Allocation strategy to use for AllocatePages ().
+// Runtime value depends on PcdExposedAcpiTableVersions.
+//
+STATIC EFI_ALLOCATE_TYPE mAcpiTableAllocType;
+
+/**
+ This function adds an ACPI table to the table list. It will detect FACS and
+ allocate the correct type of memory and properly align the table.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Table Table to add.
+ @param Checksum Does the table require checksumming.
+ @param Version The version of the list to add the table to.
+ @param Handle Pointer for returning the handle.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+ @return EFI_ABORTED The table is a duplicate of a table that is required
+ to be unique.
+
+**/
+EFI_STATUS
+AddTableToList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN VOID *Table,
+ IN BOOLEAN Checksum,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ OUT UINTN *Handle
+ );
+
+/**
+ This function finds and removes the table specified by the handle.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Version Bitmask of which versions to remove.
+ @param Handle Table to remove.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED An error occurred.
+ @return EFI_NOT_FOUND Handle not found in table list.
+
+**/
+EFI_STATUS
+RemoveTableFromList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ );
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+ @param ChecksumOffset Offset to place the checksum result in
+
+ @return EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ );
+
+/**
+ Checksum all versions of the common tables, RSDP, RSDT, XSDT.
+
+ @param AcpiTableInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ );
+
+//
+// Protocol function implementations.
+//
+
+/**
+ This function publishes the specified versions of the ACPI tables by
+ installing EFI configuration table entries for them. Any combination of
+ table versions can be published.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Version Version(s) to publish.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PublishTables (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 Buffer64;
+
+ //
+ // Reorder tables as some operating systems don't seem to find the
+ // FADT correctly if it is not in the first few entries
+ //
+
+ //
+ // Add FADT as the first entry
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) AcpiTableInstance->Rsdt1 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiTableInstance->Fadt1;
+
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) AcpiTableInstance->Rsdt3 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiTableInstance->Fadt3;
+ }
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ CurrentXsdtEntry = (VOID *) ((UINT8 *) AcpiTableInstance->Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ //
+ // Add entry to XSDT, XSDT expects 64 bit pointers, but
+ // the table pointers in XSDT are not aligned on 8 byte boundary.
+ //
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Fadt3;
+ CopyMem (
+ CurrentXsdtEntry,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ }
+
+ //
+ // Do checksum again because Dsdt/Xsdt is updated.
+ //
+ ChecksumCommonTables (AcpiTableInstance);
+
+ //
+ // Add the RSD_PTR to the system table and store that we have installed the
+ // tables.
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpi10TableGuid, AcpiTableInstance->Rsdp1);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpiTableGuid, AcpiTableInstance->Rsdp3);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Installs an ACPI table into the RSDT/XSDT.
+ Note that the ACPI table should be checksumed before installing it.
+ Otherwise it will assert.
+
+ @param This Protocol instance pointer.
+ @param AcpiTableBuffer A pointer to a buffer containing the ACPI table to be installed.
+ @param AcpiTableBufferSize Specifies the size, in bytes, of the AcpiTableBuffer buffer.
+ @param TableKey Reurns a key to refer to the ACPI table.
+
+ @return EFI_SUCCESS The table was successfully inserted.
+ @return EFI_INVALID_PARAMETER Either AcpiTableBuffer is NULL, TableKey is NULL, or AcpiTableBufferSize
+ and the size field embedded in the ACPI table pointed to by AcpiTableBuffer
+ are not in sync.
+ @return EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the request.
+ @retval EFI_ACCESS_DENIED The table signature matches a table already
+ present in the system and platform policy
+ does not allow duplicate tables of this type.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiTable (
+ IN EFI_ACPI_TABLE_PROTOCOL *This,
+ IN VOID *AcpiTableBuffer,
+ IN UINTN AcpiTableBufferSize,
+ OUT UINTN *TableKey
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ VOID *AcpiTableBufferConst;
+ EFI_ACPI_TABLE_VERSION Version;
+
+ //
+ // Check for invalid input parameters
+ //
+ if ((AcpiTableBuffer == NULL) || (TableKey == NULL)
+ || (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer)->Length != AcpiTableBufferSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Version = PcdGet32 (PcdAcpiExposedTableVersions);
+
+ //
+ // Get the instance of the ACPI table protocol
+ //
+ AcpiTableInstance = EFI_ACPI_TABLE_INSTANCE_FROM_THIS (This);
+
+ //
+ // Install the ACPI table
+ //
+ AcpiTableBufferConst = AllocateCopyPool (AcpiTableBufferSize,AcpiTableBuffer);
+ *TableKey = 0;
+ Status = AddTableToList (
+ AcpiTableInstance,
+ AcpiTableBufferConst,
+ TRUE,
+ Version,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PublishTables (
+ AcpiTableInstance,
+ Version
+ );
+ }
+ FreePool (AcpiTableBufferConst);
+
+ //
+ // Add a new table successfully, notify registed callback
+ //
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ if (!EFI_ERROR (Status)) {
+ SdtNotifyAcpiList (
+ AcpiTableInstance,
+ Version,
+ *TableKey
+ );
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Removes an ACPI table from the RSDT/XSDT.
+
+ @param This Protocol instance pointer.
+ @param TableKey Specifies the table to uninstall. The key was returned from InstallAcpiTable().
+
+ @return EFI_SUCCESS The table was successfully uninstalled.
+ @return EFI_NOT_FOUND TableKey does not refer to a valid key for a table entry.
+
+**/
+EFI_STATUS
+EFIAPI
+UninstallAcpiTable (
+ IN EFI_ACPI_TABLE_PROTOCOL *This,
+ IN UINTN TableKey
+ )
+{
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance;
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_VERSION Version;
+
+ //
+ // Get the instance of the ACPI table protocol
+ //
+ AcpiTableInstance = EFI_ACPI_TABLE_INSTANCE_FROM_THIS (This);
+
+ Version = PcdGet32 (PcdAcpiExposedTableVersions);
+
+ //
+ // Uninstall the ACPI table
+ //
+ Status = RemoveTableFromList (
+ AcpiTableInstance,
+ Version,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PublishTables (
+ AcpiTableInstance,
+ Version
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ If the number of APCI tables exceeds the preallocated max table number, enlarge the table buffer.
+
+ @param AcpiTableInstance ACPI table protocol instance data structure.
+
+ @return EFI_SUCCESS reallocate the table beffer successfully.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+ReallocateAcpiTableBuffer (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ UINTN NewMaxTableNumber;
+ UINTN TotalSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ EFI_ACPI_TABLE_INSTANCE TempPrivateData;
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+
+ CopyMem (&TempPrivateData, AcpiTableInstance, sizeof (EFI_ACPI_TABLE_INSTANCE));
+ //
+ // Enlarge the max table number from mEfiAcpiMaxNumTables to mEfiAcpiMaxNumTables + EFI_ACPI_MAX_NUM_TABLES
+ //
+ NewMaxTableNumber = mEfiAcpiMaxNumTables + EFI_ACPI_MAX_NUM_TABLES;
+ //
+ // Create RSDT, XSDT structures and allocate buffers.
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ NewMaxTableNumber * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ TotalSize += sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ NewMaxTableNumber * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ NewMaxTableNumber * sizeof (UINT32);
+ }
+
+ //
+ // Allocate memory in the lower 32 bit of address range for
+ // compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiTableInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ AcpiTableInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ }
+ AcpiTableInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Update RSDP to point to the new Rsdt and Xsdt address.
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt1;
+ AcpiTableInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt3;
+ }
+ CurrentData = (UINT64) (UINTN) AcpiTableInstance->Xsdt;
+ CopyMem (&AcpiTableInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+
+ //
+ // copy the original Rsdt1, Rsdt3 and Xsdt structure to new buffer
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CopyMem (AcpiTableInstance->Rsdt1, TempPrivateData.Rsdt1, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ CopyMem (AcpiTableInstance->Rsdt3, TempPrivateData.Rsdt3, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ }
+ CopyMem (AcpiTableInstance->Xsdt, TempPrivateData.Xsdt, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT64)));
+
+ //
+ // Calculate orignal ACPI table buffer size
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ TotalSize += sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32);
+ }
+
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TempPrivateData.Rsdt1, EFI_SIZE_TO_PAGES (TotalSize));
+
+ //
+ // Update the Max ACPI table number
+ //
+ mEfiAcpiMaxNumTables = NewMaxTableNumber;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function adds an ACPI table to the table list. It will detect FACS and
+ allocate the correct type of memory and properly align the table.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Table Table to add.
+ @param Checksum Does the table require checksumming.
+ @param Version The version of the list to add the table to.
+ @param Handle Pointer for returning the handle.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+ @retval EFI_ACCESS_DENIED The table signature matches a table already
+ present in the system and platform policy
+ does not allow duplicate tables of this type.
+
+**/
+EFI_STATUS
+AddTableToList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN VOID *Table,
+ IN BOOLEAN Checksum,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ OUT UINTN *Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+ UINT32 CurrentTableSignature;
+ UINT32 CurrentTableSize;
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 Buffer64;
+ BOOLEAN AddToRsdt;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+ ASSERT (Table);
+ ASSERT (Handle);
+
+ //
+ // Init locals
+ //
+ AddToRsdt = TRUE;
+
+ //
+ // Create a new list entry
+ //
+ CurrentTableList = AllocatePool (sizeof (EFI_ACPI_TABLE_LIST));
+ ASSERT (CurrentTableList);
+
+ //
+ // Determine table type and size
+ //
+ CurrentTableSignature = ((EFI_ACPI_COMMON_HEADER *) Table)->Signature;
+ CurrentTableSize = ((EFI_ACPI_COMMON_HEADER *) Table)->Length;
+
+ //
+ // Allocate a buffer for the table. All tables are allocated in the lower 32 bits of address space
+ // for backwards compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ CurrentTableList->PageAddress = 0xFFFFFFFF;
+ CurrentTableList->NumberOfPages = EFI_SIZE_TO_PAGES (CurrentTableSize);
+
+ //
+ // Allocation memory type depends on the type of the table
+ //
+ if ((CurrentTableSignature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE)) {
+ //
+ // Allocate memory for the FACS. This structure must be aligned
+ // on a 64 byte boundary and must be ACPI NVS memory.
+ // Using AllocatePages should ensure that it is always aligned.
+ // Do not change signature for new ACPI version because they are same.
+ //
+ // UEFI table also need to be in ACPI NVS memory, because some data field
+ // could be updated by OS present agent. For example, BufferPtrAddress in
+ // SMM communication ACPI table.
+ //
+ ASSERT ((EFI_PAGE_SIZE % 64) == 0);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ CurrentTableList->NumberOfPages,
+ &CurrentTableList->PageAddress
+ );
+ } else {
+ //
+ // All other tables are ACPI reclaim memory, no alignment requirements.
+ //
+ Status = gBS->AllocatePages (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ CurrentTableList->NumberOfPages,
+ &CurrentTableList->PageAddress
+ );
+ }
+ //
+ // Check return value from memory alloc.
+ //
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (CurrentTableList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Update the table pointer with the allocated memory start
+ //
+ CurrentTableList->Table = (EFI_ACPI_COMMON_HEADER *) (UINTN) CurrentTableList->PageAddress;
+
+ //
+ // Initialize the table contents
+ //
+ CurrentTableList->Signature = EFI_ACPI_TABLE_LIST_SIGNATURE;
+ CopyMem (CurrentTableList->Table, Table, CurrentTableSize);
+ CurrentTableList->Handle = AcpiTableInstance->CurrentHandle++;
+ *Handle = CurrentTableList->Handle;
+ CurrentTableList->Version = Version;
+
+ //
+ // Update internal pointers if this is a required table. If it is a required
+ // table and a table of that type already exists, return an error.
+ //
+ // Calculate the checksum if the table is not FACS.
+ //
+ switch (CurrentTableSignature) {
+
+ case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ //
+ // We don't add the FADT in the standard way because some
+ // OS expect the FADT to be early in the table list.
+ // So we always add it as the first element in the list.
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiTableInstance->Fadt1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->Fadt3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Fadt1 = (EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *) CurrentTableList->Table;
+
+ //
+ // Update pointers in FADT. If tables don't exist this will put NULL pointers there.
+ //
+ AcpiTableInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs1;
+ AcpiTableInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt1;
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdp1->OemId,
+ &AcpiTableInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ //
+ // RSDT OEM information is updated to match the FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdt1->OemId,
+ &AcpiTableInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ CopyMem (
+ &AcpiTableInstance->Rsdt1->OemTableId,
+ &AcpiTableInstance->Fadt1->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Rsdt1->OemRevision = AcpiTableInstance->Fadt1->Header.OemRevision;
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Fadt3 = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) CurrentTableList->Table;
+
+ //
+ // Update pointers in FADT. If tables don't exist this will put NULL pointers there.
+ // Note: If the FIRMWARE_CTRL is non-zero, then X_FIRMWARE_CTRL must be zero, and
+ // vice-versa.
+ //
+ if ((UINT64)(UINTN)AcpiTableInstance->Facs3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs3;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+ } else {
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Facs3;
+ CopyMem (
+ &AcpiTableInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ }
+ if ((UINT64)(UINTN)AcpiTableInstance->Dsdt3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt3;
+ //
+ // Comment block "the caller installs the tables in "DSDT, FADT" order"
+ // The below comments are also in "the caller installs the tables in "FADT, DSDT" order" comment block.
+ //
+ // The ACPI specification, up to and including revision 5.1 Errata A,
+ // allows the DSDT and X_DSDT fields to be both set in the FADT.
+ // (Obviously, this only makes sense if the DSDT address is representable in 4 bytes.)
+ // Starting with 5.1 Errata B, specifically for Mantis 1393 <https://mantis.uefi.org/mantis/view.php?id=1393>,
+ // the spec requires at most one of DSDT and X_DSDT fields to be set to a nonzero value,
+ // but strangely an exception is 6.0 that has no this requirement.
+ //
+ // Here we do not make the DSDT and X_DSDT fields mutual exclusion conditionally
+ // by checking FADT revision, but always set both DSDT and X_DSDT fields in the FADT
+ // to have better compatibility as some OS may have assumption to only consume X_DSDT
+ // field even the DSDT address is < 4G.
+ //
+ Buffer64 = AcpiTableInstance->Fadt3->Dsdt;
+ } else {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Dsdt3;
+ }
+ CopyMem (&AcpiTableInstance->Fadt3->XDsdt, &Buffer64, sizeof (UINT64));
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdp3->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // RSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Rsdt3->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiTableInstance->Rsdt3->OemTableId,
+ &AcpiTableInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Rsdt3->OemRevision = AcpiTableInstance->Fadt3->Header.OemRevision;
+ }
+
+ //
+ // XSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiTableInstance->Xsdt->OemId,
+ &AcpiTableInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiTableInstance->Xsdt->OemTableId,
+ &AcpiTableInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Xsdt->OemRevision = AcpiTableInstance->Fadt3->Header.OemRevision;
+ }
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+
+ case EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiTableInstance->Facs1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->Facs3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // FACS is referenced by FADT and is not part of RSDT
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Facs1 = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Facs3 = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ //
+ // Note: If the FIRMWARE_CTRL is non-zero, then X_FIRMWARE_CTRL must be zero, and
+ // vice-versa.
+ //
+ if ((UINT64)(UINTN)AcpiTableInstance->Facs3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiTableInstance->Facs3;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+ } else {
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Facs3;
+ CopyMem (
+ &AcpiTableInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ }
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ break;
+
+ case EFI_ACPI_1_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiTableInstance->Dsdt1 != NULL) ||
+ ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0 && AcpiTableInstance->Dsdt3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // DSDT is referenced by FADT and is not part of RSDT
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Dsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiTableInstance->Dsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ if ((UINT64)(UINTN)AcpiTableInstance->Dsdt3 < BASE_4GB) {
+ AcpiTableInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiTableInstance->Dsdt3;
+ //
+ // Comment block "the caller installs the tables in "FADT, DSDT" order"
+ // The below comments are also in "the caller installs the tables in "DSDT, FADT" order" comment block.
+ //
+ // The ACPI specification, up to and including revision 5.1 Errata A,
+ // allows the DSDT and X_DSDT fields to be both set in the FADT.
+ // (Obviously, this only makes sense if the DSDT address is representable in 4 bytes.)
+ // Starting with 5.1 Errata B, specifically for Mantis 1393 <https://mantis.uefi.org/mantis/view.php?id=1393>,
+ // the spec requires at most one of DSDT and X_DSDT fields to be set to a nonzero value,
+ // but strangely an exception is 6.0 that has no this requirement.
+ //
+ // Here we do not make the DSDT and X_DSDT fields mutual exclusion conditionally
+ // by checking FADT revision, but always set both DSDT and X_DSDT fields in the FADT
+ // to have better compatibility as some OS may have assumption to only consume X_DSDT
+ // field even the DSDT address is < 4G.
+ //
+ Buffer64 = AcpiTableInstance->Fadt3->Dsdt;
+ } else {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ Buffer64 = (UINT64) (UINTN) AcpiTableInstance->Dsdt3;
+ }
+ CopyMem (&AcpiTableInstance->Fadt3->XDsdt, &Buffer64, sizeof (UINT64));
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+
+ default:
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+ }
+ //
+ // Add the table to the current list of tables
+ //
+ InsertTailList (&AcpiTableInstance->TableList, &CurrentTableList->Link);
+
+ //
+ // Add the table to RSDT and/or XSDT table entry lists.
+ //
+ //
+ // Add to ACPI 1.0b table tree
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ if (AddToRsdt) {
+ //
+ // If the table number exceed the gEfiAcpiMaxNumTables, enlarge the table buffer
+ //
+ if (AcpiTableInstance->NumberOfTableEntries1 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiTableInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+ CurrentRsdtEntry = (UINT32 *)
+ (
+ (UINT8 *) AcpiTableInstance->Rsdt1 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries1 *
+ sizeof (UINT32)
+ );
+
+ //
+ // Add entry to the RSDT unless its the FACS or DSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiTableInstance->Rsdt1->Length = AcpiTableInstance->Rsdt1->Length + sizeof (UINT32);
+
+ AcpiTableInstance->NumberOfTableEntries1++;
+ }
+ }
+ //
+ // Add to ACPI 2.0/3.0 table tree
+ //
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ if (AddToRsdt) {
+ //
+ // If the table number exceed the gEfiAcpiMaxNumTables, enlarge the table buffer
+ //
+ if (AcpiTableInstance->NumberOfTableEntries3 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiTableInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // At this time, it is assumed that RSDT and XSDT maintain parallel lists of tables.
+ // If it becomes necessary to maintain separate table lists, changes will be required.
+ //
+ CurrentRsdtEntry = (UINT32 *)
+ (
+ (UINT8 *) AcpiTableInstance->Rsdt3 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries3 *
+ sizeof (UINT32)
+ );
+
+ //
+ // Add entry to the RSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiTableInstance->Rsdt3->Length = AcpiTableInstance->Rsdt3->Length + sizeof (UINT32);
+ }
+
+ //
+ // This pointer must not be directly dereferenced as the XSDT entries may not
+ // be 64 bit aligned resulting in a possible fault. Use CopyMem to update.
+ //
+ CurrentXsdtEntry = (VOID *)
+ (
+ (UINT8 *) AcpiTableInstance->Xsdt +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiTableInstance->NumberOfTableEntries3 *
+ sizeof (UINT64)
+ );
+
+ //
+ // Add entry to XSDT, XSDT expects 64 bit pointers, but
+ // the table pointers in XSDT are not aligned on 8 byte boundary.
+ //
+ Buffer64 = (UINT64) (UINTN) CurrentTableList->Table;
+ CopyMem (
+ CurrentXsdtEntry,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+
+ //
+ // Update length
+ //
+ AcpiTableInstance->Xsdt->Length = AcpiTableInstance->Xsdt->Length + sizeof (UINT64);
+
+ AcpiTableInstance->NumberOfTableEntries3++;
+ }
+ }
+
+ ChecksumCommonTables (AcpiTableInstance);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function finds the table specified by the handle and returns a pointer to it.
+ If the handle is not found, EFI_NOT_FOUND is returned and the contents of Table are
+ undefined.
+
+ @param Handle Table to find.
+ @param TableList Table list to search
+ @param Table Pointer to table found.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_NOT_FOUND No table found matching the handle specified.
+
+**/
+EFI_STATUS
+FindTableByHandle (
+ IN UINTN Handle,
+ IN LIST_ENTRY *TableList,
+ OUT EFI_ACPI_TABLE_LIST **Table
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ EFI_ACPI_TABLE_LIST *CurrentTable;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (Table);
+
+ //
+ // Find the table
+ //
+ CurrentLink = TableList->ForwardLink;
+
+ while (CurrentLink != TableList) {
+ CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ if (CurrentTable->Handle == Handle) {
+ //
+ // Found handle, so return this table.
+ //
+ *Table = CurrentTable;
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ //
+ // Table not found
+ //
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function removes a basic table from the RSDT and/or XSDT.
+ For Acpi 1.0 tables, pass in the Rsdt.
+ For Acpi 2.0 tables, pass in both Rsdt and Xsdt.
+
+ @param Table Pointer to table found.
+ @param NumberOfTableEntries Current number of table entries in the RSDT/XSDT
+ @param Rsdt Pointer to the RSDT to remove from
+ @param Xsdt Pointer to the Xsdt to remove from
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_INVALID_PARAMETER The table was not found in both Rsdt and Xsdt.
+
+**/
+EFI_STATUS
+RemoveTableFromRsdt (
+ IN OUT EFI_ACPI_TABLE_LIST * Table,
+ IN OUT UINTN *NumberOfTableEntries,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER * Rsdt OPTIONAL,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER * Xsdt OPTIONAL
+ )
+{
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 CurrentTablePointer64;
+ UINTN Index;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (Table);
+ ASSERT (NumberOfTableEntries);
+ ASSERT (Rsdt || Xsdt);
+
+ //
+ // Find the table entry in the RSDT and XSDT
+ //
+ for (Index = 0; Index < *NumberOfTableEntries; Index++) {
+ //
+ // At this time, it is assumed that RSDT and XSDT maintain parallel lists of tables.
+ // If it becomes necessary to maintain separate table lists, changes will be required.
+ //
+ if (Rsdt != NULL) {
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER) + Index * sizeof (UINT32));
+ } else {
+ CurrentRsdtEntry = NULL;
+ }
+ if (Xsdt != NULL) {
+ //
+ // This pointer must not be directly dereferenced as the XSDT entries may not
+ // be 64 bit aligned resulting in a possible fault. Use CopyMem to update.
+ //
+ CurrentXsdtEntry = (VOID *) ((UINT8 *) Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER) + Index * sizeof (UINT64));
+
+ //
+ // Read the entry value out of the XSDT
+ //
+ CopyMem (&CurrentTablePointer64, CurrentXsdtEntry, sizeof (UINT64));
+ } else {
+ //
+ // Initialize to NULL
+ //
+ CurrentXsdtEntry = 0;
+ CurrentTablePointer64 = 0;
+ }
+ //
+ // Check if we have found the corresponding entry in both RSDT and XSDT
+ //
+ if (((Rsdt == NULL) || *CurrentRsdtEntry == (UINT32) (UINTN) Table->Table) &&
+ ((Xsdt == NULL) || CurrentTablePointer64 == (UINT64) (UINTN) Table->Table)
+ ) {
+ //
+ // Found entry, so copy all following entries and shrink table
+ // We actually copy all + 1 to copy the initialized value of memory over
+ // the last entry.
+ //
+ if (Rsdt != NULL) {
+ CopyMem (CurrentRsdtEntry, CurrentRsdtEntry + 1, (*NumberOfTableEntries - Index) * sizeof (UINT32));
+ Rsdt->Length = Rsdt->Length - sizeof (UINT32);
+ }
+ if (Xsdt != NULL) {
+ CopyMem (CurrentXsdtEntry, ((UINT64 *) CurrentXsdtEntry) + 1, (*NumberOfTableEntries - Index) * sizeof (UINT64));
+ Xsdt->Length = Xsdt->Length - sizeof (UINT64);
+ }
+ break;
+ } else if (Index + 1 == *NumberOfTableEntries) {
+ //
+ // At the last entry, and table not found
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Checksum the tables
+ //
+ if (Rsdt != NULL) {
+ AcpiPlatformChecksum (
+ Rsdt,
+ Rsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+
+ if (Xsdt != NULL) {
+ AcpiPlatformChecksum (
+ Xsdt,
+ Xsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ //
+ // Decrement the number of tables
+ //
+ (*NumberOfTableEntries)--;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes a table and frees any associated memory.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Version Version(s) to delete.
+ @param Table Pointer to table found.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+DeleteTable (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN OUT EFI_ACPI_TABLE_LIST *Table
+ )
+{
+ UINT32 CurrentTableSignature;
+ BOOLEAN RemoveFromRsdt;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+ ASSERT (Table);
+
+ //
+ // Init locals
+ //
+ RemoveFromRsdt = TRUE;
+ //
+ // Check for Table->Table
+ //
+ ASSERT (Table->Table != NULL);
+ CurrentTableSignature = ((EFI_ACPI_COMMON_HEADER *) Table->Table)->Signature;
+
+ //
+ // Basic tasks to accomplish delete are:
+ // Determine removal requirements (in RSDT/XSDT or not)
+ // Remove entry from RSDT/XSDT
+ // Remove any table references to the table
+ // If no one is using the table
+ // Free the table (removing pointers from private data and tables)
+ // Remove from list
+ // Free list structure
+ //
+ //
+ // Determine if this table is in the RSDT or XSDT
+ //
+ if ((CurrentTableSignature == EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)
+ ) {
+ RemoveFromRsdt = FALSE;
+ }
+ //
+ // We don't remove the FADT in the standard way because some
+ // OS expect the FADT to be early in the table list.
+ // So we always put it as the first element in the list.
+ //
+ if (CurrentTableSignature == EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+ RemoveFromRsdt = FALSE;
+ }
+
+ //
+ // Remove the table from RSDT and XSDT
+ //
+ if (Table->Table != NULL) {
+ //
+ // This is a basic table, remove it from any lists and the Rsdt and/or Xsdt
+ //
+ if (Version & EFI_ACPI_TABLE_VERSION_NONE & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_NONE;
+ }
+
+ if (Version & EFI_ACPI_TABLE_VERSION_1_0B & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_1_0B;
+
+ //
+ // Remove from Rsdt. We don't care about the return value because it is
+ // acceptable for the table to not exist in Rsdt.
+ // We didn't add some tables so we don't remove them.
+ //
+ if (RemoveFromRsdt) {
+ RemoveTableFromRsdt (
+ Table,
+ &AcpiTableInstance->NumberOfTableEntries1,
+ AcpiTableInstance->Rsdt1,
+ NULL
+ );
+ }
+ }
+
+ if (Version & ACPI_TABLE_VERSION_GTE_2_0 & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~(Version & ACPI_TABLE_VERSION_GTE_2_0);
+
+ //
+ // Remove from Rsdt and Xsdt. We don't care about the return value
+ // because it is acceptable for the table to not exist in Rsdt/Xsdt.
+ // We didn't add some tables so we don't remove them.
+ //
+ if (RemoveFromRsdt) {
+ RemoveTableFromRsdt (
+ Table,
+ &AcpiTableInstance->NumberOfTableEntries3,
+ AcpiTableInstance->Rsdt3,
+ AcpiTableInstance->Xsdt
+ );
+ }
+ }
+ //
+ // Free the table, clean up any dependent tables and our private data pointers.
+ //
+ switch (Table->Table->Signature) {
+
+ case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Fadt1 = NULL;
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Fadt3 = NULL;
+ }
+ break;
+
+ case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Facs1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->FirmwareCtrl = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Facs3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ AcpiTableInstance->Fadt3->FirmwareCtrl = 0;
+ ZeroMem (&AcpiTableInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ break;
+
+ case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Dsdt1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt1 != NULL) {
+ AcpiTableInstance->Fadt1->Dsdt = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt1,
+ AcpiTableInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+
+ if ((Version & ACPI_TABLE_VERSION_GTE_2_0) != 0) {
+ AcpiTableInstance->Dsdt3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiTableInstance->Fadt3 != NULL) {
+ AcpiTableInstance->Fadt3->Dsdt = 0;
+ ZeroMem (&AcpiTableInstance->Fadt3->XDsdt, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Fadt3,
+ AcpiTableInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ break;
+
+ default:
+ //
+ // Do nothing
+ //
+ break;
+ }
+ }
+ //
+ // If no version is using this table anymore, remove and free list entry.
+ //
+ if (Table->Version == 0) {
+ //
+ // Free the Table
+ //
+ gBS->FreePages (Table->PageAddress, Table->NumberOfPages);
+ RemoveEntryList (&(Table->Link));
+ gBS->FreePool (Table);
+ }
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function finds and removes the table specified by the handle.
+
+ @param AcpiTableInstance Instance of the protocol.
+ @param Version Bitmask of which versions to remove.
+ @param Handle Table to remove.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED An error occurred.
+ @return EFI_NOT_FOUND Handle not found in table list.
+
+**/
+EFI_STATUS
+RemoveTableFromList (
+ IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ )
+{
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_STATUS Status;
+
+ Table = (EFI_ACPI_TABLE_LIST*) NULL;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+
+ //
+ // Find the table
+ //
+ Status = FindTableByHandle (
+ Handle,
+ &AcpiTableInstance->TableList,
+ &Table
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Remove the table
+ //
+ Status = DeleteTable (AcpiTableInstance, Version, Table);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Completed successfully
+ //
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+ @param ChecksumOffset Offset to place the checksum result in
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ )
+{
+ UINT8 Sum;
+ UINT8 *Ptr;
+
+ Sum = 0;
+ //
+ // Initialize pointer
+ //
+ Ptr = Buffer;
+
+ //
+ // set checksum to 0 first
+ //
+ Ptr[ChecksumOffset] = 0;
+
+ //
+ // add all content of buffer
+ //
+ while ((Size--) != 0) {
+ Sum = (UINT8) (Sum + (*Ptr++));
+ }
+ //
+ // set checksum
+ //
+ Ptr = Buffer;
+ Ptr[ChecksumOffset] = (UINT8) (0xff - Sum + 1);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Checksum all versions of the common tables, RSDP, RSDT, XSDT.
+
+ @param AcpiTableInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ //
+ // RSDP ACPI 1.0 checksum for 1.0 table. This is only the first 20 bytes of the structure
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdp1,
+ sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ Checksum)
+ );
+ }
+
+ //
+ // RSDP ACPI 1.0 checksum for 2.0/3.0 table. This is only the first 20 bytes of the structure
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdp3,
+ sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ Checksum)
+ );
+
+ //
+ // RSDP ACPI 2.0/3.0 checksum, this is the entire table
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdp3,
+ sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ ExtendedChecksum)
+ );
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // RSDT checksums
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdt1,
+ AcpiTableInstance->Rsdt1->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Rsdt3,
+ AcpiTableInstance->Rsdt3->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+
+ //
+ // XSDT checksum
+ //
+ AcpiPlatformChecksum (
+ AcpiTableInstance->Xsdt,
+ AcpiTableInstance->Xsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Constructor for the ACPI table protocol. Initializes instance
+ data.
+
+ @param AcpiTableInstance Instance to construct
+
+ @return EFI_SUCCESS Instance initialized.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+AcpiTableAcpiTableConstructor (
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+ UINTN TotalSize;
+ UINTN RsdpTableSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiTableInstance);
+
+ //
+ // If ACPI v1.0b is among the ACPI versions we aim to support, we have to
+ // ensure that all memory allocations are below 4 GB.
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ mAcpiTableAllocType = AllocateMaxAddress;
+ } else {
+ mAcpiTableAllocType = AllocateAnyPages;
+ }
+
+ InitializeListHead (&AcpiTableInstance->TableList);
+ AcpiTableInstance->CurrentHandle = 1;
+
+ AcpiTableInstance->AcpiTableProtocol.InstallAcpiTable = InstallAcpiTable;
+ AcpiTableInstance->AcpiTableProtocol.UninstallAcpiTable = UninstallAcpiTable;
+
+ if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
+ SdtAcpiTableAcpiSdtConstructor (AcpiTableInstance);
+ }
+
+ //
+ // Create RSDP table
+ //
+ RsdpTableSize = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ RsdpTableSize += sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ }
+
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (RsdpTableSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, RsdpTableSize);
+
+ AcpiTableInstance->Rsdp1 = (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ }
+ AcpiTableInstance->Rsdp3 = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+
+ //
+ // Create RSDT, XSDT structures
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ TotalSize += sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32);
+ }
+
+ //
+ // Allocate memory in the lower 32 bit of address range for
+ // compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ mAcpiTableAllocType,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)AcpiTableInstance->Rsdp1, EFI_SIZE_TO_PAGES (RsdpTableSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiTableInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ AcpiTableInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ }
+ AcpiTableInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Initialize RSDP
+ //
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CurrentData = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiTableInstance->Rsdp1->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiTableInstance->Rsdp1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdp1->OemId));
+ AcpiTableInstance->Rsdp1->Reserved = EFI_ACPI_RESERVED_BYTE;
+ AcpiTableInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt1;
+ }
+
+ CurrentData = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiTableInstance->Rsdp3->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiTableInstance->Rsdp3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdp3->OemId));
+ AcpiTableInstance->Rsdp3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION;
+ AcpiTableInstance->Rsdp3->Length = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiTableInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiTableInstance->Rsdt3;
+ }
+ CurrentData = (UINT64) (UINTN) AcpiTableInstance->Xsdt;
+ CopyMem (&AcpiTableInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+ SetMem (AcpiTableInstance->Rsdp3->Reserved, 3, EFI_ACPI_RESERVED_BYTE);
+
+ if ((PcdGet32 (PcdAcpiExposedTableVersions) & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Initialize Rsdt
+ //
+ // Note that we "reserve" one entry for the FADT so it can always be
+ // at the beginning of the list of tables. Some OS don't seem
+ // to find it correctly if it is too far down the list.
+ //
+ AcpiTableInstance->Rsdt1->Signature = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Rsdt1->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Rsdt1->Revision = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Rsdt1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdt1->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Rsdt1->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Rsdt1->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Rsdt1->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Rsdt1->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->NumberOfTableEntries1 = 1;
+ AcpiTableInstance->Rsdt1->Length = AcpiTableInstance->Rsdt1->Length + sizeof(UINT32);
+
+ AcpiTableInstance->Rsdt3->Signature = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Rsdt3->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Rsdt3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Rsdt3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Rsdt3->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Rsdt3->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Rsdt3->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Rsdt3->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Rsdt3->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->Rsdt3->Length = AcpiTableInstance->Rsdt3->Length + sizeof(UINT32);
+ }
+ AcpiTableInstance->NumberOfTableEntries3 = 1;
+
+ //
+ // Initialize Xsdt
+ //
+ AcpiTableInstance->Xsdt->Signature = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiTableInstance->Xsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiTableInstance->Xsdt->Revision = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiTableInstance->Xsdt->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiTableInstance->Xsdt->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiTableInstance->Xsdt->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiTableInstance->Xsdt->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiTableInstance->Xsdt->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiTableInstance->Xsdt->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiTableInstance->Xsdt->Length = AcpiTableInstance->Xsdt->Length + sizeof(UINT64);
+
+ ChecksumCommonTables (AcpiTableInstance);
+
+ //
+ // Completed successfully
+ //
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c
new file mode 100644
index 0000000000..30f71bdda4
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/Aml.c
@@ -0,0 +1,302 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
+ 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 "AcpiTable.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+AML_BYTE_ENCODING mAmlByteEncoding[] = {
+ // OpCode SubOpCode Num 1 2 3 4 5 6 Attribute
+/* ZeroOp - 0x00 */ {AML_ZERO_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OneOp - 0x01 */ {AML_ONE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AliasOp - 0x06 */ {AML_ALIAS_OP, 0, 2, {AML_NAME, AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* NameOp - 0x08 */ {AML_NAME_OP, 0, 2, {AML_NAME, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* BytePrefix - 0x0A */ {AML_BYTE_PREFIX, 0, 1, {AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* WordPrefix - 0x0B */ {AML_WORD_PREFIX, 0, 1, {AML_UINT16, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DWordPrefix - 0x0C */ {AML_DWORD_PREFIX, 0, 1, {AML_UINT32, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StringPrefix - 0x0D */ {AML_STRING_PREFIX, 0, 1, {AML_STRING, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* QWordPrefix - 0x0E */ {AML_QWORD_PREFIX, 0, 1, {AML_UINT64, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ScopeOp - 0x10 */ {AML_SCOPE_OP, 0, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* BufferOp - 0x11 */ {AML_BUFFER_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* PackageOp - 0x12 */ {AML_PACKAGE_OP, 0, 1, {AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* VarPackageOp - 0x13 */ {AML_VAR_PACKAGE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* MethodOp - 0x14 */ {AML_METHOD_OP, 0, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* DualNamePrefix - 0x2F */ {AML_DUAL_NAME_PREFIX, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* MultiNamePrefix - 0x2F */ {AML_MULTI_NAME_PREFIX, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x41 */ {'A', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x42 */ {'B', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x43 */ {'C', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x44 */ {'D', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x45 */ {'E', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x46 */ {'F', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x47 */ {'G', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x48 */ {'H', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x49 */ {'I', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4A */ {'J', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4B */ {'K', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4C */ {'L', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4D */ {'M', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4E */ {'N', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x4F */ {'O', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x50 */ {'P', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x51 */ {'Q', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x52 */ {'R', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x53 */ {'S', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x54 */ {'T', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x55 */ {'U', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x56 */ {'V', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x57 */ {'W', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x58 */ {'X', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x59 */ {'Y', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x5A */ {'Z', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* MutexOp - 0x5B 0x01 */ {AML_EXT_OP, AML_EXT_MUTEX_OP, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* EventOp - 0x5B 0x02 */ {AML_EXT_OP, AML_EXT_EVENT_OP, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* CondRefOfOp - 0x5B 0x12 */ {AML_EXT_OP, AML_EXT_COND_REF_OF_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateFieldOp - 0x5B 0x13 */ {AML_EXT_OP, AML_EXT_CREATE_FIELD_OP,4, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE}, 0},
+/* LoadTableOp - 0x5B 0x1F */ {AML_EXT_OP, AML_EXT_LOAD_TABLE_OP, 6, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT}, 0},
+/* LoadOp - 0x5B 0x20 */ {AML_EXT_OP, AML_EXT_LOAD_OP, 2, {AML_NAME, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StallOp - 0x5B 0x21 */ {AML_EXT_OP, AML_EXT_STALL_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SleepOp - 0x5B 0x22 */ {AML_EXT_OP, AML_EXT_SLEEP_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AcquireOp - 0x5B 0x23 */ {AML_EXT_OP, AML_EXT_ACQUIRE_OP, 2, {AML_OBJECT, AML_UINT16, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SignalOp - 0x5B 0x24 */ {AML_EXT_OP, AML_EXT_SIGNAL_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* WaitOp - 0x5B 0x25 */ {AML_EXT_OP, AML_EXT_WAIT_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ResetOp - 0x5B 0x26 */ {AML_EXT_OP, AML_EXT_RESET_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ReleaseOp - 0x5B 0x27 */ {AML_EXT_OP, AML_EXT_RELEASE_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FromBCDOp - 0x5B 0x28 */ {AML_EXT_OP, AML_EXT_FROM_BCD_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToBCDOp - 0x5B 0x29 */ {AML_EXT_OP, AML_EXT_TO_BCD_OP, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* UnloadOp - 0x5B 0x2A */ {AML_EXT_OP, AML_EXT_UNLOAD_OP, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* RevisionOp - 0x5B 0x30 */ {AML_EXT_OP, AML_EXT_REVISION_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DebugOp - 0x5B 0x31 */ {AML_EXT_OP, AML_EXT_DEBUG_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FatalOp - 0x5B 0x32 */ {AML_EXT_OP, AML_EXT_FATAL_OP, 3, {AML_UINT8, AML_UINT32, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* TimerOp - 0x5B 0x33 */ {AML_EXT_OP, AML_EXT_TIMER_OP, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OpRegionOp - 0x5B 0x80 */ {AML_EXT_OP, AML_EXT_REGION_OP, 4, {AML_NAME, AML_UINT8, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* FieldOp - 0x5B 0x81 */ {AML_EXT_OP, AML_EXT_FIELD_OP, 2, {AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* DeviceOp - 0x5B 0x82 */ {AML_EXT_OP, AML_EXT_DEVICE_OP, 1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* ProcessorOp - 0x5B 0x83 */ {AML_EXT_OP, AML_EXT_PROCESSOR_OP, 4, {AML_NAME, AML_UINT8, AML_UINT32, AML_UINT8, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* PowerResOp - 0x5B 0x84 */ {AML_EXT_OP, AML_EXT_POWER_RES_OP, 3, {AML_NAME, AML_UINT8, AML_UINT16, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* ThermalZoneOp - 0x5B 0x85 */ {AML_EXT_OP, AML_EXT_THERMAL_ZONE_OP,1, {AML_NAME, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ | AML_IN_NAMESPACE},
+/* IndexFieldOp - 0x5B 0x86 */ {AML_EXT_OP, AML_EXT_INDEX_FIELD_OP, 3, {AML_NAME, AML_NAME, AML_UINT8, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* BankFieldOp - 0x5B 0x87 */ {AML_EXT_OP, AML_EXT_BANK_FIELD_OP, 4, {AML_NAME, AML_NAME, AML_OBJECT, AML_UINT8, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH},
+/* DataRegionOp - 0x5B 0x88 */ {AML_EXT_OP, AML_EXT_DATA_REGION_OP, 4, {AML_NAME, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, AML_IN_NAMESPACE},
+/* RootChar - 0x5C */ {AML_ROOT_CHAR, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* ParentPrefixChar - 0x5E */ {AML_PARENT_PREFIX_CHAR, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* NameChar - 0x5F */ {'_', 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_IS_NAME_CHAR},
+/* Local0Op - 0x60 */ {AML_LOCAL0, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local1Op - 0x61 */ {AML_LOCAL1, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local2Op - 0x62 */ {AML_LOCAL2, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local3Op - 0x63 */ {AML_LOCAL3, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local4Op - 0x64 */ {AML_LOCAL4, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local5Op - 0x65 */ {AML_LOCAL5, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local6Op - 0x66 */ {AML_LOCAL6, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Local7Op - 0x67 */ {AML_LOCAL7, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg0Op - 0x68 */ {AML_ARG0, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg1Op - 0x69 */ {AML_ARG1, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg2Op - 0x6A */ {AML_ARG2, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg3Op - 0x6B */ {AML_ARG3, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg4Op - 0x6C */ {AML_ARG4, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg5Op - 0x6D */ {AML_ARG5, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* Arg6Op - 0x6E */ {AML_ARG6, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* StoreOp - 0x70 */ {AML_STORE_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* RefOfOp - 0x71 */ {AML_REF_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AddOp - 0x72 */ {AML_ADD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ConcatOp - 0x73 */ {AML_CONCAT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SubtractOp - 0x74 */ {AML_SUBTRACT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IncrementOp - 0x75 */ {AML_INCREMENT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DecrementOp - 0x76 */ {AML_DECREMENT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MultiplyOp - 0x77 */ {AML_MULTIPLY_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DivideOp - 0x78 */ {AML_DIVIDE_OP, 0, 4, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE}, 0},
+/* ShiftLeftOp - 0x79 */ {AML_SHIFT_LEFT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ShiftRightOp - 0x7A */ {AML_SHIFT_RIGHT_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* AndOp - 0x7B */ {AML_AND_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NAndOp - 0x7C */ {AML_NAND_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OrOp - 0x7D */ {AML_OR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NorOp - 0x7E */ {AML_NOR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* XOrOp - 0x7F */ {AML_XOR_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NotOp - 0x80 */ {AML_NOT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FindSetLeftBitOp - 0x81 */ {AML_FIND_SET_LEFT_BIT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* FindSetRightBitOp - 0x82 */ {AML_FIND_SET_RIGHT_BIT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* DerefOfOp - 0x83 */ {AML_DEREF_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ConcatResOp - 0x84 */ {AML_CONCAT_RES_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ModOp - 0x85 */ {AML_MOD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* NotifyOp - 0x86 */ {AML_NOTIFY_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* SizeOfOp - 0x87 */ {AML_SIZE_OF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IndexOp - 0x88 */ {AML_INDEX_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MatchOp - 0x89 */ {AML_MATCH_OP, 0, 6, {AML_OBJECT, AML_UINT8, AML_OBJECT, AML_UINT8, AML_OBJECT, AML_OBJECT}, 0},
+/* CreateDWordFieldOp - 0x8A */ {AML_CREATE_DWORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateWordFieldOp - 0x8B */ {AML_CREATE_WORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateByteFieldOp - 0x8C */ {AML_CREATE_BYTE_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateBitFieldOp - 0x8D */ {AML_CREATE_BIT_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ObjectTypeOp - 0x8E */ {AML_OBJECT_TYPE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CreateQWordFieldOp - 0x8F */ {AML_CREATE_QWORD_FIELD_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_NAME, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LAndOp - 0x90 */ {AML_LAND_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LOrOp - 0x91 */ {AML_LOR_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LNotOp - 0x92 */ {AML_LNOT_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LEqualOp - 0x93 */ {AML_LEQUAL_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LGreaterOp - 0x94 */ {AML_LGREATER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* LLessOp - 0x95 */ {AML_LLESS_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToBufferOp - 0x96 */ {AML_TO_BUFFER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToDecimalStringOp - 0x97 */ {AML_TO_DEC_STRING_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToHexStringOp - 0x98 */ {AML_TO_HEX_STRING_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToIntegerOp - 0x99 */ {AML_TO_INTEGER_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ToStringOp - 0x9C */ {AML_TO_STRING_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* CopyObjectOp - 0x9D */ {AML_COPY_OBJECT_OP, 0, 2, {AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* MidOp - 0x9E */ {AML_MID_OP, 0, 3, {AML_OBJECT, AML_OBJECT, AML_OBJECT, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ContinueOp - 0x9F */ {AML_CONTINUE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* IfOp - 0xA0 */ {AML_IF_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* ElseOp - 0xA1 */ {AML_ELSE_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* WhileOp - 0xA2 */ {AML_WHILE_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, AML_HAS_PKG_LENGTH | AML_HAS_CHILD_OBJ},
+/* NoopOp - 0xA3 */ {AML_NOOP_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* ReturnOp - 0xA4 */ {AML_RETURN_OP, 0, 1, {AML_OBJECT, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* BreakOp - 0xA5 */ {AML_BREAK_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* BreakPointOp - 0xCC */ {AML_BREAK_POINT_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+/* OnesOp - 0xFF */ {AML_ONES_OP, 0, 0, {AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE, AML_NONE}, 0},
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_ACPI_DATA_TYPE mAmlTypeToAcpiType[] = {
+ EFI_ACPI_DATA_TYPE_NONE, // AML_NONE
+ EFI_ACPI_DATA_TYPE_OPCODE, // AML_OPCODE
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT8
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT16
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT32
+ EFI_ACPI_DATA_TYPE_UINT, // AML_UINT64
+ EFI_ACPI_DATA_TYPE_NAME_STRING, // AML_NAME
+ EFI_ACPI_DATA_TYPE_STRING, // AML_STRING
+ EFI_ACPI_DATA_TYPE_CHILD // AML_OBJECT
+};
+
+/**
+ This function returns AmlByteEncoding according to OpCode Byte.
+
+ @param[in] OpByteBuffer OpCode byte buffer.
+
+ @return AmlByteEncoding
+**/
+AML_BYTE_ENCODING *
+AmlSearchByOpByte (
+ IN UINT8 *OpByteBuffer
+ )
+{
+ UINT8 OpCode;
+ UINT8 SubOpCode;
+ UINTN Index;
+
+ //
+ // Get OpCode and SubOpCode
+ //
+ OpCode = OpByteBuffer[0];
+ if (OpCode == AML_EXT_OP) {
+ SubOpCode = OpByteBuffer[1];
+ } else {
+ SubOpCode = 0;
+ }
+
+ //
+ // Search the table
+ //
+ for (Index = 0; Index < sizeof(mAmlByteEncoding)/sizeof(mAmlByteEncoding[0]); Index++) {
+ if ((mAmlByteEncoding[Index].OpCode == OpCode) && (mAmlByteEncoding[Index].SubOpCode == SubOpCode)) {
+ return &mAmlByteEncoding[Index];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ This function returns AcpiDataType according to AmlType.
+
+ @param[in] AmlType AML Type.
+
+ @return AcpiDataType
+**/
+EFI_ACPI_DATA_TYPE
+AmlTypeToAcpiType (
+ IN AML_OP_PARSE_FORMAT AmlType
+ )
+{
+ if (AmlType >= sizeof(mAmlTypeToAcpiType)/sizeof(mAmlTypeToAcpiType[0])) {
+ ASSERT(FALSE);
+ return EFI_ACPI_DATA_TYPE_NONE;
+ }
+ return mAmlTypeToAcpiType [AmlType];
+}
+
+/**
+ This function retuns package length from the buffer.
+
+ @param[in] Buffer AML buffer
+ @param[out] PkgLength The total length of package.
+
+ @return The byte data count to present the package length.
+**/
+UINTN
+AmlGetPkgLength (
+ IN UINT8 *Buffer,
+ OUT UINTN *PkgLength
+ )
+{
+ UINT8 LeadByte;
+ UINT8 ByteCount;
+ UINTN RealLength;
+ UINTN Offset;
+
+ //
+ // <bit 7-6: ByteData count that follows (0-3)>
+ // <bit 5-4: Only used if PkgLength < 63>
+ // <bit 3-0: Least significant package length nybble>
+ //
+ // Note: The high 2 bits of the first byte reveal how many follow bytes are in the
+ // If the PkgLength has only one byte, bit 0 through 5 are used to encode the
+ // package length (in other words, values 0-63). If the package length value is more than
+ // 63, more than one byte must be used for the encoding in which case bit 4 and 5 of the
+ // PkgLeadByte are reserved and must be zero. If the multiple bytes encoding is used,
+ // bits 0-3 of the PkgLeadByte become the least significant 4 bits of the resulting
+ // package length value. The next ByteData will become the next least significant 8 bits
+ // of the resulting value and so on, up to 3 ByteData bytes. Thus, the maximum package
+ // length is 2**28.
+ //
+
+ LeadByte = *Buffer;
+ ByteCount = (UINT8)((LeadByte >> 6) & 0x03);
+ Offset = ByteCount + 1;
+ RealLength = 0;
+
+ switch (ByteCount) {
+ case 0:
+ RealLength = (UINT32)LeadByte;
+ break;
+ case 1:
+ RealLength = *(Buffer + 1);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ case 2:
+ RealLength = *(Buffer + 1);
+ RealLength |= (UINTN)((*(Buffer + 2)) << 8);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ case 3:
+ RealLength = *(Buffer + 1);
+ RealLength |= (UINTN)((*(Buffer + 2)) << 8);
+ RealLength |= (UINTN)((*(Buffer + 3)) << 16);
+ RealLength = (RealLength << 4) | (LeadByte & 0xF);
+ break;
+ default:
+ ASSERT (0);
+ break;
+ }
+
+ *PkgLength = RealLength;
+ return Offset;
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c
new file mode 100644
index 0000000000..c7e8af96d3
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlChild.c
@@ -0,0 +1,280 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
+ 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 "AcpiTable.h"
+
+/**
+ Return the child objects buffer from AML Handle's buffer.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] CurrentBuffer The current child buffer.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromObjectBuffer (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN UINT8 *CurrentBuffer,
+ OUT VOID **Buffer
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ UINTN DataSize;
+
+ //
+ // Root is considered as SCOPE, which has TermList.
+ // We need return only Object in TermList.
+ //
+ while ((UINTN)CurrentBuffer < (UINTN)(AmlParentHandle->Buffer + AmlParentHandle->Size)) {
+ AmlByteEncoding = AmlSearchByOpByte (CurrentBuffer);
+ if (AmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // NOTE: We need return everything, because user might need parse the returned object.
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0) {
+ *Buffer = CurrentBuffer;
+ return EFI_SUCCESS;
+ }
+
+ DataSize = AmlGetObjectSize (
+ AmlByteEncoding,
+ CurrentBuffer,
+ (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)CurrentBuffer
+ );
+ if (DataSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBuffer += DataSize;
+ }
+
+ //
+ // No more
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child ACPI objects from Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ UINT8 *CurrentBuffer;
+
+ if (AmlHandle == NULL) {
+ //
+ // First One
+ //
+ CurrentBuffer = (VOID *)AmlParentHandle->Buffer;
+ } else {
+ CurrentBuffer = (VOID *)(AmlHandle->Buffer + AmlHandle->Size);
+ }
+
+ return AmlGetChildFromObjectBuffer (AmlParentHandle, CurrentBuffer, Buffer);
+}
+
+/**
+ Return the child objects buffer from AML Handle's option list.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] AmlHandle The current child handle.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromOptionList (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *Data;
+ UINTN DataSize;
+ AML_OP_PARSE_INDEX Index;
+ EFI_STATUS Status;
+ AML_OP_PARSE_INDEX MaxTerm;
+
+ Index = AML_OP_PARSE_INDEX_GET_TERM1;
+ MaxTerm = AmlParentHandle->AmlByteEncoding->MaxIndex;
+ while (Index <= MaxTerm) {
+ Status = AmlParseOptionHandleCommon (
+ AmlParentHandle,
+ (AML_OP_PARSE_INDEX)Index,
+ &DataType,
+ (VOID **)&Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataType == EFI_ACPI_DATA_TYPE_NONE) {
+ //
+ // Not found
+ //
+ break;
+ }
+
+ //
+ // Find it, and Check Data
+ //
+ if ((DataType == EFI_ACPI_DATA_TYPE_CHILD) &&
+ ((UINTN)AmlHandle->Buffer < (UINTN)Data)) {
+ //
+ // Buffer < Data means current node is next one
+ //
+ *Buffer = Data;
+ return EFI_SUCCESS;
+ }
+ //
+ // Not Child
+ //
+ Index ++;
+ }
+
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the child objects buffer from AML Handle's object child list.
+
+ @param[in] AmlParentHandle Parent handle.
+ @param[in] AmlHandle The current child handle.
+ @param[out] Buffer On return, points to the next returned child buffer or NULL if there are no
+ child buffer.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER AmlParentHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromObjectChildList (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *CurrentBuffer;
+
+ CurrentBuffer = NULL;
+
+ if ((AmlParentHandle->AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
+ //
+ // No ObjectList
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do we need add node within METHOD?
+ // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
+ //
+
+ //
+ // Now, we get the last node.
+ //
+ Status = AmlGetOffsetAfterLastOption (AmlParentHandle, &CurrentBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Go through all the reset buffer.
+ //
+ if ((UINTN)AmlHandle->Buffer < (UINTN)CurrentBuffer) {
+ //
+ // Buffer < Data means next node is first object
+ //
+ } else if ((UINTN)AmlHandle->Buffer + AmlHandle->Size < (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size) {
+ //
+ // There is still more node
+ //
+ CurrentBuffer = AmlHandle->Buffer + AmlHandle->Size;
+ } else {
+ //
+ // No more data
+ //
+ *Buffer = NULL;
+ return EFI_SUCCESS;
+ }
+
+ return AmlGetChildFromObjectBuffer (AmlParentHandle, CurrentBuffer, Buffer);
+}
+
+/**
+ Return the child ACPI objects from Non-Root Handle.
+
+ @param[in] AmlParentHandle Parent handle. It is Non-Root Handle.
+ @param[in] AmlHandle The previously returned handle or NULL to start with the first handle.
+ @param[out] Buffer On return, points to the next returned ACPI handle or NULL if there are no
+ child objects.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetChildFromNonRoot (
+ IN EFI_AML_HANDLE *AmlParentHandle,
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (AmlHandle == NULL) {
+ //
+ // NULL means first one
+ //
+ AmlHandle = AmlParentHandle;
+ }
+
+ //
+ // 1. Get Option
+ //
+ Status = AmlGetChildFromOptionList (AmlParentHandle, AmlHandle, Buffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*Buffer != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 2. search ObjectList
+ //
+ return AmlGetChildFromObjectChildList (AmlParentHandle, AmlHandle, Buffer);
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
new file mode 100644
index 0000000000..03b7394c4d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
@@ -0,0 +1,614 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
+ 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 "AcpiTable.h"
+
+/**
+ Construct node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeList (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ );
+
+/**
+ Create AML Node.
+
+ @param[in] NameSeg AML NameSeg.
+ @param[in] Parent AML parent node list.
+ @param[in] AmlByteEncoding AML Byte Encoding.
+
+ @return AML Node.
+**/
+EFI_AML_NODE_LIST *
+AmlCreateNode (
+ IN UINT8 *NameSeg,
+ IN EFI_AML_NODE_LIST *Parent,
+ IN AML_BYTE_ENCODING *AmlByteEncoding
+ )
+{
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ AmlNodeList = AllocatePool (sizeof(*AmlNodeList));
+ ASSERT (AmlNodeList != NULL);
+
+ AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE;
+ CopyMem (AmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE);
+ AmlNodeList->Buffer = NULL;
+ AmlNodeList->Size = 0;
+ InitializeListHead (&AmlNodeList->Link);
+ InitializeListHead (&AmlNodeList->Children);
+ AmlNodeList->Parent = Parent;
+ AmlNodeList->AmlByteEncoding = AmlByteEncoding;
+
+ return AmlNodeList;
+}
+
+/**
+ Find the AML NameSeg in the children of AmlParentNodeList.
+
+ @param[in] NameSeg AML NameSeg.
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Create TRUE means to create node if not found.
+
+ @return AmlChildNode whoes name is same as NameSeg.
+**/
+EFI_AML_NODE_LIST *
+AmlFindNodeInThis (
+ IN UINT8 *NameSeg,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN BOOLEAN Create
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ StartLink = &AmlParentNodeList->Children;
+ CurrentLink = StartLink->ForwardLink;
+
+ while (CurrentLink != StartLink) {
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ //
+ // AML name is same as the one stored
+ //
+ if (CompareMem (CurrentAmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE) == 0) {
+ //
+ // Good! Found it
+ //
+ return CurrentAmlNodeList;
+ }
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ //
+ // Not found
+ //
+ if (!Create) {
+ return NULL;
+ }
+
+ //
+ // Create new node with NULL buffer - it means namespace not be returned.
+ //
+ AmlNodeList = AmlCreateNode (NameSeg, AmlParentNodeList, NULL);
+ InsertTailList (&AmlParentNodeList->Children, &AmlNodeList->Link);
+
+ return AmlNodeList;
+}
+
+/**
+ Find the AML NameString in the children of AmlParentNodeList or AmlRootNodeList.
+
+ @param[in] NameString AML NameString.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Create TRUE means to create node if not found.
+
+ @return AmlChildNode whoes name is same as NameSeg.
+**/
+EFI_AML_NODE_LIST *
+AmlFindNodeInTheTree (
+ IN UINT8 *NameString,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN BOOLEAN Create
+ )
+{
+ UINT8 *Buffer;
+ EFI_AML_NODE_LIST *AmlNodeList;
+ EFI_AML_NODE_LIST *AmlCurrentNodeList;
+ UINT8 Index;
+ UINT8 SegCount;
+
+ Buffer = NameString;
+
+ //
+ // Handle root or parent prefix
+ //
+ if (*Buffer == AML_ROOT_CHAR) {
+ AmlCurrentNodeList = AmlRootNodeList;
+ Buffer += 1;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ AmlCurrentNodeList = AmlParentNodeList;
+ do {
+ if (AmlCurrentNodeList->Parent != NULL) {
+ AmlCurrentNodeList = AmlCurrentNodeList->Parent;
+ } else {
+ //
+ // Only root has no parent
+ //
+ ASSERT (AmlCurrentNodeList == AmlRootNodeList);
+ }
+ Buffer += 1;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ } else {
+ AmlCurrentNodeList = AmlParentNodeList;
+ }
+
+ //
+ // Handle name segment
+ //
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ Buffer += 1;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ Buffer += 1;
+ SegCount = *Buffer;
+ Buffer += 1;
+ } else if (*Buffer == 0) {
+ //
+ // NULL name, only for Root
+ //
+ ASSERT (AmlCurrentNodeList == AmlRootNodeList);
+ return AmlCurrentNodeList;
+ } else {
+ SegCount = 1;
+ }
+
+ //
+ // Handle NamePath
+ //
+ Index = 0;
+ do {
+ AmlNodeList = AmlFindNodeInThis (Buffer, AmlCurrentNodeList, Create);
+ if (AmlNodeList == NULL) {
+ return NULL;
+ }
+ AmlCurrentNodeList = AmlNodeList;
+ Buffer += AML_NAME_SEG_SIZE;
+ Index ++;
+ } while (Index < SegCount);
+
+ return AmlNodeList;
+}
+
+/**
+ Insert the NameString to the AmlNodeList.
+
+ @param[in] NameString AML NameString.
+ @param[in] Buffer Buffer for the Node.
+ @param[in] Size Size for the Node.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @return AmlChildNode whoes name is NameString.
+**/
+EFI_AML_NODE_LIST *
+AmlInsertNodeToTree (
+ IN UINT8 *NameString,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ AmlNodeList = AmlFindNodeInTheTree (
+ NameString,
+ AmlRootNodeList,
+ AmlParentNodeList,
+ TRUE // Find and Create
+ );
+ ASSERT (AmlNodeList != NULL);
+ if (AmlNodeList == NULL) {
+ return NULL;
+ }
+
+ //
+ // Check buffer
+ //
+ if (AmlNodeList->Buffer == NULL) {
+ //
+ // NULL means new added one or SCOPE_OP
+ //
+ if (*(UINT8 *)Buffer != AML_SCOPE_OP) {
+ //
+ // We need check if new one is SCOPE_OP, because SCOPE_OP just means namespace, not a real device.
+ // We should not return SCOPE_OP.
+ //
+ AmlNodeList->Buffer = Buffer;
+ AmlNodeList->Size = Size;
+ AmlNodeList->AmlByteEncoding = AmlSearchByOpByte (Buffer);
+ }
+ return AmlNodeList;
+ }
+
+ //
+ // Already added
+ //
+ if (*(UINT8 *)Buffer == AML_SCOPE_OP) {
+ //
+ // The new one is SCOPE_OP, OK just return;
+ //
+ return AmlNodeList;
+ }
+
+ //
+ // Oops!!!, There must be something wrong.
+ //
+ DEBUG ((EFI_D_ERROR, "AML: Override Happen - %a!\n", NameString));
+ DEBUG ((EFI_D_ERROR, "AML: Existing Node - %x\n", AmlNodeList->Buffer));
+ DEBUG ((EFI_D_ERROR, "AML: New Buffer - %x\n", Buffer));
+
+ return NULL;
+}
+
+/**
+ Construct child node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeListForChild (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ UINT8 *CurrentBuffer;
+ EFI_AML_HANDLE *AmlChildHandle;
+ EFI_STATUS Status;
+
+ CurrentBuffer = NULL;
+ AmlChildHandle = NULL;
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+ Buffer = AmlHandle->Buffer;
+ BufferSize = AmlHandle->Size;
+
+ //
+ // Check if we need recursively add node
+ //
+ if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
+ //
+ // No more node need to be added
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do we need add node within METHOD?
+ // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
+ //
+
+ //
+ // Now, we get the last node.
+ //
+ Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Go through all the reset buffer.
+ //
+ while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {
+ //
+ // Find the child node.
+ //
+ Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // No child found, break now.
+ //
+ break;
+ }
+
+ //
+ // Good, find the child. Construct node recursively
+ //
+ Status = AmlConstructNodeList (
+ AmlChildHandle,
+ AmlRootNodeList,
+ AmlParentNodeList
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Parse next one
+ //
+ CurrentBuffer += AmlChildHandle->Size;
+
+ Close ((EFI_ACPI_HANDLE)AmlChildHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct node list according to the AML handle.
+
+ @param[in] AmlHandle AML handle.
+ @param[in] AmlRootNodeList AML root node list.
+ @param[in] AmlParentNodeList AML parent node list.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlConstructNodeList (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN EFI_AML_NODE_LIST *AmlRootNodeList,
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ VOID *NameString;
+ EFI_AML_NODE_LIST *AmlNodeList;
+
+ //
+ // 1. Check if there is need to construct node for this OpCode.
+ //
+ if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {
+ //
+ // No need to construct node, so we just skip this OpCode.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 2. Now, we need construct node for this OpCode.
+ //
+ NameString = AmlGetObjectName (AmlHandle);
+ if (NameString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Now, we need to insert node to the node list.
+ // NOTE: The name here could be AML NameString. So the callee need parse it.
+ //
+ AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);
+ ASSERT (AmlNodeList != NULL);
+
+ //
+ // 3. Ok, we need to parse the object list to see if there are more node to be added.
+ //
+ return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);
+}
+
+/**
+ Destruct node list
+
+ @param[in] AmlParentNodeList AML parent node list.
+**/
+VOID
+AmlDestructNodeList (
+ IN EFI_AML_NODE_LIST *AmlParentNodeList
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+
+ //
+ // Get the children link
+ //
+ StartLink = &AmlParentNodeList->Children;
+ CurrentLink = StartLink->ForwardLink;
+
+ //
+ // Go through all the children
+ //
+ while (CurrentLink != StartLink) {
+ //
+ // Destruct the child's list recursively
+ //
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ CurrentLink = CurrentLink->ForwardLink;
+
+ //
+ // Remove this child from list and free the node
+ //
+ RemoveEntryList (&(CurrentAmlNodeList->Link));
+
+ AmlDestructNodeList (CurrentAmlNodeList);
+ }
+
+ //
+ // Done.
+ //
+ FreePool (AmlParentNodeList);
+ return ;
+}
+
+/**
+ Dump node list
+
+ @param[in] AmlParentNodeList AML parent node list.
+ @param[in] Level Output debug level.
+**/
+VOID
+AmlDumpNodeInfo (
+ IN EFI_AML_NODE_LIST *AmlParentNodeList,
+ IN UINTN Level
+ )
+{
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ volatile LIST_ENTRY *CurrentLink;
+ UINTN Index;
+
+ CurrentLink = AmlParentNodeList->Children.ForwardLink;
+
+ if (Level == 0) {
+ DEBUG ((EFI_D_ERROR, "\\"));
+ } else {
+ for (Index = 0; Index < Level; Index++) {
+ DEBUG ((EFI_D_ERROR, " "));
+ }
+ AmlPrintNameSeg (AmlParentNodeList->Name);
+ }
+ DEBUG ((EFI_D_ERROR, "\n"));
+
+ while (CurrentLink != &AmlParentNodeList->Children) {
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return ;
+}
+
+/**
+ Returns the handle of the ACPI object representing the specified ACPI AML path
+
+ @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
+ @param[in] AmlPath Points to the ACPI AML path.
+ @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
+ HandleIn.
+ @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
+ FALSE means to find AML path from this Node (The HandleIn).
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlFindPath (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN UINT8 *AmlPath,
+ OUT VOID **Buffer,
+ IN BOOLEAN FromRoot
+ )
+{
+ EFI_AML_NODE_LIST *AmlRootNodeList;
+ EFI_STATUS Status;
+ EFI_AML_NODE_LIST *AmlNodeList;
+ UINT8 RootNameSeg[AML_NAME_SEG_SIZE];
+ EFI_AML_NODE_LIST *CurrentAmlNodeList;
+ LIST_ENTRY *CurrentLink;
+
+ //
+ // 1. create tree
+ //
+
+ //
+ // Create root handle
+ //
+ RootNameSeg[0] = AML_ROOT_CHAR;
+ RootNameSeg[1] = 0;
+ AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);
+
+ Status = AmlConstructNodeList (
+ AmlHandle,
+ AmlRootNodeList, // Root
+ AmlRootNodeList // Parent
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));
+ AmlDumpNodeInfo (AmlRootNodeList, 0);
+ DEBUG_CODE_END ();
+
+ //
+ // 2. Search the node in the tree
+ //
+ if (FromRoot) {
+ //
+ // Search from Root
+ //
+ CurrentAmlNodeList = AmlRootNodeList;
+ } else {
+ //
+ // Search from this node, NOT ROOT.
+ // Since we insert node to ROOT one by one, we just get the first node and search from it.
+ //
+ CurrentLink = AmlRootNodeList->Children.ForwardLink;
+ if (CurrentLink != &AmlRootNodeList->Children) {
+ //
+ // First node
+ //
+ CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
+ } else {
+ //
+ // No child
+ //
+ CurrentAmlNodeList = NULL;
+ }
+ }
+
+ //
+ // Search
+ //
+ if (CurrentAmlNodeList != NULL) {
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));
+ AmlPrintNameSeg (CurrentAmlNodeList->Name);
+ DEBUG ((EFI_D_ERROR, "\n"));
+ DEBUG_CODE_END ();
+ AmlNodeList = AmlFindNodeInTheTree (
+ AmlPath,
+ AmlRootNodeList, // Root
+ CurrentAmlNodeList, // Parent
+ FALSE
+ );
+ } else {
+ AmlNodeList = NULL;
+ }
+
+ *Buffer = NULL;
+ Status = EFI_SUCCESS;
+ if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {
+ *Buffer = AmlNodeList->Buffer;
+ }
+
+ //
+ // 3. free the tree
+ //
+ AmlDestructNodeList (AmlRootNodeList);
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c
new file mode 100644
index 0000000000..f4cad10af6
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlOption.c
@@ -0,0 +1,452 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>
+ 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 "AcpiTable.h"
+
+/**
+ Retrieve option term according to AmlByteEncoding and Buffer.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML buffer.
+ @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
+ @param[in] TermIndex Index of the data to retrieve from the object.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionTerm (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize,
+ IN AML_OP_PARSE_INDEX TermIndex,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ AML_BYTE_ENCODING *ChildAmlByteEncoding;
+ EFI_STATUS Status;
+
+ if (DataType != NULL) {
+ *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
+ }
+ if (Data != NULL) {
+ *Data = Buffer;
+ }
+ //
+ // Parse term according to AML type
+ //
+ switch (AmlByteEncoding->Format[TermIndex - 1]) {
+ case AML_UINT8:
+ *DataSize = sizeof(UINT8);
+ break;
+ case AML_UINT16:
+ *DataSize = sizeof(UINT16);
+ break;
+ case AML_UINT32:
+ *DataSize = sizeof(UINT32);
+ break;
+ case AML_UINT64:
+ *DataSize = sizeof(UINT64);
+ break;
+ case AML_STRING:
+ *DataSize = AsciiStrSize((CHAR8 *)Buffer);
+ break;
+ case AML_NAME:
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case AML_OBJECT:
+ ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
+ if (ChildAmlByteEncoding == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
+ // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
+ // We should not return CHILD because there is NO OpCode for NameString.
+ //
+ if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ if (DataType != NULL) {
+ *DataType = AmlTypeToAcpiType (AML_NAME);
+ }
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ //
+ // It is real AML_OBJECT
+ //
+ *DataSize = AmlGetObjectSize (
+ ChildAmlByteEncoding,
+ Buffer,
+ MaxBufferSize
+ );
+ if (*DataSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case AML_NONE:
+ //
+ // No term
+ //
+ case AML_OPCODE:
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*DataSize > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information according to AmlByteEncoding and Buffer.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML buffer.
+ @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionCommon (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ UINT8 *CurrentBuffer;
+ UINTN PkgLength;
+ UINTN OpLength;
+ UINTN PkgOffset;
+ AML_OP_PARSE_INDEX TermIndex;
+ EFI_STATUS Status;
+
+ ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
+
+ //
+ // 0. Check if this is NAME string.
+ //
+ if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
+ //
+ // Only allow GET_SIZE
+ //
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // return NameString size
+ //
+ Status = AmlGetNameStringSize (Buffer, DataSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*DataSize > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Not NAME string, start parsing
+ //
+ CurrentBuffer = Buffer;
+
+ //
+ // 1. Get OpCode
+ //
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ *DataType = EFI_ACPI_DATA_TYPE_OPCODE;
+ *Data = (VOID *)CurrentBuffer;
+ }
+ if (*CurrentBuffer == AML_EXT_OP) {
+ OpLength = 2;
+ } else {
+ OpLength = 1;
+ }
+ *DataSize = OpLength;
+ if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
+ return EFI_SUCCESS;
+ }
+ if (OpLength > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CurrentBuffer += OpLength;
+
+ //
+ // 2. Skip PkgLength field, if have
+ //
+ if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
+ PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength);
+ //
+ // Override MaxBufferSize if it is valid PkgLength
+ //
+ if (OpLength + PkgLength > MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ MaxBufferSize = OpLength + PkgLength;
+ }
+ } else {
+ PkgOffset = 0;
+ PkgLength = 0;
+ }
+ CurrentBuffer += PkgOffset;
+
+ //
+ // 3. Get Term one by one.
+ //
+ TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
+ while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
+ Status = AmlParseOptionTerm (
+ AmlByteEncoding,
+ CurrentBuffer,
+ (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
+ TermIndex,
+ DataType,
+ Data,
+ DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Index == TermIndex) {
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Parse next one
+ //
+ CurrentBuffer += *DataSize;
+ TermIndex ++;
+ }
+
+ //
+ // Finish all options, but no option found.
+ //
+ if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
+ if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 4. Finish parsing all node, return size
+ //
+ ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
+ if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
+ *DataSize = OpLength + PkgLength;
+ } else {
+ *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return object size.
+
+ @param[in] AmlByteEncoding AML Byte Encoding.
+ @param[in] Buffer AML object buffer.
+ @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
+
+ @return Size of the object.
+**/
+UINTN
+AmlGetObjectSize (
+ IN AML_BYTE_ENCODING *AmlByteEncoding,
+ IN UINT8 *Buffer,
+ IN UINTN MaxBufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+
+ Status = AmlParseOptionCommon (
+ AmlByteEncoding,
+ Buffer,
+ MaxBufferSize,
+ AML_OP_PARSE_INDEX_GET_SIZE,
+ NULL,
+ NULL,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ } else {
+ return DataSize;
+ }
+}
+
+/**
+ Return object name.
+
+ @param[in] AmlHandle AML handle.
+
+ @return Name of the object.
+**/
+CHAR8 *
+AmlGetObjectName (
+ IN EFI_AML_HANDLE *AmlHandle
+ )
+{
+ AML_BYTE_ENCODING *AmlByteEncoding;
+ VOID *NameString;
+ UINTN NameSize;
+ AML_OP_PARSE_INDEX TermIndex;
+ EFI_STATUS Status;
+ EFI_ACPI_DATA_TYPE DataType;
+
+ AmlByteEncoding = AmlHandle->AmlByteEncoding;
+
+ ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
+
+ //
+ // Find out Last Name index, according to OpCode table.
+ // The last name will be the node name by design.
+ //
+ TermIndex = AmlByteEncoding->MaxIndex;
+ for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
+ if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
+ break;
+ }
+ }
+ ASSERT (TermIndex != 0);
+
+ //
+ // Get Name for this node.
+ //
+ Status = AmlParseOptionHandleCommon (
+ AmlHandle,
+ TermIndex,
+ &DataType,
+ &NameString,
+ &NameSize
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
+
+ return NameString;
+}
+
+/**
+ Return offset of last option.
+
+ @param[in] AmlHandle AML Handle.
+ @param[out] Buffer Upon return, points to the offset after last option.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlGetOffsetAfterLastOption (
+ IN EFI_AML_HANDLE *AmlHandle,
+ OUT UINT8 **Buffer
+ )
+{
+ EFI_ACPI_DATA_TYPE DataType;
+ VOID *Data;
+ UINTN DataSize;
+ EFI_STATUS Status;
+
+ Status = AmlParseOptionHandleCommon (
+ AmlHandle,
+ AmlHandle->AmlByteEncoding->MaxIndex,
+ &DataType,
+ &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We need to parse the rest buffer after last node.
+ //
+ *Buffer = (UINT8 *)((UINTN)Data + DataSize);
+
+ //
+ // We need skip PkgLength if no Option
+ //
+ if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
+ *Buffer += AmlGetPkgLength (*Buffer, &DataSize);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve information according to AmlHandle
+
+ @param[in] AmlHandle AML handle.
+ @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
+ in the ACPI encoding, with index 0 always being the ACPI opcode.
+ @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
+ for the specified index.
+ @param[out] Data Upon return, points to the pointer to the data.
+ @param[out] DataSize Upon return, points to the size of Data.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
+**/
+EFI_STATUS
+AmlParseOptionHandleCommon (
+ IN EFI_AML_HANDLE *AmlHandle,
+ IN AML_OP_PARSE_INDEX Index,
+ OUT EFI_ACPI_DATA_TYPE *DataType,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ return AmlParseOptionCommon (
+ AmlHandle->AmlByteEncoding,
+ AmlHandle->Buffer,
+ AmlHandle->Size,
+ Index,
+ DataType,
+ Data,
+ DataSize
+ );
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c
new file mode 100644
index 0000000000..9f47b48835
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlString.c
@@ -0,0 +1,545 @@
+/** @file
+ ACPI Sdt Protocol Driver
+
+ Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved. <BR>
+ 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 "AcpiTable.h"
+
+/**
+ Check if it is AML Root name
+
+ @param[in] Buffer AML path.
+
+ @retval TRUE AML path is root.
+ @retval FALSE AML path is not root.
+**/
+BOOLEAN
+AmlIsRootPath (
+ IN UINT8 *Buffer
+ )
+{
+ if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is AML LeadName.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is AML LeadName.
+ @retval FALSE Char is not AML LeadName.
+**/
+BOOLEAN
+AmlIsLeadName (
+ IN CHAR8 Ch
+ )
+{
+ if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is AML Name.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is AML Name.
+ @retval FALSE Char is not AML Name.
+**/
+BOOLEAN
+AmlIsName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Return is buffer is AML NameSeg.
+
+ @param[in] Buffer AML NameSement.
+
+ @retval TRUE It is AML NameSegment.
+ @retval FALSE It is not AML NameSegment.
+**/
+BOOLEAN
+AmlIsNameSeg (
+ IN UINT8 *Buffer
+ )
+{
+ UINTN Index;
+ if (!AmlIsLeadName (Buffer[0])) {
+ return FALSE;
+ }
+ for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
+ if (!AmlIsName (Buffer[Index])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Get AML NameString size.
+
+ @param[in] Buffer AML NameString.
+ @param[out] BufferSize AML NameString size
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
+**/
+EFI_STATUS
+AmlGetNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *BufferSize
+ )
+{
+ UINTN SegCount;
+ UINTN Length;
+ UINTN Index;
+
+ Length = 0;
+
+ //
+ // Parse root or parent prefix
+ //
+ if (*Buffer == AML_ROOT_CHAR) {
+ Buffer ++;
+ Length ++;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ do {
+ Buffer ++;
+ Length ++;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ //
+ // Parse name segment
+ //
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ Buffer ++;
+ Length ++;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ Buffer ++;
+ Length ++;
+ SegCount = *Buffer;
+ Buffer ++;
+ Length ++;
+ } else if (*Buffer == 0) {
+ //
+ // NULL Name, only for Root
+ //
+ SegCount = 0;
+ Buffer --;
+ if ((Length == 1) && (*Buffer == AML_ROOT_CHAR)) {
+ *BufferSize = 2;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // NameSeg
+ //
+ SegCount = 1;
+ }
+
+ Index = 0;
+ do {
+ if (!AmlIsNameSeg (Buffer)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Buffer += AML_NAME_SEG_SIZE;
+ Length += AML_NAME_SEG_SIZE;
+ Index ++;
+ } while (Index < SegCount);
+
+ *BufferSize = Length;
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if it is ASL LeadName.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is ASL LeadName.
+ @retval FALSE Char is not ASL LeadName.
+**/
+BOOLEAN
+AmlIsAslLeadName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsLeadName (Ch) || (Ch >= 'a' && Ch <= 'z')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it is ASL Name.
+
+ @param[in] Ch Char.
+
+ @retval TRUE Char is ASL Name.
+ @retval FALSE Char is not ASL Name.
+**/
+BOOLEAN
+AmlIsAslName (
+ IN CHAR8 Ch
+ )
+{
+ if (AmlIsAslLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Get ASL NameString size.
+
+ @param[in] Buffer ASL NameString.
+
+ @return ASL NameString size.
+**/
+UINTN
+AmlGetAslNameSegLength (
+ IN UINT8 *Buffer
+ )
+{
+ UINTN Length;
+ UINTN Index;
+
+ if (*Buffer == 0) {
+ return 0;
+ }
+
+ Length = 0;
+ //
+ // 1st
+ //
+ if (AmlIsAslLeadName (*Buffer)) {
+ Length ++;
+ Buffer ++;
+ }
+ if ((*Buffer == 0) || (*Buffer == '.')) {
+ return Length;
+ }
+ //
+ // 2, 3, 4 name char
+ //
+ for (Index = 0; Index < 3; Index++) {
+ if (AmlIsAslName (*Buffer)) {
+ Length ++;
+ Buffer ++;
+ }
+ if ((*Buffer == 0) || (*Buffer == '.')) {
+ return Length;
+ }
+ }
+
+ //
+ // Invalid ASL name
+ //
+ return 0;
+}
+
+/**
+ Get ASL NameString size.
+
+ @param[in] Buffer ASL NameString.
+ @param[out] Root On return, points to Root char number.
+ @param[out] Parent On return, points to Parent char number.
+ @param[out] SegCount On return, points to Segment count.
+
+ @return ASL NameString size.
+**/
+UINTN
+AmlGetAslNameStringSize (
+ IN UINT8 *Buffer,
+ OUT UINTN *Root,
+ OUT UINTN *Parent,
+ OUT UINTN *SegCount
+ )
+{
+ UINTN NameLength;
+ UINTN TotalLength;
+
+ *Root = 0;
+ *Parent = 0;
+ *SegCount = 0;
+ TotalLength = 0;
+ NameLength = 0;
+ if (*Buffer == AML_ROOT_CHAR) {
+ *Root = 1;
+ Buffer ++;
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ do {
+ Buffer ++;
+ (*Parent) ++;
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ //
+ // Now parse name
+ //
+ while (*Buffer != 0) {
+ NameLength = AmlGetAslNameSegLength (Buffer);
+ if ((NameLength == 0) || (NameLength > AML_NAME_SEG_SIZE)) {
+ return 0;
+ }
+ (*SegCount) ++;
+ Buffer += NameLength;
+ if (*Buffer == 0) {
+ break;
+ }
+ Buffer ++;
+ }
+
+ //
+ // Check SegCoount
+ //
+ if (*SegCount > 0xFF) {
+ return 0;
+ }
+
+ //
+ // Calculate total length
+ //
+ TotalLength = *Root + *Parent + (*SegCount) * AML_NAME_SEG_SIZE;
+ if (*SegCount > 2) {
+ TotalLength += 2;
+ } else if (*SegCount == 2) {
+ TotalLength += 1;
+ }
+
+ //
+ // Add NULL char
+ //
+ TotalLength ++;
+
+ return TotalLength;
+}
+
+/**
+ Copy mem, and cast all the char in dest to be upper case.
+
+ @param[in] DstBuffer Destination buffer.
+ @param[in] SrcBuffer Source buffer.
+ @param[in] Length Buffer length.
+**/
+VOID
+AmlUpperCaseCopyMem (
+ IN UINT8 *DstBuffer,
+ IN UINT8 *SrcBuffer,
+ IN UINTN Length
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Length; Index++) {
+ if (SrcBuffer[Index] >= 'a' && SrcBuffer[Index] <= 'z') {
+ DstBuffer[Index] = (UINT8)(SrcBuffer[Index] - 'a' + 'A');
+ } else {
+ DstBuffer[Index] = SrcBuffer[Index];
+ }
+ }
+}
+
+/**
+ Return AML name according to ASL name.
+ The caller need free the AmlName returned.
+
+ @param[in] AslPath ASL name.
+
+ @return AmlName
+**/
+UINT8 *
+AmlNameFromAslName (
+ IN UINT8 *AslPath
+ )
+{
+ UINTN Root;
+ UINTN Parent;
+ UINTN SegCount;
+ UINTN TotalLength;
+ UINTN NameLength;
+ UINT8 *Buffer;
+ UINT8 *AmlPath;
+ UINT8 *AmlBuffer;
+
+ TotalLength = AmlGetAslNameStringSize (AslPath, &Root, &Parent, &SegCount);
+ if (TotalLength == 0) {
+ return NULL;
+ }
+
+ AmlPath = AllocatePool (TotalLength);
+ ASSERT (AmlPath != NULL);
+
+ AmlBuffer = AmlPath;
+ Buffer = AslPath;
+
+ //
+ // Handle Root and Parent
+ //
+ if (Root == 1) {
+ *AmlBuffer = AML_ROOT_CHAR;
+ AmlBuffer ++;
+ Buffer ++;
+ } else if (Parent > 0) {
+ SetMem (AmlBuffer, Parent, AML_PARENT_PREFIX_CHAR);
+ AmlBuffer += Parent;
+ Buffer += Parent;
+ }
+
+ //
+ // Handle SegCount
+ //
+ if (SegCount > 2) {
+ *AmlBuffer = AML_MULTI_NAME_PREFIX;
+ AmlBuffer ++;
+ *AmlBuffer = (UINT8)SegCount;
+ AmlBuffer ++;
+ } else if (SegCount == 2) {
+ *AmlBuffer = AML_DUAL_NAME_PREFIX;
+ AmlBuffer ++;
+ }
+
+ //
+ // Now to name
+ //
+ while (*Buffer != 0) {
+ NameLength = AmlGetAslNameSegLength (Buffer);
+ ASSERT ((NameLength != 0) && (NameLength <= AML_NAME_SEG_SIZE));
+ AmlUpperCaseCopyMem (AmlBuffer, Buffer, NameLength);
+ SetMem (AmlBuffer + NameLength, AML_NAME_SEG_SIZE - NameLength, AML_NAME_CHAR__);
+ Buffer += NameLength;
+ AmlBuffer += AML_NAME_SEG_SIZE;
+ if (*Buffer == 0) {
+ break;
+ }
+ Buffer ++;
+ }
+
+ //
+ // Add NULL
+ //
+ AmlPath[TotalLength - 1] = 0;
+
+ return AmlPath;
+}
+
+/**
+ Print AML NameSeg.
+
+ @param[in] Buffer AML NameSeg.
+**/
+VOID
+AmlPrintNameSeg (
+ IN UINT8 *Buffer
+ )
+{
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[0]));
+ if ((Buffer[1] == '_') && (Buffer[2] == '_') && (Buffer[3] == '_')) {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[1]));
+ if ((Buffer[2] == '_') && (Buffer[3] == '_')) {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[2]));
+ if (Buffer[3] == '_') {
+ return ;
+ }
+ DEBUG ((EFI_D_ERROR, "%c", Buffer[3]));
+ return ;
+}
+
+/**
+ Print AML NameString.
+
+ @param[in] Buffer AML NameString.
+**/
+VOID
+AmlPrintNameString (
+ IN UINT8 *Buffer
+ )
+{
+ UINT8 SegCount;
+ UINT8 Index;
+
+ if (*Buffer == AML_ROOT_CHAR) {
+ //
+ // RootChar
+ //
+ Buffer ++;
+ DEBUG ((EFI_D_ERROR, "\\"));
+ } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
+ //
+ // ParentPrefixChar
+ //
+ do {
+ Buffer ++;
+ DEBUG ((EFI_D_ERROR, "^"));
+ } while (*Buffer == AML_PARENT_PREFIX_CHAR);
+ }
+
+ if (*Buffer == AML_DUAL_NAME_PREFIX) {
+ //
+ // DualName
+ //
+ Buffer ++;
+ SegCount = 2;
+ } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
+ //
+ // MultiName
+ //
+ Buffer ++;
+ SegCount = *Buffer;
+ Buffer ++;
+ } else if (*Buffer == 0) {
+ //
+ // NULL Name
+ //
+ return ;
+ } else {
+ //
+ // NameSeg
+ //
+ SegCount = 1;
+ }
+
+ AmlPrintNameSeg (Buffer);
+ Buffer += AML_NAME_SEG_SIZE;
+ for (Index = 0; Index < SegCount - 1; Index++) {
+ DEBUG ((EFI_D_ERROR, "."));
+ AmlPrintNameSeg (Buffer);
+ Buffer += AML_NAME_SEG_SIZE;
+ }
+
+ return ;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c
new file mode 100644
index 0000000000..6a7165a954
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c
@@ -0,0 +1,465 @@
+/** @file
+ This module install ACPI Boot Graphics Resource Table (BGRT).
+
+ Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
+ 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 <Uefi.h>
+
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Bmp.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/BootLogo.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Module globals.
+//
+EFI_EVENT mBootGraphicsReadyToBootEvent;
+UINTN mBootGraphicsResourceTableKey = 0;
+
+EFI_HANDLE mBootLogoHandle = NULL;
+BOOLEAN mIsLogoValid = FALSE;
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mLogoBltBuffer = NULL;
+UINTN mLogoDestX = 0;
+UINTN mLogoDestY = 0;
+UINTN mLogoWidth = 0;
+UINTN mLogoHeight = 0;
+
+BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
+ 'B', // CharB
+ 'M', // CharM
+ 0, // Size will be updated at runtime
+ {0, 0}, // Reserved
+ sizeof (BMP_IMAGE_HEADER), // ImageOffset
+ sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
+ 0, // PixelWidth will be updated at runtime
+ 0, // PixelHeight will be updated at runtime
+ 1, // Planes
+ 24, // BitPerPixel
+ 0, // CompressionType
+ 0, // ImageSize will be updated at runtime
+ 0, // XPixelsPerMeter
+ 0, // YPixelsPerMeter
+ 0, // NumberOfColors
+ 0 // ImportantColors
+};
+
+BOOLEAN mAcpiBgrtInstalled = FALSE;
+BOOLEAN mAcpiBgrtStatusChanged = FALSE;
+BOOLEAN mAcpiBgrtBufferChanged = FALSE;
+
+EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = {
+ {
+ EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE,
+ sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
+ EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION, // Revision
+ 0x00, // Checksum will be updated at runtime
+ //
+ // It is expected that these values will be updated at EntryPoint.
+ //
+ {0x00}, // OEM ID is a 6 bytes long field
+ 0x00, // OEM Table ID(8 bytes long)
+ 0x00, // OEM Revision
+ 0x00, // Creator ID
+ 0x00, // Creator Revision
+ },
+ EFI_ACPI_5_0_BGRT_VERSION, // Version
+ EFI_ACPI_5_0_BGRT_STATUS_VALID, // Status
+ EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP, // Image Type
+ 0, // Image Address
+ 0, // Image Offset X
+ 0 // Image Offset Y
+};
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param This The pointer to the Boot Logo protocol instance.
+ @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo (
+ IN EFI_BOOT_LOGO_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ );
+
+EFI_BOOT_LOGO_PROTOCOL mBootLogoProtocolTemplate = { SetBootLogo };
+
+/**
+ Update information of logo image drawn on screen.
+
+ @param This The pointer to the Boot Logo protocol instance.
+ @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer
+ is set to NULL, it indicates that logo image is no
+ longer on the screen.
+ @param DestinationX X coordinate of destination for the BltBuffer.
+ @param DestinationY Y coordinate of destination for the BltBuffer.
+ @param Width Width of rectangle in BltBuffer in pixels.
+ @param Height Hight of rectangle in BltBuffer in pixels.
+
+ @retval EFI_SUCCESS The boot logo information was updated.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to
+ insufficient memory resources.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBootLogo (
+ IN EFI_BOOT_LOGO_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ UINT64 BufferSize;
+
+ if (BltBuffer == NULL) {
+ mIsLogoValid = FALSE;
+ mAcpiBgrtStatusChanged = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mAcpiBgrtBufferChanged = TRUE;
+ if (mLogoBltBuffer != NULL) {
+ FreePool (mLogoBltBuffer);
+ mLogoBltBuffer = NULL;
+ }
+
+ //
+ // Ensure the Height * Width doesn't overflow
+ //
+ if (Height > DivU64x64Remainder ((UINTN) ~0, Width, NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+ BufferSize = MultU64x64 (Width, Height);
+
+ //
+ // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mLogoBltBuffer = AllocateCopyPool (
+ (UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
+ BltBuffer
+ );
+ if (mLogoBltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mLogoDestX = DestinationX;
+ mLogoDestY = DestinationY;
+ mLogoWidth = Width;
+ mLogoHeight = Height;
+ mIsLogoValid = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param[in] Buffer Pointer to buffer to checksum.
+ @param[in] Size Number of bytes to checksum.
+
+**/
+VOID
+BgrtAcpiTableChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
+
+ //
+ // Set checksum to 0 first.
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value.
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
+}
+
+/**
+ Install Boot Graphics Resource Table to ACPI table.
+
+ @return Status code.
+
+**/
+EFI_STATUS
+InstallBootGraphicsResourceTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ UINT8 *ImageBuffer;
+ UINTN PaddingSize;
+ UINTN BmpSize;
+ UINTN OrigBmpSize;
+ UINT8 *Image;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
+ UINTN Col;
+ UINTN Row;
+
+ //
+ // Get ACPI Table protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check whether Boot Graphics Resource Table is already installed.
+ //
+ if (mAcpiBgrtInstalled) {
+ if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) {
+ //
+ // Nothing has changed
+ //
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If BGRT data change happens. Uninstall Orignal AcpiTable first
+ //
+ Status = AcpiTableProtocol->UninstallAcpiTable (
+ AcpiTableProtocol,
+ mBootGraphicsResourceTableKey
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ } else {
+ //
+ // Check whether Logo exist.
+ //
+ if ( mLogoBltBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (mAcpiBgrtBufferChanged) {
+ //
+ // reserve original BGRT buffer size
+ //
+ OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER);
+ //
+ // Free orignal BMP memory
+ //
+ if (mBootGraphicsResourceTableTemplate.ImageAddress) {
+ gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES(OrigBmpSize));
+ }
+
+ //
+ // Allocate memory for BMP file.
+ //
+ PaddingSize = mLogoWidth & 0x3;
+
+ //
+ // First check mLogoWidth * 3 + PaddingSize doesn't overflow
+ //
+ if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
+ //
+ if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The image should be stored in EfiBootServicesData, allowing the system to reclaim the memory
+ //
+ BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER);
+ ImageBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BmpSize));
+ if (ImageBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (ImageBuffer, BmpSize);
+
+ mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
+ mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
+ mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth;
+ mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight;
+ CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
+
+ //
+ // Convert BLT buffer to BMP file.
+ //
+ Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER);
+ for (Row = 0; Row < mLogoHeight; Row++) {
+ BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth];
+
+ for (Col = 0; Col < mLogoWidth; Col++) {
+ *Image++ = BltPixel->Blue;
+ *Image++ = BltPixel->Green;
+ *Image++ = BltPixel->Red;
+ BltPixel++;
+ }
+
+ //
+ // Padding for 4 byte alignment.
+ //
+ Image += PaddingSize;
+ }
+ FreePool (mLogoBltBuffer);
+ mLogoBltBuffer = NULL;
+
+ mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer;
+ mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX;
+ mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY;
+ }
+
+ mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID);
+
+ //
+ // Update Checksum.
+ //
+ BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE));
+
+ //
+ // Publish Boot Graphics Resource Table.
+ //
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ &mBootGraphicsResourceTableTemplate,
+ sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
+ &mBootGraphicsResourceTableKey
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mAcpiBgrtInstalled = TRUE;
+ mAcpiBgrtStatusChanged = FALSE;
+ mAcpiBgrtBufferChanged = FALSE;
+
+ return Status;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ install the Boot Graphics Resource Table.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+BgrtReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ InstallBootGraphicsResourceTable ();
+}
+
+/**
+ The module Entry Point of the Boot Graphics Resource Table DXE driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+BootGraphicsDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OemTableId;
+
+ CopyMem (
+ mBootGraphicsResourceTableTemplate.Header.OemId,
+ PcdGetPtr (PcdAcpiDefaultOemId),
+ sizeof (mBootGraphicsResourceTableTemplate.Header.OemId)
+ );
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mBootGraphicsResourceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mBootGraphicsResourceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mBootGraphicsResourceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mBootGraphicsResourceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Install Boot Logo protocol.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mBootLogoHandle,
+ &gEfiBootLogoProtocolGuid,
+ &mBootLogoProtocolTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function to install BGRT on ReadyToBoot Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ BgrtReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mBootGraphicsReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
new file mode 100644
index 0000000000..9fd1da448c
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# This module install ACPI Boot Graphics Resource Table (BGRT).
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+# 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 = BootGraphicsResourceTableDxe
+ MODULE_UNI_FILE = BootGraphicsResourceTableDxe.uni
+ FILE_GUID = B8E62775-BB0A-43f0-A843-5BE8B14F8CCD
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BootGraphicsDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BootGraphicsResourceTableDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gEfiBootLogoProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[Guids]
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootGraphicsResourceTableDxeExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni
new file mode 100644
index 0000000000..cda6ae1f60
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// This module install ACPI Boot Graphics Resource Table (BGRT).
+//
+// This module installs the ACPI Boot Graphics Resource Table (BGRT).
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs ACPI Boot Graphics Resource Table (BGRT)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs the ACPI Boot Graphics Resource Table (BGRT)."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni
new file mode 100644
index 0000000000..a64b85725d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// BootGraphicsResourceTableDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Boot Graphics Resource Table DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
new file mode 100644
index 0000000000..29af7f55ec
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
@@ -0,0 +1,95 @@
+## @file
+# Boot Script Executor Module
+#
+# This is a standalone Boot Script Executor. Standalone means it does not
+# depends on any PEI or DXE service.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#
+# 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 = BootScriptExecutorDxe
+ MODULE_UNI_FILE = BootScriptExecutorDxe.uni
+ FILE_GUID = FA20568B-548B-4b2b-81EF-1BA08D4A3CEC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BootScriptExecutorEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ScriptExecute.h
+ ScriptExecute.c
+
+[Sources.X64]
+ X64/SetIdtEntry.c
+ X64/S3Asm.nasm
+ X64/S3Asm.asm
+ X64/S3Asm.S
+
+[Sources.Ia32]
+ IA32/SetIdtEntry.c
+ IA32/S3Asm.nasm
+ IA32/S3Asm.asm
+ IA32/S3Asm.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ BaseLib
+ S3BootScriptLib
+ PeCoffLib
+ DxeServicesLib
+ UefiBootServicesTableLib
+ CacheMaintenanceLib
+ UefiLib
+ DebugAgentLib
+ LockBoxLib
+ CpuExceptionHandlerLib
+ DevicePathLib
+
+[Guids]
+ gEfiBootScriptExecutorVariableGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+ gEfiBootScriptExecutorContextGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+ gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+
+[Protocols]
+ ## NOTIFY
+ ## CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
+
+[Depex]
+ gEfiLockBoxProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BootScriptExecutorDxeExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni
new file mode 100644
index 0000000000..f362a02b56
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Boot Script Executor Module
+//
+// This is a standalone Boot Script Executor. Standalone means it does not
+// depends on any PEI or DXE service.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Boot Script Executor Module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This is a standalone Boot Script Executor. Standalone means it does not depends on any PEI or DXE service."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni
new file mode 100644
index 0000000000..3fd8ad68ef
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// BootScriptExecutorDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Boot Script Execution DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S
new file mode 100644
index 0000000000..21516d5ad9
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.S
@@ -0,0 +1,66 @@
+## @file
+#
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+#-----------------------------------------
+#VOID
+#AsmTransferControl (
+# IN UINT32 S3WakingVector,
+# IN UINT32 AcpiLowMemoryBase
+# );
+#-----------------------------------------
+
+ASM_GLOBAL ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ # S3WakingVector :DWORD
+ # AcpiLowMemoryBase :DWORD
+ pushl %ebp
+ movl %esp,%ebp
+ leal LABLE, %eax
+ pushl $0x28 # CS
+ pushl %eax
+ movl 8(%ebp),%ecx
+ shrdl $20,%ecx,%ebx
+ andl $0xf,%ecx
+ movw %cx,%bx
+ movl %ebx, jmp_addr
+ lret
+LABLE:
+ .byte 0xb8,0x30,0 # mov ax, 30h as selector
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+ movw %ax,%ss
+ movl %cr0, %eax # Get control register 0
+ .byte 0x66
+ .byte 0x83,0xe0,0xfe # and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ .byte 0xf,0x22,0xc0 # mov cr0, eax ; Activate real mode
+ .byte 0xea # jmp far @jmp_addr
+jmp_addr:
+ .long 0
+
+ASM_GLOBAL ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+ jmp ASM_PFX(AsmTransferControl)
+
+# dummy
+ASM_GLOBAL ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+ASM_GLOBAL ASM_PFX(AsmFixAddress16)
+ASM_PFX(AsmFixAddress16):
+ .long 0
+ASM_GLOBAL ASM_PFX(AsmJmpAddr32)
+ASM_PFX(AsmJmpAddr32):
+ .long 0
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm
new file mode 100644
index 0000000000..2fc14a1e28
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.asm
@@ -0,0 +1,71 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for IA32 platform
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+ .586P
+ .model flat,C
+ .code
+
+PUBLIC AsmFixAddress16
+PUBLIC AsmJmpAddr32
+
+;-----------------------------------------
+;VOID
+;AsmTransferControl (
+; IN UINT32 S3WakingVector,
+; IN UINT32 AcpiLowMemoryBase
+; );
+;-----------------------------------------
+
+AsmTransferControl PROC
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ lea eax, @F
+ push 28h ; CS
+ push eax
+ mov ecx, [ebp + 8]
+ shrd ebx, ecx, 20
+ and ecx, 0fh
+ mov bx, cx
+ mov [@jmp_addr], ebx
+ retf
+@@:
+ DB 0b8h, 30h, 0 ; mov ax, 30h as selector
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov eax, cr0 ; Get control register 0
+ DB 66h
+ DB 83h, 0e0h, 0feh ; and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ DB 0fh, 22h, 0c0h ; mov cr0, eax ; Activate real mode
+ DB 0eah ; jmp far @jmp_addr
+@jmp_addr DD ?
+
+AsmTransferControl ENDP
+
+AsmTransferControl32 PROC
+ jmp AsmTransferControl
+AsmTransferControl32 ENDP
+
+; dummy
+AsmTransferControl16 PROC
+AsmFixAddress16 DD ?
+AsmJmpAddr32 DD ?
+AsmTransferControl16 ENDP
+
+ END \ No newline at end of file
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm
new file mode 100644
index 0000000000..cedc11a066
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/S3Asm.nasm
@@ -0,0 +1,68 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for IA32 platform
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+ SECTION .text
+
+global ASM_PFX(AsmFixAddress16)
+global ASM_PFX(AsmJmpAddr32)
+
+;-----------------------------------------
+;VOID
+;AsmTransferControl (
+; IN UINT32 S3WakingVector,
+; IN UINT32 AcpiLowMemoryBase
+; );
+;-----------------------------------------
+
+global ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ lea eax, [.0]
+ push 0x28 ; CS
+ push eax
+ mov ecx, [ebp + 8]
+ shrd ebx, ecx, 20
+ and ecx, 0xf
+ mov bx, cx
+ mov [@jmp_addr + 1], ebx
+ retf
+
+BITS 16
+.0:
+ mov ax, 0x30
+o32 mov ds, eax
+o32 mov es, eax
+o32 mov fs, eax
+o32 mov gs, eax
+o32 mov ss, eax
+ mov eax, cr0 ; Get control register 0
+ and eax, 0x0fffffffe ; Clear PE bit (bit #0)
+ mov cr0, eax ; Activate real mode
+@jmp_addr:
+ jmp 0x0:0x0
+
+global ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+ jmp ASM_PFX(AsmTransferControl)
+
+; dummy
+global ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+ASM_PFX(AsmFixAddress16): DD 0
+ASM_PFX(AsmJmpAddr32): DD 0
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c
new file mode 100644
index 0000000000..63b06ba5d6
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c
@@ -0,0 +1,62 @@
+/** @file
+ Set a IDT entry for debug purpose
+
+ Set a IDT entry for interrupt vector 3 for debug purpose for IA32 platform
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+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 "ScriptExecute.h"
+
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR *IdtDescriptor;
+ UINTN S3DebugBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Restore IDT for debug
+ //
+ IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
+ AsmWriteIdtr (IdtDescriptor);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ //
+ // Update IDT entry INT3 if the instruction is valid in it
+ //
+ S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
+ if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
+ }
+ );
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
new file mode 100644
index 0000000000..4545d6e581
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
@@ -0,0 +1,489 @@
+/** @file
+ This is the code for Boot Script Executer module.
+
+ This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory
+ in the entry point. The functionality is to interpret and restore the S3 boot script
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+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 "ScriptExecute.h"
+
+EFI_GUID mBootScriptExecutorImageGuid = {
+ 0x9a8d3433, 0x9fe8, 0x42b6, { 0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b }
+};
+
+BOOLEAN mPage1GSupport = FALSE;
+UINT64 mAddressEncMask = 0;
+
+/**
+ Entry function of Boot script exector. This function will be executed in
+ S3 boot path.
+ This function should not return, because it is invoked by switch stack.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+ @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE
+
+ @retval EFI_INVALID_PARAMETER - OS waking vector not found
+ @retval EFI_UNSUPPORTED - something wrong when we resume to OS
+**/
+EFI_STATUS
+EFIAPI
+S3BootScriptExecutorEntryFunction (
+ IN ACPI_S3_CONTEXT *AcpiS3Context,
+ IN PEI_S3_RESUME_STATE *PeiS3ResumeState
+ )
+{
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ EFI_STATUS Status;
+ UINTN TempStackTop;
+ UINTN TempStack[0x10];
+ UINTN AsmTransferControl16Address;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ //
+ // Disable interrupt of Debug timer, since new IDT table cannot handle it.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ AsmReadIdtr (&IdtDescriptor);
+ //
+ // Restore IDT for debug
+ //
+ SetIdtEntry (AcpiS3Context);
+
+ //
+ // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer.
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL);
+
+ //
+ // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
+ // for that parameter.
+ //
+ Status = S3BootScriptExecute ();
+
+ //
+ // If invalid script table or opcode in S3 boot script table.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ CpuDeadLoop ();
+ return Status;
+ }
+
+ AsmWbinvd ();
+
+ //
+ // Get ACPI Table Address
+ //
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+
+ //
+ // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
+ //
+ if (PeiS3ResumeState != 0) {
+ //
+ // Need report status back to S3ResumePeim.
+ // If boot script execution is failed, S3ResumePeim wil report the error status code.
+ //
+ PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ //
+ // X64 S3 Resume
+ //
+ DEBUG ((DEBUG_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
+ PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32;
+
+ if ((Facs != NULL) &&
+ (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) &&
+ (Facs->FirmwareWakingVector != 0) ) {
+ //
+ // more step needed - because relative address is handled differently between X64 and IA32.
+ //
+ AsmTransferControl16Address = (UINTN)AsmTransferControl16;
+ AsmFixAddress16 = (UINT32)AsmTransferControl16Address;
+ AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12));
+ }
+
+ AsmDisablePaging64 (
+ PeiS3ResumeState->ReturnCs,
+ (UINT32)PeiS3ResumeState->ReturnEntryPoint,
+ (UINT32)(UINTN)AcpiS3Context,
+ (UINT32)(UINTN)PeiS3ResumeState,
+ (UINT32)PeiS3ResumeState->ReturnStackPointer
+ );
+ } else {
+ //
+ // IA32 S3 Resume
+ //
+ DEBUG ((DEBUG_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
+ PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl;
+
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
+ (VOID *)(UINTN)AcpiS3Context,
+ (VOID *)(UINTN)PeiS3ResumeState,
+ (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
+ );
+ }
+
+ //
+ // Never run to here
+ //
+ CpuDeadLoop();
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly
+ //
+ if (Facs->XFirmwareWakingVector != 0) {
+ //
+ // Switch to native waking vector
+ //
+ TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
+ ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+ //
+ // X64 long mode waking vector
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+ NULL,
+ NULL,
+ (VOID *)(UINTN)TempStackTop
+ );
+ } else {
+ // Unsupported for 32bit DXE, 64bit OS vector
+ DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
+ ASSERT (FALSE);
+ }
+ } else {
+ //
+ // IA32 protected mode waking vector (Page disabled)
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ AsmDisablePaging64 (
+ 0x10,
+ (UINT32)Facs->XFirmwareWakingVector,
+ 0,
+ 0,
+ (UINT32)TempStackTop
+ );
+ } else {
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,
+ NULL,
+ NULL,
+ (VOID *)(UINTN)TempStackTop
+ );
+ }
+ }
+ } else {
+ //
+ // 16bit Realmode waking vector
+ //
+ DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
+ AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
+ }
+
+ //
+ // Never run to here
+ //
+ CpuDeadLoop();
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Register image to memory profile.
+
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param FileType File type of the image.
+
+**/
+VOID
+RegisterMemoryProfileImage (
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) {
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+ Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);
+ if (!EFI_ERROR (Status)) {
+ EfiInitializeFwVolDevicepathNode (FilePath, FileName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ Status = ProfileProtocol->RegisterImage (
+ ProfileProtocol,
+ (EFI_DEVICE_PATH_PROTOCOL *) FilePath,
+ ImageBase,
+ ImageSize,
+ FileType
+ );
+ }
+ }
+}
+
+/**
+ This is the Event notification function to reload BootScriptExecutor image
+ to RESERVED mem and save it to LockBox.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+ **/
+VOID
+EFIAPI
+ReadyToLockEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ EFI_HANDLE NewImageHandle;
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS FfsBuffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // A workaround: Here we install a dummy handle
+ //
+ NewImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Reload BootScriptExecutor image itself to RESERVED mem
+ //
+ Status = GetSectionFromAnyFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_PE32,
+ 0,
+ (VOID **) &Buffer,
+ &BufferSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ ImageContext.Handle = Buffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
+ } else {
+ Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
+ }
+ FfsBuffer = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ Pages,
+ &FfsBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
+ //
+ gBS->FreePool (Buffer);
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ RegisterMemoryProfileImage (
+ &gEfiCallerIdGuid,
+ ImageContext.ImageAddress,
+ ImageContext.ImageSize,
+ EFI_FV_FILETYPE_DRIVER
+ );
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Additional step for BootScript integrity
+ // Save BootScriptExecutor image
+ //
+ Status = SaveLockBox (
+ &mBootScriptExecutorImageGuid,
+ (VOID *)(UINTN)ImageContext.ImageAddress,
+ (UINTN)ImageContext.ImageSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ Entrypoint of Boot script exector driver, this function will be executed in
+ normal boot phase and invoked by DXE dispatch.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+BootScriptExecutorEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN BufferSize;
+ UINTN Pages;
+ BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;
+ EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer;
+ EFI_STATUS Status;
+ VOID *DevicePath;
+ EFI_EVENT ReadyToLockEvent;
+ VOID *Registration;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure AddressEncMask is contained to smallest supported address field.
+ //
+ mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+ //
+ // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
+ // point is loaded by DXE code which is the first time loaded. or else, it is already
+ // be reloaded be itself.This is a work-around
+ //
+ Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // Create ReadyToLock event to reload BootScriptExecutor image
+ // to RESERVED mem and save it to LockBox.
+ //
+ ReadyToLockEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ ReadyToLockEventNotify,
+ NULL,
+ &Registration
+ );
+ ASSERT (ReadyToLockEvent != NULL);
+ } else {
+ //
+ // the entry point is invoked after reloading. following code only run in RESERVED mem
+ //
+ if (PcdGetBool(PcdUse1GPageTable)) {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ mPage1GSupport = TRUE;
+ }
+ }
+ }
+
+ BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);
+
+ BootScriptExecutorBuffer = 0xFFFFFFFF;
+ Pages = EFI_SIZE_TO_PAGES(BufferSize);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ Pages,
+ &BootScriptExecutorBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;
+ EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;
+
+ Status = SaveLockBox (
+ &gEfiBootScriptExecutorVariableGuid,
+ &BootScriptExecutorBuffer,
+ sizeof(BootScriptExecutorBuffer)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Additional step for BootScript integrity
+ // Save BootScriptExecutor context
+ //
+ Status = SaveLockBox (
+ &gEfiBootScriptExecutorContextGuid,
+ EfiBootScriptExecutorVariable,
+ sizeof(*EfiBootScriptExecutorVariable)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h
new file mode 100644
index 0000000000..75327569d7
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h
@@ -0,0 +1,96 @@
+/** @file
+ The header file for Boot Script Executer module.
+
+ This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory
+ in the entry point. The functionality is to interpret and restore the S3 boot script
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+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 _BOOT_SCRIPT_EXECUTOR_H_
+#define _BOOT_SCRIPT_EXECUTOR_H_
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/AcpiS3Context.h>
+#include <Guid/BootScriptExecutorVariable.h>
+#include <Guid/MemoryProfile.h>
+
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <IndustryStandard/Acpi.h>
+
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+/**
+ a ASM function to transfer control to OS.
+
+ @param S3WakingVector The S3 waking up vector saved in ACPI Facs table
+ @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer
+**/
+VOID
+AsmTransferControl (
+ IN UINT32 S3WakingVector,
+ IN UINT32 AcpiLowMemoryBase
+ );
+/**
+ a 32bit ASM function to transfer control to OS.
+
+ @param S3WakingVector The S3 waking up vector saved in ACPI Facs table
+ @param AcpiLowMemoryBase a buffer under 1M which could be used during the transfer
+**/
+VOID
+AsmTransferControl32 (
+ IN UINT32 S3WakingVector,
+ IN UINT32 AcpiLowMemoryBase
+ );
+/**
+ a 16bit ASM function to transfer control to OS.
+**/
+VOID
+AsmTransferControl16 (
+ VOID
+ );
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ );
+
+extern UINT32 AsmFixAddress16;
+extern UINT32 AsmJmpAddr32;
+extern BOOLEAN mPage1GSupport;
+extern UINT64 mAddressEncMask;
+
+#endif //_BOOT_SCRIPT_EXECUTOR_H_
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S
new file mode 100644
index 0000000000..e59fd048b0
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S
@@ -0,0 +1,130 @@
+## @file
+# This is the assembly code for transferring to control to OS S3 waking vector
+# for X64 platform
+#
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+ASM_GLOBAL ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ # rcx S3WakingVector :DWORD
+ # rdx AcpiLowMemoryBase :DWORD
+ lea _AsmTransferControl_al_0000(%rip), %eax
+ movq $0x2800000000, %r8
+ orq %r8, %rax
+ pushq %rax
+ shrd $20, %ecx, %ebx
+ andl $0x0f, %ecx
+ movw %cx, %bx
+ movl %ebx, jmp_addr(%rip)
+ lret
+_AsmTransferControl_al_0000:
+ .byte 0x0b8, 0x30, 0 # mov ax, 30h as selector
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+ movq %cr0, %rax
+ movq %cr4, %rbx
+ .byte 0x66
+ andl $0x7ffffffe, %eax
+ andb $0xdf, %bl
+ movq %rax, %cr0
+ .byte 0x66
+ movl $0x0c0000080, %ecx
+ rdmsr
+ andb $0xfe, %ah
+ wrmsr
+ movq %rbx, %cr4
+ .byte 0x0ea # jmp far jmp_addr
+jmp_addr:
+ .long 0
+
+ASM_GLOBAL ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+ # S3WakingVector :DWORD
+ # AcpiLowMemoryBase :DWORD
+ pushq %rbp
+ movl %esp,%ebp
+ .byte 0x8d, 0x05 # lea eax, AsmTransferControl16
+ASM_GLOBAL ASM_PFX(AsmFixAddress16)
+ASM_PFX(AsmFixAddress16):
+ .long 0
+ pushq $0x28 # CS
+ pushq %rax
+ lret
+
+ASM_GLOBAL ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+ .byte 0xb8,0x30,0 # mov ax, 30h as selector
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+ movw %ax,%ss
+ movq %cr0, %rax # Get control register 0
+ .byte 0x66
+ .byte 0x83,0xe0,0xfe # and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ .byte 0xf,0x22,0xc0 # mov cr0, eax ; Activate real mode
+ .byte 0xea # jmp far AsmJmpAddr32
+ASM_GLOBAL ASM_PFX(AsmJmpAddr32)
+ASM_PFX(AsmJmpAddr32):
+ .long 0
+
+ASM_GLOBAL ASM_PFX(PageFaultHandlerHook)
+ASM_PFX(PageFaultHandlerHook):
+ pushq %rax # save all volatile registers
+ pushq %rcx
+ pushq %rdx
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ # save volatile fp registers
+ addq $-0x68, %rsp
+ stmxcsr 0x60(%rsp)
+ movdqa %xmm0, 0x0(%rsp)
+ movdqa %xmm1, 0x10(%rsp)
+ movdqa %xmm2, 0x20(%rsp)
+ movdqa %xmm3, 0x30(%rsp)
+ movdqa %xmm4, 0x40(%rsp)
+ movdqa %xmm5, 0x50(%rsp)
+
+ addq $-0x20, %rsp
+ call ASM_PFX(PageFaultHandler)
+ addq $0x20, %rsp
+
+ # load volatile fp registers
+ ldmxcsr 0x60(%rsp)
+ movdqa 0x0(%rsp), %xmm0
+ movdqa 0x10(%rsp), %xmm1
+ movdqa 0x20(%rsp), %xmm2
+ movdqa 0x30(%rsp), %xmm3
+ movdqa 0x40(%rsp), %xmm4
+ movdqa 0x50(%rsp), %xmm5
+ addq $0x68, %rsp
+
+ testb %al, %al
+
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rdx
+ popq %rcx
+ popq %rax # restore all volatile registers
+ jnz L1
+ jmpq *ASM_PFX(mOriginalHandler)(%rip)
+L1:
+ addq $0x08, %rsp # skip error code for PF
+ iretq
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm
new file mode 100644
index 0000000000..4422f22fe7
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm
@@ -0,0 +1,135 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for X64 platform
+;
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+
+EXTERN mOriginalHandler:QWORD
+EXTERN PageFaultHandler:PROC
+
+ .code
+
+PUBLIC AsmFixAddress16
+PUBLIC AsmJmpAddr32
+
+AsmTransferControl PROC
+ ; rcx S3WakingVector :DWORD
+ ; rdx AcpiLowMemoryBase :DWORD
+ lea eax, @F
+ mov r8, 2800000000h
+ or rax, r8
+ push rax
+ shrd ebx, ecx, 20
+ and ecx, 0fh
+ mov bx, cx
+ mov [@jmp_addr], ebx
+ retf
+@@:
+ DB 0b8h, 30h, 0 ; mov ax, 30h as selector
+ mov ds, eax
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ss, eax
+ mov rax, cr0
+ mov rbx, cr4
+ DB 66h
+ and eax, ((NOT 080000001h) AND 0ffffffffh)
+ and bl, NOT (1 SHL 5)
+ mov cr0, rax
+ DB 66h
+ mov ecx, 0c0000080h
+ rdmsr
+ and ah, NOT 1
+ wrmsr
+ mov cr4, rbx
+ DB 0eah ; jmp far @jmp_addr
+@jmp_addr DD ?
+AsmTransferControl ENDP
+
+AsmTransferControl32 PROC
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push rbp
+ mov ebp, esp
+ DB 8dh, 05h ; lea eax, AsmTransferControl16
+AsmFixAddress16 DD ?
+ push 28h ; CS
+ push rax
+ retf
+AsmTransferControl32 ENDP
+
+AsmTransferControl16 PROC
+ DB 0b8h, 30h, 0 ; mov ax, 30h as selector
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov rax, cr0 ; Get control register 0
+ DB 66h
+ DB 83h, 0e0h, 0feh ; and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ DB 0fh, 22h, 0c0h ; mov cr0, eax ; Activate real mode
+ DB 0eah ; jmp far AsmJmpAddr32
+AsmJmpAddr32 DD ?
+AsmTransferControl16 ENDP
+
+PageFaultHandlerHook PROC
+ push rax ; save all volatile registers
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ ; save volatile fp registers
+ add rsp, -68h
+ stmxcsr [rsp + 60h]
+ movdqa [rsp + 0h], xmm0
+ movdqa [rsp + 10h], xmm1
+ movdqa [rsp + 20h], xmm2
+ movdqa [rsp + 30h], xmm3
+ movdqa [rsp + 40h], xmm4
+ movdqa [rsp + 50h], xmm5
+
+ add rsp, -20h
+ call PageFaultHandler
+ add rsp, 20h
+
+ ; load volatile fp registers
+ ldmxcsr [rsp + 60h]
+ movdqa xmm0, [rsp + 0h]
+ movdqa xmm1, [rsp + 10h]
+ movdqa xmm2, [rsp + 20h]
+ movdqa xmm3, [rsp + 30h]
+ movdqa xmm4, [rsp + 40h]
+ movdqa xmm5, [rsp + 50h]
+ add rsp, 68h
+
+ test al, al
+
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax ; restore all volatile registers
+ jnz @F
+ jmp mOriginalHandler
+@@:
+ add rsp, 08h ; skip error code for PF
+ iretq
+PageFaultHandlerHook ENDP
+
+ END
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
new file mode 100644
index 0000000000..403e4c05aa
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
@@ -0,0 +1,136 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for X64 platform
+;
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+
+extern ASM_PFX(mOriginalHandler)
+extern ASM_PFX(PageFaultHandler)
+
+ DEFAULT REL
+ SECTION .text
+
+global ASM_PFX(AsmFixAddress16)
+global ASM_PFX(AsmJmpAddr32)
+
+global ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ ; rcx S3WakingVector :DWORD
+ ; rdx AcpiLowMemoryBase :DWORD
+ lea eax, [.0]
+ mov r8, 0x2800000000
+ or rax, r8
+ push rax
+ shrd ebx, ecx, 20
+ and ecx, 0xf
+ mov bx, cx
+ mov [@jmp_addr + 1], ebx
+ retf
+BITS 16
+.0:
+ mov ax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov eax, cr0
+ mov ebx, cr4
+ and eax, ((~ 0x80000001) & 0xffffffff)
+ and bl, ~ (1 << 5)
+ mov cr0, eax
+ mov ecx, 0xc0000080
+ rdmsr
+ and ah, ~ 1
+ wrmsr
+ mov cr4, ebx
+@jmp_addr:
+ jmp 0x0:0x0
+
+global ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+BITS 32
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ DB 0x8d, 0x5 ; lea eax, AsmTransferControl16
+ASM_PFX(AsmFixAddress16): DD 0
+ push 0x28 ; CS
+ push eax
+ retf
+
+global ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+BITS 16
+ mov ax, 0x30
+o32 mov ds, eax
+o32 mov es, eax
+o32 mov fs, eax
+o32 mov gs, eax
+o32 mov ss, eax
+ mov eax, cr0 ; Get control register 0
+ and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ mov cr0, eax ; Activate real mode
+ DB 0xea ; jmp far AsmJmpAddr32
+ASM_PFX(AsmJmpAddr32): DD 0
+
+global ASM_PFX(PageFaultHandlerHook)
+ASM_PFX(PageFaultHandlerHook):
+BITS 64
+ push rax ; save all volatile registers
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ ; save volatile fp registers
+ add rsp, -0x68
+ stmxcsr [rsp + 0x60]
+ movdqa [rsp + 0x0], xmm0
+ movdqa [rsp + 0x10], xmm1
+ movdqa [rsp + 0x20], xmm2
+ movdqa [rsp + 0x30], xmm3
+ movdqa [rsp + 0x40], xmm4
+ movdqa [rsp + 0x50], xmm5
+
+ add rsp, -0x20
+ call ASM_PFX(PageFaultHandler)
+ add rsp, 0x20
+
+ ; load volatile fp registers
+ ldmxcsr [rsp + 0x60]
+ movdqa xmm0, [rsp + 0x0]
+ movdqa xmm1, [rsp + 0x10]
+ movdqa xmm2, [rsp + 0x20]
+ movdqa xmm3, [rsp + 0x30]
+ movdqa xmm4, [rsp + 0x40]
+ movdqa xmm5, [rsp + 0x50]
+ add rsp, 0x68
+
+ test al, al
+
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax ; restore all volatile registers
+ jnz .1
+ jmp qword [ASM_PFX(mOriginalHandler)]
+.1:
+ add rsp, 0x8 ; skip error code for PF
+ iretq
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
new file mode 100644
index 0000000000..70eecf5762
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
@@ -0,0 +1,267 @@
+/** @file
+ Set a IDT entry for debug purpose
+
+ Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+
+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 "ScriptExecute.h"
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+UINT64 mPhyMask;
+VOID *mOriginalHandler;
+UINTN mPageFaultBuffer;
+UINTN mPageFaultIndex = 0;
+//
+// Store the uplink information for each page being used.
+//
+UINT64 *mPageFaultUplink[EXTRA_PAGE_TABLE_PAGES];
+
+/**
+ Page fault handler.
+
+**/
+VOID
+EFIAPI
+PageFaultHandlerHook (
+ VOID
+ );
+
+/**
+ Hook IDT with our page fault handler so that the on-demand paging works on page fault.
+
+ @param IdtEntry a pointer to IDT entry
+
+**/
+VOID
+HookPageFaultHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+ UINTN PageFaultHandlerHookAddress;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
+ mPhyMask &= (1ull << 48) - SIZE_4KB;
+
+ //
+ // Set Page Fault entry to catch >4G access
+ //
+ PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
+ mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
+ IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+
+ if (mPage1GSupport) {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
+ }else {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
+ }
+ ZeroMem (mPageFaultUplink, sizeof (mPageFaultUplink));
+}
+
+/**
+ The function will check if current waking vector is long mode.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+ @retval TRUE Current context need long mode waking vector.
+ @retval FALSE Current context need not long mode waking vector.
+**/
+BOOLEAN
+IsLongModeWakingVector (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+ if ((Facs == NULL) ||
+ (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
+ // Something wrong with FACS
+ return FALSE;
+ }
+ if (Facs->XFirmwareWakingVector != 0) {
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
+ ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+ // Both BIOS and OS wants 64bit vector
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR *IdtDescriptor;
+ UINTN S3DebugBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Restore IDT for debug
+ //
+ IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
+ AsmWriteIdtr (IdtDescriptor);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ //
+ // Update IDT entry INT3 if the instruction is valid in it
+ //
+ S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
+ if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+ }
+ );
+
+ //
+ // If both BIOS and OS wants long mode waking vector,
+ // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,
+ // no need to hook page fault handler.
+ //
+ if (!IsLongModeWakingVector (AcpiS3Context)) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ HookPageFaultHandler (IdtEntry);
+ }
+}
+
+/**
+ Acquire page for page fault.
+
+ @param[in, out] Uplink Pointer to up page table entry.
+
+**/
+VOID
+AcquirePage (
+ IN OUT UINT64 *Uplink
+ )
+{
+ UINTN Address;
+
+ Address = mPageFaultBuffer + EFI_PAGES_TO_SIZE (mPageFaultIndex);
+ ZeroMem ((VOID *) Address, EFI_PAGES_TO_SIZE (1));
+
+ //
+ // Cut the previous uplink if it exists and wasn't overwritten.
+ //
+ if ((mPageFaultUplink[mPageFaultIndex] != NULL) &&
+ ((*mPageFaultUplink[mPageFaultIndex] & ~mAddressEncMask & mPhyMask) == Address)) {
+ *mPageFaultUplink[mPageFaultIndex] = 0;
+ }
+
+ //
+ // Link & Record the current uplink.
+ //
+ *Uplink = Address | mAddressEncMask | IA32_PG_P | IA32_PG_RW;
+ mPageFaultUplink[mPageFaultIndex] = Uplink;
+
+ mPageFaultIndex = (mPageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;
+}
+
+/**
+ The page fault handler that on-demand read >4G memory/MMIO.
+
+ @retval TRUE The page fault is correctly handled.
+ @retval FALSE The page fault is not handled and is passed through to original handler.
+
+**/
+BOOLEAN
+EFIAPI
+PageFaultHandler (
+ VOID
+ )
+{
+ UINT64 *PageTable;
+ UINT64 PFAddress;
+ UINTN PTIndex;
+
+ PFAddress = AsmReadCr2 ();
+ DEBUG ((DEBUG_INFO, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
+
+ if (PFAddress >= mPhyMask + SIZE_4KB) {
+ return FALSE;
+ }
+ PFAddress &= mPhyMask;
+
+ PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
+
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ // PML4E
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ // PDPTE
+ if (mPage1GSupport) {
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ } else {
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ // PD
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ }
+
+ return TRUE;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
new file mode 100644
index 0000000000..6f6ea073aa
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.c
@@ -0,0 +1,909 @@
+/** @file
+ This module install ACPI Firmware Performance Data Table (FPDT).
+
+ This module register report status code listener to collect performance data
+ for Firmware Basic Boot Performance Record and other boot performance records,
+ and install FPDT to ACPI table.
+
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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 <PiDxe.h>
+
+#include <Protocol/ReportStatusCodeHandler.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/LockBox.h>
+#include <Protocol/Variable.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/FirmwarePerformance.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/UefiLib.h>
+
+#define EXTENSION_RECORD_SIZE 0x10000
+#define SMM_BOOT_RECORD_COMM_SIZE OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE)
+
+EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+
+BOOLEAN mLockBoxReady = FALSE;
+EFI_EVENT mReadyToBootEvent;
+EFI_EVENT mLegacyBootEvent;
+EFI_EVENT mExitBootServicesEvent;
+UINTN mFirmwarePerformanceTableTemplateKey = 0;
+UINT32 mBootRecordSize = 0;
+UINT32 mBootRecordMaxSize = 0;
+UINT8 *mBootRecordBuffer = NULL;
+BOOLEAN mDxeCoreReportStatusCodeEnable = FALSE;
+
+BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;
+S3_PERFORMANCE_TABLE *mAcpiS3PerformanceTable = NULL;
+
+FIRMWARE_PERFORMANCE_TABLE mFirmwarePerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE,
+ sizeof (FIRMWARE_PERFORMANCE_TABLE),
+ EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION, // Revision
+ 0x00, // Checksum will be updated at runtime
+ //
+ // It is expected that these values will be updated at EntryPoint.
+ //
+ {0x00}, // OEM ID is a 6 bytes long field
+ 0x00, // OEM Table ID(8 bytes long)
+ 0x00, // OEM Revision
+ 0x00, // Creator ID
+ 0x00, // Creator Revision
+ },
+ //
+ // Firmware Basic Boot Performance Table Pointer Record.
+ //
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER , // Type
+ sizeof (EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER // Revision
+ },
+ 0, // Reserved
+ 0 // BootPerformanceTablePointer will be updated at runtime.
+ },
+ //
+ // S3 Performance Table Pointer Record.
+ //
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER // Revision
+ },
+ 0, // Reserved
+ 0 // S3PerformanceTablePointer will be updated at runtime.
+ }
+};
+
+BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
+ sizeof (BOOT_PERFORMANCE_TABLE)
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
+ },
+ 0, // Reserved
+ //
+ // These values will be updated at runtime.
+ //
+ 0, // ResetEnd
+ 0, // OsLoaderLoadImageStart
+ 0, // OsLoaderStartImageStart
+ 0, // ExitBootServicesEntry
+ 0 // ExitBootServicesExit
+ }
+};
+
+S3_PERFORMANCE_TABLE mS3PerformanceTableTemplate = {
+ {
+ EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE,
+ sizeof (S3_PERFORMANCE_TABLE)
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME // Revision
+ },
+ //
+ // These values will be updated by Firmware Performance PEIM.
+ //
+ 0, // ResumeCount
+ 0, // FullResume
+ 0 // AverageResume
+ },
+ {
+ {
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND, // Type
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD), // Length
+ EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND // Revision
+ },
+ //
+ // These values will be updated bye Firmware Performance SMM driver.
+ //
+ 0, // SuspendStart
+ 0 // SuspendEnd
+ }
+};
+
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param[in] Buffer Pointer to buffer to checksum
+ @param[in] Size Number of bytes to checksum
+
+**/
+VOID
+FpdtAcpiTableChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
+
+ //
+ // Set checksum to 0 first.
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value.
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
+}
+
+/**
+ Allocate EfiReservedMemoryType below 4G memory address.
+
+ This function allocates EfiReservedMemoryType below 4G memory address.
+
+ @param[in] Size Size of memory to allocate.
+
+ @return Allocated address for output.
+
+**/
+VOID *
+FpdtAllocateReservedMemoryBelow4G (
+ IN UINTN Size
+ )
+{
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ VOID *Buffer;
+
+ Buffer = NULL;
+ Pages = EFI_SIZE_TO_PAGES (Size);
+ Address = 0xffffffff;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ Pages,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ Buffer = (VOID *) (UINTN) Address;
+ ZeroMem (Buffer, Size);
+ }
+
+ return Buffer;
+}
+
+/**
+ Callback function upon VariableArchProtocol and LockBoxProtocol
+ to allocate S3 performance table memory and save the pointer to LockBox.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+FpdtAllocateS3PerformanceTableMemory (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ UINTN Size;
+ EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;
+
+ if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
+ //
+ // The memory for S3 performance table should have been ready,
+ // and the pointer should have been saved to LockBox, just return.
+ //
+ return;
+ }
+
+ if (!mLockBoxReady) {
+ Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // LockBox services has been ready.
+ //
+ mLockBoxReady = TRUE;
+ }
+ }
+
+ if (mAcpiS3PerformanceTable == NULL) {
+ Status = gBS->LocateProtocol (&gEfiVariableArchProtocolGuid, NULL, &Interface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to allocate the same runtime buffer as last time boot.
+ //
+ ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
+ Size = sizeof (PerformanceVariable);
+ Status = gRT->GetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &Size,
+ &PerformanceVariable
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)),
+ &PerformanceVariable.S3PerformanceTablePointer
+ );
+ if (!EFI_ERROR (Status)) {
+ mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.S3PerformanceTablePointer;
+ }
+ }
+ if (mAcpiS3PerformanceTable == NULL) {
+ //
+ // Fail to allocate at specified address, continue to allocate at any address.
+ //
+ mAcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (sizeof (S3_PERFORMANCE_TABLE));
+ }
+ DEBUG ((EFI_D_INFO, "FPDT: ACPI S3 Performance Table address = 0x%x\n", mAcpiS3PerformanceTable));
+ if (mAcpiS3PerformanceTable != NULL) {
+ CopyMem (mAcpiS3PerformanceTable, &mS3PerformanceTableTemplate, sizeof (mS3PerformanceTableTemplate));
+ }
+ }
+ }
+
+ if (mLockBoxReady && (mAcpiS3PerformanceTable != NULL)) {
+ //
+ // If LockBox services has been ready and memory for FPDT S3 performance table has been allocated,
+ // save the pointer to LockBox for use in S3 resume.
+ //
+ S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
+ Status = SaveLockBox (
+ &gFirmwarePerformanceS3PointerGuid,
+ &S3PerformanceTablePointer,
+ sizeof (EFI_PHYSICAL_ADDRESS)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Install ACPI Firmware Performance Data Table (FPDT).
+
+ @return Status code.
+
+**/
+EFI_STATUS
+InstallFirmwarePerformanceDataTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ UINTN Size;
+ UINT8 *SmmBootRecordCommBuffer;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
+ SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
+ UINTN CommSize;
+ UINTN BootPerformanceDataSize;
+ UINT8 *BootPerformanceData;
+ EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
+ FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
+ EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
+ UINTN Index;
+ VOID *SmmBootRecordData;
+ UINTN SmmBootRecordDataSize;
+ UINTN ReservedMemSize;
+
+ //
+ // Get AcpiTable Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Collect boot records from SMM drivers.
+ //
+ SmmBootRecordCommBuffer = NULL;
+ SmmCommData = NULL;
+ SmmBootRecordData = NULL;
+ SmmBootRecordDataSize = 0;
+ ReservedMemSize = 0;
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Initialize communicate buffer
+ // Get the prepared Reserved Memory Range
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &SmmCommRegionTable
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (SmmCommRegionTable != NULL);
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
+ for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) {
+ if (SmmCommMemRegion->Type == EfiConventionalMemory) {
+ break;
+ }
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
+ ASSERT (SmmCommMemRegion->PhysicalStart > 0);
+ ASSERT (SmmCommMemRegion->NumberOfPages > 0);
+ ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE;
+
+ //
+ // Check enough reserved memory space
+ //
+ if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {
+ SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart;
+ SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;
+ ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));
+
+ CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
+ SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);
+ CommSize = SMM_BOOT_RECORD_COMM_SIZE;
+
+ //
+ // Get the size of boot records.
+ //
+ SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
+ SmmCommData->BootRecordData = NULL;
+ Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {
+ //
+ // Get all boot records
+ //
+ SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET;
+ SmmBootRecordDataSize = SmmCommData->BootRecordSize;
+ SmmBootRecordData = AllocateZeroPool(SmmBootRecordDataSize);
+ ASSERT (SmmBootRecordData != NULL);
+ SmmCommData->BootRecordOffset = 0;
+ SmmCommData->BootRecordData = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
+ SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
+ while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) {
+ Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);
+ CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
+ SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Prepare memory for Boot Performance table.
+ // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
+ //
+ BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
+ if (SmmCommData != NULL) {
+ BootPerformanceDataSize += SmmBootRecordDataSize;
+ }
+
+ //
+ // Try to allocate the same runtime buffer as last time boot.
+ //
+ ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
+ Size = sizeof (PerformanceVariable);
+ Status = gRT->GetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ NULL,
+ &Size,
+ &PerformanceVariable
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
+ &PerformanceVariable.BootPerformanceTablePointer
+ );
+ if (!EFI_ERROR (Status)) {
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
+ }
+ }
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Fail to allocate at specified address, continue to allocate at any address.
+ //
+ mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);
+ }
+ DEBUG ((EFI_D_INFO, "FPDT: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ if (SmmCommData != NULL && SmmBootRecordData != NULL) {
+ FreePool (SmmBootRecordData);
+ }
+ if (mAcpiS3PerformanceTable != NULL) {
+ FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));
+ mAcpiS3PerformanceTable = NULL;
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Prepare Boot Performance Table.
+ //
+ BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;
+ //
+ // Fill Basic Boot record to Boot Performance Table.
+ //
+ CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
+ BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;
+ //
+ // Fill Boot records from boot drivers.
+ //
+ CopyMem (BootPerformanceData, mBootRecordBuffer, mBootRecordSize);
+ mAcpiBootPerformanceTable->Header.Length += mBootRecordSize;
+ BootPerformanceData = BootPerformanceData + mBootRecordSize;
+ if (SmmCommData != NULL && SmmBootRecordData != NULL) {
+ //
+ // Fill Boot records from SMM drivers.
+ //
+ CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize);
+ FreePool (SmmBootRecordData);
+ mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize);
+ BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize;
+ }
+
+ //
+ // Save Boot Performance Table address to Variable for use in S4 resume.
+ //
+ PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;
+ //
+ // Update Boot Performance Table Pointer in template.
+ //
+ mFirmwarePerformanceTableTemplate.BootPointerRecord.BootPerformanceTablePointer = (UINT64) (UINTN) mAcpiBootPerformanceTable;
+
+ //
+ // Save S3 Performance Table address to Variable for use in S4 resume.
+ //
+ PerformanceVariable.S3PerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiS3PerformanceTable;
+ //
+ // Update S3 Performance Table Pointer in template.
+ //
+ mFirmwarePerformanceTableTemplate.S3PointerRecord.S3PerformanceTablePointer = (UINT64) (UINTN) mAcpiS3PerformanceTable;
+ //
+ // Save Runtime Performance Table pointers to Variable.
+ // Don't check SetVariable return status. It doesn't impact FPDT table generation.
+ //
+ gRT->SetVariable (
+ EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
+ &gEfiFirmwarePerformanceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (PerformanceVariable),
+ &PerformanceVariable
+ );
+
+ //
+ // Publish Firmware Performance Data Table.
+ //
+ FpdtAcpiTableChecksum ((UINT8 *) &mFirmwarePerformanceTableTemplate, mFirmwarePerformanceTableTemplate.Header.Length);
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ &mFirmwarePerformanceTableTemplate,
+ mFirmwarePerformanceTableTemplate.Header.Length,
+ &mFirmwarePerformanceTableTemplateKey
+ );
+ if (EFI_ERROR (Status)) {
+ FreePages (mAcpiBootPerformanceTable, EFI_SIZE_TO_PAGES (BootPerformanceDataSize));
+ if (mAcpiS3PerformanceTable != NULL) {
+ FreePages (mAcpiS3PerformanceTable, EFI_SIZE_TO_PAGES (sizeof (S3_PERFORMANCE_TABLE)));
+ }
+ mAcpiBootPerformanceTable = NULL;
+ mAcpiS3PerformanceTable = NULL;
+ return Status;
+ }
+
+ //
+ // Free temp Boot record, and update Boot Record to point to Basic Boot performance table.
+ //
+ if (mBootRecordBuffer != NULL) {
+ FreePool (mBootRecordBuffer);
+ }
+ mBootRecordBuffer = (UINT8 *) mAcpiBootPerformanceTable;
+ mBootRecordSize = mAcpiBootPerformanceTable->Header.Length;
+ mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
+ install the Firmware Performance Data Table.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+FpdtReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // ACPI Firmware Performance Data Table not installed yet, install it now.
+ //
+ InstallFirmwarePerformanceDataTable ();
+ }
+}
+
+/**
+ Report status code listener of FPDT. This is used to collect performance data
+ for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT.
+
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerDxe (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Value == (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)) {
+ //
+ // DxeCore ReportStatusCode Enable so that the capability can be supported.
+ //
+ mDxeCoreReportStatusCodeEnable = TRUE;
+ }
+
+ Status = EFI_SUCCESS;
+ if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {
+ //
+ // Progress code for OS Loader LoadImage.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update OS Loader LoadImage Start for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) {
+ //
+ // Progress code for OS Loader StartImage.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update OS Loader StartImage Start for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {
+ //
+ // Unregister boot time report status code listener.
+ //
+ mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
+
+ //
+ // Progress code for ExitBootServices.
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Update ExitBootServicesExit for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ());
+ } else if (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)) {
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Firmware Performance Data Table not installed, do nothing.
+ //
+ return Status;
+ }
+
+ //
+ // Update Firmware Basic Boot Performance Record for legacy boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Dump FPDT Boot Performance record.
+ //
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = 0\n"));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = 0\n"));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesExit = 0\n"));
+ } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {
+ //
+ // Append one or more Boot records
+ //
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Append Boot records before FPDT ACPI table is installed.
+ //
+ if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {
+ mBootRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer);
+ ASSERT (mBootRecordBuffer != NULL);
+ mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE;
+ }
+ //
+ // Save boot record into the temp memory space.
+ //
+ CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);
+ mBootRecordSize += Data->Size;
+ } else {
+ //
+ // Append Boot records after FPDT ACPI table is installed.
+ //
+ if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {
+ //
+ // No enough space to save boot record.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // Save boot record into BootPerformance table
+ //
+ CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);
+ mBootRecordSize += Data->Size;
+ mAcpiBootPerformanceTable->Header.Length = mBootRecordSize;
+ }
+ }
+ } else {
+ //
+ // Ignore else progress code.
+ //
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+
+/**
+ Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record
+ performance data for ExitBootServicesEntry in FPDT.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+FpdtExitBootServicesEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (!mDxeCoreReportStatusCodeEnable) {
+ //
+ // When DxeCore Report Status Code is disabled,
+ // Unregister boot time report status code listener at ExitBootService Event.
+ //
+ mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe);
+ }
+
+ if (mAcpiBootPerformanceTable == NULL) {
+ //
+ // Firmware Performance Data Table not installed, do nothing.
+ //
+ return ;
+ }
+
+ //
+ // Update Firmware Basic Boot Performance Record for UEFI boot.
+ //
+ mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Dump FPDT Boot Performance record.
+ //
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart));
+ DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry));
+ //
+ // ExitBootServicesExit will be updated later, so don't dump it here.
+ //
+}
+
+/**
+ The module Entry Point of the Firmware Performance Data Table DXE driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwarePerformanceDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ FIRMWARE_SEC_PERFORMANCE *Performance;
+ VOID *Registration;
+ UINT64 OemTableId;
+
+ CopyMem (
+ mFirmwarePerformanceTableTemplate.Header.OemId,
+ PcdGetPtr (PcdAcpiDefaultOemId),
+ sizeof (mFirmwarePerformanceTableTemplate.Header.OemId)
+ );
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mFirmwarePerformanceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mFirmwarePerformanceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mFirmwarePerformanceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mFirmwarePerformanceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Get Report Status Code Handler Protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register report status code listener for OS Loader load and start.
+ //
+ Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerDxe, TPL_HIGH_LEVEL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the notify function to update FPDT on ExitBootServices Event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FpdtExitBootServicesEventNotify,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Create ready to boot event to install ACPI FPDT table.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FpdtReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve GUID HOB data that contains the ResetEnd.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiFirmwarePerformanceGuid);
+ if (GuidHob != NULL) {
+ Performance = (FIRMWARE_SEC_PERFORMANCE *) GET_GUID_HOB_DATA (GuidHob);
+ mBootPerformanceTableTemplate.BasicBoot.ResetEnd = Performance->ResetEnd;
+ } else {
+ //
+ // SEC Performance Data Hob not found, ResetEnd in ACPI FPDT table will be 0.
+ //
+ DEBUG ((EFI_D_ERROR, "FPDT: WARNING: SEC Performance Data Hob not found, ResetEnd will be set to 0!\n"));
+ }
+
+ if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {
+ //
+ // Register callback function upon VariableArchProtocol and LockBoxProtocol
+ // to allocate S3 performance table memory and save the pointer to LockBox.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiVariableArchProtocolGuid,
+ TPL_CALLBACK,
+ FpdtAllocateS3PerformanceTableMemory,
+ NULL,
+ &Registration
+ );
+ EfiCreateProtocolNotifyEvent (
+ &gEfiLockBoxProtocolGuid,
+ TPL_CALLBACK,
+ FpdtAllocateS3PerformanceTableMemory,
+ NULL,
+ &Registration
+ );
+ } else {
+ //
+ // Exclude S3 Performance Table Pointer from FPDT table template.
+ //
+ mFirmwarePerformanceTableTemplate.Header.Length -= sizeof (EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf
new file mode 100644
index 0000000000..49d8420ba4
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.inf
@@ -0,0 +1,92 @@
+## @file
+# This module installs ACPI Firmware Performance Data Table (FPDT).
+#
+# This module registers report status code listener to collect performance data
+# for Firmware Basic Boot Performance Record and other boot performance records,
+# and install FPDT to ACPI table.
+#
+# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+# 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 = FirmwarePerformanceDxe
+ MODULE_UNI_FILE = FirmwarePerformanceDxe.uni
+ FILE_GUID = 00160F8D-2B35-4df2-BBE0-B272A8D631F0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FirmwarePerformanceDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FirmwarePerformanceDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+ DebugLib
+ TimerLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PcdLib
+ HobLib
+ LockBoxLib
+ UefiLib
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+ gEfiRscHandlerProtocolGuid ## CONSUMES
+ gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEfiLockBoxProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+ gEfiEventLegacyBootGuid ## SOMETIMES_CONSUMES ## Event
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_CONSUMES ## Variable:L"FirmwarePerformance"
+ ## PRODUCES ## Variable:L"FirmwarePerformance"
+ ## SOMETIMES_CONSUMES ## UNDEFINED # Used to do smm communication
+ ## SOMETIMES_CONSUMES ## UNDEFINED # StatusCode Data
+ gEfiFirmwarePerformanceGuid
+ gFirmwarePerformanceS3PointerGuid ## PRODUCES ## UNDEFINED # SaveLockBox
+ gEdkiiPiSmmCommunicationRegionTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdExtFpdtBootRecordPadSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support ## CONSUMES
+
+[Depex]
+ gEfiRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformanceDxeExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni
new file mode 100644
index 0000000000..e35fa48e7d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxe.uni
@@ -0,0 +1,24 @@
+// /** @file
+// This module installs ACPI Firmware Performance Data Table (FPDT).
+//
+// This module registers report status code listener to collect performance data
+// for Firmware Basic Boot Performance Record and other boot performance records,
+// and install FPDT to ACPI table.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Installs ACPI Firmware Performance Data Table (FPDT)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module registers report status code listener to collect performance data for Firmware Basic Boot Performance Record and other boot performance records, and installs FPDT to the ACPI table."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni
new file mode 100644
index 0000000000..5a6d683a2e
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableDxe/FirmwarePerformanceDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// FirmwarePerformanceDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"ACPI Firmware Performance DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
new file mode 100644
index 0000000000..396462e7aa
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
@@ -0,0 +1,207 @@
+/** @file
+ This module updates S3 Resume Performance Record in ACPI Firmware Performance
+ Data Table in S3 resume boot mode. In normal boot mode, this module consumes
+ SecPerformance PPI produced by SEC phase and build Hob to convey the SEC
+ performance data to DXE phase.
+
+ This module register report status code listener to collect performance data
+ for S3 Resume Performance Record on S3 resume boot path.
+
+ Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+ 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 <PiPei.h>
+
+#include <Ppi/ReportStatusCodeHandler.h>
+#include <Ppi/SecPerformance.h>
+
+#include <Guid/FirmwarePerformance.h>
+
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+
+/**
+ Report status code listener for PEI. This is used to record the performance
+ data for S3 FullResume in FPDT.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerPei (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId,
+ IN CONST EFI_STATUS_CODE_DATA *Data
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentTime;
+ UINTN VarSize;
+ EFI_PHYSICAL_ADDRESS S3PerformanceTablePointer;
+ S3_PERFORMANCE_TABLE *AcpiS3PerformanceTable;
+ EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD *AcpiS3ResumeRecord;
+ UINT64 S3ResumeTotal;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD *AcpiS3SuspendRecord;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) ||
+ (Value != (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve current time as early as possible.
+ //
+ CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ //
+ // Update S3 Resume Performance Record.
+ //
+ S3PerformanceTablePointer = 0;
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = RestoreLockBox (&gFirmwarePerformanceS3PointerGuid, &S3PerformanceTablePointer, &VarSize);
+ ASSERT_EFI_ERROR (Status);
+
+ AcpiS3PerformanceTable = (S3_PERFORMANCE_TABLE *) (UINTN) S3PerformanceTablePointer;
+ ASSERT (AcpiS3PerformanceTable != NULL);
+ if (AcpiS3PerformanceTable->Header.Signature != EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE) {
+ DEBUG ((EFI_D_ERROR, "FPDT S3 performance data in ACPI memory get corrupted\n"));
+ return EFI_ABORTED;
+ }
+ AcpiS3ResumeRecord = &AcpiS3PerformanceTable->S3Resume;
+ AcpiS3ResumeRecord->FullResume = CurrentTime;
+ //
+ // Calculate average S3 resume time.
+ //
+ S3ResumeTotal = MultU64x32 (AcpiS3ResumeRecord->AverageResume, AcpiS3ResumeRecord->ResumeCount);
+ AcpiS3ResumeRecord->ResumeCount++;
+ AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);
+
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - ResumeCount = %d\n", AcpiS3ResumeRecord->ResumeCount));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - FullResume = %ld\n", AcpiS3ResumeRecord->FullResume));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Resume Performance - AverageResume = %ld\n", AcpiS3ResumeRecord->AverageResume));
+
+ //
+ // Update S3 Suspend Performance Record.
+ //
+ AcpiS3SuspendRecord = &AcpiS3PerformanceTable->S3Suspend;
+ VarSize = sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD);
+ ZeroMem (&S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD));
+ Status = RestoreLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ &S3SuspendRecord,
+ &VarSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ AcpiS3SuspendRecord->SuspendStart = S3SuspendRecord.SuspendStart;
+ AcpiS3SuspendRecord->SuspendEnd = S3SuspendRecord.SuspendEnd;
+
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendStart = %ld\n", AcpiS3SuspendRecord->SuspendStart));
+ DEBUG ((EFI_D_INFO, "FPDT: S3 Suspend Performance - SuspendEnd = %ld\n", AcpiS3SuspendRecord->SuspendEnd));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry for Firmware Performance Data Table PEIM.
+
+ This routine is to register report status code listener for FPDT.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Pointer to PEI Services table.
+
+ @retval EFI_SUCCESS Report status code listener is registered successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwarePerformancePeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RSC_HANDLER_PPI *RscHandler;
+ PEI_SEC_PERFORMANCE_PPI *SecPerf;
+ FIRMWARE_SEC_PERFORMANCE Performance;
+
+ if (FeaturePcdGet (PcdFirmwarePerformanceDataTableS3Support)) {
+ //
+ // S3 resume - register status code listener for OS wake vector.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiRscHandlerPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &RscHandler
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RscHandler->Register (FpdtStatusCodeListenerPei);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Normal boot - build Hob for SEC performance data.
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSecPerformancePpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SecPerf
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SecPerf->GetPerformance (PeiServices, SecPerf, &Performance);
+ }
+ if (!EFI_ERROR (Status)) {
+ BuildGuidDataHob (
+ &gEfiFirmwarePerformanceGuid,
+ &Performance,
+ sizeof (FIRMWARE_SEC_PERFORMANCE)
+ );
+ DEBUG ((EFI_D_INFO, "FPDT: SEC Performance Hob ResetEnd = %ld\n", Performance.ResetEnd));
+ } else {
+ //
+ // SEC performance PPI is not installed or fail to get performance data
+ // from SEC Performance PPI.
+ //
+ DEBUG ((EFI_D_ERROR, "FPDT: WARNING: SEC Performance PPI not installed or failed!\n"));
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf
new file mode 100644
index 0000000000..25049f8323
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.inf
@@ -0,0 +1,76 @@
+## @file
+# Firmware Performance Pei Module.
+#
+# In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table.
+# In normal boot mode, it consumes SecPerformance PPI produced by SEC phase
+# and build Hob to convey the SEC performance data to DXE phase.
+#
+# This module register report status code listener to collect performance data
+# for S3 Resume Performance Record on S3 resume boot path.
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+# 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 = FirmwarePerformancePei
+ MODULE_UNI_FILE = FirmwarePerformancePei.uni
+ FILE_GUID = ADF01BF6-47D6-495d-B95B-687777807214
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FirmwarePerformancePeiEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FirmwarePerformancePei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ BaseLib
+ DebugLib
+ HobLib
+ TimerLib
+ BaseMemoryLib
+ LockBoxLib
+ PcdLib
+
+[Ppis]
+ gEfiPeiRscHandlerPpiGuid ## CONSUMES
+ gPeiSecPerformancePpiGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # RestoreLockBox
+ ## SOMETIMES_PRODUCES ## HOB
+ ## SOMETIMES_CONSUMES ## Variable:L"FirmwarePerformance"
+ gEfiFirmwarePerformanceGuid
+ gFirmwarePerformanceS3PointerGuid ## SOMETIMES_CONSUMES ## UNDEFINED # RestoreLockBox
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support ## CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND gEfiPeiRscHandlerPpiGuid
+
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformancePeiExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni
new file mode 100644
index 0000000000..8e718c0c01
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Firmware Performance Pei Module.
+//
+// In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table.
+// In normal boot mode, it consumes SecPerformance PPI produced by SEC phase
+// and build Hob to convey the SEC performance data to DXE phase.
+//
+// This module register report status code listener to collect performance data
+// for S3 Resume Performance Record on S3 resume boot path.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Firmware Performance Pei Module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "In S3 resume boot mode, it updates S3 Resume Performance Record in ACPI Firmware Performance Data Table. In normal boot mode, it consumes SecPerformance PPI produced by SEC phase and builds a Hob to convey the SEC performance data to DXE phase. This module register report status code listener to collect performance data for S3 Resume Performance Record on S3 resume boot path."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni
new file mode 100644
index 0000000000..06029482cb
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePeiExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// FirmwarePerformancePei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Performance PEI Module"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c
new file mode 100644
index 0000000000..c750331374
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.c
@@ -0,0 +1,336 @@
+/** @file
+ This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+
+ This module registers report status code listener to collect performance data
+ for SMM driver boot records and S3 Suspend Performance Record.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FpdtSmiHandler() will receive untrusted input and do basic validation.
+
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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 <PiSmm.h>
+
+#include <Protocol/SmmReportStatusCodeHandler.h>
+
+#include <Guid/FirmwarePerformance.h>
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/SmmMemLib.h>
+
+#define EXTENSION_RECORD_SIZE 0x1000
+
+EFI_SMM_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+UINT64 mSuspendStartTime = 0;
+BOOLEAN mS3SuspendLockBoxSaved = FALSE;
+UINT32 mBootRecordSize = 0;
+UINT32 mBootRecordMaxSize = 0;
+UINT8 *mBootRecordBuffer = NULL;
+
+SPIN_LOCK mSmmFpdtLock;
+BOOLEAN mSmramIsOutOfResource = FALSE;
+
+/**
+ Report status code listener for SMM. This is used to record the performance
+ data for S3 Suspend Start and S3 Suspend End in FPDT.
+
+ @param[in] CodeType Indicates the type of status code being reported.
+ @param[in] Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param[in] Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param[in] CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param[in] Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code is what we expected.
+ @retval EFI_UNSUPPORTED Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtStatusCodeListenerSmm (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentTime;
+ EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord;
+ UINT8 *NewRecordBuffer;
+
+ //
+ // Check whether status code is what we are interested in.
+ //
+ if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Collect one or more Boot records in boot time
+ //
+ if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) {
+ AcquireSpinLock (&mSmmFpdtLock);
+
+ if (mBootRecordSize + Data->Size > mBootRecordMaxSize) {
+ //
+ // Try to allocate big SMRAM data to store Boot record.
+ //
+ if (mSmramIsOutOfResource) {
+ ReleaseSpinLock (&mSmmFpdtLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer);
+ if (NewRecordBuffer == NULL) {
+ ReleaseSpinLock (&mSmmFpdtLock);
+ mSmramIsOutOfResource = TRUE;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mBootRecordBuffer = NewRecordBuffer;
+ mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE;
+ }
+ //
+ // Save boot record into the temp memory space.
+ //
+ CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size);
+ mBootRecordSize += Data->Size;
+
+ ReleaseSpinLock (&mSmmFpdtLock);
+ return EFI_SUCCESS;
+ }
+
+ if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) &&
+ (Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve current time.
+ //
+ CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ());
+
+ if (Value == PcdGet32 (PcdProgressCodeS3SuspendStart)) {
+ //
+ // S3 Suspend started, record the performance data and return.
+ //
+ mSuspendStartTime = CurrentTime;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // We are going to S3 sleep, record S3 Suspend End performance data.
+ //
+ S3SuspendRecord.SuspendStart = mSuspendStartTime;
+ S3SuspendRecord.SuspendEnd = CurrentTime;
+
+ //
+ // Save S3 suspend performance data to lock box, it will be used by Firmware Performance PEIM.
+ //
+ if (!mS3SuspendLockBoxSaved) {
+ Status = SaveLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ &S3SuspendRecord,
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mS3SuspendLockBoxSaved = TRUE;
+ } else {
+ Status = UpdateLockBox (
+ &gEfiFirmwarePerformanceGuid,
+ 0,
+ &S3SuspendRecord,
+ sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for report SMM boot records.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+FpdtSmiHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
+ UINTN BootRecordOffset;
+ UINTN BootRecordSize;
+ VOID *BootRecordData;
+ UINTN TempCommBufferSize;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if(TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM communication data buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)CommBuffer;
+
+ Status = EFI_SUCCESS;
+
+ switch (SmmCommData->Function) {
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE :
+ SmmCommData->BootRecordSize = mBootRecordSize;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET :
+ BootRecordOffset = SmmCommData->BootRecordOffset;
+ BootRecordData = SmmCommData->BootRecordData;
+ BootRecordSize = SmmCommData->BootRecordSize;
+ if (BootRecordData == NULL || BootRecordOffset >= mBootRecordSize) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Sanity check
+ //
+ if (BootRecordSize > mBootRecordSize - BootRecordOffset) {
+ BootRecordSize = mBootRecordSize - BootRecordOffset;
+ }
+ SmmCommData->BootRecordSize = BootRecordSize;
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {
+ DEBUG ((EFI_D_ERROR, "FpdtSmiHandler: SMM Data buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ CopyMem (
+ (UINT8*)BootRecordData,
+ mBootRecordBuffer + BootRecordOffset,
+ BootRecordSize
+ );
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+ SmmCommData->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The module Entry Point of the Firmware Performance Data Table SMM driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwarePerformanceSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mSmmFpdtLock);
+
+ //
+ // Get SMM Report Status Code Handler Protocol.
+ //
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmRscHandlerProtocolGuid,
+ NULL,
+ (VOID **) &mRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register report status code listener for BootRecords and S3 Suspend Start and End.
+ //
+ Status = mRscHandlerProtocol->Register (FpdtStatusCodeListenerSmm);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMI handler.
+ //
+ Handle = NULL;
+ Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf
new file mode 100644
index 0000000000..724e7bcd1d
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.inf
@@ -0,0 +1,72 @@
+## @file
+# This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+#
+# This module registers report status code listener to collect performance data
+# for SMM boot performance records and S3 Suspend Performance Record.
+#
+# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+# 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 = FirmwarePerformanceSmm
+ MODULE_UNI_FILE = FirmwarePerformanceSmm.uni
+ FILE_GUID = 044310AB-77FD-402a-AF1A-87D4120E7329
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = FirmwarePerformanceSmmEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FirmwarePerformanceSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ BaseLib
+ DebugLib
+ TimerLib
+ LockBoxLib
+ PcdLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ SynchronizationLib
+ SmmMemLib
+
+[Protocols]
+ gEfiSmmRscHandlerProtocolGuid ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## UNDEFINED # SaveLockBox
+ ## PRODUCES ## UNDEFINED # SmiHandlerRegister
+ ## SOMETIMES_CONSUMES ## UNDEFINED # StatusCode Data
+ gEfiFirmwarePerformanceGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd ## CONSUMES
+
+[Depex]
+ gEfiSmmRscHandlerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FirmwarePerformanceSmmExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni
new file mode 100644
index 0000000000..94f3b8e0fd
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmm.uni
@@ -0,0 +1,23 @@
+// /** @file
+// This module collects performance data for SMM driver boot records and S3 Suspend Performance Record.
+//
+// This module registers report status code listener to collect performance data
+// for SMM boot performance records and S3 Suspend Performance Record.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Collects performance data for SMM driver boot records and S3 Suspend Performance Record"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module registers report status code listener to collect performance data for SMM boot performance records and S3 Suspend Performance Record."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni
new file mode 100644
index 0000000000..d96e87f04f
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTableSmm/FirmwarePerformanceSmmExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// FirmwarePerformanceSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM Firmware Performance Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
new file mode 100644
index 0000000000..3c05558b23
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
@@ -0,0 +1,532 @@
+/** @file
+ This is the implementation to save ACPI S3 Context.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+
+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 <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Guid/AcpiS3Context.h>
+#include <Guid/Acpi.h>
+#include <IndustryStandard/Acpi.h>
+#include <Protocol/LockBox.h>
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+EFI_GUID mAcpiS3IdtrProfileGuid = {
+ 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
+};
+
+/**
+ Allocate memory below 4G memory address.
+
+ This function allocates memory below 4G memory address.
+
+ @param MemoryType Memory type of memory to allocate.
+ @param Size Size of memory to allocate.
+
+ @return Allocated address for output.
+
+**/
+VOID*
+AllocateMemoryBelow4G (
+ IN EFI_MEMORY_TYPE MemoryType,
+ 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,
+ MemoryType,
+ Pages,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Buffer = (VOID *) (UINTN) Address;
+ ZeroMem (Buffer, Size);
+
+ return Buffer;
+}
+
+/**
+
+ This function scan ACPI table in RSDT.
+
+ @param Rsdt ACPI RSDT
+ @param Signature ACPI table signature
+
+ @return ACPI table
+
+**/
+VOID *
+ScanTableInRSDT (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
+ IN UINT32 Signature
+ )
+{
+ UINTN Index;
+ UINT32 EntryCount;
+ UINT32 *EntryPtr;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+
+ if (Rsdt == NULL) {
+ return NULL;
+ }
+
+ EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
+
+ EntryPtr = (UINT32 *)(Rsdt + 1);
+ for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
+ Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
+ if (Table->Signature == Signature) {
+ return Table;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ This function scan ACPI table in XSDT.
+
+ @param Xsdt ACPI XSDT
+ @param Signature ACPI table signature
+
+ @return ACPI table
+
+**/
+VOID *
+ScanTableInXSDT (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
+ IN UINT32 Signature
+ )
+{
+ UINTN Index;
+ UINT32 EntryCount;
+ UINT64 EntryPtr;
+ UINTN BasePtr;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+
+ if (Xsdt == NULL) {
+ return NULL;
+ }
+
+ EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
+
+ BasePtr = (UINTN)(Xsdt + 1);
+ for (Index = 0; Index < EntryCount; Index ++) {
+ CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
+ Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
+ if (Table->Signature == Signature) {
+ return Table;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ To find Facs in FADT.
+
+ @param Fadt FADT table pointer
+
+ @return Facs table pointer.
+**/
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
+FindAcpiFacsFromFadt (
+ IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt
+ )
+{
+ EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ UINT64 Data64;
+
+ if (Fadt == NULL) {
+ return NULL;
+ }
+
+ if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
+ } else {
+ if (Fadt->FirmwareCtrl != 0) {
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
+ } else {
+ CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
+ }
+ }
+ 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.
+
+ @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_DESCRIPTION_HEADER *Xsdt;
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
+ EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ UINTN Index;
+
+ Rsdp = 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;
+ }
+
+ //
+ // Search XSDT
+ //
+ if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
+ Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
+ Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ if (Fadt != NULL) {
+ Facs = FindAcpiFacsFromFadt (Fadt);
+ if (Facs != NULL) {
+ return Facs;
+ }
+ }
+ }
+
+ //
+ // Search RSDT
+ //
+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
+ Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ if (Fadt != NULL) {
+ Facs = FindAcpiFacsFromFadt (Fadt);
+ if (Facs != NULL) {
+ return Facs;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ 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);
+}
+
+/**
+ The function will check if long mode waking vector is supported.
+
+ @param[in] Facs Pointer to FACS table.
+
+ @retval TRUE Long mode waking vector is supported.
+ @retval FALSE Long mode waking vector is not supported.
+
+**/
+BOOLEAN
+IsLongModeWakingVectorSupport (
+ IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs
+ )
+{
+ if ((Facs == NULL) ||
+ (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ) {
+ //
+ // Something wrong with FACS.
+ //
+ return FALSE;
+ }
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0)) {
+ //
+ // BIOS supports 64bit waking vector.
+ //
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Allocates page table buffer.
+
+ @param[in] LongModeWakingVectorSupport Support long mode waking vector or not.
+
+ If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
+ virtual to physical mapping page table when long mode waking vector is supported, otherwise
+ create 4G page table when long mode waking vector is not supported and let PF handler to
+ handle > 4G request.
+ If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
+
+ @return Page table base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+S3AllocatePageTablesBuffer (
+ IN BOOLEAN LongModeWakingVectorSupport
+ )
+{
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ UINTN ExtraPageTablePages;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINT8 PhysicalAddressBits;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
+ UINTN TotalPageTableSize;
+ VOID *Hob;
+ BOOLEAN Page1GSupport;
+
+ Page1GSupport = FALSE;
+ if (PcdGetBool(PcdUse1GPageTable)) {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ Page1GSupport = TRUE;
+ }
+ }
+ }
+
+ //
+ // Get physical address bits supported.
+ //
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ } else {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ }
+
+ //
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+ //
+ ASSERT (PhysicalAddressBits <= 52);
+ if (PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
+ }
+
+ ExtraPageTablePages = 0;
+ if (!LongModeWakingVectorSupport) {
+ //
+ // Create 4G page table when BIOS does not support long mode waking vector,
+ // and let PF handler to handle > 4G request.
+ //
+ PhysicalAddressBits = 32;
+ ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
+ }
+
+ //
+ // Calculate the table entries needed.
+ //
+ if (PhysicalAddressBits <= 39 ) {
+ NumberOfPml4EntriesNeeded = 1;
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
+ } else {
+ NumberOfPml4EntriesNeeded = (UINT32)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.
+ //
+ if (!Page1GSupport) {
+ TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded;
+ } else {
+ TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded;
+ }
+
+ TotalPageTableSize += ExtraPageTablePages;
+ DEBUG ((DEBUG_INFO, "AcpiS3ContextSave TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));
+
+ //
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+ //
+ S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
+ ASSERT (S3NvsPageTableAddress != 0);
+ return S3NvsPageTableAddress;
+ } else {
+ //
+ // If DXE is running 32-bit mode, no need to establish page table.
+ //
+ return (EFI_PHYSICAL_ADDRESS) 0;
+ }
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+AcpiS3ContextSaveOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
+ ACPI_S3_CONTEXT *AcpiS3Context;
+ IA32_DESCRIPTOR *Idtr;
+ IA32_IDT_GATE_DESCRIPTOR *IdtGate;
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ VOID *Interface;
+
+ DEBUG ((EFI_D_INFO, "AcpiS3ContextSave!\n"));
+
+ Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO | EFI_D_WARN, "ACPI S3 context can't be saved without LockBox!\n"));
+ goto Done;
+ }
+
+ AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
+ ASSERT (AcpiS3Context != NULL);
+ AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
+
+ //
+ // Get ACPI Table because we will save its position to variable
+ //
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) FindAcpiFacsTable ();
+ AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS) (UINTN) Facs;
+ ASSERT (AcpiS3Context->AcpiFacsTable != 0);
+
+ IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, 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 = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));
+
+ //
+ // Allocate stack
+ //
+ AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
+ AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
+ ASSERT (AcpiS3Context->BootScriptStackBase != 0);
+
+ //
+ // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
+ //
+ AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
+ SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
+
+ 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));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));
+
+ 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);
+
+Done:
+ //
+ // Close the event, deregistering the callback and freeing resources.
+ //
+ Status = gBS->CloseEvent (Event);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h
new file mode 100644
index 0000000000..2cc638abbc
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/InternalS3SaveState.h
@@ -0,0 +1,178 @@
+/** @file
+ Internal header file for S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ 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 _INTERNAL_S3_SAVE_STATE_H_
+#define _INTERNAL_S3_SAVE_STATE_H_
+#include <PiDxe.h>
+
+#include <Protocol/S3SaveState.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/SmBus.h>
+#include <Guid/EventGroup.h>
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+AcpiS3ContextSaveOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINT16 OpCode,
+ ...
+ );
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINT16 OpCode,
+ ...
+ );
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ );
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ );
+
+#endif //_INTERNAL_S3_SAVE_STATE_H_
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c
new file mode 100644
index 0000000000..efc0ef9140
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveState.c
@@ -0,0 +1,935 @@
+/** @file
+ Implementation for S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ 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 "InternalS3SaveState.h"
+
+EFI_HANDLE mHandle = NULL;
+EFI_S3_SAVE_STATE_PROTOCOL mS3SaveState = {
+ BootScriptWrite,
+ BootScriptInsert,
+ BootScriptLabel,
+ BootScriptCompare
+ };
+/**
+ Internal function to add IO write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoWrite (Width, Address, Count, Buffer);
+}
+/**
+ Internal function to add IO read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add memory write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to add memory read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add PciCfg write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgReadWrite (Width, Address, Data, DataMask);
+}
+/**
+ Internal function to add PciCfg2 write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2Write (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+ UINT16 Segment;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+ Segment = VA_ARG (Marker, UINT16);
+
+ return S3BootScriptSavePciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg2 read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2ReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Segment = VA_ARG (Marker, UINT16);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2ReadWrite (Width, Segment, Address, Data, DataMask);
+}
+/**
+ Internal function to add smbus execute opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteSmbusExecute (
+ IN VA_LIST Marker
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ EFI_SMBUS_OPERATION Operation;
+ BOOLEAN PecCheck;
+ VOID *Buffer;
+ UINTN *DataSize;
+ UINTN SmBusAddress;
+
+ SlaveAddress.SmbusDeviceAddress = VA_ARG (Marker, UINTN);
+ Command = VA_ARG (Marker, EFI_SMBUS_DEVICE_COMMAND);
+ Operation = VA_ARG (Marker, EFI_SMBUS_OPERATION);
+ PecCheck = VA_ARG (Marker, BOOLEAN);
+ SmBusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress,Command,0,PecCheck);
+ DataSize = VA_ARG (Marker, UINTN *);
+ Buffer = VA_ARG (Marker, VOID *);
+
+ return S3BootScriptSaveSmbusExecute (SmBusAddress, Operation, DataSize, Buffer);
+}
+/**
+ Internal function to add stall opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteStall (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 Duration;
+
+ Duration = VA_ARG (Marker, UINT32);
+
+ return S3BootScriptSaveStall (Duration);
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE.
+ We ignore "Context" parameter
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveDispatch (EntryPoint);
+}
+
+/**
+ Internal function to add memory pool operation to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+ UINT64 LoopTimes;
+ UINT32 Remainder;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = VA_ARG (Marker, UINT64);
+ //
+ // According to the spec, the interval between 2 polls is 100ns,
+ // but the unit of Duration for S3BootScriptSaveMemPoll() is microsecond(1000ns).
+ // Duration * 1000ns * LoopTimes = Delay * 100ns
+ // Duration will be minimum 1(microsecond) to be minimum deviation,
+ // so LoopTimes = Delay / 10.
+ //
+ LoopTimes = DivU64x32Remainder (
+ Delay,
+ 10,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, LoopTimes will be rounded up by 1.
+ //
+ LoopTimes +=1;
+ }
+ return S3BootScriptSaveMemPoll (Width, Address, DataMask, Data, 1, LoopTimes);
+
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE2.
+ The "Context" parameter is not ignored.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch2 (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+ VOID *Context;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ Context = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+
+ return S3BootScriptSaveDispatch2 (EntryPoint, Context);
+}
+/**
+ Internal function to add INFORAMTION opcode node to the table
+ list.
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteInformation (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 InformationLength;
+ EFI_PHYSICAL_ADDRESS Information;
+
+ InformationLength = VA_ARG (Marker, UINT32);
+ Information = VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveInformation (InformationLength, (VOID*)(UINTN)Information);
+}
+/**
+ Internal function to add IO poll opcode node to the table
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteIoPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSaveIoPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfigPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePciPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config 2 poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfig2Poll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePci2Poll (Width, Segment, Address, Data, DataMask, Delay);
+}
+
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINT16 OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINT16 OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
+ }
+ return Status;
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Label is NULL or points to an empty string.
+ @retval EFI_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ return S3BootScriptLabel (BeforeOrAfter, CreateIfNotFound, Position, Label);
+}
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+ @retval EFI_INVALID_PARAMETER The RelativePosition is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ return S3BootScriptCompare (Position1, Position2, RelativePosition);
+}
+/**
+ This routine is entry point of ScriptSave driver.
+
+ @param ImageHandle Handle for this drivers loaded image protocol.
+ @param SystemTable EFI system table.
+
+ @retval EFI_OUT_OF_RESOURCES No enough resource
+ @retval EFI_SUCCESS Succesfully installed the ScriptSave driver.
+ @retval other Errors occured.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeS3SaveState (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT EndOfDxeEvent;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ AcpiS3ContextSaveOnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return gBS->InstallProtocolInterface (
+ &mHandle,
+ &gEfiS3SaveStateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mS3SaveState
+ );
+
+}
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
new file mode 100644
index 0000000000..05e98f40cd
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# S3 Boot Script Save State driver.
+#
+# It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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 = S3SaveStateDxe
+ MODULE_UNI_FILE = S3SaveStateDxe.uni
+ FILE_GUID = BDCE85BB-FBAA-4f4e-9264-501A2C249581
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeS3SaveState
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ S3SaveState.c
+ InternalS3SaveState.h
+ AcpiS3ContextSave.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ BaseLib
+ S3BootScriptLib
+ PcdLib
+ HobLib
+ LockBoxLib
+
+[Guids]
+ gEfiAcpiVariableGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiAcpiS3ContextGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiS3SaveStateProtocolGuid ## PRODUCES
+ gEfiLockBoxProtocolGuid ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ S3SaveStateDxeExtra.uni \ No newline at end of file
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni
new file mode 100644
index 0000000000..312803e69c
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// S3 Boot Script Save State driver.
+//
+// It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "S3 Boot Script Save State driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It will install S3 Save State protocol to store or record various IO operations to be replayed during an S3 resume."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni
new file mode 100644
index 0000000000..c648ff8ae7
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// S3SaveStateDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"S3 Save State DXE Driver"
+
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h
new file mode 100644
index 0000000000..d6263fd727
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/InternalSmmSaveState.h
@@ -0,0 +1,161 @@
+/** @file
+ Internal header file for SMM S3 Boot Script Saver state driver.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ 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 _INTERNAL_SMM_S3_SAVE_STATE_H_
+#define _INTERNAL_SMM_S3_SAVE_STATE_H_
+#include <PiDxe.h>
+
+#include <Protocol/S3SmmSaveState.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmbusLib.h>
+#include <IndustryStandard/SmBus.h>
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINT16 OpCode,
+ ...
+ );
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINT16 OpCode,
+ ...
+ );
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ );
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ );
+
+#endif //_INTERNAL_SMM_S3_SAVE_STATE_H_
diff --git a/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c
new file mode 100644
index 0000000000..0d1580dc35
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.c
@@ -0,0 +1,920 @@
+/** @file
+ Implementation for S3 SMM Boot Script Saver state driver.
+
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ 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 "InternalSmmSaveState.h"
+
+EFI_S3_SMM_SAVE_STATE_PROTOCOL mS3SmmSaveState = {
+ BootScriptWrite,
+ BootScriptInsert,
+ BootScriptLabel,
+ BootScriptCompare
+ };
+/**
+ Internal function to add IO write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoWrite (Width, Address, Count, Buffer);
+}
+/**
+ Internal function to add IO read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteIoReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveIoReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add memory write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to add memory read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSaveMemReadWrite (Width, Address, Data, DataMask);
+}
+
+/**
+ Internal function to add PciCfg write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgWrite (Width, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfgReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfgReadWrite (Width, Address, Data, DataMask);
+}
+/**
+ Internal function to add PciCfg2 write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2Write (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ UINT8 *Buffer;
+ UINT16 Segment;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Count = VA_ARG (Marker, UINTN);
+ Buffer = VA_ARG (Marker, UINT8 *);
+ Segment = VA_ARG (Marker, UINT16);
+
+ return S3BootScriptSavePciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+/**
+ Internal function to PciCfg2 read/write opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWritePciCfg2ReadWrite (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINT8 *Data;
+ UINT8 *DataMask;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Segment = VA_ARG (Marker, UINT16);
+ Data = VA_ARG (Marker, UINT8 *);
+ DataMask = VA_ARG (Marker, UINT8 *);
+
+ return S3BootScriptSavePciCfg2ReadWrite (Width, Segment, Address, Data, DataMask);
+}
+/**
+ Internal function to add smbus execute opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteSmbusExecute (
+ IN VA_LIST Marker
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ EFI_SMBUS_OPERATION Operation;
+ BOOLEAN PecCheck;
+ VOID *Buffer;
+ UINTN *DataSize;
+ UINTN SmBusAddress;
+
+ SlaveAddress.SmbusDeviceAddress = VA_ARG (Marker, UINTN);
+ Command = VA_ARG (Marker, EFI_SMBUS_DEVICE_COMMAND);
+ Operation = VA_ARG (Marker, EFI_SMBUS_OPERATION);
+ PecCheck = VA_ARG (Marker, BOOLEAN);
+ SmBusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress,Command,0,PecCheck);
+ DataSize = VA_ARG (Marker, UINTN *);
+ Buffer = VA_ARG (Marker, VOID *);
+
+ return S3BootScriptSaveSmbusExecute (SmBusAddress, Operation, DataSize, Buffer);
+}
+/**
+ Internal function to add stall opcode to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteStall (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 Duration;
+
+ Duration = VA_ARG (Marker, UINT32);
+
+ return S3BootScriptSaveStall (Duration);
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE.
+ We ignore "Context" parameter
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveDispatch (EntryPoint);
+}
+
+/**
+ Internal function to add memory pool operation to the table.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteMemPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+ UINT64 LoopTimes;
+ UINT32 Remainder;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = VA_ARG (Marker, UINT64);
+ //
+ // According to the spec, the interval between 2 polls is 100ns,
+ // but the unit of Duration for S3BootScriptSaveMemPoll() is microsecond(1000ns).
+ // Duration * 1000ns * LoopTimes = Delay * 100ns
+ // Duration will be minimum 1(microsecond) to be minimum deviation,
+ // so LoopTimes = Delay / 10.
+ //
+ LoopTimes = DivU64x32Remainder (
+ Delay,
+ 10,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, LoopTimes will be rounded up by 1.
+ //
+ LoopTimes +=1;
+ }
+ return S3BootScriptSaveMemPoll (Width, Address, DataMask, Data, 1, LoopTimes);
+
+}
+
+/**
+ Internal function to add Save jmp address according to DISPATCH_OPCODE2.
+ The "Context" parameter is not ignored.
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to do operation.
+ @retval EFI_SUCCESS Opcode is added.
+
+**/
+EFI_STATUS
+BootScriptWriteDispatch2 (
+ IN VA_LIST Marker
+ )
+{
+ VOID *EntryPoint;
+ VOID *Context;
+
+ EntryPoint = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ Context = (VOID*)(UINTN)VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+
+ return S3BootScriptSaveDispatch2 (EntryPoint, Context);
+}
+/**
+ Internal function to add INFORAMTION opcode node to the table
+ list.
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteInformation (
+ IN VA_LIST Marker
+ )
+{
+ UINT32 InformationLength;
+ EFI_PHYSICAL_ADDRESS Information;
+
+ InformationLength = VA_ARG (Marker, UINT32);
+ Information = VA_ARG (Marker, EFI_PHYSICAL_ADDRESS);
+ return S3BootScriptSaveInformation (InformationLength, (VOID*)(UINTN)Information);
+}
+/**
+ Internal function to add IO poll opcode node to the table
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWriteIoPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSaveIoPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfigPoll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePciPoll (Width, Address, Data, DataMask, Delay);
+}
+/**
+ Internal function to add PCI config 2 poll opcode node to the table
+
+ @param Marker The variable argument list to get the opcode
+ and associated attributes.
+
+ @retval EFI_OUT_OF_RESOURCES Not enought resource to complete the operations.
+ @retval EFI_SUCCESS The opcode entry is added to the table
+ successfully.
+**/
+EFI_STATUS
+BootScriptWritePciConfig2Poll (
+ IN VA_LIST Marker
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ VOID *Data;
+ VOID *DataMask;
+ UINT64 Delay;
+
+ Width = VA_ARG (Marker, S3_BOOT_SCRIPT_LIB_WIDTH);
+ Segment = VA_ARG (Marker, UINT16);
+ Address = VA_ARG (Marker, UINT64);
+ Data = VA_ARG (Marker, VOID *);
+ DataMask = VA_ARG (Marker, VOID *);
+ Delay = (UINT64)VA_ARG (Marker, UINT64);
+
+ return S3BootScriptSavePci2Poll (Width, Segment, Address, Data, DataMask, Delay);
+}
+
+/**
+ Adds a record into S3 boot script table.
+
+ This function is used to store a boot script record into a given boot
+ script table. If the table specified by TableName is nonexistent in the
+ system, a new table will automatically be created and then the script record
+ will be added into the new table. This function is responsible for allocating
+ necessary memory for the script.
+
+ This function has a variable parameter list. The exact parameter list depends on
+ the OpCode that is passed into the function. If an unsupported OpCode or illegal
+ parameter list is passed in, this function returns EFI_INVALID_PARAMETER.
+ If there are not enough resources available for storing more scripts, this function returns
+ EFI_OUT_OF_RESOURCES.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptWrite (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN UINT16 OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+/**
+ Insert a record into a specified Framework boot script table.
+
+ This function is used to store an OpCode to be replayed as part of the S3 resume boot path. It is
+ assumed this protocol has platform specific mechanism to store the OpCode set and replay them
+ during the S3 resume.
+ The opcode is inserted before or after the specified position in the boot script table. If Position is
+ NULL then that position is after the last opcode in the table (BeforeOrAfter is FALSE) or before
+ the first opcode in the table (BeforeOrAfter is TRUE). The position which is pointed to by
+ Position upon return can be used for subsequent insertions.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param OpCode The operation code (opcode) number.
+ @param ... Argument list that is specific to each opcode.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The Opcode is an invalid opcode value or the Position is not a valid position in the boot script table..
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptInsert (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN UINT16 OpCode,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ //
+ // Build script according to opcode
+ //
+ switch (OpCode) {
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfgReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteSmbusExecute (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteStall (Marker);
+ VA_END (Marker);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteDispatch2 (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteInformation (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteMemPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2Write (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciCfg2ReadWrite (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWriteIoPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfigPoll (Marker);
+ VA_END (Marker);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ VA_START (Marker, OpCode);
+ Status = BootScriptWritePciConfig2Poll (Marker);
+ VA_END (Marker);
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
+ }
+ return Status;
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ If the label Label is already exists in the boot script table, then no new label is created, the
+ position of the Label is returned in *Position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is TRUE, then it will be
+ created before or after the specified position and EFI_SUCCESS is returned.
+ If the label Label does not already exist and CreateIfNotFound is FALSE, then
+ EFI_NOT_FOUND is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param BeforeOrAfter Specifies whether the label is stored before (TRUE) or after (FALSE) the position in
+ the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new label is inserted at the beginning of the table (if TRUE) or end of
+ the table (if FALSE).
+ @param CreateIfNotFound Specifies whether the label will be created if the label does not exists (TRUE) or not
+ (FALSE).
+ @param Position On entry, specifies the position in the boot script table where the label will be inserted,
+ either before or after, depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted label in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The label already exists or was inserted.
+ @retval EFI_INVALID_PARAMETER The Label is NULL or points to an empty string.
+ @retval EFI_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptLabel (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT EFI_S3_BOOT_SCRIPT_POSITION *Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ return S3BootScriptLabel (BeforeOrAfter, CreateIfNotFound, Position, Label);
+}
+/**
+ Compare two positions in the boot script table and return their relative position.
+
+ This function compares two positions in the boot script table and returns their relative positions. If
+ Position1 is before Position2, then -1 is returned. If Position1 is equal to Position2,
+ then 0 is returned. If Position1 is after Position2, then 1 is returned.
+
+ @param This A pointer to the EFI_S3_SAVE_STATE_PROTOCOL instance.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval EFI_INVALID_PARAMETER The Position1 or Position2 is not a valid position in the boot script table.
+ @retval EFI_INVALID_PARAMETER The RelativePosition is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BootScriptCompare (
+ IN CONST EFI_S3_SAVE_STATE_PROTOCOL *This,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position1,
+ IN EFI_S3_BOOT_SCRIPT_POSITION Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ return S3BootScriptCompare (Position1, Position2, RelativePosition);
+}
+/**
+ This routine is entry point of ScriptSave driver.
+
+ @param ImageHandle Handle for this drivers loaded image protocol.
+ @param SystemTable EFI system table.
+
+ @retval EFI_OUT_OF_RESOURCES No enough resource
+ @retval EFI_SUCCESS Succesfully installed the ScriptSave driver.
+ @retval other Errors occured.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSmmS3SaveState (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE Handle;
+
+ if (!PcdGetBool (PcdAcpiS3Enable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Handle = NULL;
+ return gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEfiS3SmmSaveStateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mS3SmmSaveState
+ );
+}
diff --git a/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf
new file mode 100644
index 0000000000..f1f264ec43
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.inf
@@ -0,0 +1,62 @@
+## @file
+# S3 SMM Boot Script Save State driver.
+#
+# It will install S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# 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 = SmmS3SaveState
+ MODULE_UNI_FILE = SmmS3SaveState.uni
+ FILE_GUID = 2D59F041-53A4-40d0-A6CD-844DC0DFEF17
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+
+ ENTRY_POINT = InitializeSmmS3SaveState
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SmmS3SaveState.c
+ InternalSmmSaveState.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ BaseLib
+ S3BootScriptLib
+ PcdLib
+
+[Protocols]
+ gEfiS3SmmSaveStateProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SmmS3SaveStateExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni
new file mode 100644
index 0000000000..6fbf297333
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveState.uni
@@ -0,0 +1,22 @@
+// /** @file
+// S3 SMM Boot Script Save State driver.
+//
+// It will install S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "S3 SMM Boot Script Save State driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It will install the S3 SMM Save State protocol to store or record various IO operations to be replayed during an S3 resume."
+
diff --git a/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni
new file mode 100644
index 0000000000..531138b8b6
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Acpi/SmmS3SaveState/SmmS3SaveStateExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// SmmS3SaveState Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SMM S3 Save State Driver"
+
+