1 /** @file
2 Table Helper
3
4 Copyright (c) 2017 - 2020, 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
GetCgfMgrInfo(IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,OUT CM_STD_OBJ_CONFIGURATION_MANAGER_INFO ** CfgMfrInfo)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
AddAcpiHeader(IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,IN CONST ACPI_TABLE_GENERATOR * CONST Generator,IN OUT EFI_ACPI_DESCRIPTION_HEADER * CONST AcpiHeader,IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,IN CONST UINT32 Length)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 (Length >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
126
127 if ((CfgMgrProtocol == NULL) ||
128 (Generator == NULL) ||
129 (AcpiHeader == NULL) ||
130 (Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER))
131 ) {
132 return EFI_INVALID_PARAMETER;
133 }
134
135 Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo);
136 if (EFI_ERROR (Status)) {
137 DEBUG ((
138 DEBUG_ERROR,
139 "ERROR: Failed to get Configuration Manager info. Status = %r\n",
140 Status
141 ));
142 goto error_handler;
143 }
144
145 // UINT32 Signature
146 AcpiHeader->Signature = Generator->AcpiTableSignature;
147 // UINT32 Length
148 AcpiHeader->Length = Length;
149 // UINT8 Revision
150 AcpiHeader->Revision = AcpiTableInfo->AcpiTableRevision;
151 // UINT8 Checksum
152 AcpiHeader->Checksum = 0;
153
154 // UINT8 OemId[6]
155 CopyMem (AcpiHeader->OemId, CfgMfrInfo->OemId, sizeof (AcpiHeader->OemId));
156
157 // UINT64 OemTableId
158 if (AcpiTableInfo->OemTableId != 0) {
159 AcpiHeader->OemTableId = AcpiTableInfo->OemTableId;
160 } else {
161 AcpiHeader->OemTableId = SIGNATURE_32 (
162 CfgMfrInfo->OemId[0],
163 CfgMfrInfo->OemId[1],
164 CfgMfrInfo->OemId[2],
165 CfgMfrInfo->OemId[3]
166 ) |
167 ((UINT64)Generator->AcpiTableSignature << 32);
168 }
169
170 // UINT32 OemRevision
171 if (AcpiTableInfo->OemRevision != 0) {
172 AcpiHeader->OemRevision = AcpiTableInfo->OemRevision;
173 } else {
174 AcpiHeader->OemRevision = CfgMfrInfo->Revision;
175 }
176
177 // UINT32 CreatorId
178 AcpiHeader->CreatorId = Generator->CreatorId;
179 // UINT32 CreatorRevision
180 AcpiHeader->CreatorRevision = Generator->CreatorRevision;
181
182 error_handler:
183 return Status;
184 }
185
186 /**
187 Test and report if a duplicate entry exists in the given array of comparable
188 elements.
189
190 @param [in] Array Array of elements to test for duplicates.
191 @param [in] Count Number of elements in Array.
192 @param [in] ElementSize Size of an element in bytes
193 @param [in] EqualTestFunction The function to call to check if any two
194 elements are equal.
195
196 @retval TRUE A duplicate element was found or one of
197 the input arguments is invalid.
198 @retval FALSE Every element in Array is unique.
199 **/
200 BOOLEAN
201 EFIAPI
FindDuplicateValue(IN CONST VOID * Array,IN CONST UINTN Count,IN CONST UINTN ElementSize,IN PFN_IS_EQUAL EqualTestFunction)202 FindDuplicateValue (
203 IN CONST VOID * Array,
204 IN CONST UINTN Count,
205 IN CONST UINTN ElementSize,
206 IN PFN_IS_EQUAL EqualTestFunction
207 )
208 {
209 UINTN Index1;
210 UINTN Index2;
211 UINT8 * Element1;
212 UINT8 * Element2;
213
214 if (Array == NULL) {
215 DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: Array is NULL.\n"));
216 return TRUE;
217 }
218
219 if (ElementSize == 0) {
220 DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: ElementSize is 0.\n"));
221 return TRUE;
222 }
223
224 if (EqualTestFunction == NULL) {
225 DEBUG ((
226 DEBUG_ERROR,
227 "ERROR: FindDuplicateValues: EqualTestFunction is NULL.\n"
228 ));
229 return TRUE;
230 }
231
232 if (Count < 2) {
233 return FALSE;
234 }
235
236 for (Index1 = 0; Index1 < Count - 1; Index1++) {
237 for (Index2 = Index1 + 1; Index2 < Count; Index2++) {
238 Element1 = (UINT8*)Array + (Index1 * ElementSize);
239 Element2 = (UINT8*)Array + (Index2 * ElementSize);
240
241 if (EqualTestFunction (Element1, Element2, Index1, Index2)) {
242 return TRUE;
243 }
244 }
245 }
246 return FALSE;
247 }
248
249 /** Convert a hex number to its ASCII code.
250
251 @param [in] x Hex number to convert.
252 Must be 0 <= x < 16.
253
254 @return The ASCII code corresponding to x.
255 **/
256 UINT8
257 EFIAPI
AsciiFromHex(IN UINT8 x)258 AsciiFromHex (
259 IN UINT8 x
260 )
261 {
262 if (x < 10) {
263 return (UINT8)(x + '0');
264 }
265
266 if (x < 16) {
267 return (UINT8)(x - 10 + 'A');
268 }
269
270 ASSERT (FALSE);
271 return (UINT8)0;
272 }
273