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