]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
d92c82eac99e7dfd04f0788eafe698b48c90865f
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / TableHelperLib / TableHelper.c
1 /** @file
2 Table Helper
3
4 Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <Protocol/AcpiTable.h>
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/BaseMemoryLib.h>
13
14 // Module specific include files.
15 #include <AcpiTableGenerator.h>
16 #include <ConfigurationManagerObject.h>
17 #include <Library/TableHelperLib.h>
18 #include <Protocol/ConfigurationManagerProtocol.h>
19
20 /** The GetCgfMgrInfo function gets the CM_STD_OBJ_CONFIGURATION_MANAGER_INFO
21 object from the Configuration Manager.
22
23 @param [in] CfgMgrProtocol Pointer to the Configuration Manager protocol
24 interface.
25 @param [out] CfgMfrInfo Pointer to the Configuration Manager Info
26 object structure.
27
28 @retval EFI_SUCCESS The object is returned.
29 @retval EFI_INVALID_PARAMETER The Object ID is invalid.
30 @retval EFI_NOT_FOUND The requested Object is not found.
31 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
32 Manager is less than the Object size.
33 **/
34 EFI_STATUS
35 EFIAPI
36 GetCgfMgrInfo (
37 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
38 OUT CM_STD_OBJ_CONFIGURATION_MANAGER_INFO ** CfgMfrInfo
39 )
40 {
41 EFI_STATUS Status;
42 CM_OBJ_DESCRIPTOR CmObjectDesc;
43
44 ASSERT (CfgMgrProtocol != NULL);
45 ASSERT (CfgMfrInfo != NULL);
46
47 *CfgMfrInfo = NULL;
48 Status = CfgMgrProtocol->GetObject (
49 CfgMgrProtocol,
50 CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
51 CM_NULL_TOKEN,
52 &CmObjectDesc
53 );
54 if (EFI_ERROR (Status)) {
55 DEBUG ((
56 DEBUG_ERROR,
57 "ERROR: Failed to Get Configuration Manager Info. Status = %r\n",
58 Status
59 ));
60 return Status;
61 }
62
63 if (CmObjectDesc.ObjectId != CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo)) {
64 DEBUG ((
65 DEBUG_ERROR,
66 "ERROR: EStdObjCfgMgrInfo: Invalid ObjectId = 0x%x, expected Id = 0x%x\n",
67 CmObjectDesc.ObjectId,
68 CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo)
69 ));
70 ASSERT (FALSE);
71 return EFI_INVALID_PARAMETER;
72 }
73
74 if (CmObjectDesc.Size <
75 (sizeof (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO) * CmObjectDesc.Count)) {
76 DEBUG ((
77 DEBUG_ERROR,
78 "ERROR: EStdObjCfgMgrInfo: Buffer too small, size = 0x%x\n",
79 CmObjectDesc.Size
80 ));
81 ASSERT (FALSE);
82 return EFI_BAD_BUFFER_SIZE;
83 }
84
85 *CfgMfrInfo = (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO*)CmObjectDesc.Data;
86 return Status;
87 }
88
89 /** The AddAcpiHeader function updates the ACPI header structure pointed by
90 the AcpiHeader. It utilizes the ACPI table Generator and the Configuration
91 Manager protocol to obtain any information required for constructing the
92 header.
93
94 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
95 protocol interface.
96 @param [in] Generator Pointer to the ACPI table Generator.
97 @param [in,out] AcpiHeader Pointer to the ACPI table header to be
98 updated.
99 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
100 @param [in] Length Length of the ACPI table.
101
102 @retval EFI_SUCCESS The ACPI table is updated successfully.
103 @retval EFI_INVALID_PARAMETER A parameter is invalid.
104 @retval EFI_NOT_FOUND The required object information is not found.
105 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
106 Manager is less than the Object size for the
107 requested object.
108 **/
109 EFI_STATUS
110 EFIAPI
111 AddAcpiHeader (
112 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
113 IN CONST ACPI_TABLE_GENERATOR * CONST Generator,
114 IN OUT EFI_ACPI_DESCRIPTION_HEADER * CONST AcpiHeader,
115 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
116 IN CONST UINT32 Length
117 )
118 {
119 EFI_STATUS Status;
120 CM_STD_OBJ_CONFIGURATION_MANAGER_INFO * CfgMfrInfo;
121
122 ASSERT (CfgMgrProtocol != NULL);
123 ASSERT (Generator != NULL);
124 ASSERT (AcpiHeader != NULL);
125 ASSERT (AcpiTableInfo != NULL);
126 ASSERT (Length >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
127
128 if ((CfgMgrProtocol == NULL) ||
129 (Generator == NULL) ||
130 (AcpiHeader == NULL) ||
131 (AcpiTableInfo == NULL) ||
132 (Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER))
133 ) {
134 return EFI_INVALID_PARAMETER;
135 }
136
137 Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo);
138 if (EFI_ERROR (Status)) {
139 DEBUG ((
140 DEBUG_ERROR,
141 "ERROR: Failed to get Configuration Manager info. Status = %r\n",
142 Status
143 ));
144 goto error_handler;
145 }
146
147 // UINT32 Signature
148 AcpiHeader->Signature = Generator->AcpiTableSignature;
149 // UINT32 Length
150 AcpiHeader->Length = Length;
151 // UINT8 Revision
152 AcpiHeader->Revision = AcpiTableInfo->AcpiTableRevision;
153 // UINT8 Checksum
154 AcpiHeader->Checksum = 0;
155
156 // UINT8 OemId[6]
157 CopyMem (AcpiHeader->OemId, CfgMfrInfo->OemId, sizeof (AcpiHeader->OemId));
158
159 // UINT64 OemTableId
160 if (AcpiTableInfo->OemTableId != 0) {
161 AcpiHeader->OemTableId = AcpiTableInfo->OemTableId;
162 } else {
163 AcpiHeader->OemTableId = SIGNATURE_32 (
164 CfgMfrInfo->OemId[0],
165 CfgMfrInfo->OemId[1],
166 CfgMfrInfo->OemId[2],
167 CfgMfrInfo->OemId[3]
168 ) |
169 ((UINT64)Generator->AcpiTableSignature << 32);
170 }
171
172 // UINT32 OemRevision
173 if (AcpiTableInfo->OemRevision != 0) {
174 AcpiHeader->OemRevision = AcpiTableInfo->OemRevision;
175 } else {
176 AcpiHeader->OemRevision = CfgMfrInfo->Revision;
177 }
178
179 // UINT32 CreatorId
180 AcpiHeader->CreatorId = Generator->CreatorId;
181 // UINT32 CreatorRevision
182 AcpiHeader->CreatorRevision = Generator->CreatorRevision;
183
184 error_handler:
185 return Status;
186 }
187
188 /** Build a RootNode containing SSDT ACPI header information using the AmlLib.
189
190 The function utilizes the ACPI table Generator and the Configuration
191 Manager protocol to obtain any information required for constructing the
192 header. It then creates a RootNode. The SSDT ACPI header is part of the
193 RootNode.
194
195 This is essentially a wrapper around AmlCodeGenDefinitionBlock ()
196 from the AmlLib.
197
198 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
199 protocol interface.
200 @param [in] Generator Pointer to the ACPI table Generator.
201 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
202 @param [out] RootNode If success, contains the created RootNode.
203 The SSDT ACPI header is part of the RootNode.
204
205 @retval EFI_SUCCESS Success.
206 @retval EFI_INVALID_PARAMETER A parameter is invalid.
207 @retval EFI_NOT_FOUND The required object information is not found.
208 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
209 Manager is less than the Object size for the
210 requested object.
211 **/
212 EFI_STATUS
213 EFIAPI
214 AddSsdtAcpiHeader (
215 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
216 IN CONST ACPI_TABLE_GENERATOR * CONST Generator,
217 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
218 OUT AML_ROOT_NODE_HANDLE * RootNode
219 )
220 {
221 EFI_STATUS Status;
222 UINT64 OemTableId;
223 UINT32 OemRevision;
224 CM_STD_OBJ_CONFIGURATION_MANAGER_INFO * CfgMfrInfo;
225
226 ASSERT (CfgMgrProtocol != NULL);
227 ASSERT (Generator != NULL);
228 ASSERT (AcpiTableInfo != NULL);
229
230 if ((CfgMgrProtocol == NULL) ||
231 (Generator == NULL) ||
232 (AcpiTableInfo == NULL)) {
233 return EFI_INVALID_PARAMETER;
234 }
235
236 Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo);
237 if (EFI_ERROR (Status)) {
238 DEBUG ((
239 DEBUG_ERROR,
240 "ERROR: Failed to get Configuration Manager info. Status = %r\n",
241 Status
242 ));
243 return Status;
244 }
245
246 if (AcpiTableInfo->OemTableId != 0) {
247 OemTableId = AcpiTableInfo->OemTableId;
248 } else {
249 OemTableId = SIGNATURE_32 (
250 CfgMfrInfo->OemId[0],
251 CfgMfrInfo->OemId[1],
252 CfgMfrInfo->OemId[2],
253 CfgMfrInfo->OemId[3]
254 ) |
255 ((UINT64)Generator->AcpiTableSignature << 32);
256 }
257
258 if (AcpiTableInfo->OemRevision != 0) {
259 OemRevision = AcpiTableInfo->OemRevision;
260 } else {
261 OemRevision = CfgMfrInfo->Revision;
262 }
263
264 Status = AmlCodeGenDefinitionBlock (
265 "SSDT",
266 (CONST CHAR8*)&CfgMfrInfo->OemId,
267 (CONST CHAR8*)&OemTableId,
268 OemRevision,
269 RootNode
270 );
271 ASSERT_EFI_ERROR (Status);
272 return Status;
273 }
274
275 /**
276 Test and report if a duplicate entry exists in the given array of comparable
277 elements.
278
279 @param [in] Array Array of elements to test for duplicates.
280 @param [in] Count Number of elements in Array.
281 @param [in] ElementSize Size of an element in bytes
282 @param [in] EqualTestFunction The function to call to check if any two
283 elements are equal.
284
285 @retval TRUE A duplicate element was found or one of
286 the input arguments is invalid.
287 @retval FALSE Every element in Array is unique.
288 **/
289 BOOLEAN
290 EFIAPI
291 FindDuplicateValue (
292 IN CONST VOID * Array,
293 IN CONST UINTN Count,
294 IN CONST UINTN ElementSize,
295 IN PFN_IS_EQUAL EqualTestFunction
296 )
297 {
298 UINTN Index1;
299 UINTN Index2;
300 UINT8 * Element1;
301 UINT8 * Element2;
302
303 if (Array == NULL) {
304 DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: Array is NULL.\n"));
305 return TRUE;
306 }
307
308 if (ElementSize == 0) {
309 DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: ElementSize is 0.\n"));
310 return TRUE;
311 }
312
313 if (EqualTestFunction == NULL) {
314 DEBUG ((
315 DEBUG_ERROR,
316 "ERROR: FindDuplicateValues: EqualTestFunction is NULL.\n"
317 ));
318 return TRUE;
319 }
320
321 if (Count < 2) {
322 return FALSE;
323 }
324
325 for (Index1 = 0; Index1 < Count - 1; Index1++) {
326 for (Index2 = Index1 + 1; Index2 < Count; Index2++) {
327 Element1 = (UINT8*)Array + (Index1 * ElementSize);
328 Element2 = (UINT8*)Array + (Index2 * ElementSize);
329
330 if (EqualTestFunction (Element1, Element2, Index1, Index2)) {
331 return TRUE;
332 }
333 }
334 }
335 return FALSE;
336 }