1 | /*/@file
|
---|
2 | Hardware info parsing functions.
|
---|
3 | Binary data is expected as a consecutive series of header - object pairs.
|
---|
4 | Complete library providing list-like interface to dynamically manipulate
|
---|
5 | hardware info objects and parsing from a generic blob.
|
---|
6 |
|
---|
7 | Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
---|
8 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
9 |
|
---|
10 | **/
|
---|
11 |
|
---|
12 | #include <Uefi/UefiBaseType.h>
|
---|
13 | #include <Uefi/UefiSpec.h>
|
---|
14 | #include <Library/DebugLib.h>
|
---|
15 | #include <Library/MemoryAllocationLib.h>
|
---|
16 | #include <Library/BaseMemoryLib.h>
|
---|
17 | #include <Library/BaseLib.h>
|
---|
18 | #include <Library/UefiLib.h>
|
---|
19 |
|
---|
20 | #include <Library/HardwareInfoLib.h>
|
---|
21 |
|
---|
22 | EFI_STATUS
|
---|
23 | CreateHardwareInfoList (
|
---|
24 | IN UINT8 *Blob,
|
---|
25 | IN UINTN BlobSize,
|
---|
26 | IN HARDWARE_INFO_TYPE TypeFilter,
|
---|
27 | OUT LIST_ENTRY *ListHead
|
---|
28 | )
|
---|
29 | {
|
---|
30 | UINT8 *Index;
|
---|
31 | UINT8 *BlobEnd;
|
---|
32 | HARDWARE_INFO *HwComponent;
|
---|
33 |
|
---|
34 | if ((Blob == NULL) || (BlobSize <= 0) ||
|
---|
35 | (ListHead == NULL))
|
---|
36 | {
|
---|
37 | return EFI_INVALID_PARAMETER;
|
---|
38 | }
|
---|
39 |
|
---|
40 | Index = Blob;
|
---|
41 | BlobEnd = Blob + BlobSize;
|
---|
42 | while (Index < BlobEnd) {
|
---|
43 | HwComponent = AllocateZeroPool (sizeof (HARDWARE_INFO));
|
---|
44 |
|
---|
45 | if (HwComponent == NULL) {
|
---|
46 | goto FailedAllocate;
|
---|
47 | }
|
---|
48 |
|
---|
49 | HwComponent->Header.Type.Uint64 = *((UINT64 *)Index);
|
---|
50 | Index += sizeof (HwComponent->Header.Type);
|
---|
51 | HwComponent->Header.Size = *((UINT64 *)(Index));
|
---|
52 | Index += sizeof (HwComponent->Header.Size);
|
---|
53 |
|
---|
54 | if ((HwComponent->Header.Size > MAX_UINTN) || (Index < Blob) || ((Index + HwComponent->Header.Size) > BlobEnd)) {
|
---|
55 | goto FreeResources;
|
---|
56 | }
|
---|
57 |
|
---|
58 | //
|
---|
59 | // Check if optional TypeFilter is set, skip if the current
|
---|
60 | // object is of a different type and release the partially
|
---|
61 | // allocated object
|
---|
62 | //
|
---|
63 | if ((TypeFilter != HardwareInfoTypeUndefined) &&
|
---|
64 | (HwComponent->Header.Type.Value != TypeFilter))
|
---|
65 | {
|
---|
66 | FreePool (HwComponent);
|
---|
67 | Index += HwComponent->Header.Size;
|
---|
68 | continue;
|
---|
69 | }
|
---|
70 |
|
---|
71 | HwComponent->Data.Raw = AllocateZeroPool ((UINTN)HwComponent->Header.Size);
|
---|
72 | if (HwComponent->Data.Raw == NULL) {
|
---|
73 | goto FreeResources;
|
---|
74 | }
|
---|
75 |
|
---|
76 | CopyMem (HwComponent->Data.Raw, Index, (UINTN)HwComponent->Header.Size);
|
---|
77 | Index += HwComponent->Header.Size;
|
---|
78 |
|
---|
79 | InsertTailList (ListHead, &HwComponent->Link);
|
---|
80 | }
|
---|
81 |
|
---|
82 | return EFI_SUCCESS;
|
---|
83 |
|
---|
84 | FreeResources:
|
---|
85 | //
|
---|
86 | // Clean the resources allocated in the incomplete cycle
|
---|
87 | //
|
---|
88 | FreePool (HwComponent);
|
---|
89 |
|
---|
90 | FailedAllocate:
|
---|
91 | DEBUG ((
|
---|
92 | EFI_D_ERROR,
|
---|
93 | "%a: Failed to allocate memory for hardware info\n",
|
---|
94 | __func__
|
---|
95 | ));
|
---|
96 |
|
---|
97 | return EFI_OUT_OF_RESOURCES;
|
---|
98 | }
|
---|
99 |
|
---|
100 | VOID
|
---|
101 | FreeHardwareInfoList (
|
---|
102 | IN OUT LIST_ENTRY *ListHead
|
---|
103 | )
|
---|
104 | {
|
---|
105 | LIST_ENTRY *CurrentLink;
|
---|
106 | HARDWARE_INFO *HwComponent;
|
---|
107 |
|
---|
108 | if (IsListEmpty (ListHead)) {
|
---|
109 | return;
|
---|
110 | }
|
---|
111 |
|
---|
112 | CurrentLink = ListHead->ForwardLink;
|
---|
113 | while (CurrentLink != NULL && CurrentLink != ListHead) {
|
---|
114 | HwComponent = HARDWARE_INFO_FROM_LINK (CurrentLink);
|
---|
115 |
|
---|
116 | //
|
---|
117 | // Remove item from list before invalidating the pointers
|
---|
118 | //
|
---|
119 | CurrentLink = RemoveEntryList (CurrentLink);
|
---|
120 |
|
---|
121 | FreePool (HwComponent->Data.Raw);
|
---|
122 | FreePool (HwComponent);
|
---|
123 | }
|
---|
124 | }
|
---|
125 |
|
---|
126 | /**
|
---|
127 | Validates if the specified Node has a valid data size and is of
|
---|
128 | specified type.
|
---|
129 | The data size can be less or equal to the provided type size to be
|
---|
130 | regarded as valid and thus accessible with the typed pointer.
|
---|
131 |
|
---|
132 | For future compatibility the size is allowed to be smaller so that
|
---|
133 | different versions interpret fields differently and, particularly,
|
---|
134 | have smaller data structures. However, it cannot be larger than the
|
---|
135 | type size to avoid accessing memory out of bounds.
|
---|
136 |
|
---|
137 | @param[in] Node Hardware Info node to be validated
|
---|
138 | @param[in] TypeSize Size (in bytes) of the data type intended to be
|
---|
139 | used to dereference the data.
|
---|
140 | @retval TRUE Node is valid and can be accessed
|
---|
141 | @retval FALSE Node is not valid
|
---|
142 | /*/
|
---|
143 | STATIC
|
---|
144 | BOOLEAN
|
---|
145 | IsHardwareInfoNodeValidByType (
|
---|
146 | IN LIST_ENTRY *ListHead,
|
---|
147 | IN LIST_ENTRY *Link,
|
---|
148 | IN HARDWARE_INFO_TYPE Type,
|
---|
149 | IN UINTN TypeSize
|
---|
150 | )
|
---|
151 | {
|
---|
152 | HARDWARE_INFO *HwComponent;
|
---|
153 |
|
---|
154 | if (IsNull (ListHead, Link)) {
|
---|
155 | return FALSE;
|
---|
156 | }
|
---|
157 |
|
---|
158 | HwComponent = HARDWARE_INFO_FROM_LINK (Link);
|
---|
159 |
|
---|
160 | //
|
---|
161 | // Verify if the node type is the specified one and the size of
|
---|
162 | // the data allocated to the node is greater than the size of
|
---|
163 | // the type intended to dereference it in order to avoid access
|
---|
164 | // to memory out of bondaries.
|
---|
165 | //
|
---|
166 | if ((HwComponent->Header.Type.Value == Type) &&
|
---|
167 | (HwComponent->Header.Size >= TypeSize))
|
---|
168 | {
|
---|
169 | return TRUE;
|
---|
170 | }
|
---|
171 |
|
---|
172 | return FALSE;
|
---|
173 | }
|
---|
174 |
|
---|
175 | UINTN
|
---|
176 | GetHardwareInfoCountByType (
|
---|
177 | IN LIST_ENTRY *ListHead,
|
---|
178 | IN HARDWARE_INFO_TYPE Type,
|
---|
179 | IN UINTN TypeSize
|
---|
180 | )
|
---|
181 | {
|
---|
182 | UINTN Count;
|
---|
183 | LIST_ENTRY *Link;
|
---|
184 |
|
---|
185 | Count = 0;
|
---|
186 | for (Link = GetFirstHardwareInfoByType (ListHead, Type, TypeSize);
|
---|
187 | !IsNull (ListHead, Link);
|
---|
188 | Link = GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize))
|
---|
189 | {
|
---|
190 | if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
|
---|
191 | Count++;
|
---|
192 | }
|
---|
193 | }
|
---|
194 |
|
---|
195 | return Count;
|
---|
196 | }
|
---|
197 |
|
---|
198 | LIST_ENTRY *
|
---|
199 | GetFirstHardwareInfoByType (
|
---|
200 | IN LIST_ENTRY *ListHead,
|
---|
201 | IN HARDWARE_INFO_TYPE Type,
|
---|
202 | IN UINTN TypeSize
|
---|
203 | )
|
---|
204 | {
|
---|
205 | LIST_ENTRY *Link;
|
---|
206 |
|
---|
207 | if (IsListEmpty (ListHead)) {
|
---|
208 | return ListHead;
|
---|
209 | }
|
---|
210 |
|
---|
211 | Link = GetFirstNode (ListHead);
|
---|
212 |
|
---|
213 | if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
|
---|
214 | return Link;
|
---|
215 | }
|
---|
216 |
|
---|
217 | return GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize);
|
---|
218 | }
|
---|
219 |
|
---|
220 | LIST_ENTRY *
|
---|
221 | GetNextHardwareInfoByType (
|
---|
222 | IN LIST_ENTRY *ListHead,
|
---|
223 | IN LIST_ENTRY *Node,
|
---|
224 | IN HARDWARE_INFO_TYPE Type,
|
---|
225 | IN UINTN TypeSize
|
---|
226 | )
|
---|
227 | {
|
---|
228 | LIST_ENTRY *Link;
|
---|
229 |
|
---|
230 | Link = GetNextNode (ListHead, Node);
|
---|
231 |
|
---|
232 | while (!IsNull (ListHead, Link)) {
|
---|
233 | if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
|
---|
234 | //
|
---|
235 | // Found a node of specified type and with valid size. Break and
|
---|
236 | // return the found node.
|
---|
237 | //
|
---|
238 | break;
|
---|
239 | }
|
---|
240 |
|
---|
241 | Link = GetNextNode (ListHead, Link);
|
---|
242 | }
|
---|
243 |
|
---|
244 | return Link;
|
---|
245 | }
|
---|
246 |
|
---|
247 | BOOLEAN
|
---|
248 | EndOfHardwareInfoList (
|
---|
249 | IN LIST_ENTRY *ListHead,
|
---|
250 | IN LIST_ENTRY *Node
|
---|
251 | )
|
---|
252 | {
|
---|
253 | return IsNull (ListHead, Node);
|
---|
254 | }
|
---|