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