]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
DynamicTablesPkg: AmlLib APIs
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Api / AmlApi.c
1 /** @file
2 AML Api.
3
4 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 /* Even though this file has access to the internal Node definition,
10 i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node
11 handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE,
12 etc.
13 Indeed, the functions in the "Api" folder should be implemented only
14 using the "safe" functions available in the "Include" folder. This
15 makes the functions available in the "Api" folder easy to export.
16 */
17 #include <AmlNodeDefines.h>
18
19 #include <AmlCoreInterface.h>
20 #include <AmlInclude.h>
21 #include <Api/AmlApiHelper.h>
22 #include <String/AmlString.h>
23
24 /** Update the name of a DeviceOp object node.
25
26 @param [in] DeviceOpNode Object node representing a Device.
27 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
28 OpCode/SubOpCode.
29 DeviceOp object nodes are defined in ASL
30 using the "Device ()" function.
31 @param [in] NewNameString The new Device's name.
32 Must be a NULL-terminated ASL NameString
33 e.g.: "DEV0", "DV15.DEV0", etc.
34 The input string is copied.
35
36 @retval EFI_SUCCESS The function completed successfully.
37 @retval EFI_INVALID_PARAMETER Invalid parameter.
38 **/
39 EFI_STATUS
40 EFIAPI
41 AmlDeviceOpUpdateName (
42 IN AML_OBJECT_NODE_HANDLE DeviceOpNode,
43 IN CHAR8 * NewNameString
44 )
45 {
46 EFI_STATUS Status;
47
48 AML_DATA_NODE_HANDLE DeviceNameDataNode;
49 CHAR8 * NewAmlNameString;
50 UINT32 NewAmlNameStringSize;
51
52 // Check the input node is an object node.
53 if ((DeviceOpNode == NULL) ||
54 (AmlGetNodeType ((AML_NODE_HANDLE)DeviceOpNode) != EAmlNodeObject) ||
55 (!AmlNodeHasOpCode (DeviceOpNode, AML_EXT_OP, AML_EXT_DEVICE_OP)) ||
56 (NewNameString == NULL)) {
57 ASSERT (0);
58 return EFI_INVALID_PARAMETER;
59 }
60
61 // Get the Device's name, being a data node
62 // which is the 1st fixed argument (i.e. index 0).
63 DeviceNameDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
64 DeviceOpNode,
65 EAmlParseIndexTerm0
66 );
67 if ((DeviceNameDataNode == NULL) ||
68 (AmlGetNodeType ((AML_NODE_HANDLE)DeviceNameDataNode) != EAmlNodeData) ||
69 (!AmlNodeHasDataType (DeviceNameDataNode, EAmlNodeDataTypeNameString))) {
70 ASSERT (0);
71 return EFI_INVALID_PARAMETER;
72 }
73
74 Status = ConvertAslNameToAmlName (NewNameString, &NewAmlNameString);
75 if (EFI_ERROR (Status)) {
76 ASSERT (0);
77 return Status;
78 }
79
80 Status = AmlGetNameStringSize (NewAmlNameString, &NewAmlNameStringSize);
81 if (EFI_ERROR (Status)) {
82 ASSERT (0);
83 goto exit_handler;
84 }
85
86 // Update the Device's name node.
87 Status = AmlUpdateDataNode (
88 DeviceNameDataNode,
89 EAmlNodeDataTypeNameString,
90 (UINT8*)NewAmlNameString,
91 NewAmlNameStringSize
92 );
93 ASSERT_EFI_ERROR (Status);
94
95 exit_handler:
96 FreePool (NewAmlNameString);
97 return Status;
98 }
99
100 /** Update an integer value defined by a NameOp object node.
101
102 For compatibility reasons, the NameOpNode must initially
103 contain an integer.
104
105 @param [in] NameOpNode NameOp object node.
106 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
107 NameOp object nodes are defined in ASL
108 using the "Name ()" function.
109 @param [in] NewInt New Integer value to assign.
110 Must be a UINT64.
111
112 @retval EFI_SUCCESS The function completed successfully.
113 @retval EFI_INVALID_PARAMETER Invalid parameter.
114 **/
115 EFI_STATUS
116 EFIAPI
117 AmlNameOpUpdateInteger (
118 IN AML_OBJECT_NODE_HANDLE NameOpNode,
119 IN UINT64 NewInt
120 )
121 {
122 EFI_STATUS Status;
123 AML_OBJECT_NODE_HANDLE IntegerOpNode;
124
125 if ((NameOpNode == NULL) ||
126 (AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) ||
127 (!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) {
128 ASSERT (0);
129 return EFI_INVALID_PARAMETER;
130 }
131
132 // Get the Integer object node defined by the "Name ()" function:
133 // it must have an Integer OpCode (Byte/Word/DWord/QWord).
134 // It is the 2nd fixed argument (i.e. index 1) of the NameOp node.
135 // This can also be a ZeroOp or OneOp node.
136 IntegerOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
137 NameOpNode,
138 EAmlParseIndexTerm1
139 );
140 if ((IntegerOpNode == NULL) ||
141 (AmlGetNodeType ((AML_NODE_HANDLE)IntegerOpNode) != EAmlNodeObject)) {
142 ASSERT (0);
143 return EFI_INVALID_PARAMETER;
144 }
145
146 // Update the Integer value.
147 Status = AmlUpdateInteger (IntegerOpNode, NewInt);
148 ASSERT_EFI_ERROR (Status);
149
150 return Status;
151 }
152
153 /** Update a string value defined by a NameOp object node.
154
155 The NameOpNode must initially contain a string.
156 The EISAID ASL macro converts a string to an integer. This, it is
157 not accepted.
158
159 @param [in] NameOpNode NameOp object node.
160 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
161 NameOp object nodes are defined in ASL
162 using the "Name ()" function.
163 @param [in] NewName New NULL terminated string to assign to
164 the NameOpNode.
165 The input string is copied.
166
167 @retval EFI_SUCCESS The function completed successfully.
168 @retval EFI_INVALID_PARAMETER Invalid parameter.
169 **/
170 EFI_STATUS
171 EFIAPI
172 AmlNameOpUpdateString (
173 IN AML_OBJECT_NODE_HANDLE NameOpNode,
174 IN CONST CHAR8 * NewName
175 )
176 {
177 EFI_STATUS Status;
178 AML_OBJECT_NODE_HANDLE StringOpNode;
179 AML_DATA_NODE_HANDLE StringDataNode;
180
181 if ((NameOpNode == NULL) ||
182 (AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) ||
183 (!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) {
184 ASSERT (0);
185 return EFI_INVALID_PARAMETER;
186 }
187
188 // Get the String object node defined by the "Name ()" function:
189 // it must have a string OpCode.
190 // It is the 2nd fixed argument (i.e. index 1) of the NameOp node.
191 StringOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
192 NameOpNode,
193 EAmlParseIndexTerm1
194 );
195 if ((StringOpNode == NULL) ||
196 (AmlGetNodeType ((AML_NODE_HANDLE)StringOpNode) != EAmlNodeObject)) {
197 ASSERT (0);
198 return EFI_INVALID_PARAMETER;
199 }
200
201 // Get the string data node.
202 // It is the 1st fixed argument (i.e. index 0) of the StringOpNode node.
203 StringDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
204 StringOpNode,
205 EAmlParseIndexTerm0
206 );
207 if ((StringDataNode == NULL) ||
208 (AmlGetNodeType ((AML_NODE_HANDLE)StringDataNode) != EAmlNodeData)) {
209 ASSERT (0);
210 return EFI_INVALID_PARAMETER;
211 }
212
213 // Update the string value.
214 Status = AmlUpdateDataNode (
215 StringDataNode,
216 EAmlNodeDataTypeString,
217 (UINT8*)NewName,
218 (UINT32)AsciiStrLen (NewName) + 1
219 );
220 ASSERT_EFI_ERROR (Status);
221
222 return Status;
223 }
224
225 /** Get the first Resource Data element contained in a "_CRS" object.
226
227 In the following ASL code, the function will return the Resource Data
228 node corresponding to the "QWordMemory ()" ASL macro.
229 Name (_CRS, ResourceTemplate() {
230 QWordMemory (...) {...},
231 Interrupt (...) {...}
232 }
233 )
234
235 Note:
236 - The "_CRS" object must be declared using ASL "Name (Declare Named Object)".
237 - "_CRS" declared using ASL "Method (Declare Control Method)" is not
238 supported.
239
240 @param [in] NameOpCrsNode NameOp object node defining a "_CRS" object.
241 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
242 NameOp object nodes are defined in ASL
243 using the "Name ()" function.
244 @param [out] OutRdNode Pointer to the first Resource Data element of
245 the "_CRS" object. A Resource Data element
246 is stored in a data node.
247
248 @retval EFI_SUCCESS The function completed successfully.
249 @retval EFI_INVALID_PARAMETER Invalid parameter.
250 **/
251 EFI_STATUS
252 EFIAPI
253 AmlNameOpCrsGetFirstRdNode (
254 IN AML_OBJECT_NODE_HANDLE NameOpCrsNode,
255 OUT AML_DATA_NODE_HANDLE * OutRdNode
256 )
257 {
258 AML_OBJECT_NODE_HANDLE BufferOpNode;
259 AML_DATA_NODE_HANDLE FirstRdNode;
260
261 if ((NameOpCrsNode == NULL) ||
262 (AmlGetNodeType ((AML_NODE_HANDLE)NameOpCrsNode) != EAmlNodeObject) ||
263 (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
264 (!AmlNameOpCompareName (NameOpCrsNode, "_CRS")) ||
265 (OutRdNode == NULL)) {
266 ASSERT (0);
267 return EFI_INVALID_PARAMETER;
268 }
269
270 *OutRdNode = NULL;
271
272 // Get the _CRS value which is represented as a BufferOp object node
273 // which is the 2nd fixed argument (i.e. index 1).
274 BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
275 NameOpCrsNode,
276 EAmlParseIndexTerm1
277 );
278 if ((BufferOpNode == NULL) ||
279 (AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) ||
280 (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) {
281 ASSERT (0);
282 return EFI_INVALID_PARAMETER;
283 }
284
285 // Get the first Resource data node in the variable list of
286 // argument of the BufferOp node.
287 FirstRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument (
288 (AML_NODE_HANDLE)BufferOpNode,
289 NULL
290 );
291 if ((FirstRdNode == NULL) ||
292 (AmlGetNodeType ((AML_NODE_HANDLE)FirstRdNode) != EAmlNodeData) ||
293 (!AmlNodeHasDataType (FirstRdNode, EAmlNodeDataTypeResourceData))) {
294 ASSERT (0);
295 return EFI_INVALID_PARAMETER;
296 }
297
298 *OutRdNode = FirstRdNode;
299 return EFI_SUCCESS;
300 }
301
302 /** Get the Resource Data element following the CurrRdNode Resource Data.
303
304 In the following ASL code, if CurrRdNode corresponds to the first
305 "QWordMemory ()" ASL macro, the function will return the Resource Data
306 node corresponding to the "Interrupt ()" ASL macro.
307 Name (_CRS, ResourceTemplate() {
308 QwordMemory (...) {...},
309 Interrupt (...) {...}
310 }
311 )
312
313 The CurrRdNode Resource Data node must be defined in an object named "_CRS"
314 and defined by a "Name ()" ASL function.
315
316 @param [in] CurrRdNode Pointer to the current Resource Data element of
317 the "_CRS" object.
318 @param [out] OutRdNode Pointer to the Resource Data element following
319 the CurrRdNode.
320 Contain a NULL pointer if CurrRdNode is the
321 last Resource Data element in the list.
322 The "End Tag" is not considered as a resource
323 data element and is not returned.
324
325 @retval EFI_SUCCESS The function completed successfully.
326 @retval EFI_INVALID_PARAMETER Invalid parameter.
327 **/
328 EFI_STATUS
329 EFIAPI
330 AmlNameOpCrsGetNextRdNode (
331 IN AML_DATA_NODE_HANDLE CurrRdNode,
332 OUT AML_DATA_NODE_HANDLE * OutRdNode
333 )
334 {
335 AML_OBJECT_NODE_HANDLE NameOpCrsNode;
336 AML_OBJECT_NODE_HANDLE BufferOpNode;
337
338 if ((CurrRdNode == NULL) ||
339 (AmlGetNodeType ((AML_NODE_HANDLE)CurrRdNode) != EAmlNodeData) ||
340 (!AmlNodeHasDataType (CurrRdNode, EAmlNodeDataTypeResourceData)) ||
341 (OutRdNode == NULL)) {
342 ASSERT (0);
343 return EFI_INVALID_PARAMETER;
344 }
345
346 *OutRdNode = NULL;
347
348 // The parent of the CurrRdNode must be a BufferOp node.
349 BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent (
350 (AML_NODE_HANDLE)CurrRdNode
351 );
352 if ((BufferOpNode == NULL) ||
353 (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) {
354 ASSERT (0);
355 return EFI_INVALID_PARAMETER;
356 }
357
358 // The parent of the BufferOpNode must be a NameOp node.
359 NameOpCrsNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent (
360 (AML_NODE_HANDLE)BufferOpNode
361 );
362 if ((NameOpCrsNode == NULL) ||
363 (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
364 (!AmlNameOpCompareName (NameOpCrsNode, "_CRS"))) {
365 ASSERT (0);
366 return EFI_INVALID_PARAMETER;
367 }
368
369 *OutRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument (
370 (AML_NODE_HANDLE)BufferOpNode,
371 (AML_NODE_HANDLE)CurrRdNode
372 );
373
374 // If the Resource Data is an End Tag, return NULL.
375 if (AmlNodeHasRdDataType (
376 *OutRdNode,
377 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
378 *OutRdNode = NULL;
379 }
380
381 return EFI_SUCCESS;
382 }