]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
DynamicTablesPkg: Add SSDT Serial port for SPCR
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSpcrLibArm / SpcrGenerator.c
1 /** @file
2 SPCR Table Generator
3
4 Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Reference(s):
9 - Microsoft Serial Port Console Redirection Table
10 Specification - Version 1.03 - August 10, 2015.
11
12 **/
13
14 #include <IndustryStandard/DebugPort2Table.h>
15 #include <IndustryStandard/SerialPortConsoleRedirectionTable.h>
16 #include <Library/AcpiLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Protocol/AcpiTable.h>
20
21 // Module specific include files.
22 #include <AcpiTableGenerator.h>
23 #include <ConfigurationManagerObject.h>
24 #include <ConfigurationManagerHelper.h>
25 #include <Library/SsdtSerialPortFixupLib.h>
26 #include <Library/TableHelperLib.h>
27 #include <Protocol/ConfigurationManagerProtocol.h>
28
29 /** ARM standard SPCR Table Generator
30
31 Constructs the SPCR table for PL011 or SBSA UART peripherals.
32
33 Requirements:
34 The following Configuration Manager Object(s) are required by
35 this Generator:
36 - EArmObjSerialConsolePortInfo
37
38 NOTE: This implementation ignores the possibility that the Serial settings may
39 be modified from the UEFI Shell. A more complex handler would be needed
40 to (e.g.) recover serial port settings from the UART, or non-volatile
41 storage.
42 */
43
44 #pragma pack(1)
45
46 /** A string representing the name of the SPCR port.
47 */
48 #define NAME_STR_SPCR_PORT "COM1"
49
50 /** An UID representing the SPCR port.
51 */
52 #define UID_SPCR_PORT 1
53
54 /** This macro defines the no flow control option.
55 */
56 #define SPCR_FLOW_CONTROL_NONE 0
57
58 /**A template for generating the SPCR Table.
59
60 Note: fields marked "{Template}" will be updated dynamically.
61 */
62 STATIC
63 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE AcpiSpcr = {
64 ACPI_HEADER (
65 EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE,
66 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE,
67 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION
68 ),
69 0, // {Template}: Serial Port Subtype
70 {
71 EFI_ACPI_RESERVED_BYTE,
72 EFI_ACPI_RESERVED_BYTE,
73 EFI_ACPI_RESERVED_BYTE
74 },
75 ARM_GAS32 (0), // {Template}: Serial Port Base Address
76 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC,
77 0, // Not used on ARM
78 0, // {Template}: Serial Port Interrupt
79 0, // {Template}: Serial Port Baudrate
80 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_PARITY_NO_PARITY,
81 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1,
82 SPCR_FLOW_CONTROL_NONE,
83 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_ANSI,
84 EFI_ACPI_RESERVED_BYTE,
85 0xFFFF,
86 0xFFFF,
87 0x00,
88 0x00,
89 0x00,
90 0x00000000,
91 0x00,
92 EFI_ACPI_RESERVED_DWORD
93 };
94
95 #pragma pack()
96
97 /** This macro expands to a function that retrieves the Serial
98 Port Information from the Configuration Manager.
99 */
100 GET_OBJECT_LIST (
101 EObjNameSpaceArm,
102 EArmObjSerialConsolePortInfo,
103 CM_ARM_SERIAL_PORT_INFO
104 )
105
106 /** Free any resources allocated for constructing the tables.
107
108 @param [in] This Pointer to the ACPI table generator.
109 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
110 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
111 Protocol Interface.
112 @param [in, out] Table Pointer to an array of pointers
113 to ACPI Table(s).
114 @param [in] TableCount Number of ACPI table(s).
115
116 @retval EFI_SUCCESS The resources were freed successfully.
117 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
118 **/
119 STATIC
120 EFI_STATUS
121 EFIAPI
122 FreeSpcrTableEx (
123 IN CONST ACPI_TABLE_GENERATOR * CONST This,
124 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
125 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
126 IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
127 IN CONST UINTN TableCount
128 )
129 {
130 EFI_STATUS Status;
131 EFI_ACPI_DESCRIPTION_HEADER ** TableList;
132
133 ASSERT (This != NULL);
134 ASSERT (AcpiTableInfo != NULL);
135 ASSERT (CfgMgrProtocol != NULL);
136 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
137 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
138
139 if ((Table == NULL) ||
140 (*Table == NULL) ||
141 (TableCount != 2)) {
142 DEBUG ((DEBUG_ERROR, "ERROR: SPCR: Invalid Table Pointer\n"));
143 return EFI_INVALID_PARAMETER;
144 }
145
146 TableList = *Table;
147
148 if ((TableList[1] == NULL) ||
149 (TableList[1]->Signature !=
150 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
151 DEBUG ((DEBUG_ERROR, "ERROR: SPCR: Invalid SSDT table pointer.\n"));
152 return EFI_INVALID_PARAMETER;
153 }
154
155 // Only need to free the SSDT table at index 1. The SPCR table is static.
156 Status = FreeSsdtSerialPortTable (TableList[1]);
157 ASSERT_EFI_ERROR (Status);
158
159 // Free the table list.
160 FreePool (*Table);
161
162 return Status;
163 }
164
165 /** Construct the SPCR ACPI table and its associated SSDT table.
166
167 This function invokes the Configuration Manager protocol interface
168 to get the required hardware information for generating the ACPI
169 table.
170
171 If this function allocates any resources then they must be freed
172 in the FreeXXXXTableResourcesEx function.
173
174 @param [in] This Pointer to the ACPI table generator.
175 @param [in] AcpiTableInfo Pointer to the ACPI table information.
176 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
177 Protocol interface.
178 @param [out] Table Pointer to a list of generated ACPI table(s).
179 @param [out] TableCount Number of generated ACPI table(s).
180
181 @retval EFI_SUCCESS Table generated successfully.
182 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
183 Manager is less than the Object size for
184 the requested object.
185 @retval EFI_INVALID_PARAMETER A parameter is invalid.
186 @retval EFI_NOT_FOUND Could not find information.
187 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
188 @retval EFI_UNSUPPORTED Unsupported configuration.
189 **/
190 STATIC
191 EFI_STATUS
192 EFIAPI
193 BuildSpcrTableEx (
194 IN CONST ACPI_TABLE_GENERATOR * This,
195 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
196 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
197 OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
198 OUT UINTN * CONST TableCount
199 )
200 {
201 EFI_STATUS Status;
202 CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;
203 UINT32 SerialPortCount;
204 EFI_ACPI_DESCRIPTION_HEADER ** TableList;
205
206 ASSERT (This != NULL);
207 ASSERT (AcpiTableInfo != NULL);
208 ASSERT (CfgMgrProtocol != NULL);
209 ASSERT (Table != NULL);
210 ASSERT (TableCount != NULL);
211 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
212 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
213
214 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
215 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
216 DEBUG ((
217 DEBUG_ERROR,
218 "ERROR: SPCR: Requested table revision = %d, is not supported."
219 "Supported table revision: Minimum = %d, Maximum = %d\n",
220 AcpiTableInfo->AcpiTableRevision,
221 This->MinAcpiTableRevision,
222 This->AcpiTableRevision
223 ));
224 return EFI_INVALID_PARAMETER;
225 }
226
227 *Table = NULL;
228
229 Status = GetEArmObjSerialConsolePortInfo (
230 CfgMgrProtocol,
231 CM_NULL_TOKEN,
232 &SerialPortInfo,
233 &SerialPortCount
234 );
235 if (EFI_ERROR (Status)) {
236 DEBUG ((
237 DEBUG_ERROR,
238 "ERROR: SPCR: Failed to get serial port information. Status = %r\n",
239 Status
240 ));
241 return Status;
242 }
243
244 if (SerialPortCount == 0) {
245 DEBUG ((
246 DEBUG_ERROR,
247 "ERROR: SPCR: Serial port information not found. Status = %r\n",
248 EFI_NOT_FOUND
249 ));
250 return EFI_NOT_FOUND;
251 }
252
253 // Validate the SerialPort info. Only one SPCR port can be described.
254 // If platform provides description for multiple SPCR ports, use the
255 // first SPCR port information.
256 Status = ValidateSerialPortInfo (SerialPortInfo, 1);
257 if (EFI_ERROR (Status)) {
258 DEBUG ((
259 DEBUG_ERROR,
260 "ERROR: SPCR: Invalid serial port information. Status = %r\n",
261 Status
262 ));
263 return Status;
264 }
265
266 // Allocate a table to store pointers to the SPCR and SSDT tables.
267 TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
268 AllocateZeroPool (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * 2);
269 if (TableList == NULL) {
270 Status = EFI_OUT_OF_RESOURCES;
271 DEBUG ((
272 DEBUG_ERROR,
273 "ERROR: SPCR: Failed to allocate memory for Table List," \
274 " Status = %r\n",
275 Status
276 ));
277 return Status;
278 }
279
280 // Build SPCR table.
281 Status = AddAcpiHeader (
282 CfgMgrProtocol,
283 This,
284 (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr,
285 AcpiTableInfo,
286 sizeof (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE)
287 );
288 if (EFI_ERROR (Status)) {
289 DEBUG ((
290 DEBUG_ERROR,
291 "ERROR: SPCR: Failed to add ACPI header. Status = %r\n",
292 Status
293 ));
294 goto error_handler;
295 }
296
297 // The SPCR InterfaceType uses the same encoding as that of the
298 // DBG2 table Port Subtype field. However InterfaceType is 8-bit
299 // while the Port Subtype field in the DBG2 table is 16-bit.
300 if ((SerialPortInfo->PortSubtype & 0xFF00) != 0) {
301 Status = EFI_INVALID_PARAMETER;
302 DEBUG ((
303 DEBUG_ERROR,
304 "ERROR: SPCR: Invalid Port subtype (must be < 256). Status = %r\n",
305 Status
306 ));
307 goto error_handler;
308 }
309
310 // Update the serial port subtype
311 AcpiSpcr.InterfaceType = (UINT8)SerialPortInfo->PortSubtype;
312
313 // Update the base address
314 AcpiSpcr.BaseAddress.Address = SerialPortInfo->BaseAddress;
315
316 // Update the UART interrupt
317 AcpiSpcr.GlobalSystemInterrupt = SerialPortInfo->Interrupt;
318
319 switch (SerialPortInfo->BaudRate) {
320 case 9600:
321 AcpiSpcr.BaudRate =
322 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_9600;
323 break;
324 case 19200:
325 AcpiSpcr.BaudRate =
326 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_19200;
327 break;
328 case 57600:
329 AcpiSpcr.BaudRate =
330 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_57600;
331 break;
332 case 115200:
333 AcpiSpcr.BaudRate =
334 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_115200;
335 break;
336 default:
337 Status = EFI_UNSUPPORTED;
338 DEBUG ((
339 DEBUG_ERROR,
340 "ERROR: SPCR: Invalid Baud Rate %ld, Status = %r\n",
341 SerialPortInfo->BaudRate,
342 Status
343 ));
344 goto error_handler;
345 } // switch
346
347 TableList[0] = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr;
348
349 // Build a SSDT table describing the serial port.
350 Status = BuildSsdtSerialPortTable (
351 AcpiTableInfo,
352 SerialPortInfo,
353 NAME_STR_SPCR_PORT,
354 UID_SPCR_PORT,
355 &TableList[1]
356 );
357 if (EFI_ERROR (Status)) {
358 DEBUG ((
359 DEBUG_ERROR,
360 "ERROR: SPCR: Failed to build associated SSDT table. Status = %r\n",
361 Status
362 ));
363 goto error_handler;
364 }
365
366 *TableCount = 2;
367 *Table = TableList;
368
369 return Status;
370
371 error_handler:
372 if (TableList != NULL) {
373 FreePool (TableList);
374 }
375
376 return Status;
377 }
378
379 /** This macro defines the SPCR Table Generator revision.
380 */
381 #define SPCR_GENERATOR_REVISION CREATE_REVISION (1, 0)
382
383 /** The interface for the SPCR Table Generator.
384 */
385 STATIC
386 CONST
387 ACPI_TABLE_GENERATOR SpcrGenerator = {
388 // Generator ID
389 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSpcr),
390 // Generator Description
391 L"ACPI.STD.SPCR.GENERATOR",
392 // ACPI Table Signature
393 EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE,
394 // ACPI Table Revision supported by this Generator
395 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION,
396 // Minimum supported ACPI Table Revision
397 EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION,
398 // Creator ID
399 TABLE_GENERATOR_CREATOR_ID_ARM,
400 // Creator Revision
401 SPCR_GENERATOR_REVISION,
402 // Build table function. Use the extended version instead.
403 NULL,
404 // Free table function. Use the extended version instead.
405 NULL,
406 // Extended Build table function.
407 BuildSpcrTableEx,
408 // Extended free function.
409 FreeSpcrTableEx
410 };
411
412 /** Register the Generator with the ACPI Table Factory.
413
414 @param [in] ImageHandle The handle to the image.
415 @param [in] SystemTable Pointer to the System Table.
416
417 @retval EFI_SUCCESS The Generator is registered.
418 @retval EFI_INVALID_PARAMETER A parameter is invalid.
419 @retval EFI_ALREADY_STARTED The Generator for the Table ID
420 is already registered.
421 **/
422 EFI_STATUS
423 EFIAPI
424 AcpiSpcrLibConstructor (
425 IN EFI_HANDLE ImageHandle,
426 IN EFI_SYSTEM_TABLE * SystemTable
427 )
428 {
429 EFI_STATUS Status;
430 Status = RegisterAcpiTableGenerator (&SpcrGenerator);
431 DEBUG ((DEBUG_INFO, "SPCR: Register Generator. Status = %r\n", Status));
432 ASSERT_EFI_ERROR (Status);
433 return Status;
434 }
435
436 /** Deregister the Generator from the ACPI Table Factory.
437
438 @param [in] ImageHandle The handle to the image.
439 @param [in] SystemTable Pointer to the System Table.
440
441 @retval EFI_SUCCESS The Generator is deregistered.
442 @retval EFI_INVALID_PARAMETER A parameter is invalid.
443 @retval EFI_NOT_FOUND The Generator is not registered.
444 **/
445 EFI_STATUS
446 EFIAPI
447 AcpiSpcrLibDestructor (
448 IN EFI_HANDLE ImageHandle,
449 IN EFI_SYSTEM_TABLE * SystemTable
450 )
451 {
452 EFI_STATUS Status;
453 Status = DeregisterAcpiTableGenerator (&SpcrGenerator);
454 DEBUG ((DEBUG_INFO, "SPCR: Deregister Generator. Status = %r\n", Status));
455 ASSERT_EFI_ERROR (Status);
456 return Status;
457 }