]>
Commit | Line | Data |
---|---|---|
667aa7cc PG |
1 | /** @file\r |
2 | AML Utility.\r | |
3 | \r | |
6d2777d8 | 4 | Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>\r |
667aa7cc PG |
5 | \r |
6 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
7 | **/\r | |
8 | \r | |
9 | #include <Utils/AmlUtility.h>\r | |
10 | \r | |
11 | #include <AmlCoreInterface.h>\r | |
12 | #include <Tree/AmlNode.h>\r | |
13 | #include <Tree/AmlTree.h>\r | |
14 | \r | |
15 | /** This function computes and updates the ACPI table checksum.\r | |
16 | \r | |
17 | @param [in] AcpiTable Pointer to an Acpi table.\r | |
18 | \r | |
19 | @retval EFI_SUCCESS The function completed successfully.\r | |
20 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
21 | **/\r | |
22 | EFI_STATUS\r | |
23 | EFIAPI\r | |
24 | AcpiPlatformChecksum (\r | |
731c67e1 | 25 | IN EFI_ACPI_DESCRIPTION_HEADER *AcpiTable\r |
667aa7cc PG |
26 | )\r |
27 | {\r | |
731c67e1 MK |
28 | UINT8 *Ptr;\r |
29 | UINT8 Sum;\r | |
30 | UINT32 Size;\r | |
667aa7cc PG |
31 | \r |
32 | if (AcpiTable == NULL) {\r | |
33 | ASSERT (0);\r | |
34 | return EFI_INVALID_PARAMETER;\r | |
35 | }\r | |
36 | \r | |
731c67e1 | 37 | Ptr = (UINT8 *)AcpiTable;\r |
667aa7cc | 38 | Size = AcpiTable->Length;\r |
731c67e1 | 39 | Sum = 0;\r |
667aa7cc PG |
40 | \r |
41 | // Set the checksum field to 0 first.\r | |
42 | AcpiTable->Checksum = 0;\r | |
43 | \r | |
44 | // Compute the checksum.\r | |
45 | while ((Size--) != 0) {\r | |
46 | Sum = (UINT8)(Sum + (*Ptr++));\r | |
47 | }\r | |
48 | \r | |
49 | // Set the checksum.\r | |
50 | AcpiTable->Checksum = (UINT8)(0xFF - Sum + 1);\r | |
51 | \r | |
52 | return EFI_SUCCESS;\r | |
53 | }\r | |
54 | \r | |
55 | /** A callback function that computes the size of a Node and adds it to the\r | |
56 | Size pointer stored in the Context.\r | |
57 | Calling this function on the root node will compute the total size of the\r | |
58 | AML bytestream.\r | |
59 | \r | |
60 | @param [in] Node Node to compute the size.\r | |
61 | @param [in, out] Context Pointer holding the computed size.\r | |
62 | (UINT32 *) Context.\r | |
63 | @param [in, out] Status Pointer holding:\r | |
64 | - At entry, the Status returned by the\r | |
65 | last call to this exact function during\r | |
66 | the enumeration;\r | |
67 | - At exit, he returned status of the\r | |
68 | call to this function.\r | |
69 | Optional, can be NULL.\r | |
70 | \r | |
71 | @retval TRUE if the enumeration can continue or has finished without\r | |
72 | interruption.\r | |
73 | @retval FALSE if the enumeration needs to stopped or has stopped.\r | |
74 | **/\r | |
75 | STATIC\r | |
76 | BOOLEAN\r | |
77 | EFIAPI\r | |
78 | AmlComputeSizeCallback (\r | |
731c67e1 MK |
79 | IN AML_NODE_HEADER *Node,\r |
80 | IN OUT VOID *Context,\r | |
81 | IN OUT EFI_STATUS *Status OPTIONAL\r | |
667aa7cc PG |
82 | )\r |
83 | {\r | |
731c67e1 MK |
84 | UINT32 Size;\r |
85 | EAML_PARSE_INDEX IndexPtr;\r | |
86 | CONST AML_OBJECT_NODE *ParentNode;\r | |
667aa7cc PG |
87 | \r |
88 | if (!IS_AML_NODE_VALID (Node) ||\r | |
731c67e1 MK |
89 | (Context == NULL))\r |
90 | {\r | |
667aa7cc PG |
91 | ASSERT (0);\r |
92 | if (Status != NULL) {\r | |
93 | *Status = EFI_INVALID_PARAMETER;\r | |
94 | }\r | |
731c67e1 | 95 | \r |
667aa7cc PG |
96 | return FALSE;\r |
97 | }\r | |
98 | \r | |
99 | // Ignore the second fixed argument of method invocation nodes\r | |
100 | // as the information stored there (the argument count) is not in the\r | |
101 | // ACPI specification.\r | |
731c67e1 | 102 | ParentNode = (CONST AML_OBJECT_NODE *)AmlGetParent (Node);\r |
667aa7cc PG |
103 | if (IS_AML_OBJECT_NODE (ParentNode) &&\r |
104 | AmlNodeCompareOpCode (ParentNode, AML_METHOD_INVOC_OP, 0) &&\r | |
731c67e1 MK |
105 | AmlIsNodeFixedArgument (Node, &IndexPtr))\r |
106 | {\r | |
667aa7cc PG |
107 | if (IndexPtr == EAmlParseIndexTerm1) {\r |
108 | if (Status != NULL) {\r | |
109 | *Status = EFI_SUCCESS;\r | |
110 | }\r | |
731c67e1 | 111 | \r |
667aa7cc PG |
112 | return TRUE;\r |
113 | }\r | |
114 | }\r | |
115 | \r | |
731c67e1 | 116 | Size = *((UINT32 *)Context);\r |
667aa7cc PG |
117 | \r |
118 | if (IS_AML_DATA_NODE (Node)) {\r | |
731c67e1 | 119 | Size += ((AML_DATA_NODE *)Node)->Size;\r |
667aa7cc PG |
120 | } else if (IS_AML_OBJECT_NODE (Node) &&\r |
121 | !AmlNodeHasAttribute (\r | |
731c67e1 MK |
122 | (CONST AML_OBJECT_NODE *)Node,\r |
123 | AML_IS_PSEUDO_OPCODE\r | |
124 | ))\r | |
125 | {\r | |
667aa7cc PG |
126 | // Ignore pseudo-opcodes as they are not part of the\r |
127 | // ACPI specification.\r | |
128 | \r | |
731c67e1 MK |
129 | Size += (((AML_OBJECT_NODE *)Node)->AmlByteEncoding->OpCode ==\r |
130 | AML_EXT_OP) ? 2 : 1;\r | |
667aa7cc PG |
131 | \r |
132 | // Add the size of the PkgLen.\r | |
133 | if (AmlNodeHasAttribute (\r | |
731c67e1 MK |
134 | (AML_OBJECT_NODE *)Node,\r |
135 | AML_HAS_PKG_LENGTH\r | |
136 | ))\r | |
137 | {\r | |
138 | Size += AmlComputePkgLengthWidth (((AML_OBJECT_NODE *)Node)->PkgLen);\r | |
667aa7cc PG |
139 | }\r |
140 | }\r | |
141 | \r | |
142 | // Check for overflow.\r | |
143 | // The root node has a null size, thus the strict comparison.\r | |
731c67e1 | 144 | if (*((UINT32 *)Context) > Size) {\r |
667aa7cc PG |
145 | ASSERT (0);\r |
146 | *Status = EFI_INVALID_PARAMETER;\r | |
147 | return FALSE;\r | |
148 | }\r | |
149 | \r | |
731c67e1 | 150 | *((UINT32 *)Context) = Size;\r |
667aa7cc PG |
151 | \r |
152 | if (Status != NULL) {\r | |
153 | *Status = EFI_SUCCESS;\r | |
154 | }\r | |
155 | \r | |
156 | return TRUE;\r | |
157 | }\r | |
158 | \r | |
159 | /** Compute the size of a tree/sub-tree.\r | |
160 | \r | |
161 | @param [in] Node Node to compute the size.\r | |
162 | @param [in, out] Size Pointer holding the computed size.\r | |
163 | \r | |
164 | @retval EFI_SUCCESS The function completed successfully.\r | |
165 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
166 | **/\r | |
167 | EFI_STATUS\r | |
168 | EFIAPI\r | |
169 | AmlComputeSize (\r | |
731c67e1 MK |
170 | IN CONST AML_NODE_HEADER *Node,\r |
171 | IN OUT UINT32 *Size\r | |
667aa7cc PG |
172 | )\r |
173 | {\r | |
174 | EFI_STATUS Status;\r | |
175 | \r | |
176 | if (!IS_AML_NODE_VALID (Node) ||\r | |
731c67e1 MK |
177 | (Size == NULL))\r |
178 | {\r | |
667aa7cc PG |
179 | ASSERT (0);\r |
180 | return EFI_INVALID_PARAMETER;\r | |
181 | }\r | |
182 | \r | |
183 | *Size = 0;\r | |
184 | \r | |
185 | AmlEnumTree (\r | |
731c67e1 | 186 | (AML_NODE_HEADER *)Node,\r |
667aa7cc | 187 | AmlComputeSizeCallback,\r |
731c67e1 | 188 | (VOID *)Size,\r |
667aa7cc PG |
189 | &Status\r |
190 | );\r | |
191 | \r | |
192 | return Status;\r | |
193 | }\r | |
194 | \r | |
195 | /** Get the value contained in an integer node.\r | |
196 | \r | |
197 | @param [in] Node Pointer to an integer node.\r | |
198 | Must be an object node.\r | |
199 | @param [out] Value Value contained in the integer node.\r | |
200 | \r | |
201 | @retval EFI_SUCCESS The function completed successfully.\r | |
202 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
203 | **/\r | |
667aa7cc PG |
204 | EFI_STATUS\r |
205 | EFIAPI\r | |
206 | AmlNodeGetIntegerValue (\r | |
731c67e1 MK |
207 | IN AML_OBJECT_NODE *Node,\r |
208 | OUT UINT64 *Value\r | |
667aa7cc PG |
209 | )\r |
210 | {\r | |
731c67e1 | 211 | AML_DATA_NODE *DataNode;\r |
667aa7cc PG |
212 | \r |
213 | if ((!IsIntegerNode (Node) &&\r | |
214 | !IsSpecialIntegerNode (Node)) ||\r | |
731c67e1 MK |
215 | (Value == NULL))\r |
216 | {\r | |
667aa7cc PG |
217 | ASSERT (0);\r |
218 | return EFI_INVALID_PARAMETER;\r | |
219 | }\r | |
220 | \r | |
221 | // For ZeroOp and OneOp, there is no data node.\r | |
222 | if (IsSpecialIntegerNode (Node)) {\r | |
223 | if (AmlNodeCompareOpCode (Node, AML_ZERO_OP, 0)) {\r | |
224 | *Value = 0;\r | |
225 | } else if (AmlNodeCompareOpCode (Node, AML_ONE_OP, 0)) {\r | |
226 | *Value = 1;\r | |
227 | } else {\r | |
228 | // OnesOp cannot be handled: it represents a maximum value.\r | |
229 | ASSERT (0);\r | |
230 | return EFI_INVALID_PARAMETER;\r | |
231 | }\r | |
731c67e1 | 232 | \r |
667aa7cc PG |
233 | return EFI_SUCCESS;\r |
234 | }\r | |
235 | \r | |
236 | // For integer nodes, the value is in the first fixed argument.\r | |
731c67e1 | 237 | DataNode = (AML_DATA_NODE *)Node->FixedArgs[EAmlParseIndexTerm0];\r |
667aa7cc | 238 | if (!IS_AML_DATA_NODE (DataNode) ||\r |
731c67e1 MK |
239 | (DataNode->DataType != EAmlNodeDataTypeUInt))\r |
240 | {\r | |
667aa7cc PG |
241 | ASSERT (0);\r |
242 | return EFI_INVALID_PARAMETER;\r | |
243 | }\r | |
244 | \r | |
245 | switch (DataNode->Size) {\r | |
246 | case 1:\r | |
247 | {\r | |
731c67e1 | 248 | *Value = *((UINT8 *)(DataNode->Buffer));\r |
667aa7cc PG |
249 | break;\r |
250 | }\r | |
251 | case 2:\r | |
252 | {\r | |
731c67e1 | 253 | *Value = *((UINT16 *)(DataNode->Buffer));\r |
667aa7cc PG |
254 | break;\r |
255 | }\r | |
256 | case 4:\r | |
257 | {\r | |
731c67e1 | 258 | *Value = *((UINT32 *)(DataNode->Buffer));\r |
667aa7cc PG |
259 | break;\r |
260 | }\r | |
261 | case 8:\r | |
262 | {\r | |
731c67e1 | 263 | *Value = *((UINT64 *)(DataNode->Buffer));\r |
667aa7cc PG |
264 | break;\r |
265 | }\r | |
266 | default:\r | |
267 | {\r | |
268 | ASSERT (0);\r | |
269 | return EFI_INVALID_PARAMETER;\r | |
270 | }\r | |
271 | } // switch\r | |
272 | \r | |
273 | return EFI_SUCCESS;\r | |
274 | }\r | |
275 | \r | |
276 | /** Replace a Zero (AML_ZERO_OP) or One (AML_ONE_OP) object node\r | |
277 | with a byte integer (AML_BYTE_PREFIX) object node having the same value.\r | |
278 | \r | |
279 | @param [in] Node Pointer to an integer node.\r | |
280 | Must be an object node having ZeroOp or OneOp.\r | |
281 | \r | |
282 | @retval EFI_SUCCESS The function completed successfully.\r | |
283 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
284 | **/\r | |
285 | STATIC\r | |
286 | EFI_STATUS\r | |
287 | EFIAPI\r | |
288 | AmlUnwindSpecialInteger (\r | |
731c67e1 | 289 | IN AML_OBJECT_NODE *Node\r |
667aa7cc PG |
290 | )\r |
291 | {\r | |
731c67e1 | 292 | EFI_STATUS Status;\r |
667aa7cc | 293 | \r |
731c67e1 MK |
294 | AML_DATA_NODE *NewDataNode;\r |
295 | UINT8 Value;\r | |
296 | CONST AML_BYTE_ENCODING *ByteEncoding;\r | |
667aa7cc PG |
297 | \r |
298 | if (!IsSpecialIntegerNode (Node)) {\r | |
299 | ASSERT (0);\r | |
300 | return EFI_INVALID_PARAMETER;\r | |
301 | }\r | |
302 | \r | |
303 | // Find the value.\r | |
304 | if (AmlNodeCompareOpCode (Node, AML_ZERO_OP, 0)) {\r | |
305 | Value = 0;\r | |
306 | } else if (AmlNodeCompareOpCode (Node, AML_ONE_OP, 0)) {\r | |
307 | Value = 1;\r | |
308 | } else {\r | |
309 | // OnesOp cannot be handled: it represents a maximum value.\r | |
310 | ASSERT (0);\r | |
311 | return EFI_INVALID_PARAMETER;\r | |
312 | }\r | |
313 | \r | |
314 | Status = AmlCreateDataNode (\r | |
731c67e1 MK |
315 | EAmlNodeDataTypeUInt,\r |
316 | &Value,\r | |
317 | sizeof (UINT8),\r | |
318 | (AML_DATA_NODE **)&NewDataNode\r | |
319 | );\r | |
667aa7cc PG |
320 | if (EFI_ERROR (Status)) {\r |
321 | ASSERT (0);\r | |
322 | return Status;\r | |
323 | }\r | |
324 | \r | |
325 | // Change the encoding of the special node to a ByteOp encoding.\r | |
326 | ByteEncoding = AmlGetByteEncodingByOpCode (AML_BYTE_PREFIX, 0);\r | |
327 | if (ByteEncoding == NULL) {\r | |
328 | ASSERT (0);\r | |
329 | Status = EFI_INVALID_PARAMETER;\r | |
330 | goto error_handler;\r | |
331 | }\r | |
332 | \r | |
333 | // Update the ByteEncoding from ZERO_OP/ONE_OP to AML_BYTE_PREFIX.\r | |
334 | Node->AmlByteEncoding = ByteEncoding;\r | |
335 | \r | |
336 | // Add the data node as the first fixed argument of the ByteOp object.\r | |
337 | Status = AmlSetFixedArgument (\r | |
731c67e1 MK |
338 | (AML_OBJECT_NODE *)Node,\r |
339 | EAmlParseIndexTerm0,\r | |
340 | (AML_NODE_HEADER *)NewDataNode\r | |
341 | );\r | |
667aa7cc PG |
342 | if (EFI_ERROR (Status)) {\r |
343 | ASSERT (0);\r | |
344 | goto error_handler;\r | |
345 | }\r | |
346 | \r | |
347 | return Status;\r | |
348 | \r | |
349 | error_handler:\r | |
731c67e1 | 350 | AmlDeleteTree ((AML_NODE_HEADER *)NewDataNode);\r |
667aa7cc PG |
351 | return Status;\r |
352 | }\r | |
353 | \r | |
354 | /** Set the value contained in an integer node.\r | |
355 | \r | |
356 | The OpCode is updated accordingly to the new value\r | |
357 | (e.g.: If the original value was a UINT8 value, then the OpCode\r | |
358 | would be AML_BYTE_PREFIX. If it the new value is a UINT16\r | |
359 | value then the OpCode will be updated to AML_WORD_PREFIX).\r | |
360 | \r | |
361 | @param [in] Node Pointer to an integer node.\r | |
362 | Must be an object node.\r | |
363 | @param [in] NewValue New value to write in the integer node.\r | |
364 | @param [out] ValueWidthDiff Difference in number of bytes used to store\r | |
365 | the new value.\r | |
366 | Can be negative.\r | |
367 | \r | |
368 | @retval EFI_SUCCESS The function completed successfully.\r | |
369 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
370 | @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r | |
371 | **/\r | |
372 | EFI_STATUS\r | |
373 | EFIAPI\r | |
374 | AmlNodeSetIntegerValue (\r | |
731c67e1 MK |
375 | IN AML_OBJECT_NODE *Node,\r |
376 | IN UINT64 NewValue,\r | |
377 | OUT INT8 *ValueWidthDiff\r | |
667aa7cc PG |
378 | )\r |
379 | {\r | |
731c67e1 MK |
380 | EFI_STATUS Status;\r |
381 | AML_DATA_NODE *DataNode;\r | |
667aa7cc | 382 | \r |
731c67e1 MK |
383 | UINT8 NewOpCode;\r |
384 | UINT8 NumberOfBytes;\r | |
667aa7cc PG |
385 | \r |
386 | if ((!IsIntegerNode (Node) &&\r | |
387 | !IsSpecialIntegerNode (Node)) ||\r | |
731c67e1 MK |
388 | (ValueWidthDiff == NULL))\r |
389 | {\r | |
667aa7cc PG |
390 | ASSERT (0);\r |
391 | return EFI_INVALID_PARAMETER;\r | |
392 | }\r | |
393 | \r | |
394 | *ValueWidthDiff = 0;\r | |
395 | // For ZeroOp and OneOp, there is no data node.\r | |
396 | // Thus the object node is converted to a byte object node holding 0 or 1.\r | |
397 | if (IsSpecialIntegerNode (Node)) {\r | |
398 | switch (NewValue) {\r | |
399 | case AML_ZERO_OP:\r | |
400 | Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0);\r | |
401 | return EFI_SUCCESS;\r | |
402 | case AML_ONE_OP:\r | |
403 | Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (AML_ONE_OP, 0);\r | |
404 | return EFI_SUCCESS;\r | |
405 | default:\r | |
406 | {\r | |
407 | Status = AmlUnwindSpecialInteger (Node);\r | |
408 | if (EFI_ERROR (Status)) {\r | |
409 | ASSERT (0);\r | |
410 | return Status;\r | |
411 | }\r | |
731c67e1 | 412 | \r |
667aa7cc PG |
413 | // The AmlUnwindSpecialInteger functions converts a special integer\r |
414 | // node to a UInt8/Byte data node. Thus, the size increments by one:\r | |
415 | // special integer are encoded as one byte (the opcode only) while byte\r | |
416 | // integers are encoded as two bytes (the opcode + the value).\r | |
417 | *ValueWidthDiff += sizeof (UINT8);\r | |
418 | }\r | |
419 | } // switch\r | |
420 | } // IsSpecialIntegerNode (Node)\r | |
421 | \r | |
422 | // For integer nodes, the value is in the first fixed argument.\r | |
731c67e1 | 423 | DataNode = (AML_DATA_NODE *)Node->FixedArgs[EAmlParseIndexTerm0];\r |
667aa7cc | 424 | if (!IS_AML_DATA_NODE (DataNode) ||\r |
731c67e1 MK |
425 | (DataNode->DataType != EAmlNodeDataTypeUInt))\r |
426 | {\r | |
667aa7cc PG |
427 | ASSERT (0);\r |
428 | return EFI_INVALID_PARAMETER;\r | |
429 | }\r | |
430 | \r | |
431 | // The value can be encoded with a special 0 or 1 OpCode.\r | |
432 | // The AML_ONES_OP is not handled.\r | |
433 | if (NewValue <= 1) {\r | |
731c67e1 | 434 | NewOpCode = (NewValue == 0) ? AML_ZERO_OP : AML_ONE_OP;\r |
667aa7cc PG |
435 | Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (NewOpCode, 0);\r |
436 | \r | |
437 | // The value is encoded with a AML_ZERO_OP or AML_ONE_OP.\r | |
438 | // This means there is no need for a DataNode containing the value.\r | |
439 | // The change in size is equal to the size of the DataNode's buffer.\r | |
440 | *ValueWidthDiff = -((INT8)DataNode->Size);\r | |
441 | \r | |
442 | // Detach and free the DataNode containing the integer value.\r | |
731c67e1 | 443 | DataNode->NodeHeader.Parent = NULL;\r |
667aa7cc | 444 | Node->FixedArgs[EAmlParseIndexTerm0] = NULL;\r |
731c67e1 | 445 | Status = AmlDeleteNode ((AML_NODE_HEADER *)DataNode);\r |
667aa7cc PG |
446 | if (EFI_ERROR (Status)) {\r |
447 | ASSERT (0);\r | |
448 | return Status;\r | |
449 | }\r | |
450 | \r | |
451 | return EFI_SUCCESS;\r | |
452 | }\r | |
453 | \r | |
454 | // Check the number of bits needed to represent the value.\r | |
455 | if (NewValue > MAX_UINT32) {\r | |
456 | // Value is 64 bits.\r | |
731c67e1 | 457 | NewOpCode = AML_QWORD_PREFIX;\r |
667aa7cc PG |
458 | NumberOfBytes = 8;\r |
459 | } else if (NewValue > MAX_UINT16) {\r | |
460 | // Value is 32 bits.\r | |
731c67e1 | 461 | NewOpCode = AML_DWORD_PREFIX;\r |
667aa7cc PG |
462 | NumberOfBytes = 4;\r |
463 | } else if (NewValue > MAX_UINT8) {\r | |
464 | // Value is 16 bits.\r | |
731c67e1 | 465 | NewOpCode = AML_WORD_PREFIX;\r |
667aa7cc PG |
466 | NumberOfBytes = 2;\r |
467 | } else {\r | |
468 | // Value is 8 bits.\r | |
731c67e1 | 469 | NewOpCode = AML_BYTE_PREFIX;\r |
667aa7cc PG |
470 | NumberOfBytes = 1;\r |
471 | }\r | |
472 | \r | |
473 | *ValueWidthDiff += (INT8)(NumberOfBytes - DataNode->Size);\r | |
474 | \r | |
475 | // Update the ByteEncoding as it may have changed between [8 .. 64] bits.\r | |
476 | Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (NewOpCode, 0);\r | |
477 | if (Node->AmlByteEncoding == NULL) {\r | |
478 | ASSERT (0);\r | |
479 | return EFI_INVALID_PARAMETER;\r | |
480 | }\r | |
481 | \r | |
482 | // Free the old DataNode buffer and allocate a buffer with the right size\r | |
483 | // to store the new data.\r | |
484 | if (*ValueWidthDiff != 0) {\r | |
485 | FreePool (DataNode->Buffer);\r | |
486 | DataNode->Buffer = AllocateZeroPool (NumberOfBytes);\r | |
487 | if (DataNode->Buffer == NULL) {\r | |
488 | ASSERT (0);\r | |
489 | return EFI_OUT_OF_RESOURCES;\r | |
490 | }\r | |
731c67e1 | 491 | \r |
667aa7cc PG |
492 | DataNode->Size = NumberOfBytes;\r |
493 | }\r | |
494 | \r | |
495 | // Write the new value.\r | |
496 | CopyMem (DataNode->Buffer, &NewValue, NumberOfBytes);\r | |
497 | \r | |
498 | return EFI_SUCCESS;\r | |
499 | }\r | |
500 | \r | |
501 | /** Increment/decrement the value contained in the IntegerNode.\r | |
502 | \r | |
503 | @param [in] IntegerNode Pointer to an object node containing\r | |
504 | an integer.\r | |
505 | @param [in] IsIncrement Choose the operation to do:\r | |
506 | - TRUE: Increment the Node's size and\r | |
507 | the Node's count;\r | |
508 | - FALSE: Decrement the Node's size and\r | |
509 | the Node's count.\r | |
510 | @param [in] Diff Value to add/subtract to the integer.\r | |
511 | @param [out] ValueWidthDiff When modifying the integer, it can be\r | |
512 | promoted/demoted, e.g. from UINT8 to UINT16.\r | |
513 | Stores the change in width.\r | |
514 | Can be negative.\r | |
515 | \r | |
516 | @retval EFI_SUCCESS The function completed successfully.\r | |
517 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
518 | **/\r | |
519 | STATIC\r | |
520 | EFI_STATUS\r | |
521 | EFIAPI\r | |
522 | AmlNodeUpdateIntegerValue (\r | |
731c67e1 MK |
523 | IN AML_OBJECT_NODE *IntegerNode,\r |
524 | IN BOOLEAN IsIncrement,\r | |
525 | IN UINT64 Diff,\r | |
526 | OUT INT8 *ValueWidthDiff\r | |
667aa7cc PG |
527 | )\r |
528 | {\r | |
731c67e1 MK |
529 | EFI_STATUS Status;\r |
530 | UINT64 Value;\r | |
667aa7cc PG |
531 | \r |
532 | if (ValueWidthDiff == NULL) {\r | |
533 | ASSERT (0);\r | |
534 | return EFI_INVALID_PARAMETER;\r | |
535 | }\r | |
536 | \r | |
537 | // Get the current value.\r | |
538 | // Checks on the IntegerNode are done in the call.\r | |
539 | Status = AmlNodeGetIntegerValue (IntegerNode, &Value);\r | |
540 | if (EFI_ERROR (Status)) {\r | |
541 | ASSERT (0);\r | |
542 | return Status;\r | |
543 | }\r | |
544 | \r | |
545 | // Check for UINT64 over/underflow.\r | |
546 | if ((IsIncrement && (Value > (MAX_UINT64 - Diff))) ||\r | |
731c67e1 MK |
547 | (!IsIncrement && (Value < Diff)))\r |
548 | {\r | |
667aa7cc PG |
549 | ASSERT (0);\r |
550 | return EFI_INVALID_PARAMETER;\r | |
551 | }\r | |
552 | \r | |
553 | // Compute the new value.\r | |
554 | if (IsIncrement) {\r | |
555 | Value += Diff;\r | |
556 | } else {\r | |
557 | Value -= Diff;\r | |
558 | }\r | |
559 | \r | |
560 | Status = AmlNodeSetIntegerValue (\r | |
561 | IntegerNode,\r | |
562 | Value,\r | |
563 | ValueWidthDiff\r | |
564 | );\r | |
565 | ASSERT_EFI_ERROR (Status);\r | |
566 | return Status;\r | |
567 | }\r | |
568 | \r | |
569 | /** Propagate the size information up the tree.\r | |
570 | \r | |
571 | The length of the ACPI table is updated in the RootNode,\r | |
572 | but not the checksum.\r | |
573 | \r | |
574 | @param [in] Node Pointer to a node.\r | |
575 | Must be a root node or an object node.\r | |
576 | @param [in] IsIncrement Choose the operation to do:\r | |
577 | - TRUE: Increment the Node's size and\r | |
578 | the Node's count;\r | |
579 | - FALSE: Decrement the Node's size and\r | |
580 | the Node's count.\r | |
581 | @param [in] Diff Value to add/subtract to the Node's size.\r | |
582 | \r | |
583 | @retval EFI_SUCCESS The function completed successfully.\r | |
584 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
585 | **/\r | |
586 | STATIC\r | |
587 | EFI_STATUS\r | |
588 | EFIAPI\r | |
589 | AmlPropagateSize (\r | |
731c67e1 MK |
590 | IN AML_NODE_HEADER *Node,\r |
591 | IN BOOLEAN IsIncrement,\r | |
592 | IN UINT32 *Diff\r | |
667aa7cc PG |
593 | )\r |
594 | {\r | |
731c67e1 MK |
595 | EFI_STATUS Status;\r |
596 | AML_OBJECT_NODE *ObjectNode;\r | |
597 | AML_NODE_HEADER *ParentNode;\r | |
667aa7cc | 598 | \r |
731c67e1 MK |
599 | UINT32 Value;\r |
600 | UINT32 InitialPkgLenWidth;\r | |
601 | UINT32 NewPkgLenWidth;\r | |
602 | UINT32 ReComputedPkgLenWidth;\r | |
603 | INT8 FieldWidthChange;\r | |
667aa7cc PG |
604 | \r |
605 | if (!IS_AML_OBJECT_NODE (Node) &&\r | |
731c67e1 MK |
606 | !IS_AML_ROOT_NODE (Node))\r |
607 | {\r | |
667aa7cc PG |
608 | ASSERT (0);\r |
609 | return EFI_INVALID_PARAMETER;\r | |
610 | }\r | |
611 | \r | |
612 | if (IS_AML_OBJECT_NODE (Node)) {\r | |
731c67e1 | 613 | ObjectNode = (AML_OBJECT_NODE *)Node;\r |
667aa7cc PG |
614 | \r |
615 | // For BufferOp, the buffer size is stored in BufferSize. Therefore,\r | |
616 | // BufferOp needs special handling to update the BufferSize.\r | |
617 | // BufferSize must be updated before the PkgLen to accommodate any\r | |
618 | // increment resulting from the update of the BufferSize.\r | |
619 | // DefBuffer := BufferOp PkgLength BufferSize ByteList\r | |
620 | // BufferOp := 0x11\r | |
621 | // BufferSize := TermArg => Integer\r | |
622 | if (AmlNodeCompareOpCode (ObjectNode, AML_BUFFER_OP, 0)) {\r | |
623 | // First fixed argument of BufferOp is an integer (BufferSize)\r | |
624 | // (can be a BYTE, WORD, DWORD or QWORD).\r | |
625 | // BufferSize is an object node.\r | |
626 | Status = AmlNodeUpdateIntegerValue (\r | |
731c67e1 MK |
627 | (AML_OBJECT_NODE *)AmlGetFixedArgument (\r |
628 | ObjectNode,\r | |
629 | EAmlParseIndexTerm0\r | |
630 | ),\r | |
667aa7cc PG |
631 | IsIncrement,\r |
632 | (UINT64)(*Diff),\r | |
633 | &FieldWidthChange\r | |
634 | );\r | |
635 | if (EFI_ERROR (Status)) {\r | |
636 | ASSERT (0);\r | |
637 | return Status;\r | |
638 | }\r | |
639 | \r | |
640 | // FieldWidthChange is an integer.\r | |
641 | // It must be positive if IsIncrement is TRUE, negative otherwise.\r | |
642 | if ((IsIncrement &&\r | |
643 | (FieldWidthChange < 0)) ||\r | |
644 | (!IsIncrement &&\r | |
731c67e1 MK |
645 | (FieldWidthChange > 0)))\r |
646 | {\r | |
667aa7cc PG |
647 | ASSERT (0);\r |
648 | return EFI_INVALID_PARAMETER;\r | |
649 | }\r | |
650 | \r | |
651 | // Check for UINT32 overflow.\r | |
652 | if (*Diff > (MAX_UINT32 - (UINT32)ABS (FieldWidthChange))) {\r | |
653 | ASSERT (0);\r | |
654 | return EFI_INVALID_PARAMETER;\r | |
655 | }\r | |
656 | \r | |
657 | // Update Diff if the field width changed.\r | |
658 | *Diff = (UINT32)(*Diff + ABS (FieldWidthChange));\r | |
659 | } // AML_BUFFER_OP node.\r | |
660 | \r | |
661 | // Update the PgkLen.\r | |
662 | // Needs to be done at last to reflect the potential field width changes.\r | |
663 | if (AmlNodeHasAttribute (ObjectNode, AML_HAS_PKG_LENGTH)) {\r | |
664 | Value = ObjectNode->PkgLen;\r | |
665 | \r | |
666 | // Subtract the size of the PkgLen encoding. The size of the PkgLen\r | |
667 | // encoding must be computed after having updated Value.\r | |
668 | InitialPkgLenWidth = AmlComputePkgLengthWidth (Value);\r | |
731c67e1 | 669 | Value -= InitialPkgLenWidth;\r |
667aa7cc PG |
670 | \r |
671 | // Check for an over/underflows.\r | |
672 | // PkgLen is a 28 bit value, cf 20.2.4 Package Length Encoding\r | |
673 | // i.e. the maximum value is (2^28 - 1) = ((BIT0 << 28) - 1).\r | |
674 | if ((IsIncrement && ((((BIT0 << 28) - 1) - Value) < *Diff)) ||\r | |
731c67e1 MK |
675 | (!IsIncrement && (Value < *Diff)))\r |
676 | {\r | |
667aa7cc PG |
677 | ASSERT (0);\r |
678 | return EFI_INVALID_PARAMETER;\r | |
679 | }\r | |
680 | \r | |
681 | // Update the size.\r | |
682 | if (IsIncrement) {\r | |
683 | Value += *Diff;\r | |
684 | } else {\r | |
685 | Value -= *Diff;\r | |
686 | }\r | |
687 | \r | |
688 | // Compute the new PkgLenWidth.\r | |
689 | NewPkgLenWidth = AmlComputePkgLengthWidth (Value);\r | |
690 | if (NewPkgLenWidth == 0) {\r | |
691 | ASSERT (0);\r | |
692 | return EFI_INVALID_PARAMETER;\r | |
693 | }\r | |
694 | \r | |
695 | // Add it to the Value.\r | |
696 | Value += NewPkgLenWidth;\r | |
697 | \r | |
698 | // Check that adding the PkgLenWidth didn't trigger a domino effect,\r | |
699 | // increasing the encoding width of the PkgLen again.\r | |
700 | // The PkgLen is encoded on at most 4 bytes. It is possible to increase\r | |
701 | // the PkgLen width if its encoding is on less than 3 bytes.\r | |
702 | ReComputedPkgLenWidth = AmlComputePkgLengthWidth (Value);\r | |
703 | if (ReComputedPkgLenWidth != NewPkgLenWidth) {\r | |
704 | if ((ReComputedPkgLenWidth != 0) &&\r | |
731c67e1 MK |
705 | (ReComputedPkgLenWidth < 4))\r |
706 | {\r | |
667aa7cc PG |
707 | // No need to recompute the PkgLen since a new threshold cannot\r |
708 | // be reached by incrementing the value by one.\r | |
709 | Value += 1;\r | |
710 | } else {\r | |
711 | ASSERT (0);\r | |
712 | return EFI_INVALID_PARAMETER;\r | |
713 | }\r | |
714 | }\r | |
715 | \r | |
716 | *Diff += (InitialPkgLenWidth > ReComputedPkgLenWidth) ?\r | |
731c67e1 MK |
717 | (InitialPkgLenWidth - ReComputedPkgLenWidth) :\r |
718 | (ReComputedPkgLenWidth - InitialPkgLenWidth);\r | |
667aa7cc PG |
719 | ObjectNode->PkgLen = Value;\r |
720 | } // PkgLen update.\r | |
721 | \r | |
722 | // During CodeGeneration, the tree is incomplete and\r | |
723 | // there is no root node at the top of the tree. Stop\r | |
724 | // propagating the new size when finding a root node\r | |
725 | // OR when a NULL parent is found.\r | |
731c67e1 | 726 | ParentNode = AmlGetParent ((AML_NODE_HEADER *)Node);\r |
667aa7cc PG |
727 | if (ParentNode != NULL) {\r |
728 | // Propagate the size up the tree.\r | |
729 | Status = AmlPropagateSize (\r | |
730 | Node->Parent,\r | |
731 | IsIncrement,\r | |
732 | Diff\r | |
733 | );\r | |
734 | if (EFI_ERROR (Status)) {\r | |
735 | ASSERT (0);\r | |
736 | return Status;\r | |
737 | }\r | |
738 | }\r | |
667aa7cc PG |
739 | } else if (IS_AML_ROOT_NODE (Node)) {\r |
740 | // Update the length field in the SDT header.\r | |
731c67e1 | 741 | Value = ((AML_ROOT_NODE *)Node)->SdtHeader->Length;\r |
667aa7cc PG |
742 | \r |
743 | // Check for an over/underflows.\r | |
744 | if ((IsIncrement && (Value > (MAX_UINT32 - *Diff))) ||\r | |
731c67e1 MK |
745 | (!IsIncrement && (Value < *Diff)))\r |
746 | {\r | |
667aa7cc PG |
747 | ASSERT (0);\r |
748 | return EFI_INVALID_PARAMETER;\r | |
749 | }\r | |
750 | \r | |
751 | // Update the size.\r | |
752 | if (IsIncrement) {\r | |
753 | Value += *Diff;\r | |
754 | } else {\r | |
755 | Value -= *Diff;\r | |
756 | }\r | |
757 | \r | |
731c67e1 | 758 | ((AML_ROOT_NODE *)Node)->SdtHeader->Length = Value;\r |
667aa7cc PG |
759 | }\r |
760 | \r | |
761 | return EFI_SUCCESS;\r | |
762 | }\r | |
763 | \r | |
764 | /** Propagate the node count information up the tree.\r | |
765 | \r | |
766 | @param [in] ObjectNode Pointer to an object node.\r | |
767 | @param [in] IsIncrement Choose the operation to do:\r | |
768 | - TRUE: Increment the Node's size and\r | |
769 | the Node's count;\r | |
770 | - FALSE: Decrement the Node's size and\r | |
771 | the Node's count.\r | |
772 | @param [in] NodeCount Number of nodes added/removed (depends on the\r | |
773 | value of Operation).\r | |
774 | @param [out] FieldWidthChange When modifying the integer, it can be\r | |
775 | promoted/demoted, e.g. from UINT8 to UINT16.\r | |
776 | Stores the change in width.\r | |
777 | Can be negative.\r | |
778 | \r | |
779 | @retval EFI_SUCCESS The function completed successfully.\r | |
780 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
781 | **/\r | |
782 | STATIC\r | |
783 | EFI_STATUS\r | |
784 | EFIAPI\r | |
785 | AmlPropagateNodeCount (\r | |
731c67e1 MK |
786 | IN AML_OBJECT_NODE *ObjectNode,\r |
787 | IN BOOLEAN IsIncrement,\r | |
788 | IN UINT8 NodeCount,\r | |
789 | OUT INT8 *FieldWidthChange\r | |
667aa7cc PG |
790 | )\r |
791 | {\r | |
731c67e1 | 792 | EFI_STATUS Status;\r |
667aa7cc | 793 | \r |
731c67e1 MK |
794 | AML_NODE_HEADER *NodeCountArg;\r |
795 | UINT8 CurrNodeCount;\r | |
667aa7cc PG |
796 | \r |
797 | // Currently there is no use case where (NodeCount > 1).\r | |
798 | if (!IS_AML_OBJECT_NODE (ObjectNode) ||\r | |
799 | (FieldWidthChange == NULL) ||\r | |
731c67e1 MK |
800 | (NodeCount > 1))\r |
801 | {\r | |
667aa7cc PG |
802 | ASSERT (0);\r |
803 | return EFI_INVALID_PARAMETER;\r | |
804 | }\r | |
805 | \r | |
806 | *FieldWidthChange = 0;\r | |
807 | \r | |
808 | // Update the number of elements stored in PackageOp and VarPackageOp.\r | |
809 | // The number of elements is stored as the first fixed argument.\r | |
810 | // DefPackage := PackageOp PkgLength NumElements PackageElementList\r | |
811 | // PackageOp := 0x12\r | |
812 | // DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList\r | |
813 | // VarPackageOp := 0x13\r | |
814 | // NumElements := ByteData\r | |
815 | // VarNumElements := TermArg => Integer\r | |
816 | NodeCountArg = AmlGetFixedArgument (ObjectNode, EAmlParseIndexTerm0);\r | |
817 | if (AmlNodeCompareOpCode (ObjectNode, AML_PACKAGE_OP, 0)) {\r | |
818 | // First fixed argument of PackageOp stores the number of elements\r | |
819 | // in the package. It is an UINT8.\r | |
820 | \r | |
821 | // Check for over/underflow.\r | |
731c67e1 | 822 | CurrNodeCount = *(((AML_DATA_NODE *)NodeCountArg)->Buffer);\r |
667aa7cc | 823 | if ((IsIncrement && (CurrNodeCount == MAX_UINT8)) ||\r |
731c67e1 MK |
824 | (!IsIncrement && (CurrNodeCount == 0)))\r |
825 | {\r | |
667aa7cc PG |
826 | ASSERT (0);\r |
827 | return EFI_INVALID_PARAMETER;\r | |
828 | }\r | |
829 | \r | |
830 | // Update the node count in the DataNode.\r | |
731c67e1 MK |
831 | CurrNodeCount = IsIncrement ? (CurrNodeCount + 1) : (CurrNodeCount - 1);\r |
832 | *(((AML_DATA_NODE *)NodeCountArg)->Buffer) = CurrNodeCount;\r | |
667aa7cc PG |
833 | } else if (AmlNodeCompareOpCode (ObjectNode, AML_VAR_PACKAGE_OP, 0)) {\r |
834 | // First fixed argument of PackageOp stores the number of elements\r | |
835 | // in the package. It is an integer (can be a BYTE, WORD, DWORD, QWORD).\r | |
836 | Status = AmlNodeUpdateIntegerValue (\r | |
731c67e1 MK |
837 | (AML_OBJECT_NODE *)NodeCountArg,\r |
838 | IsIncrement,\r | |
839 | NodeCount,\r | |
840 | FieldWidthChange\r | |
841 | );\r | |
667aa7cc PG |
842 | if (EFI_ERROR (Status)) {\r |
843 | ASSERT (0);\r | |
844 | return Status;\r | |
845 | }\r | |
846 | }\r | |
847 | \r | |
848 | return EFI_SUCCESS;\r | |
849 | }\r | |
850 | \r | |
851 | /** Propagate information up the tree.\r | |
852 | \r | |
853 | The information can be a new size, a new number of arguments.\r | |
854 | \r | |
855 | @param [in] Node Pointer to a node.\r | |
856 | Must be a root node or an object node.\r | |
857 | @param [in] IsIncrement Choose the operation to do:\r | |
858 | - TRUE: Increment the Node's size and\r | |
859 | the Node's count;\r | |
860 | - FALSE: Decrement the Node's size and\r | |
861 | the Node's count.\r | |
862 | @param [in] Diff Value to add/subtract to the Node's size.\r | |
863 | @param [in] NodeCount Number of nodes added/removed.\r | |
864 | \r | |
865 | @retval EFI_SUCCESS The function completed successfully.\r | |
866 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
867 | **/\r | |
868 | EFI_STATUS\r | |
869 | EFIAPI\r | |
870 | AmlPropagateInformation (\r | |
731c67e1 MK |
871 | IN AML_NODE_HEADER *Node,\r |
872 | IN BOOLEAN IsIncrement,\r | |
873 | IN UINT32 Diff,\r | |
874 | IN UINT8 NodeCount\r | |
667aa7cc PG |
875 | )\r |
876 | {\r | |
877 | EFI_STATUS Status;\r | |
878 | INT8 FieldWidthChange;\r | |
879 | \r | |
880 | // Currently there is no use case where (NodeCount > 1).\r | |
881 | if ((!IS_AML_ROOT_NODE (Node) &&\r | |
882 | !IS_AML_OBJECT_NODE (Node)) ||\r | |
731c67e1 MK |
883 | (NodeCount > 1))\r |
884 | {\r | |
667aa7cc PG |
885 | ASSERT (0);\r |
886 | return EFI_INVALID_PARAMETER;\r | |
887 | }\r | |
888 | \r | |
889 | // Propagate the node count first as it may change the number of bytes\r | |
890 | // needed to store the node count, and then impact FieldWidthChange.\r | |
891 | if ((NodeCount != 0) &&\r | |
731c67e1 MK |
892 | IS_AML_OBJECT_NODE (Node))\r |
893 | {\r | |
667aa7cc | 894 | Status = AmlPropagateNodeCount (\r |
731c67e1 | 895 | (AML_OBJECT_NODE *)Node,\r |
667aa7cc PG |
896 | IsIncrement,\r |
897 | NodeCount,\r | |
898 | &FieldWidthChange\r | |
899 | );\r | |
900 | if (EFI_ERROR (Status)) {\r | |
901 | ASSERT (0);\r | |
902 | return Status;\r | |
903 | }\r | |
904 | \r | |
905 | // Propagate the potential field width change.\r | |
906 | // Maximum change is between UINT8/UINT64: 8 bytes.\r | |
907 | if ((ABS (FieldWidthChange) > 8) ||\r | |
908 | (IsIncrement &&\r | |
731c67e1 MK |
909 | ((FieldWidthChange < 0) ||\r |
910 | ((Diff + (UINT8)FieldWidthChange) > MAX_UINT32))) ||\r | |
667aa7cc | 911 | (!IsIncrement &&\r |
731c67e1 MK |
912 | ((FieldWidthChange > 0) ||\r |
913 | (Diff < (UINT32)ABS (FieldWidthChange)))))\r | |
914 | {\r | |
667aa7cc PG |
915 | ASSERT (0);\r |
916 | return EFI_INVALID_PARAMETER;\r | |
917 | }\r | |
731c67e1 | 918 | \r |
667aa7cc PG |
919 | Diff = (UINT32)(Diff + (UINT8)ABS (FieldWidthChange));\r |
920 | }\r | |
921 | \r | |
922 | // Diff can be zero if some data is updated without modifying the data size.\r | |
923 | if (Diff != 0) {\r | |
924 | Status = AmlPropagateSize (Node, IsIncrement, &Diff);\r | |
925 | if (EFI_ERROR (Status)) {\r | |
926 | ASSERT (0);\r | |
927 | return Status;\r | |
928 | }\r | |
929 | }\r | |
930 | \r | |
931 | return EFI_SUCCESS;\r | |
932 | }\r | |
74addfea PG |
933 | \r |
934 | /** Find and set the EndTag's Checksum of a list of Resource Data elements.\r | |
935 | \r | |
936 | Lists of Resource Data elements end with an EndTag (most of the time). This\r | |
937 | function finds the EndTag (if present) in a list of Resource Data elements\r | |
938 | and sets the checksum.\r | |
939 | \r | |
940 | ACPI 6.4, s6.4.2.9 "End Tag":\r | |
941 | "This checksum is generated such that adding it to the sum of all the data\r | |
942 | bytes will produce a zero sum."\r | |
943 | "If the checksum field is zero, the resource data is treated as if the\r | |
944 | checksum operation succeeded. Configuration proceeds normally."\r | |
945 | \r | |
946 | To avoid re-computing checksums, if a new resource data elements is\r | |
947 | added/removed/modified in a list of resource data elements, the AmlLib\r | |
948 | resets the checksum to 0.\r | |
949 | \r | |
950 | @param [in] BufferOpNode Node having a list of Resource Data elements.\r | |
951 | @param [in] CheckSum CheckSum to store in the EndTag.\r | |
952 | To ignore/avoid computing the checksum,\r | |
953 | give 0.\r | |
954 | \r | |
955 | @retval EFI_SUCCESS The function completed successfully.\r | |
956 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
957 | @retval EFI_NOT_FOUND No EndTag found.\r | |
958 | **/\r | |
959 | EFI_STATUS\r | |
960 | EFIAPI\r | |
961 | AmlSetRdListCheckSum (\r | |
731c67e1 MK |
962 | IN AML_OBJECT_NODE *BufferOpNode,\r |
963 | IN UINT8 CheckSum\r | |
74addfea PG |
964 | )\r |
965 | {\r | |
731c67e1 MK |
966 | EFI_STATUS Status;\r |
967 | AML_DATA_NODE *LastRdNode;\r | |
968 | AML_RD_HEADER RdDataType;\r | |
74addfea PG |
969 | \r |
970 | if (!AmlNodeCompareOpCode (BufferOpNode, AML_BUFFER_OP, 0)) {\r | |
971 | ASSERT (0);\r | |
972 | return EFI_INVALID_PARAMETER;\r | |
973 | }\r | |
974 | \r | |
975 | // Get the last Resource data node in the variable list of\r | |
976 | // argument of the BufferOp node.\r | |
731c67e1 MK |
977 | LastRdNode = (AML_DATA_NODE *)AmlGetPreviousVariableArgument (\r |
978 | (AML_NODE_HEADER *)BufferOpNode,\r | |
979 | NULL\r | |
980 | );\r | |
74addfea PG |
981 | if ((LastRdNode == NULL) ||\r |
982 | !IS_AML_DATA_NODE (LastRdNode) ||\r | |
731c67e1 MK |
983 | (LastRdNode->DataType != EAmlNodeDataTypeResourceData))\r |
984 | {\r | |
74addfea PG |
985 | ASSERT (0);\r |
986 | return EFI_INVALID_PARAMETER;\r | |
987 | }\r | |
988 | \r | |
989 | Status = AmlGetResourceDataType (LastRdNode, &RdDataType);\r | |
990 | if (EFI_ERROR (Status)) {\r | |
991 | ASSERT (0);\r | |
992 | return Status;\r | |
993 | }\r | |
994 | \r | |
995 | // Check the LastRdNode is an EndTag.\r | |
996 | // It is possible to have only one Resource Data in a BufferOp with\r | |
997 | // no EndTag. Return EFI_NOT_FOUND is such case.\r | |
998 | if (!AmlRdCompareDescId (\r | |
731c67e1 MK |
999 | &RdDataType,\r |
1000 | AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME)\r | |
1001 | ))\r | |
1002 | {\r | |
74addfea PG |
1003 | ASSERT (0);\r |
1004 | return EFI_NOT_FOUND;\r | |
1005 | }\r | |
1006 | \r | |
1007 | Status = AmlRdSetEndTagChecksum (LastRdNode->Buffer, CheckSum);\r | |
1008 | ASSERT_EFI_ERROR (Status);\r | |
1009 | \r | |
1010 | return Status;\r | |
1011 | }\r |