]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
MdeModulePkg/ACPI: Install ACPI table from HOB.
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / AcpiTableDxe / AcpiTableProtocol.c
index 5a2afdff27e27816757adda513aa0391603818e0..34d4a1cec01d0004e01f5a4ebccbd1a65550a80b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   ACPI Table Protocol Implementation\r
 \r
-  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>\r
   Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -30,6 +30,7 @@ STATIC EFI_ALLOCATE_TYPE      mAcpiTableAllocType;
   @param  Table                     Table to add.\r
   @param  Checksum                  Does the table require checksumming.\r
   @param  Version                   The version of the list to add the table to.\r
+  @param  IsFromHob                 True, if add Apci Table from Hob List.\r
   @param  Handle                    Pointer for returning the handle.\r
 \r
   @return EFI_SUCCESS               The function completed successfully.\r
@@ -44,6 +45,7 @@ AddTableToList (
   IN VOID                                 *Table,\r
   IN BOOLEAN                              Checksum,\r
   IN EFI_ACPI_TABLE_VERSION               Version,\r
+  IN BOOLEAN                              IsFromHob,\r
   OUT UINTN                               *Handle\r
   );\r
 \r
@@ -238,6 +240,7 @@ InstallAcpiTable (
              AcpiTableBufferConst,\r
              TRUE,\r
              Version,\r
+             FALSE,\r
              TableKey\r
              );\r
   if (!EFI_ERROR (Status)) {\r
@@ -472,6 +475,7 @@ FreeTableMemory (
   @param  Table                     Table to add.\r
   @param  Checksum                  Does the table require checksumming.\r
   @param  Version                   The version of the list to add the table to.\r
+  @param  IsFromHob                 True, if add Apci Table from Hob List.\r
   @param  Handle                    Pointer for returning the handle.\r
 \r
   @return EFI_SUCCESS               The function completed successfully.\r
@@ -487,6 +491,7 @@ AddTableToList (
   IN VOID                                 *Table,\r
   IN BOOLEAN                              Checksum,\r
   IN EFI_ACPI_TABLE_VERSION               Version,\r
+  IN BOOLEAN                              IsFromHob,\r
   OUT UINTN                               *Handle\r
   )\r
 {\r
@@ -553,12 +558,17 @@ AddTableToList (
     // SMM communication ACPI table.\r
     //\r
     ASSERT ((EFI_PAGE_SIZE % 64) == 0);\r
-    Status = gBS->AllocatePages (\r
-                    AllocateMaxAddress,\r
-                    EfiACPIMemoryNVS,\r
-                    EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),\r
-                    &AllocPhysAddress\r
-                    );\r
+    if (IsFromHob){\r
+      AllocPhysAddress = (UINTN)Table;\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = gBS->AllocatePages (\r
+                      AllocateMaxAddress,\r
+                      EfiACPIMemoryNVS,\r
+                      EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),\r
+                      &AllocPhysAddress\r
+                      );\r
+    }\r
   } else if (mAcpiTableAllocType == AllocateAnyPages) {\r
     //\r
     // If there is no allocation limit, there is also no need to use page\r
@@ -1689,6 +1699,151 @@ ChecksumCommonTables (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This function will find gUniversalPayloadAcpiTableGuid Guid Hob, and install Acpi table from it.\r
+\r
+  @param  AcpiTableInstance  Protocol instance private data.\r
+\r
+  @return EFI_SUCCESS        The function completed successfully.\r
+  @return EFI_NOT_FOUND      The function doesn't find the gEfiAcpiTableGuid Guid Hob.\r
+  @return EFI_ABORTED        The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallAcpiTableFromHob (\r
+  EFI_ACPI_TABLE_INSTANCE                   *AcpiTableInstance\r
+  )\r
+{\r
+  EFI_HOB_GUID_TYPE                             *GuidHob;\r
+  EFI_ACPI_TABLE_VERSION                        Version;\r
+  EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;\r
+  EFI_ACPI_DESCRIPTION_HEADER                   *ChildTable;\r
+  UINT64                                        ChildTableAddress;\r
+  UINTN                                         Count;\r
+  UINTN                                         Index;\r
+  UINTN                                         TableKey;\r
+  EFI_STATUS                                    Status;\r
+  UINTN                                         EntrySize;\r
+  UNIVERSAL_PAYLOAD_ACPI_TABLE                  *AcpiTableAdress;\r
+  VOID                                          *TableToInstall;\r
+  EFI_ACPI_SDT_HEADER                           *Table;\r
+  UNIVERSAL_PAYLOAD_GENERIC_HEADER              *GenericHeader;\r
+\r
+  TableKey = 0;\r
+  Version = PcdGet32 (PcdAcpiExposedTableVersions);\r
+  Status = EFI_SUCCESS;\r
+  //\r
+  // HOB only contains the ACPI table in 2.0+ format.\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);\r
+  if (GuidHob == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *) GET_GUID_HOB_DATA (GuidHob);\r
+  if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob))) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION) {\r
+    //\r
+    // UNIVERSAL_PAYLOAD_ACPI_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION\r
+    //\r
+    AcpiTableAdress = (UNIVERSAL_PAYLOAD_ACPI_TABLE *) GET_GUID_HOB_DATA (GuidHob);\r
+    if (AcpiTableAdress->Header.Length < UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_ACPI_TABLE, Rsdp)) {\r
+      //\r
+      // Retrun if can't find the ACPI Info Hob with enough length\r
+      //\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) (UINTN) (AcpiTableAdress->Rsdp);\r
+\r
+    //\r
+    // An ACPI-compatible OS must use the XSDT if present.\r
+    // It shouldn't happen that XsdtAddress points beyond 4G range in 32-bit environment.\r
+    //\r
+    ASSERT ((UINTN) Rsdp->XsdtAddress == Rsdp->XsdtAddress);\r
+\r
+    EntrySize = sizeof (UINT64);\r
+    Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;\r
+    if (Rsdt == NULL) {\r
+      //\r
+      // XsdtAddress is zero, then we use Rsdt which has 32 bit entry\r
+      //\r
+      Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;\r
+      EntrySize = sizeof (UINT32);\r
+    }\r
+\r
+    if (Rsdt->Length <= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    Count = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / EntrySize;\r
+\r
+    for (Index = 0; Index < Count; Index++){\r
+      ChildTableAddress = 0;\r
+      CopyMem (&ChildTableAddress, (UINT8 *) (Rsdt + 1) + EntrySize * Index, EntrySize);\r
+      //\r
+      // If the address is of UINT64 while this module runs at 32 bits,\r
+      // make sure the upper bits are all-zeros.\r
+      //\r
+      ASSERT (ChildTableAddress == (UINTN) ChildTableAddress);\r
+      if (ChildTableAddress != (UINTN) ChildTableAddress) {\r
+        Status = EFI_ABORTED;\r
+        break;\r
+      }\r
+\r
+      ChildTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) ChildTableAddress;\r
+      Status = AddTableToList (AcpiTableInstance, ChildTable, TRUE, Version, TRUE, &TableKey);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table at 0x%p\n", ChildTable));\r
+        ASSERT_EFI_ERROR (Status);\r
+        break;\r
+      }\r
+      if (ChildTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE){\r
+        //\r
+        // Add the FACS and DSDT tables if it is not NULL.\r
+        //\r
+        if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->FirmwareCtrl != 0) {\r
+          TableToInstall = (VOID *) (UINTN) ((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->FirmwareCtrl;\r
+          Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE, Version, TRUE, &TableKey);\r
+          if (EFI_ERROR (Status)) {\r
+            DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table FACS\n"));\r
+            ASSERT_EFI_ERROR (Status);\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt != 0) {\r
+          TableToInstall = (VOID *) (UINTN) ((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt;\r
+          Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE, Version, TRUE, &TableKey);\r
+          if (EFI_ERROR (Status)) {\r
+            DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table DSDT\n"));\r
+            ASSERT_EFI_ERROR (Status);\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Error happens when trying to add ACPI table to the list.\r
+    // Remove all of them from list because at this time, no other tables except from HOB are in the list\r
+    //\r
+    while (SdtGetAcpiTable (AcpiTableInstance, 0, &Table, &Version, &TableKey) == EFI_SUCCESS) {\r
+      RemoveTableFromList (AcpiTableInstance, Version, TableKey);\r
+    }\r
+  } else {\r
+    Status = PublishTables (AcpiTableInstance, Version);\r
+  }\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  return Status;\r
+}\r
 \r
 /**\r
   Constructor for the ACPI table protocol.  Initializes instance\r
@@ -1918,6 +2073,8 @@ AcpiTableAcpiTableConstructor (
 \r
   ChecksumCommonTables (AcpiTableInstance);\r
 \r
+  InstallAcpiTableFromHob (AcpiTableInstance);\r
+\r
   //\r
   // Completed successfully\r
   //\r