]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
MdeModulePkg/Universal/SmbiosDxe: Scan for existing tables
[mirror_edk2.git] / MdeModulePkg / Universal / SmbiosDxe / SmbiosDxe.c
index 3cdb0b1ed74f1a4ea3c8e9747f9ca050e02f77b5..400b0fa578a3287daae2ebac8843c20b0a36ebdf 100644 (file)
@@ -2,7 +2,7 @@
   This code produces the Smbios protocol. It also responsible for constructing\r
   SMBIOS table into system table.\r
 \r
-Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>\r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -148,6 +148,12 @@ SMBIOS_TABLE_3_0_ENTRY_POINT Smbios30EntryPointStructureData = {
   //\r
   0\r
 };\r
+\r
+IS_SMBIOS_TABLE_VALID_ENTRY mIsSmbiosTableValid[] = {\r
+  {&gUniversalPayloadSmbios3TableGuid, IsValidSmbios30Table },\r
+  {&gUniversalPayloadSmbiosTableGuid,  IsValidSmbios20Table }\r
+};\r
+\r
 /**\r
 \r
   Get the full size of SMBIOS structure including optional strings that follow the formatted structure.\r
@@ -1408,6 +1414,290 @@ SmbiosTableConstruction (
   }\r
 }\r
 \r
+/**\r
+  Validates a SMBIOS 2.0 table entry point.\r
+\r
+  @param  TableEntry       The SmBios table entry to validate.\r
+  @param  TableAddress     On exit, point to the smbios table addres.\r
+  @param  TableMaximumSize On exit, point to the maximum size of the table.\r
+\r
+  @retval TRUE           SMBIOS table entry point is valid.\r
+  @retval FALSE          SMBIOS table entry point is malformed.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsValidSmbios20Table (\r
+  IN  VOID               *TableEntry,\r
+  OUT VOID               **TableAddress,\r
+  OUT UINTN              *TableMaximumSize\r
+  )\r
+{\r
+  UINT8                                      Checksum;\r
+  SMBIOS_TABLE_ENTRY_POINT                   *SmbiosTable;\r
+  SmbiosTable = (SMBIOS_TABLE_ENTRY_POINT *) TableEntry;\r
+\r
+  if (CompareMem (SmbiosTable->AnchorString, "_SM_", 4) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (CompareMem (SmbiosTable->IntermediateAnchorString, "_DMI_", 5) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The actual value of the EntryPointLength should be 1Fh.\r
+  // However, it was incorrectly stated in version 2.1 of smbios specification.\r
+  // Therefore, 0x1F and 0x1E are both accepted.\r
+  //\r
+  if (SmbiosTable->EntryPointLength != 0x1E && SmbiosTable->EntryPointLength != sizeof (SMBIOS_TABLE_ENTRY_POINT)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // MajorVersion should not be less than 2.\r
+  //\r
+  if (SmbiosTable->MajorVersion < 2) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The whole struct check sum should be zero\r
+  //\r
+  Checksum = CalculateSum8 (\r
+               (UINT8 *) SmbiosTable,\r
+               SmbiosTable->EntryPointLength\r
+               );\r
+  if (Checksum != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The Intermediate Entry Point Structure check sum should be zero.\r
+  //\r
+  Checksum = CalculateSum8 (\r
+               (UINT8 *) SmbiosTable + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),\r
+               SmbiosTable->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)\r
+               );\r
+  if (Checksum != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  *TableAddress     = (VOID *) (UINTN) SmbiosTable->TableAddress;\r
+  *TableMaximumSize = SmbiosTable->TableLength;\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Validates a SMBIOS 3.0 table entry point.\r
+\r
+  @param  TableEntry       The SmBios table entry to validate.\r
+  @param  TableAddress     On exit, point to the smbios table addres.\r
+  @param  TableMaximumSize On exit, point to the maximum size of the table.\r
+\r
+  @retval TRUE           SMBIOS table entry point is valid.\r
+  @retval FALSE          SMBIOS table entry point is malformed.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsValidSmbios30Table (\r
+  IN  VOID               *TableEntry,\r
+  OUT VOID               **TableAddress,\r
+  OUT UINTN              *TableMaximumSize\r
+  )\r
+{\r
+  UINT8                          Checksum;\r
+  SMBIOS_TABLE_3_0_ENTRY_POINT   *SmbiosTable;\r
+  SmbiosTable = (SMBIOS_TABLE_3_0_ENTRY_POINT *) TableEntry;\r
+\r
+  if (CompareMem (SmbiosTable->AnchorString, "_SM3_", 5) != 0) {\r
+    return FALSE;\r
+  }\r
+  if (SmbiosTable->EntryPointLength < sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)) {\r
+    return FALSE;\r
+  }\r
+  if (SmbiosTable->MajorVersion < 3) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // The whole struct check sum should be zero\r
+  //\r
+  Checksum = CalculateSum8 (\r
+               (UINT8 *) SmbiosTable,\r
+               SmbiosTable->EntryPointLength\r
+               );\r
+  if (Checksum != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  *TableAddress     = (VOID *) (UINTN) SmbiosTable->TableAddress;\r
+  *TableMaximumSize = SmbiosTable->TableMaximumSize;\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Parse an existing SMBIOS table and insert it using SmbiosAdd.\r
+\r
+  @param  ImageHandle           The EFI_HANDLE to this driver.\r
+  @param  Smbios                The SMBIOS table to parse.\r
+  @param  Length                The length of the SMBIOS table.\r
+\r
+  @retval EFI_SUCCESS           SMBIOS table was parsed and installed.\r
+  @retval EFI_OUT_OF_RESOURCES  Record was not added due to lack of system resources.\r
+  @retval EFI_INVALID_PARAMETER Smbios is not a correct smbios table\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ParseAndAddExistingSmbiosTable (\r
+  IN EFI_HANDLE                    ImageHandle,\r
+  IN SMBIOS_STRUCTURE_POINTER      Smbios,\r
+  IN UINTN                         Length\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  CHAR8                         *String;\r
+  EFI_SMBIOS_HANDLE             SmbiosHandle;\r
+  SMBIOS_STRUCTURE_POINTER      SmbiosEnd;\r
+\r
+  SmbiosEnd.Raw = Smbios.Raw + Length;\r
+\r
+  if (Smbios.Raw >= SmbiosEnd.Raw || Smbios.Raw == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  do {\r
+    //\r
+    // Make sure not to access memory beyond SmbiosEnd\r
+    //\r
+    if (Smbios.Raw + sizeof (SMBIOS_STRUCTURE) > SmbiosEnd.Raw ||\r
+      Smbios.Raw + sizeof (SMBIOS_STRUCTURE) < Smbios.Raw) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // Check for end marker\r
+    //\r
+    if (Smbios.Hdr->Type == SMBIOS_TYPE_END_OF_TABLE) {\r
+      break;\r
+    }\r
+    //\r
+    // Make sure not to access memory beyond SmbiosEnd\r
+    // Each structure shall be terminated by a double-null (0000h).\r
+    //\r
+    if (Smbios.Raw + Smbios.Hdr->Length + 2 * sizeof (UINT8) > SmbiosEnd.Raw ||\r
+      Smbios.Raw + Smbios.Hdr->Length + 2 * sizeof (UINT8) < Smbios.Raw) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // Install the table\r
+    //\r
+    SmbiosHandle = Smbios.Hdr->Handle;\r
+    Status = SmbiosAdd (\r
+               &mPrivateData.Smbios,\r
+               ImageHandle,\r
+               &SmbiosHandle,\r
+               Smbios.Hdr\r
+               );\r
+\r
+    ASSERT_EFI_ERROR (Status);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:\r
+    // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed\r
+    // to skip one SMBIOS structure.\r
+    //\r
+\r
+    //\r
+    // Step 1: Skip over formatted section.\r
+    //\r
+    String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);\r
+\r
+    //\r
+    // Step 2: Skip over unformatted string section.\r
+    //\r
+    do {\r
+      //\r
+      // Each string is terminated with a NULL(00h) BYTE and the sets of strings\r
+      // is terminated with an additional NULL(00h) BYTE.\r
+      //\r
+      for ( ; *String != 0; String++) {\r
+        if ((UINTN) String >= (UINTN) SmbiosEnd.Raw - sizeof (UINT8)) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+      }\r
+\r
+      if (*(UINT8 *) ++String == 0) {\r
+        //\r
+        // Pointer to the next SMBIOS structure.\r
+        //\r
+        Smbios.Raw = (UINT8 *) ++String;\r
+        break;\r
+      }\r
+    } while (TRUE);\r
+  } while (Smbios.Raw < SmbiosEnd.Raw);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieve SMBIOS from Hob.\r
+  @param ImageHandle     Module's image handle\r
+\r
+  @retval EFI_SUCCESS    Smbios from Hob is installed.\r
+  @return EFI_NOT_FOUND  Not found Smbios from Hob.\r
+  @retval Other          No Smbios from Hob is installed.\r
+\r
+**/\r
+EFI_STATUS\r
+RetrieveSmbiosFromHob (\r
+  IN EFI_HANDLE           ImageHandle\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINTN                              Index;\r
+  SMBIOS_STRUCTURE_POINTER           Smbios;\r
+  EFI_HOB_GUID_TYPE                  *GuidHob;\r
+  UNIVERSAL_PAYLOAD_SMBIOS_TABLE     *SmBiosTableAdress;\r
+  UNIVERSAL_PAYLOAD_GENERIC_HEADER   *GenericHeader;\r
+  VOID                               *TableAddress;\r
+  UINTN                              TableMaximumSize;\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  for (Index = 0; Index < ARRAY_SIZE (mIsSmbiosTableValid); Index++) {\r
+    GuidHob = GetFirstGuidHob (mIsSmbiosTableValid[Index].Guid);\r
+    if (GuidHob == NULL) {\r
+      continue;\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
+      if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION) {\r
+        //\r
+        // UNIVERSAL_PAYLOAD_SMBIOS_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION\r
+        //\r
+        SmBiosTableAdress = (UNIVERSAL_PAYLOAD_SMBIOS_TABLE *) GET_GUID_HOB_DATA (GuidHob);\r
+        if (GenericHeader->Length >= UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_SMBIOS_TABLE, SmBiosEntryPoint)) {\r
+          if (mIsSmbiosTableValid[Index].IsValid ((VOID *) (UINTN )SmBiosTableAdress->SmBiosEntryPoint, &TableAddress, &TableMaximumSize)) {\r
+            Smbios.Raw = TableAddress;\r
+            Status = ParseAndAddExistingSmbiosTable (ImageHandle, Smbios, TableMaximumSize);\r
+            if (EFI_ERROR (Status)) {\r
+              DEBUG ((DEBUG_ERROR, "RetrieveSmbiosFromHob: Failed to parse preinstalled tables from Guid Hob\n"));\r
+              Status = EFI_UNSUPPORTED;\r
+            } else {\r
+              return EFI_SUCCESS;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
 /**\r
 \r
   Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.\r
@@ -1451,5 +1741,6 @@ SmbiosDriverEntryPoint (
                   &mPrivateData.Smbios\r
                   );\r
 \r
+  RetrieveSmbiosFromHob (ImageHandle);\r
   return Status;\r
 }\r