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