]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
DynamicTablesPkg: Apply uncrustify changes
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / CodeGen / AmlResourceDataCodeGen.c
1 /** @file
2 AML Resource Data Code Generation.
3
4 Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Glossary:
9 - Rd or RD - Resource Data
10 - Rds or RDS - Resource Data Small
11 - Rdl or RDL - Resource Data Large
12 **/
13
14 #include <AmlNodeDefines.h>
15 #include <CodeGen/AmlResourceDataCodeGen.h>
16
17 #include <AmlCoreInterface.h>
18 #include <AmlDefines.h>
19 #include <Api/AmlApiHelper.h>
20 #include <Tree/AmlNode.h>
21 #include <ResourceData/AmlResourceData.h>
22
23 /** If ParentNode is not NULL, append RdNode.
24 If NewRdNode is not NULL, update its value to RdNode.
25
26 @param [in] RdNode Newly created Resource Data node.
27 RdNode is deleted if an error occurs.
28 @param [in] ParentNode If not NULL, ParentNode must:
29 - be a NameOp node, i.e. have the AML_NAME_OP
30 opcode (cf "Name ()" ASL statement)
31 - contain a list of resource data elements
32 (cf "ResourceTemplate ()" ASL statement)
33 RdNode is then added at the end of the variable
34 list of resource data elements, but before the
35 "End Tag" Resource Data.
36 @param [out] NewRdNode If not NULL:
37 - and Success, contains RdNode.
38 - and Error, reset to NULL.
39
40 @retval EFI_SUCCESS The function completed successfully.
41 @retval EFI_INVALID_PARAMETER Invalid parameter.
42 **/
43 STATIC
44 EFI_STATUS
45 EFIAPI
46 LinkRdNode (
47 IN AML_DATA_NODE *RdNode,
48 IN AML_OBJECT_NODE *ParentNode,
49 OUT AML_DATA_NODE **NewRdNode
50 )
51 {
52 EFI_STATUS Status;
53 EFI_STATUS Status1;
54 AML_OBJECT_NODE *BufferOpNode;
55
56 if (NewRdNode != NULL) {
57 *NewRdNode = NULL;
58 }
59
60 if (ParentNode != NULL) {
61 // Check this is a NameOp node.
62 if ((!AmlNodeHasOpCode (ParentNode, AML_NAME_OP, 0))) {
63 ASSERT (0);
64 Status = EFI_INVALID_PARAMETER;
65 goto error_handler;
66 }
67
68 // Get the value which is represented as a BufferOp object node
69 // which is the 2nd fixed argument (i.e. index 1).
70 BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
71 ParentNode,
72 EAmlParseIndexTerm1
73 );
74 if ((BufferOpNode == NULL) ||
75 (AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) ||
76 (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0)))
77 {
78 ASSERT (0);
79 Status = EFI_INVALID_PARAMETER;
80 goto error_handler;
81 }
82
83 // Add RdNode as the last element, but before the EndTag.
84 Status = AmlAppendRdNode (BufferOpNode, RdNode);
85 if (EFI_ERROR (Status)) {
86 ASSERT (0);
87 goto error_handler;
88 }
89 }
90
91 if (NewRdNode != NULL) {
92 *NewRdNode = RdNode;
93 }
94
95 return EFI_SUCCESS;
96
97 error_handler:
98 Status1 = AmlDeleteTree ((AML_NODE_HEADER *)RdNode);
99 ASSERT_EFI_ERROR (Status1);
100 // Return original error.
101 return Status;
102 }
103
104 /** Code generation for the "Interrupt ()" ASL function.
105
106 The Resource Data effectively created is an Extended Interrupt Resource
107 Data. Cf ACPI 6.4:
108 - s6.4.3.6 "Extended Interrupt Descriptor"
109 - s19.6.64 "Interrupt (Interrupt Resource Descriptor Macro)"
110
111 The created resource data node can be:
112 - appended to the list of resource data elements of the NameOpNode.
113 In such case NameOpNode must be defined by a the "Name ()" ASL statement
114 and initially contain a "ResourceTemplate ()".
115 - returned through the NewRdNode parameter.
116
117 @param [in] ResourceConsumer The device consumes the specified interrupt
118 or produces it for use by a child device.
119 @param [in] EdgeTriggered The interrupt is edge triggered or
120 level triggered.
121 @param [in] ActiveLow The interrupt is active-high or active-low.
122 @param [in] Shared The interrupt can be shared with other
123 devices or not (Exclusive).
124 @param [in] IrqList Interrupt list. Must be non-NULL.
125 @param [in] IrqCount Interrupt count. Must be non-zero.
126 @param [in] NameOpNode NameOp object node defining a named object.
127 If provided, append the new resource data node
128 to the list of resource data elements of this
129 node.
130 @param [out] NewRdNode If provided and success,
131 contain the created node.
132
133 @retval EFI_SUCCESS The function completed successfully.
134 @retval EFI_INVALID_PARAMETER Invalid parameter.
135 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
136 **/
137 EFI_STATUS
138 EFIAPI
139 AmlCodeGenRdInterrupt (
140 IN BOOLEAN ResourceConsumer,
141 IN BOOLEAN EdgeTriggered,
142 IN BOOLEAN ActiveLow,
143 IN BOOLEAN Shared,
144 IN UINT32 *IrqList,
145 IN UINT8 IrqCount,
146 IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
147 OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
148 )
149 {
150 EFI_STATUS Status;
151
152 AML_DATA_NODE *RdNode;
153 EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR RdInterrupt;
154 UINT32 *FirstInterrupt;
155
156 if ((IrqList == NULL) ||
157 (IrqCount == 0) ||
158 ((NameOpNode == NULL) && (NewRdNode == NULL)))
159 {
160 ASSERT (0);
161 return EFI_INVALID_PARAMETER;
162 }
163
164 // Header
165 RdInterrupt.Header.Header.Bits.Name =
166 ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME;
167 RdInterrupt.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
168 RdInterrupt.Header.Length = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) -
169 sizeof (ACPI_LARGE_RESOURCE_HEADER);
170
171 // Body
172 RdInterrupt.InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
173 (EdgeTriggered ? BIT1 : 0) |
174 (ActiveLow ? BIT2 : 0) |
175 (Shared ? BIT3 : 0);
176 RdInterrupt.InterruptTableLength = IrqCount;
177
178 // Get the address of the first interrupt field.
179 FirstInterrupt = RdInterrupt.InterruptNumber;
180
181 // Copy the list of interrupts.
182 CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));
183
184 Status = AmlCreateDataNode (
185 EAmlNodeDataTypeResourceData,
186 (UINT8 *)&RdInterrupt,
187 sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR),
188 &RdNode
189 );
190 if (EFI_ERROR (Status)) {
191 ASSERT (0);
192 return Status;
193 }
194
195 return LinkRdNode (RdNode, NameOpNode, NewRdNode);
196 }
197
198 /** Code generation for the "Register ()" ASL function.
199
200 The Resource Data effectively created is a Generic Register Descriptor.
201 Data. Cf ACPI 6.4:
202 - s6.4.3.7 "Generic Register Descriptor".
203 - s19.6.114 "Register".
204
205 The created resource data node can be:
206 - appended to the list of resource data elements of the NameOpNode.
207 In such case NameOpNode must be defined by a the "Name ()" ASL statement
208 and initially contain a "ResourceTemplate ()".
209 - returned through the NewRdNode parameter.
210
211 @param [in] AddressSpace Address space where the register exists.
212 Can be one of I/O space, System Memory, etc.
213 @param [in] BitWidth Number of bits in the register.
214 @param [in] BitOffset Offset in bits from the start of the register
215 indicated by the Address.
216 @param [in] Address Register address.
217 @param [in] AccessSize Size of data values used when accessing the
218 address space. Can be one of:
219 0 - Undefined, legacy (EFI_ACPI_6_4_UNDEFINED)
220 1 - Byte access (EFI_ACPI_6_4_BYTE)
221 2 - Word access (EFI_ACPI_6_4_WORD)
222 3 - DWord access (EFI_ACPI_6_4_DWORD)
223 4 - QWord access (EFI_ACPI_6_4_QWORD)
224 @param [in] NameOpNode NameOp object node defining a named object.
225 If provided, append the new resource data node
226 to the list of resource data elements of this
227 node.
228 @param [out] NewRdNode If provided and success,
229 contain the created node.
230
231 @retval EFI_SUCCESS The function completed successfully.
232 @retval EFI_INVALID_PARAMETER Invalid parameter.
233 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
234 **/
235 EFI_STATUS
236 EFIAPI
237 AmlCodeGenRdRegister (
238 IN UINT8 AddressSpace,
239 IN UINT8 BitWidth,
240 IN UINT8 BitOffset,
241 IN UINT64 Address,
242 IN UINT8 AccessSize,
243 IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
244 OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
245 )
246 {
247 EFI_STATUS Status;
248 AML_DATA_NODE *RdNode;
249 EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR RdRegister;
250
251 if ((AccessSize > EFI_ACPI_6_4_QWORD) ||
252 ((NameOpNode == NULL) && (NewRdNode == NULL)))
253 {
254 ASSERT (0);
255 return EFI_INVALID_PARAMETER;
256 }
257
258 // Header
259 RdRegister.Header.Header.Bits.Name =
260 ACPI_LARGE_GENERIC_REGISTER_DESCRIPTOR_NAME;
261 RdRegister.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
262 RdRegister.Header.Length = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR) -
263 sizeof (ACPI_LARGE_RESOURCE_HEADER);
264
265 // Body
266 RdRegister.AddressSpaceId = AddressSpace;
267 RdRegister.RegisterBitWidth = BitWidth;
268 RdRegister.RegisterBitOffset = BitOffset;
269 RdRegister.AddressSize = AccessSize;
270 RdRegister.RegisterAddress = Address;
271
272 Status = AmlCreateDataNode (
273 EAmlNodeDataTypeResourceData,
274 (UINT8 *)&RdRegister,
275 sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR),
276 &RdNode
277 );
278 if (EFI_ERROR (Status)) {
279 ASSERT (0);
280 return Status;
281 }
282
283 return LinkRdNode (RdNode, NameOpNode, NewRdNode);
284 }
285
286 /** Code generation for the EndTag resource data.
287
288 The EndTag resource data is automatically generated by the ASL compiler
289 at the end of a list of resource data elements. Thus, it doesn't have
290 a corresponding ASL function.
291
292 This function allocates memory to create a data node. It is the caller's
293 responsibility to either:
294 - attach this node to an AML tree;
295 - delete this node.
296
297 ACPI 6.4, s6.4.2.9 "End Tag":
298 "This checksum is generated such that adding it to the sum of all the data
299 bytes will produce a zero sum."
300 "If the checksum field is zero, the resource data is treated as if the
301 checksum operation succeeded. Configuration proceeds normally."
302
303 To avoid re-computing checksums, if a new resource data elements is
304 added/removed/modified in a list of resource data elements, the AmlLib
305 resets the checksum to 0.
306
307 @param [in] CheckSum CheckSum to store in the EndTag.
308 To ignore/avoid computing the checksum,
309 give 0.
310 @param [in] ParentNode If not NULL, add the generated node
311 to the end of the variable list of
312 argument of the ParentNode.
313 The ParentNode must not initially contain
314 an EndTag resource data element.
315 @param [out] NewRdNode If success, contains the generated node.
316
317 @retval EFI_SUCCESS The function completed successfully.
318 @retval EFI_INVALID_PARAMETER Invalid parameter.
319 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
320 **/
321 EFI_STATUS
322 EFIAPI
323 AmlCodeGenEndTag (
324 IN UINT8 CheckSum OPTIONAL,
325 IN AML_OBJECT_NODE *ParentNode OPTIONAL,
326 OUT AML_DATA_NODE **NewRdNode OPTIONAL
327 )
328 {
329 EFI_STATUS Status;
330 AML_DATA_NODE *RdNode;
331 EFI_ACPI_END_TAG_DESCRIPTOR EndTag;
332 ACPI_SMALL_RESOURCE_HEADER SmallResHdr;
333
334 if ((ParentNode == NULL) && (NewRdNode == NULL)) {
335 ASSERT (0);
336 return EFI_INVALID_PARAMETER;
337 }
338
339 RdNode = NULL;
340
341 // Header
342 SmallResHdr.Bits.Length = sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) -
343 sizeof (ACPI_SMALL_RESOURCE_HEADER);
344 SmallResHdr.Bits.Name = ACPI_SMALL_END_TAG_DESCRIPTOR_NAME;
345 SmallResHdr.Bits.Type = ACPI_SMALL_ITEM_FLAG;
346
347 // Body
348 EndTag.Desc = SmallResHdr.Byte;
349 EndTag.Checksum = CheckSum;
350
351 Status = AmlCreateDataNode (
352 EAmlNodeDataTypeResourceData,
353 (UINT8 *)&EndTag,
354 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
355 &RdNode
356 );
357 if (EFI_ERROR (Status)) {
358 ASSERT (0);
359 return Status;
360 }
361
362 if (NewRdNode != NULL) {
363 *NewRdNode = RdNode;
364 }
365
366 if (ParentNode != NULL) {
367 // Check the BufferOp doesn't contain any resource data yet.
368 // This is a hard check: do not allow to add an EndTag if the BufferNode
369 // already has resource data elements attached. Indeed, the EndTag should
370 // have already been added.
371 if (AmlGetNextVariableArgument ((AML_NODE_HEADER *)ParentNode, NULL) !=
372 NULL)
373 {
374 ASSERT (0);
375 Status = EFI_INVALID_PARAMETER;
376 goto error_handler;
377 }
378
379 // Add the EndTag RdNode. Indeed, the AmlAppendRdNode function
380 // is looking for an EndTag, which we are adding here.
381 Status = AmlVarListAddTail (
382 (AML_NODE_HEADER *)ParentNode,
383 (AML_NODE_HEADER *)RdNode
384 );
385 if (EFI_ERROR (Status)) {
386 ASSERT (0);
387 goto error_handler;
388 }
389 }
390
391 return Status;
392
393 error_handler:
394 if (RdNode != NULL) {
395 AmlDeleteTree ((AML_NODE_HEADER *)RdNode);
396 }
397
398 return Status;
399 }
400
401 // DEPRECATED APIS
402 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
403
404 /** DEPRECATED API
405
406 Add an Interrupt Resource Data node.
407
408 This function creates a Resource Data element corresponding to the
409 "Interrupt ()" ASL function, stores it in an AML Data Node.
410
411 It then adds it after the input CurrRdNode in the list of resource data
412 element.
413
414 The Resource Data effectively created is an Extended Interrupt Resource
415 Data. See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
416 for more information about Extended Interrupt Resource Data.
417
418 The Extended Interrupt contains one single interrupt.
419
420 This function allocates memory to create a data node. It is the caller's
421 responsibility to either:
422 - attach this node to an AML tree;
423 - delete this node.
424
425 Note: The _CRS node must be defined using the ASL Name () function.
426 e.g. Name (_CRS, ResourceTemplate () {
427 ...
428 }
429
430 @ingroup UserApis
431
432 @param [in] NameOpCrsNode NameOp object node defining a "_CRS" object.
433 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
434 NameOp object nodes are defined in ASL
435 using the "Name ()" function.
436 @param [in] ResourceConsumer The device consumes the specified interrupt
437 or produces it for use by a child device.
438 @param [in] EdgeTriggered The interrupt is edge triggered or
439 level triggered.
440 @param [in] ActiveLow The interrupt is active-high or active-low.
441 @param [in] Shared The interrupt can be shared with other
442 devices or not (Exclusive).
443 @param [in] IrqList Interrupt list. Must be non-NULL.
444 @param [in] IrqCount Interrupt count. Must be non-zero.
445
446
447 @retval EFI_SUCCESS The function completed successfully.
448 @retval EFI_INVALID_PARAMETER Invalid parameter.
449 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
450 **/
451 EFI_STATUS
452 EFIAPI
453 AmlCodeGenCrsAddRdInterrupt (
454 IN AML_OBJECT_NODE_HANDLE NameOpCrsNode,
455 IN BOOLEAN ResourceConsumer,
456 IN BOOLEAN EdgeTriggered,
457 IN BOOLEAN ActiveLow,
458 IN BOOLEAN Shared,
459 IN UINT32 *IrqList,
460 IN UINT8 IrqCount
461 )
462 {
463 return AmlCodeGenRdInterrupt (
464 ResourceConsumer,
465 EdgeTriggered,
466 ActiveLow,
467 Shared,
468 IrqList,
469 IrqCount,
470 NameOpCrsNode,
471 NULL
472 );
473 }
474
475 #endif // DISABLE_NEW_DEPRECATED_INTERFACES