]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c
DynamicTablesPkg: Fix order of assert checks
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtSerialPortLibArm / SsdtSerialPortGenerator.c
CommitLineData
5b035def
PG
1/** @file\r
2 SSDT Serial Port Table Generator.\r
3\r
4 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <IndustryStandard/DebugPort2Table.h>\r
10#include <Library/AcpiLib.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Library/UefiBootServicesTableLib.h>\r
16#include <Protocol/AcpiTable.h>\r
17\r
18// Module specific include files.\r
19#include <AcpiTableGenerator.h>\r
20#include <ConfigurationManagerObject.h>\r
21#include <ConfigurationManagerHelper.h>\r
22#include <Library/SsdtSerialPortFixupLib.h>\r
23#include <Library/TableHelperLib.h>\r
24#include <Protocol/ConfigurationManagerProtocol.h>\r
25\r
26/** ARM standard SSDT Serial Port Table Generator\r
27\r
28 Constructs SSDT tables describing serial ports (other than the serial ports\r
29 used by the SPCR or DBG2 tables).\r
30\r
31Requirements:\r
32 The following Configuration Manager Object(s) are required by\r
33 this Generator:\r
34 - EArmObjSerialPortInfo\r
35*/\r
36\r
37/** This macro expands to a function that retrieves the Serial-port\r
38 information from the Configuration Manager.\r
39*/\r
40GET_OBJECT_LIST (\r
41 EObjNameSpaceArm,\r
42 EArmObjSerialPortInfo,\r
43 CM_ARM_SERIAL_PORT_INFO\r
44 );\r
45\r
46/** Starting value for the UID to represent the serial ports.\r
47 Note: The UID 0 and 1 are reserved for use by DBG2 port and SPCR\r
48 respectively. So, the UIDs for serial ports for general use\r
49 start at 2.\r
50*/\r
51#define SERIAL_PORT_START_UID 2\r
52\r
53/** Maximum serial ports supported by this generator.\r
54 This generator supports a maximum of 14 (16 - 2) serial ports.\r
55 The -2 here reflects the reservation for serial ports for the DBG2\r
56 and SPCR ports regardless of whether the DBG2 or SPCR port is enabled.\r
57 Note: This is not a hard limitation and can be extended if needed.\r
58 Corresponding changes would be needed to support the Name and\r
59 UID fields describing the serial port.\r
60\r
61*/\r
62#define MAX_SERIAL_PORTS_SUPPORTED 14\r
63\r
64/** Free any resources allocated for constructing the tables.\r
65\r
66 @param [in] This Pointer to the ACPI table generator.\r
67 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
68 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
69 Protocol Interface.\r
70 @param [in, out] Table Pointer to an array of pointers\r
71 to ACPI Table(s).\r
72 @param [in] TableCount Number of ACPI table(s).\r
73\r
74 @retval EFI_SUCCESS The resources were freed successfully.\r
75 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
76**/\r
77STATIC\r
78EFI_STATUS\r
79EFIAPI\r
80FreeSsdtSerialPortTableEx (\r
81 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
82 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
83 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
84 IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,\r
85 IN CONST UINTN TableCount\r
86 )\r
87{\r
88 EFI_STATUS Status;\r
89 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
90 UINTN Index;\r
91\r
92 ASSERT (This != NULL);\r
653fb710
SM
93 ASSERT (AcpiTableInfo != NULL);\r
94 ASSERT (CfgMgrProtocol != NULL);\r
5b035def
PG
95 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
96 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
5b035def
PG
97\r
98 if ((Table == NULL) ||\r
99 (*Table == NULL) ||\r
100 (TableCount == 0)) {\r
101 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-SERIAL-PORT: Invalid Table Pointer\n"));\r
102 return EFI_INVALID_PARAMETER;\r
103 }\r
104\r
105 TableList = *Table;\r
106\r
107 for (Index = 0; Index < TableCount; Index++) {\r
108 if ((TableList[Index] != NULL) &&\r
109 (TableList[Index]->Signature ==\r
110 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {\r
111 Status = FreeSsdtSerialPortTable (TableList[Index]);\r
112 } else {\r
113 Status = EFI_INVALID_PARAMETER;\r
114 }\r
115\r
116 if (EFI_ERROR (Status)) {\r
117 DEBUG ((\r
118 DEBUG_ERROR,\r
119 "ERROR: SSDT-SERIAL-PORT: Could not free SSDT table at index %d."\r
120 " Status = %r\n",\r
121 Index,\r
122 Status\r
123 ));\r
124 return Status;\r
125 }\r
126 } //for\r
127\r
128 // Free the table list.\r
129 FreePool (*Table);\r
130\r
131 return EFI_SUCCESS;\r
132}\r
133\r
134/** Construct SSDT tables describing serial-ports.\r
135\r
136 This function invokes the Configuration Manager protocol interface\r
137 to get the required hardware information for generating the ACPI\r
138 table.\r
139\r
140 If this function allocates any resources then they must be freed\r
141 in the FreeXXXXTableResourcesEx function.\r
142\r
143 @param [in] This Pointer to the ACPI table generator.\r
144 @param [in] AcpiTableInfo Pointer to the ACPI table information.\r
145 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
146 Protocol interface.\r
147 @param [out] Table Pointer to a list of generated ACPI table(s).\r
148 @param [out] TableCount Number of generated ACPI table(s).\r
149\r
150 @retval EFI_SUCCESS Table generated successfully.\r
151 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
152 Manager is less than the Object size for\r
153 the requested object.\r
154 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
155 @retval EFI_NOT_FOUND Could not find information.\r
156 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
157 @retval EFI_UNSUPPORTED Unsupported configuration.\r
158**/\r
159STATIC\r
160EFI_STATUS\r
161EFIAPI\r
162BuildSsdtSerialPortTableEx (\r
163 IN CONST ACPI_TABLE_GENERATOR * This,\r
164 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
165 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
166 OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,\r
167 OUT UINTN * CONST TableCount\r
168 )\r
169{\r
170 EFI_STATUS Status;\r
171 CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;\r
172 UINT32 SerialPortCount;\r
173 UINTN Index;\r
174 CHAR8 NewName[] = "COMx";\r
175 UINT64 Uid;\r
176 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
177\r
178 ASSERT (This != NULL);\r
179 ASSERT (AcpiTableInfo != NULL);\r
180 ASSERT (CfgMgrProtocol != NULL);\r
181 ASSERT (Table != NULL);\r
182 ASSERT (TableCount != NULL);\r
183 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
184 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
185\r
186 *Table = NULL;\r
187\r
188 Status = GetEArmObjSerialPortInfo (\r
189 CfgMgrProtocol,\r
190 CM_NULL_TOKEN,\r
191 &SerialPortInfo,\r
192 &SerialPortCount\r
193 );\r
194 if (EFI_ERROR (Status)) {\r
195 DEBUG ((\r
196 DEBUG_ERROR,\r
197 "ERROR: SSDT-SERIAL-PORT: Failed to get serial port information."\r
198 " Status = %r\n",\r
199 Status\r
200 ));\r
201 return Status;\r
202 }\r
203\r
204 if (SerialPortCount > MAX_SERIAL_PORTS_SUPPORTED) {\r
205 DEBUG ((\r
206 DEBUG_ERROR,\r
207 "ERROR: SSDT-SERIAL-PORT: Too many serial ports: %d."\r
208 " Maximum serial ports supported = %d.\n",\r
209 SerialPortCount,\r
210 MAX_SERIAL_PORTS_SUPPORTED\r
211 ));\r
212 return EFI_INVALID_PARAMETER;\r
213 }\r
214\r
215 // Validate the SerialPort info.\r
216 Status = ValidateSerialPortInfo (SerialPortInfo, SerialPortCount);\r
217 if (EFI_ERROR (Status)) {\r
218 DEBUG ((\r
219 DEBUG_ERROR,\r
220 "ERROR: SSDT-SERIAL-PORT: Invalid serial port information. Status = %r\n",\r
221 Status\r
222 ));\r
223 return Status;\r
224 }\r
225\r
226 // Allocate a table to store pointers to the SSDT tables.\r
227 TableList = (EFI_ACPI_DESCRIPTION_HEADER**)\r
228 AllocateZeroPool (\r
229 (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * SerialPortCount)\r
230 );\r
231 if (TableList == NULL) {\r
232 Status = EFI_OUT_OF_RESOURCES;\r
233 DEBUG ((\r
234 DEBUG_ERROR,\r
235 "ERROR: SSDT-SERIAL-PORT: Failed to allocate memory for Table List."\r
236 " Status = %r\n",\r
237 Status\r
238 ));\r
239 return Status;\r
240 }\r
241\r
242 // Setup the table list early so that that appropriate cleanup\r
243 // can be done in case of failure.\r
244 *Table = TableList;\r
245\r
246 for (Index = 0; Index < SerialPortCount; Index++) {\r
247 Uid = SERIAL_PORT_START_UID + Index;\r
248 NewName[3] = AsciiFromHex ((UINT8)(Uid));\r
249\r
250 // Build a SSDT table describing the serial port.\r
251 Status = BuildSsdtSerialPortTable (\r
252 AcpiTableInfo,\r
253 &SerialPortInfo[Index],\r
254 NewName,\r
255 Uid,\r
256 &TableList[Index]\r
257 );\r
258 if (EFI_ERROR (Status)) {\r
259 DEBUG ((\r
260 DEBUG_ERROR,\r
261 "ERROR: SSDT-SERIAL-PORT: Failed to build associated SSDT table."\r
262 " Status = %r\n",\r
263 Status\r
264 ));\r
265 goto error_handler;\r
266 }\r
267\r
268 // Increment the table count here so that appropriate cleanup\r
269 // can be done in case of failure.\r
270 *TableCount += 1;\r
271 } // for\r
272\r
273error_handler:\r
274 // Note: Table list and Serial port count has been setup. The\r
275 // error handler does nothing here as the framework will invoke\r
276 // FreeSsdtSerialPortTableEx() even on failure.\r
277 return Status;\r
278}\r
279\r
280/** This macro defines the SSDT Serial Port Table Generator revision.\r
281*/\r
282#define SSDT_SERIAL_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
283\r
284/** The interface for the SSDT Serial Port Table Generator.\r
285*/\r
286STATIC\r
287CONST\r
288ACPI_TABLE_GENERATOR SsdtSerialPortGenerator = {\r
289 // Generator ID\r
290 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtSerialPort),\r
291 // Generator Description\r
292 L"ACPI.STD.SSDT.SERIAL.PORT.GENERATOR",\r
293 // ACPI Table Signature\r
294 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,\r
295 // ACPI Table Revision - Unused\r
296 0,\r
297 // Minimum ACPI Table Revision - Unused\r
298 0,\r
299 // Creator ID\r
300 TABLE_GENERATOR_CREATOR_ID_ARM,\r
301 // Creator Revision\r
302 SSDT_SERIAL_GENERATOR_REVISION,\r
303 // Build table function. Use the extended version instead.\r
304 NULL,\r
305 // Free table function. Use the extended version instead.\r
306 NULL,\r
307 // Extended Build table function.\r
308 BuildSsdtSerialPortTableEx,\r
309 // Extended free function.\r
310 FreeSsdtSerialPortTableEx\r
311};\r
312\r
313/** Register the Generator with the ACPI Table Factory.\r
314\r
315 @param [in] ImageHandle The handle to the image.\r
316 @param [in] SystemTable Pointer to the System Table.\r
317\r
318 @retval EFI_SUCCESS The Generator is registered.\r
319 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
320 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
321 is already registered.\r
322**/\r
323EFI_STATUS\r
324EFIAPI\r
325AcpiSsdtSerialPortLibConstructor (\r
326 IN EFI_HANDLE ImageHandle,\r
327 IN EFI_SYSTEM_TABLE * SystemTable\r
328 )\r
329{\r
330 EFI_STATUS Status;\r
331 Status = RegisterAcpiTableGenerator (&SsdtSerialPortGenerator);\r
332 DEBUG ((\r
333 DEBUG_INFO,\r
334 "SSDT-SERIAL-PORT: Register Generator. Status = %r\n",\r
335 Status\r
336 ));\r
337 ASSERT_EFI_ERROR (Status);\r
338\r
339 return Status;\r
340}\r
341\r
342/** Deregister the Generator from the ACPI Table Factory.\r
343\r
344 @param [in] ImageHandle The handle to the image.\r
345 @param [in] SystemTable Pointer to the System Table.\r
346\r
347 @retval EFI_SUCCESS The Generator is deregistered.\r
348 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
349 @retval EFI_NOT_FOUND The Generator is not registered.\r
350**/\r
351EFI_STATUS\r
352EFIAPI\r
353AcpiSsdtSerialPortLibDestructor (\r
354 IN EFI_HANDLE ImageHandle,\r
355 IN EFI_SYSTEM_TABLE * SystemTable\r
356 )\r
357{\r
358 EFI_STATUS Status;\r
359 Status = DeregisterAcpiTableGenerator (&SsdtSerialPortGenerator);\r
360 DEBUG ((\r
361 DEBUG_INFO,\r
362 "SSDT-SERIAL-PORT: Deregister Generator. Status = %r\n",\r
363 Status\r
364 ));\r
365 ASSERT_EFI_ERROR (Status);\r
366 return Status;\r
367}\r