TianoCore EDK2 master
Loading...
Searching...
No Matches
SsdtSerialPortFixupLib.c
Go to the documentation of this file.
1
18#include <Library/AcpiLib.h>
19#include <Library/BaseLib.h>
21#include <Library/DebugLib.h>
23#include <Protocol/AcpiTable.h>
24
25// Module specific include files.
26#include <AcpiTableGenerator.h>
32
33#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
35#endif
36
42
45#define MIN_UART_ADDRESS_LENGTH 0x1000U
46
56EFIAPI
58 IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfoTable,
59 IN UINT32 SerialPortCount
60 )
61{
62 UINT32 Index;
64
65 if ((SerialPortInfoTable == NULL) ||
66 (SerialPortCount == 0))
67 {
68 ASSERT (0);
69 return EFI_INVALID_PARAMETER;
70 }
71
72 for (Index = 0; Index < SerialPortCount; Index++) {
73 SerialPortInfo = &SerialPortInfoTable[Index];
74 ASSERT (SerialPortInfo != NULL);
75
76 if ((SerialPortInfo == NULL) ||
77 (SerialPortInfo->BaseAddress == 0))
78 {
79 DEBUG ((
80 DEBUG_ERROR,
81 "ERROR: UART port base address is invalid. BaseAddress = 0x%llx\n",
82 SerialPortInfo->BaseAddress
83 ));
84 return EFI_INVALID_PARAMETER;
85 }
86
87 if ((SerialPortInfo->PortSubtype !=
88 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&
89 (SerialPortInfo->PortSubtype !=
90 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X) &&
91 (SerialPortInfo->PortSubtype !=
92 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART) &&
93 (SerialPortInfo->PortSubtype !=
94 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC) &&
95 (SerialPortInfo->PortSubtype !=
96 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) &&
97 (SerialPortInfo->PortSubtype !=
98 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS))
99 {
100 DEBUG ((
101 DEBUG_ERROR,
102 "ERROR: UART port subtype is invalid."
103 " UART Base = 0x%llx, PortSubtype = 0x%x\n",
104 SerialPortInfo->BaseAddress,
105 SerialPortInfo->PortSubtype
106 ));
107 return EFI_INVALID_PARAMETER;
108 }
109
110 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
111 // If an interrupt is not wired to the serial port, the Configuration
112 // Manager specifies the interrupt as 0.
113 // Any other value must be within the SPI or extended SPI range.
114 if ((SerialPortInfo->Interrupt != 0) &&
115 !(((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_SPI_MIN) &&
116 (SerialPortInfo->Interrupt <= ARM_GIC_ARCH_SPI_MAX)) ||
117 ((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_EXT_SPI_MIN) &&
118 (SerialPortInfo->Interrupt <= ARM_GIC_ARCH_EXT_SPI_MAX))))
119 {
120 DEBUG ((
121 DEBUG_ERROR,
122 "ERROR: Invalid UART port interrupt ID. Interrupt = %lu\n",
123 SerialPortInfo->Interrupt
124 ));
125 return EFI_INVALID_PARAMETER;
126 }
127
128 #endif
129
130 DEBUG ((DEBUG_INFO, "UART Configuration:\n"));
131 DEBUG ((
132 DEBUG_INFO,
133 " UART Base = 0x%llx\n",
134 SerialPortInfo->BaseAddress
135 ));
136 DEBUG ((
137 DEBUG_INFO,
138 " Length = 0x%llx\n",
139 SerialPortInfo->BaseAddressLength
140 ));
141 DEBUG ((DEBUG_INFO, " Clock = %lu\n", SerialPortInfo->Clock));
142 DEBUG ((DEBUG_INFO, " BaudRate = %llu\n", SerialPortInfo->BaudRate));
143 DEBUG ((DEBUG_INFO, " Interrupt = %lu\n", SerialPortInfo->Interrupt));
144 } // for
145
146 return EFI_SUCCESS;
147}
148
162STATIC
164EFIAPI
166 IN AML_ROOT_NODE_HANDLE RootNodeHandle,
167 IN CONST UINT64 Uid,
169 )
170{
171 EFI_STATUS Status;
172 AML_OBJECT_NODE_HANDLE NameOpIdNode;
173 CONST CHAR8 *HidString;
174 CONST CHAR8 *CidString;
175 CONST CHAR8 *NonBsaHid;
176
177 // Get the _CID and _HID value to write.
178 switch (SerialPortInfo->PortSubtype) {
179 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550:
180 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS:
181 {
182 // If there is a non-BSA compliant HID, use that.
183 NonBsaHid = (CONST CHAR8 *)PcdGetPtr (PcdNonBsaCompliant16550SerialHid);
184 if ((NonBsaHid != NULL) && (AsciiStrLen (NonBsaHid) != 0)) {
185 if (!(IsValidPnpId (NonBsaHid) || IsValidAcpiId (NonBsaHid))) {
186 return EFI_INVALID_PARAMETER;
187 }
188
189 HidString = NonBsaHid;
190 CidString = "";
191 } else {
192 HidString = "PNP0501";
193 CidString = "PNP0500";
194 }
195
196 break;
197 }
198 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART:
199 {
200 HidString = "ARMH0011";
201 CidString = "ARMHB000";
202 break;
203 }
204 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART:
205 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X:
206 {
207 HidString = "ARMHB000";
208 CidString = "";
209 break;
210 }
211 default:
212 {
213 return EFI_INVALID_PARAMETER;
214 }
215 } // switch
216
217 // Get the _UID NameOp object defined by the "Name ()" statement,
218 // and update its value.
219 Status = AmlFindNode (
220 RootNodeHandle,
221 "\\_SB_.COM0._UID",
222 &NameOpIdNode
223 );
224 if (EFI_ERROR (Status)) {
225 return Status;
226 }
227
228 Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
229 if (EFI_ERROR (Status)) {
230 return Status;
231 }
232
233 // Get the _HID NameOp object defined by the "Name ()" statement,
234 // and update its value.
235 Status = AmlFindNode (
236 RootNodeHandle,
237 "\\_SB_.COM0._HID",
238 &NameOpIdNode
239 );
240 if (EFI_ERROR (Status)) {
241 return Status;
242 }
243
244 Status = AmlNameOpUpdateString (NameOpIdNode, HidString);
245 if (EFI_ERROR (Status)) {
246 return Status;
247 }
248
249 // Get the _CID NameOp object defined by the "Name ()" statement,
250 // and update its value.
251 Status = AmlFindNode (
252 RootNodeHandle,
253 "\\_SB_.COM0._CID",
254 &NameOpIdNode
255 );
256 if (EFI_ERROR (Status)) {
257 return Status;
258 }
259
260 // If we have a CID then update a _CID node else delete the node.
261 if (AsciiStrLen (CidString) != 0) {
262 Status = AmlNameOpUpdateString (NameOpIdNode, CidString);
263 } else {
264 // First detach the node from the tree.
265 Status = AmlDetachNode (NameOpIdNode);
266 if (EFI_ERROR (Status)) {
267 return Status;
268 }
269
270 // Delete the detached node.
271 Status = AmlDeleteTree (NameOpIdNode);
272 }
273
274 return Status;
275}
276
289STATIC
291EFIAPI
293 IN AML_ROOT_NODE_HANDLE RootNodeHandle,
295 )
296{
297 EFI_STATUS Status;
298 AML_OBJECT_NODE_HANDLE NameOpCrsNode;
299 AML_DATA_NODE_HANDLE QWordRdNode;
300
301 // Get the "_CRS" object defined by the "Name ()" statement.
302 Status = AmlFindNode (
303 RootNodeHandle,
304 "\\_SB_.COM0._CRS",
305 &NameOpCrsNode
306 );
307 if (EFI_ERROR (Status)) {
308 return Status;
309 }
310
311 // Get the first Rd node in the "_CRS" object.
312 Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &QWordRdNode);
313 if (EFI_ERROR (Status)) {
314 return Status;
315 }
316
317 if (QWordRdNode == NULL) {
318 return EFI_INVALID_PARAMETER;
319 }
320
321 // Update the Serial Port base address and length.
322 Status = AmlUpdateRdQWord (
323 QWordRdNode,
324 SerialPortInfo->BaseAddress,
325 ((SerialPortInfo->BaseAddressLength < MIN_UART_ADDRESS_LENGTH) ?
326 MIN_UART_ADDRESS_LENGTH : SerialPortInfo->BaseAddressLength)
327 );
328 if (EFI_ERROR (Status)) {
329 return Status;
330 }
331
332 // Generate an interrupt node as the second Resource Data element in the
333 // NameOpCrsNode, if the interrupt for the serial-port is a valid SPI from
334 // Table 2-1 in Arm Generic Interrupt Controller Architecture Specification.
335 Status = AmlCodeGenRdInterrupt (
336 TRUE, // Resource Consumer
337 FALSE, // Level Triggered
338 FALSE, // Active High
339 FALSE, // Exclusive
340 (UINT32 *)&SerialPortInfo->Interrupt,
341 1,
342 NameOpCrsNode,
343 NULL
344 );
345 ASSERT_EFI_ERROR (Status);
346
347 return Status;
348}
349
365STATIC
367EFIAPI
369 IN AML_ROOT_NODE_HANDLE RootNodeHandle,
371 IN CONST CHAR8 *Name
372 )
373{
374 EFI_STATUS Status;
375 AML_OBJECT_NODE_HANDLE DeviceNode;
376
377 // Get the COM0 variable defined by the "Device ()" statement.
378 Status = AmlFindNode (RootNodeHandle, "\\_SB_.COM0", &DeviceNode);
379 if (EFI_ERROR (Status)) {
380 return Status;
381 }
382
383 // Update the Device's name.
384 return AmlDeviceOpUpdateName (DeviceNode, Name);
385}
386
409STATIC
411EFIAPI
413 IN AML_ROOT_NODE_HANDLE RootNodeHandle,
415 IN CONST CHAR8 *Name,
416 IN CONST UINT64 Uid,
418 )
419{
420 EFI_STATUS Status;
421
422 ASSERT (RootNodeHandle != NULL);
423 ASSERT (SerialPortInfo != NULL);
424 ASSERT (Name != NULL);
425 ASSERT (Table != NULL);
426
427 // Fixup the _UID, _HID and _CID values.
428 Status = FixupIds (RootNodeHandle, Uid, SerialPortInfo);
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 // Fixup the _CRS values.
434 Status = FixupCrs (RootNodeHandle, SerialPortInfo);
435 if (EFI_ERROR (Status)) {
436 return Status;
437 }
438
439 // Fixup the serial-port name.
440 // This MUST be done at the end, otherwise AML paths won't be valid anymore.
441 return FixupName (RootNodeHandle, SerialPortInfo, Name);
442}
443
453EFIAPI
456 )
457{
458 ASSERT (Table != NULL);
459 FreePool (Table);
460 return EFI_SUCCESS;
461}
462
481EFIAPI
483 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *AcpiTableInfo,
485 IN CONST CHAR8 *Name,
486 IN CONST UINT64 Uid,
488 )
489{
490 EFI_STATUS Status;
491 EFI_STATUS Status1;
492 AML_ROOT_NODE_HANDLE RootNodeHandle;
493
494 ASSERT (AcpiTableInfo != NULL);
495 ASSERT (SerialPortInfo != NULL);
496 ASSERT (Name != NULL);
497 ASSERT (Table != NULL);
498
499 // Validate the Serial Port Info.
500 Status = ValidateSerialPortInfo (SerialPortInfo, 1);
501 if (EFI_ERROR (Status)) {
502 return Status;
503 }
504
505 // Parse the SSDT Serial Port Template.
506 Status = AmlParseDefinitionBlock (
508 &RootNodeHandle
509 );
510 if (EFI_ERROR (Status)) {
511 DEBUG ((
512 DEBUG_ERROR,
513 "ERROR: SSDT-SERIAL-PORT-FIXUP:"
514 " Failed to parse SSDT Serial Port Template. Status = %r\n",
515 Status
516 ));
517 return Status;
518 }
519
520 // Fixup the template values.
521 Status = FixupSerialPortInfo (
522 RootNodeHandle,
523 SerialPortInfo,
524 Name,
525 Uid,
526 Table
527 );
528 if (EFI_ERROR (Status)) {
529 DEBUG ((
530 DEBUG_ERROR,
531 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to fixup SSDT Serial Port Table."
532 " Status = %r\n",
533 Status
534 ));
535 goto exit_handler;
536 }
537
538 // Serialize the tree.
540 RootNodeHandle,
541 Table
542 );
543 if (EFI_ERROR (Status)) {
544 DEBUG ((
545 DEBUG_ERROR,
546 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to Serialize SSDT Table Data."
547 " Status = %r\n",
548 Status
549 ));
550 }
551
552exit_handler:
553 // Cleanup
554 if (RootNodeHandle != NULL) {
555 Status1 = AmlDeleteTree (RootNodeHandle);
556 if (EFI_ERROR (Status1)) {
557 DEBUG ((
558 DEBUG_ERROR,
559 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to cleanup AML tree."
560 " Status = %r\n",
561 Status1
562 ));
563 // If Status was success but we failed to delete the AML Tree
564 // return Status1 else return the original error code, i.e. Status.
565 if (!EFI_ERROR (Status)) {
566 return Status1;
567 }
568 }
569 }
570
571 return Status;
572}
BOOLEAN IsValidAcpiId(IN CONST CHAR8 *Hid)
Definition: AcpiHelper.c:115
BOOLEAN IsValidPnpId(IN CONST CHAR8 *Hid)
Definition: AcpiHelper.c:80
void * AML_ROOT_NODE_HANDLE
Definition: AmlLib.h:51
void * AML_DATA_NODE_HANDLE
Definition: AmlLib.h:59
EFI_STATUS EFIAPI AmlCodeGenRdInterrupt(IN BOOLEAN ResourceConsumer, IN BOOLEAN EdgeTriggered, IN BOOLEAN ActiveLow, IN BOOLEAN Shared, IN UINT32 *IrqList, IN UINT8 IrqCount, IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL, OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL)
void * AML_OBJECT_NODE_HANDLE
Definition: AmlLib.h:55
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGetPtr(TokenName)
Definition: PcdLib.h:388
STATIC EFI_STATUS EFIAPI FixupIds(IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST UINT64 Uid, IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo)
CHAR8 ssdtserialporttemplate_aml_code[]
EFI_STATUS EFIAPI ValidateSerialPortInfo(IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfoTable, IN UINT32 SerialPortCount)
STATIC EFI_STATUS EFIAPI FixupName(IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo, IN CONST CHAR8 *Name)
STATIC EFI_STATUS EFIAPI FixupSerialPortInfo(IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo, IN CONST CHAR8 *Name, IN CONST UINT64 Uid, OUT EFI_ACPI_DESCRIPTION_HEADER **Table)
STATIC EFI_STATUS EFIAPI FixupCrs(IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo)
#define MIN_UART_ADDRESS_LENGTH
EFI_STATUS EFIAPI FreeSsdtSerialPortTable(IN EFI_ACPI_DESCRIPTION_HEADER *Table)
EFI_STATUS EFIAPI BuildSsdtSerialPortTable(IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *AcpiTableInfo, IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo, IN CONST CHAR8 *Name, IN CONST UINT64 Uid, OUT EFI_ACPI_DESCRIPTION_HEADER **Table)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS EFIAPI AmlFindNode(IN AML_NODE_HANDLE ReferenceNode, IN CONST CHAR8 *AslPath, OUT AML_NODE_HANDLE *OutNode)
EFI_STATUS EFIAPI AmlDeleteTree(IN AML_NODE_HANDLE Node)
EFI_STATUS EFIAPI AmlUpdateRdQWord(IN AML_DATA_NODE_HANDLE QWordRdNode, IN UINT64 BaseAddress, IN UINT64 BaseAddressLength)
EFI_STATUS EFIAPI AmlParseDefinitionBlock(IN CONST EFI_ACPI_DESCRIPTION_HEADER *DefinitionBlock, OUT AML_ROOT_NODE_HANDLE *RootPtr)
EFI_STATUS EFIAPI AmlNameOpGetFirstRdNode(IN AML_OBJECT_NODE_HANDLE NameOpNode, OUT AML_DATA_NODE_HANDLE *OutRdNode)
Definition: AmlApi.c:259
EFI_STATUS EFIAPI AmlDeviceOpUpdateName(IN AML_OBJECT_NODE_HANDLE DeviceOpNode, IN CONST CHAR8 *NewNameString)
Definition: AmlApi.c:41
EFI_STATUS EFIAPI AmlNameOpUpdateInteger(IN AML_OBJECT_NODE_HANDLE NameOpNode, IN UINT64 NewInt)
Definition: AmlApi.c:119
EFI_STATUS EFIAPI AmlNameOpUpdateString(IN AML_OBJECT_NODE_HANDLE NameOpNode, IN CONST CHAR8 *NewName)
Definition: AmlApi.c:176
EFI_STATUS EFIAPI AmlDetachNode(IN AML_NODE_HANDLE Node)
EFI_STATUS EFIAPI AmlSerializeDefinitionBlock(IN AML_ROOT_NODE_HANDLE RootNode, OUT EFI_ACPI_DESCRIPTION_HEADER **Table)