]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Tree/AmlNodeInterface.c
DynamicTablesPkg: Apply uncrustify changes
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Tree / AmlNodeInterface.c
1 /** @file
2 AML Node Interface.
3
4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <AmlNodeDefines.h>
10
11 #include <AmlCoreInterface.h>
12 #include <ResourceData/AmlResourceData.h>
13 #include <String/AmlString.h>
14 #include <Tree/AmlNode.h>
15 #include <Tree/AmlTree.h>
16 #include <Utils/AmlUtility.h>
17
18 /** Returns the tree node type (Root/Object/Data).
19
20 @param [in] Node Pointer to a Node.
21
22 @return The node type.
23 EAmlNodeUnknown if invalid parameter.
24 **/
25 EAML_NODE_TYPE
26 EFIAPI
27 AmlGetNodeType (
28 IN AML_NODE_HEADER *Node
29 )
30 {
31 if (!IS_AML_NODE_VALID (Node)) {
32 ASSERT (0);
33 return EAmlNodeUnknown;
34 }
35
36 return Node->NodeType;
37 }
38
39 /** Get the RootNode information.
40 The Node must be a root node.
41
42 @param [in] RootNode Pointer to a root node.
43 @param [out] SdtHeaderBuffer Buffer to copy the ACPI DSDT/SSDT header to.
44
45 @retval EFI_SUCCESS The function completed successfully.
46 @retval EFI_INVALID_PARAMETER Invalid parameter.
47 **/
48 EFI_STATUS
49 EFIAPI
50 AmlGetRootNodeInfo (
51 IN AML_ROOT_NODE *RootNode,
52 OUT EFI_ACPI_DESCRIPTION_HEADER *SdtHeaderBuffer
53 )
54 {
55 if (!IS_AML_ROOT_NODE (RootNode) ||
56 (SdtHeaderBuffer == NULL))
57 {
58 ASSERT (0);
59 return EFI_INVALID_PARAMETER;
60 }
61
62 CopyMem (
63 SdtHeaderBuffer,
64 RootNode->SdtHeader,
65 sizeof (EFI_ACPI_DESCRIPTION_HEADER)
66 );
67
68 return EFI_SUCCESS;
69 }
70
71 /** Get the ObjectNode information.
72 The Node must be an object node.
73
74 @ingroup NodeInterfaceApi
75
76 @param [in] ObjectNode Pointer to an object node.
77 @param [out] OpCode Pointer holding the OpCode.
78 Optional, can be NULL.
79 @param [out] SubOpCode Pointer holding the SubOpCode.
80 Optional, can be NULL.
81 @param [out] PkgLen Pointer holding the PkgLen.
82 The PkgLen is 0 for nodes
83 not having the Pkglen attribute.
84 Optional, can be NULL.
85 @param [out] IsNameSpaceNode Pointer holding TRUE if the node is defining
86 or changing the NameSpace scope.
87 E.g.: The "Name ()" and "Scope ()" ASL
88 statements add/modify the NameSpace scope.
89 Their corresponding node are NameSpace nodes.
90 Optional, can be NULL.
91
92 @retval EFI_SUCCESS The function completed successfully.
93 @retval EFI_INVALID_PARAMETER Invalid parameter.
94 **/
95 EFI_STATUS
96 EFIAPI
97 AmlGetObjectNodeInfo (
98 IN AML_OBJECT_NODE *ObjectNode,
99 OUT UINT8 *OpCode OPTIONAL,
100 OUT UINT8 *SubOpCode OPTIONAL,
101 OUT UINT32 *PkgLen OPTIONAL,
102 OUT BOOLEAN *IsNameSpaceNode OPTIONAL
103 )
104 {
105 if (!IS_AML_OBJECT_NODE (ObjectNode)) {
106 ASSERT (0);
107 return EFI_INVALID_PARAMETER;
108 }
109
110 if (OpCode != NULL) {
111 *OpCode = ObjectNode->AmlByteEncoding->OpCode;
112 }
113
114 if (SubOpCode != NULL) {
115 *SubOpCode = ObjectNode->AmlByteEncoding->SubOpCode;
116 }
117
118 if (PkgLen != NULL) {
119 *PkgLen = ObjectNode->PkgLen;
120 }
121
122 if (IsNameSpaceNode != NULL) {
123 *IsNameSpaceNode = AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE);
124 }
125
126 return EFI_SUCCESS;
127 }
128
129 /** Returns the count of the fixed arguments for the input Node.
130
131 @param [in] Node Pointer to an object node.
132
133 @return Number of fixed arguments of the object node.
134 Return 0 if the node is not an object node.
135 **/
136 UINT8
137 AmlGetFixedArgumentCount (
138 IN AML_OBJECT_NODE *Node
139 )
140 {
141 if (IS_AML_OBJECT_NODE (Node) &&
142 (Node->AmlByteEncoding != NULL))
143 {
144 return (UINT8)Node->AmlByteEncoding->MaxIndex;
145 }
146
147 return 0;
148 }
149
150 /** Get the data type of the DataNode.
151 The Node must be a data node.
152
153 @param [in] DataNode Pointer to a data node.
154 @param [out] DataType Pointer holding the data type of the data buffer.
155
156 @retval EFI_SUCCESS The function completed successfully.
157 @retval EFI_INVALID_PARAMETER Invalid parameter.
158 **/
159 EFI_STATUS
160 EFIAPI
161 AmlGetNodeDataType (
162 IN AML_DATA_NODE *DataNode,
163 OUT EAML_NODE_DATA_TYPE *DataType
164 )
165 {
166 if (!IS_AML_DATA_NODE (DataNode) ||
167 (DataType == NULL))
168 {
169 ASSERT (0);
170 return EFI_INVALID_PARAMETER;
171 }
172
173 *DataType = DataNode->DataType;
174
175 return EFI_SUCCESS;
176 }
177
178 /** Get the descriptor Id of the resource data element
179 contained in the DataNode.
180
181 The Node must be a data node.
182 The Node must have the resource data type, i.e. have the
183 EAmlNodeDataTypeResourceData data type.
184
185 @param [in] DataNode Pointer to a data node containing a
186 resource data element.
187 @param [out] ResourceDataType Pointer holding the descriptor Id of
188 the resource data.
189
190 @retval EFI_SUCCESS The function completed successfully.
191 @retval EFI_INVALID_PARAMETER Invalid parameter.
192 **/
193 EFI_STATUS
194 EFIAPI
195 AmlGetResourceDataType (
196 IN AML_DATA_NODE *DataNode,
197 OUT AML_RD_HEADER *ResourceDataType
198 )
199 {
200 if (!IS_AML_DATA_NODE (DataNode) ||
201 (ResourceDataType == NULL) ||
202 (DataNode->DataType != EAmlNodeDataTypeResourceData))
203 {
204 ASSERT (0);
205 return EFI_INVALID_PARAMETER;
206 }
207
208 *ResourceDataType = AmlRdGetDescId (DataNode->Buffer);
209
210 return EFI_SUCCESS;
211 }
212
213 /** Get the data buffer and size of the DataNode.
214 The Node must be a data node.
215
216 BufferSize is always updated to the size of buffer of the DataNode.
217
218 If:
219 - the content of BufferSize is >= to the DataNode's buffer size;
220 - Buffer is not NULL;
221 then copy the content of the DataNode's buffer in Buffer.
222
223 @param [in] DataNode Pointer to a data node.
224 @param [out] Buffer Buffer to write the data to.
225 Optional, if NULL, only update BufferSize.
226 @param [in, out] BufferSize Pointer holding:
227 - At entry, the size of the Buffer;
228 - At exit, the size of the DataNode's
229 buffer size.
230
231 @retval EFI_SUCCESS The function completed successfully.
232 @retval EFI_INVALID_PARAMETER Invalid parameter.
233 **/
234 EFI_STATUS
235 EFIAPI
236 AmlGetDataNodeBuffer (
237 IN AML_DATA_NODE *DataNode,
238 OUT UINT8 *Buffer OPTIONAL,
239 IN OUT UINT32 *BufferSize
240 )
241 {
242 if (!IS_AML_DATA_NODE (DataNode) ||
243 (BufferSize == NULL))
244 {
245 ASSERT (0);
246 return EFI_INVALID_PARAMETER;
247 }
248
249 if ((*BufferSize >= DataNode->Size) &&
250 (Buffer != NULL))
251 {
252 CopyMem (Buffer, DataNode->Buffer, DataNode->Size);
253 }
254
255 *BufferSize = DataNode->Size;
256
257 return EFI_SUCCESS;
258 }
259
260 /** Update the ACPI DSDT/SSDT table header.
261
262 The input SdtHeader information is copied to the tree RootNode.
263 The table Length field is automatically updated.
264 The checksum field is only updated when serializing the tree.
265
266 @param [in] RootNode Pointer to a root node.
267 @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT table header.
268
269 @retval EFI_SUCCESS The function completed successfully.
270 @retval EFI_INVALID_PARAMETER Invalid parameter.
271 **/
272 EFI_STATUS
273 EFIAPI
274 AmlUpdateRootNode (
275 IN AML_ROOT_NODE *RootNode,
276 IN CONST EFI_ACPI_DESCRIPTION_HEADER *SdtHeader
277 )
278 {
279 EFI_STATUS Status;
280 UINT32 Length;
281
282 if (!IS_AML_ROOT_NODE (RootNode) ||
283 (SdtHeader == NULL) ||
284 ((SdtHeader->Signature !=
285 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) &&
286 (SdtHeader->Signature !=
287 EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)))
288 {
289 ASSERT (0);
290 return EFI_INVALID_PARAMETER;
291 }
292
293 CopyMem (
294 RootNode->SdtHeader,
295 SdtHeader,
296 sizeof (EFI_ACPI_DESCRIPTION_HEADER)
297 );
298
299 // Update the Length field.
300 Status = AmlComputeSize ((AML_NODE_HEADER *)RootNode, &Length);
301 if (EFI_ERROR (Status)) {
302 ASSERT (0);
303 return Status;
304 }
305
306 RootNode->SdtHeader->Length = Length +
307 (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
308
309 return Status;
310 }
311
312 /** Update an object node representing an integer with a new value.
313
314 The object node must have one of the following OpCodes:
315 - AML_BYTE_PREFIX
316 - AML_WORD_PREFIX
317 - AML_DWORD_PREFIX
318 - AML_QWORD_PREFIX
319 - AML_ZERO_OP
320 - AML_ONE_OP
321
322 The following OpCode is not supported:
323 - AML_ONES_OP
324
325 @param [in] IntegerOpNode Pointer an object node containing an integer.
326 Must not be an object node with an AML_ONES_OP
327 OpCode.
328 @param [in] NewInteger New integer value to set.
329
330 @retval EFI_SUCCESS The function completed successfully.
331 @retval EFI_INVALID_PARAMETER Invalid parameter.
332 **/
333 EFI_STATUS
334 EFIAPI
335 AmlUpdateInteger (
336 IN AML_OBJECT_NODE *IntegerOpNode,
337 IN UINT64 NewInteger
338 )
339 {
340 EFI_STATUS Status;
341
342 INT8 ValueWidthDiff;
343
344 if (!IS_AML_OBJECT_NODE (IntegerOpNode) ||
345 (!IsIntegerNode (IntegerOpNode) &&
346 !IsSpecialIntegerNode (IntegerOpNode)) ||
347 AmlNodeCompareOpCode (IntegerOpNode, AML_ONES_OP, 0))
348 {
349 ASSERT (0);
350 return EFI_INVALID_PARAMETER;
351 }
352
353 Status = AmlNodeSetIntegerValue (IntegerOpNode, NewInteger, &ValueWidthDiff);
354 if (EFI_ERROR (Status)) {
355 ASSERT (0);
356 return Status;
357 }
358
359 // If the new size is different from the old size, propagate the new size.
360 if (ValueWidthDiff != 0) {
361 // Propagate the information.
362 Status = AmlPropagateInformation (
363 (AML_NODE_HEADER *)IntegerOpNode,
364 (ValueWidthDiff > 0) ? TRUE : FALSE,
365 ABS (ValueWidthDiff),
366 0
367 );
368 if (EFI_ERROR (Status)) {
369 ASSERT (0);
370 }
371 }
372
373 return Status;
374 }
375
376 /** Update the buffer of a data node.
377
378 Note: The data type of the buffer's content must match the data type of the
379 DataNode. This is a hard restriction to prevent undesired behaviour.
380
381 @param [in] DataNode Pointer to a data node.
382 @param [in] DataType Data type of the Buffer's content.
383 @param [in] Buffer Buffer containing the new data. The content of
384 the Buffer is copied.
385 @param [in] Size Size of the Buffer.
386
387 @retval EFI_SUCCESS The function completed successfully.
388 @retval EFI_INVALID_PARAMETER Invalid parameter.
389 @retval EFI_UNSUPPORTED Operation not supporter.
390 **/
391 EFI_STATUS
392 EFIAPI
393 AmlUpdateDataNode (
394 IN AML_DATA_NODE *DataNode,
395 IN EAML_NODE_DATA_TYPE DataType,
396 IN UINT8 *Buffer,
397 IN UINT32 Size
398 )
399 {
400 EFI_STATUS Status;
401
402 UINT32 ExpectedSize;
403 AML_OBJECT_NODE *ParentNode;
404 EAML_NODE_DATA_TYPE ExpectedArgType;
405 EAML_PARSE_INDEX Index;
406
407 if (!IS_AML_DATA_NODE (DataNode) ||
408 (DataType > EAmlNodeDataTypeMax) ||
409 (Buffer == NULL) ||
410 (Size == 0))
411 {
412 ASSERT (0);
413 return EFI_INVALID_PARAMETER;
414 }
415
416 ParentNode = (AML_OBJECT_NODE *)AmlGetParent ((AML_NODE_HEADER *)DataNode);
417 if (!IS_AML_OBJECT_NODE (ParentNode)) {
418 ASSERT (0);
419 return EFI_INVALID_PARAMETER;
420 }
421
422 // The NewNode and OldNode must have the same type.
423 // We do not allow to change the argument type of a data node.
424 // If required, the initial ASL template should be modified
425 // accordingly.
426 // It is however possible to interchange a raw buffer and a
427 // resource data element, since raw data can be misinterpreted
428 // as a resource data element.
429 ExpectedArgType = DataNode->DataType;
430 if ((ExpectedArgType != DataType) &&
431 (((ExpectedArgType != EAmlNodeDataTypeRaw) &&
432 (ExpectedArgType != EAmlNodeDataTypeResourceData)) ||
433 ((DataType != EAmlNodeDataTypeRaw) &&
434 (DataType != EAmlNodeDataTypeResourceData))))
435 {
436 ASSERT (0);
437 return EFI_UNSUPPORTED;
438 }
439
440 // Perform some compatibility checks.
441 switch (DataType) {
442 case EAmlNodeDataTypeNameString:
443 {
444 // Check the name contained in the Buffer is an AML name
445 // with the right size.
446 Status = AmlGetNameStringSize ((CONST CHAR8 *)Buffer, &ExpectedSize);
447 if (EFI_ERROR (Status) ||
448 (Size != ExpectedSize))
449 {
450 ASSERT (0);
451 return Status;
452 }
453
454 break;
455 }
456 case EAmlNodeDataTypeString:
457 {
458 ExpectedSize = 0;
459 while (ExpectedSize < Size) {
460 // Cf ACPI 6.3 specification 20.2.3 Data Objects Encoding.
461 // AsciiCharList := Nothing | <AsciiChar AsciiCharList>
462 // AsciiChar := 0x01 - 0x7F
463 // NullChar := 0x00
464 if (Buffer[ExpectedSize] > 0x7F) {
465 ASSERT (0);
466 return EFI_INVALID_PARAMETER;
467 }
468
469 ExpectedSize++;
470 }
471
472 if (ExpectedSize != Size) {
473 ASSERT (0);
474 return EFI_INVALID_PARAMETER;
475 }
476
477 break;
478 }
479 case EAmlNodeDataTypeUInt:
480 {
481 if (AmlIsNodeFixedArgument ((CONST AML_NODE_HEADER *)DataNode, &Index)) {
482 if ((ParentNode->AmlByteEncoding == NULL) ||
483 (ParentNode->AmlByteEncoding->Format == NULL))
484 {
485 ASSERT (0);
486 return EFI_INVALID_PARAMETER;
487 }
488
489 // It is not possible to change the size of a fixed length UintX.
490 // E.g. for PackageOp the first fixed argument is of type EAmlUInt8
491 // and represents the count of elements. This type cannot be changed.
492 if ((ParentNode->AmlByteEncoding->Format[Index] != EAmlObject) &&
493 (DataNode->Size != Size))
494 {
495 ASSERT (0);
496 return EFI_UNSUPPORTED;
497 }
498 }
499
500 break;
501 }
502 case EAmlNodeDataTypeRaw:
503 {
504 // Check if the parent node has the byte list flag set.
505 if (!AmlNodeHasAttribute (ParentNode, AML_HAS_BYTE_LIST)) {
506 ASSERT (0);
507 return EFI_INVALID_PARAMETER;
508 }
509
510 break;
511 }
512 case EAmlNodeDataTypeResourceData:
513 {
514 // The resource data can be either small or large resource data.
515 // Small resource data must be at least 1 byte.
516 // Large resource data must be at least as long as the header
517 // of a large resource data.
518 if (AML_RD_IS_LARGE (Buffer) &&
519 (Size < sizeof (ACPI_LARGE_RESOURCE_HEADER)))
520 {
521 ASSERT (0);
522 return EFI_INVALID_PARAMETER;
523 }
524
525 // Check if the parent node has the byte list flag set.
526 if (!AmlNodeHasAttribute (ParentNode, AML_HAS_BYTE_LIST)) {
527 ASSERT (0);
528 return EFI_INVALID_PARAMETER;
529 }
530
531 // Check the size of the buffer is equal to the resource data size
532 // encoded in the input buffer.
533 ExpectedSize = AmlRdGetSize (Buffer);
534 if (ExpectedSize != Size) {
535 ASSERT (0);
536 return EFI_INVALID_PARAMETER;
537 }
538
539 Status = AmlSetRdListCheckSum (ParentNode, 0);
540 if (EFI_ERROR (Status)) {
541 ASSERT (0);
542 return Status;
543 }
544
545 break;
546 }
547 case EAmlNodeDataTypeFieldPkgLen:
548 {
549 // Check the parent is a FieldNamed field element.
550 if (!AmlNodeCompareOpCode (ParentNode, AML_FIELD_NAMED_OP, 0)) {
551 ASSERT (0);
552 return EFI_INVALID_PARAMETER;
553 }
554
555 break;
556 }
557 // None and reserved types.
558 default:
559 {
560 ASSERT (0);
561 return EFI_INVALID_PARAMETER;
562 break;
563 }
564 } // switch
565
566 // If the new size is different from the old size, propagate the new size.
567 if (DataNode->Size != Size) {
568 // Propagate the information.
569 Status = AmlPropagateInformation (
570 DataNode->NodeHeader.Parent,
571 (Size > DataNode->Size) ? TRUE : FALSE,
572 (Size > DataNode->Size) ?
573 (Size - DataNode->Size) :
574 (DataNode->Size - Size),
575 0
576 );
577 if (EFI_ERROR (Status)) {
578 ASSERT (0);
579 return Status;
580 }
581
582 // Free the old DataNode buffer and allocate a new buffer to store the
583 // new data.
584 FreePool (DataNode->Buffer);
585 DataNode->Buffer = AllocateZeroPool (Size);
586 if (DataNode->Buffer == NULL) {
587 ASSERT (0);
588 return EFI_OUT_OF_RESOURCES;
589 }
590
591 DataNode->Size = Size;
592 }
593
594 CopyMem (DataNode->Buffer, Buffer, Size);
595
596 return EFI_SUCCESS;
597 }