--- /dev/null
+/*/@file\r
+ Hardware info parsing functions.\r
+ Binary data is expected as a consecutive series of header - object pairs.\r
+ Complete library providing list-like interface to dynamically manipulate\r
+ hardware info objects and parsing from a generic blob.\r
+\r
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Uefi/UefiSpec.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Library/HardwareInfoLib.h>\r
+\r
+EFI_STATUS\r
+CreateHardwareInfoList (\r
+ IN UINT8 *Blob,\r
+ IN UINTN BlobSize,\r
+ IN HARDWARE_INFO_TYPE TypeFilter,\r
+ OUT LIST_ENTRY *ListHead\r
+ )\r
+{\r
+ UINT8 *Index;\r
+ UINT8 *BlobEnd;\r
+ HARDWARE_INFO *HwComponent;\r
+\r
+ if ((Blob == NULL) || (BlobSize <= 0) ||\r
+ (ListHead == NULL))\r
+ {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Index = Blob;\r
+ BlobEnd = Blob + BlobSize;\r
+ while (Index < BlobEnd) {\r
+ HwComponent = AllocateZeroPool (sizeof (HARDWARE_INFO));\r
+\r
+ if (HwComponent == NULL) {\r
+ goto FailedAllocate;\r
+ }\r
+\r
+ HwComponent->Header.Type.Uint64 = *((UINT64 *)Index);\r
+ Index += sizeof (HwComponent->Header.Type);\r
+ HwComponent->Header.Size = *((UINT64 *)(Index));\r
+ Index += sizeof (HwComponent->Header.Size);\r
+\r
+ if ((HwComponent->Header.Size > MAX_UINTN) || (Index < Blob) || ((Index + HwComponent->Header.Size) > BlobEnd)) {\r
+ goto FreeResources;\r
+ }\r
+\r
+ //\r
+ // Check if optional TypeFilter is set, skip if the current\r
+ // object is of a different type and release the partially\r
+ // allocated object\r
+ //\r
+ if ((TypeFilter != HardwareInfoTypeUndefined) &&\r
+ (HwComponent->Header.Type.Value != TypeFilter))\r
+ {\r
+ FreePool (HwComponent);\r
+ Index += HwComponent->Header.Size;\r
+ continue;\r
+ }\r
+\r
+ HwComponent->Data.Raw = AllocateZeroPool ((UINTN)HwComponent->Header.Size);\r
+ if (HwComponent->Data.Raw == NULL) {\r
+ goto FreeResources;\r
+ }\r
+\r
+ CopyMem (HwComponent->Data.Raw, Index, (UINTN)HwComponent->Header.Size);\r
+ Index += HwComponent->Header.Size;\r
+\r
+ InsertTailList (ListHead, &HwComponent->Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+FreeResources:\r
+ //\r
+ // Clean the resources allocated in the incomplete cycle\r
+ //\r
+ FreePool (HwComponent);\r
+\r
+FailedAllocate:\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "%a: Failed to allocate memory for hardware info\n",\r
+ __FUNCTION__\r
+ ));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+VOID\r
+FreeHardwareInfoList (\r
+ IN OUT LIST_ENTRY *ListHead\r
+ )\r
+{\r
+ LIST_ENTRY *CurrentLink;\r
+ HARDWARE_INFO *HwComponent;\r
+\r
+ if (IsListEmpty (ListHead)) {\r
+ return;\r
+ }\r
+\r
+ CurrentLink = ListHead->ForwardLink;\r
+ while (CurrentLink != NULL && CurrentLink != ListHead) {\r
+ HwComponent = HARDWARE_INFO_FROM_LINK (CurrentLink);\r
+\r
+ //\r
+ // Remove item from list before invalidating the pointers\r
+ //\r
+ CurrentLink = RemoveEntryList (CurrentLink);\r
+\r
+ FreePool (HwComponent->Data.Raw);\r
+ FreePool (HwComponent);\r
+ }\r
+}\r
+\r
+/**\r
+ Validates if the specified Node has a valid data size and is of\r
+ specified type.\r
+ The data size can be less or equal to the provided type size to be\r
+ regarded as valid and thus accessible with the typed pointer.\r
+\r
+ For future compatibility the size is allowed to be smaller so that\r
+ different versions interpret fields differently and, particularly,\r
+ have smaller data structures. However, it cannot be larger than the\r
+ type size to avoid accessing memory out of bounds.\r
+\r
+ @param[in] Node Hardware Info node to be validated\r
+ @param[in] TypeSize Size (in bytes) of the data type intended to be\r
+ used to dereference the data.\r
+ @retval TRUE Node is valid and can be accessed\r
+ @retval FALSE Node is not valid\r
+/*/\r
+STATIC\r
+BOOLEAN\r
+IsHardwareInfoNodeValidByType (\r
+ IN LIST_ENTRY *ListHead,\r
+ IN LIST_ENTRY *Link,\r
+ IN HARDWARE_INFO_TYPE Type,\r
+ IN UINTN TypeSize\r
+ )\r
+{\r
+ HARDWARE_INFO *HwComponent;\r
+\r
+ if (IsNull (ListHead, Link)) {\r
+ return FALSE;\r
+ }\r
+\r
+ HwComponent = HARDWARE_INFO_FROM_LINK (Link);\r
+\r
+ //\r
+ // Verify if the node type is the specified one and the size of\r
+ // the data allocated to the node is greater than the size of\r
+ // the type intended to dereference it in order to avoid access\r
+ // to memory out of bondaries.\r
+ //\r
+ if ((HwComponent->Header.Type.Value == Type) &&\r
+ (HwComponent->Header.Size >= TypeSize))\r
+ {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+UINTN\r
+GetHardwareInfoCountByType (\r
+ IN LIST_ENTRY *ListHead,\r
+ IN HARDWARE_INFO_TYPE Type,\r
+ IN UINTN TypeSize\r
+ )\r
+{\r
+ UINTN Count;\r
+ LIST_ENTRY *Link;\r
+\r
+ Count = 0;\r
+ for (Link = GetFirstHardwareInfoByType (ListHead, Type, TypeSize);\r
+ !IsNull (ListHead, Link);\r
+ Link = GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize))\r
+ {\r
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {\r
+ Count++;\r
+ }\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+LIST_ENTRY *\r
+GetFirstHardwareInfoByType (\r
+ IN LIST_ENTRY *ListHead,\r
+ IN HARDWARE_INFO_TYPE Type,\r
+ IN UINTN TypeSize\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+\r
+ if (IsListEmpty (ListHead)) {\r
+ return ListHead;\r
+ }\r
+\r
+ Link = GetFirstNode (ListHead);\r
+\r
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {\r
+ return Link;\r
+ }\r
+\r
+ return GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize);\r
+}\r
+\r
+LIST_ENTRY *\r
+GetNextHardwareInfoByType (\r
+ IN LIST_ENTRY *ListHead,\r
+ IN LIST_ENTRY *Node,\r
+ IN HARDWARE_INFO_TYPE Type,\r
+ IN UINTN TypeSize\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+\r
+ Link = GetNextNode (ListHead, Node);\r
+\r
+ while (!IsNull (ListHead, Link)) {\r
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {\r
+ //\r
+ // Found a node of specified type and with valid size. Break and\r
+ // return the found node.\r
+ //\r
+ break;\r
+ }\r
+\r
+ Link = GetNextNode (ListHead, Link);\r
+ }\r
+\r
+ return Link;\r
+}\r
+\r
+BOOLEAN\r
+EndOfHardwareInfoList (\r
+ IN LIST_ENTRY *ListHead,\r
+ IN LIST_ENTRY *Node\r
+ )\r
+{\r
+ return IsNull (ListHead, Node);\r
+}\r