]>
Commit | Line | Data |
---|---|---|
e2c1104c PG |
1 | /** @file\r |
2 | AML Tree Iterator.\r | |
3 | \r | |
4 | Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r | |
5 | \r | |
6 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
7 | **/\r | |
8 | \r | |
9 | #include <AmlNodeDefines.h>\r | |
10 | #include <Tree/AmlTreeIterator.h>\r | |
11 | \r | |
12 | #include <AmlCoreInterface.h>\r | |
13 | #include <Tree/AmlTreeTraversal.h>\r | |
14 | \r | |
15 | /** Iterator to traverse the tree.\r | |
16 | \r | |
17 | This is an internal structure.\r | |
18 | */\r | |
19 | typedef struct AmlTreeInternalIterator {\r | |
20 | /// External iterator structure, containing the external APIs.\r | |
21 | /// Must be the first field.\r | |
22 | AML_TREE_ITERATOR Iterator;\r | |
23 | \r | |
24 | // Note: The following members of this structure are opaque to the users\r | |
25 | // of the Tree iterator APIs.\r | |
26 | \r | |
27 | /// Pointer to the node on which the iterator has been initialized.\r | |
731c67e1 | 28 | CONST AML_NODE_HEADER *InitialNode;\r |
e2c1104c PG |
29 | \r |
30 | /// Pointer to the current node.\r | |
731c67e1 | 31 | CONST AML_NODE_HEADER *CurrentNode;\r |
e2c1104c PG |
32 | \r |
33 | /// Iteration mode.\r | |
34 | /// Allow to choose how to traverse the tree/choose which node is next.\r | |
35 | EAML_ITERATOR_MODE Mode;\r | |
36 | } AML_TREE_ITERATOR_INTERNAL;\r | |
37 | \r | |
38 | /** Get the current node of an iterator.\r | |
39 | \r | |
40 | @param [in] Iterator Pointer to an iterator.\r | |
41 | @param [out] OutNode Pointer holding the current node.\r | |
42 | \r | |
43 | @retval EFI_SUCCESS The function completed successfully.\r | |
44 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
45 | **/\r | |
46 | STATIC\r | |
47 | EFI_STATUS\r | |
48 | EFIAPI\r | |
49 | AmlIteratorGetNode (\r | |
731c67e1 MK |
50 | IN AML_TREE_ITERATOR *Iterator,\r |
51 | OUT AML_NODE_HEADER **OutNode\r | |
e2c1104c PG |
52 | )\r |
53 | {\r | |
731c67e1 | 54 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
e2c1104c | 55 | \r |
731c67e1 | 56 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)Iterator;\r |
e2c1104c PG |
57 | \r |
58 | // CurrentNode can be NULL, but InitialNode cannot.\r | |
59 | if ((OutNode == NULL) ||\r | |
60 | (InternalIterator == NULL) ||\r | |
61 | (InternalIterator->Mode <= EAmlIteratorUnknown) ||\r | |
62 | (InternalIterator->Mode >= EAmlIteratorModeMax) ||\r | |
63 | !IS_AML_NODE_VALID (InternalIterator->InitialNode) ||\r | |
64 | ((InternalIterator->CurrentNode != NULL) &&\r | |
731c67e1 MK |
65 | !IS_AML_NODE_VALID (InternalIterator->CurrentNode)))\r |
66 | {\r | |
e2c1104c PG |
67 | ASSERT (0);\r |
68 | return EFI_INVALID_PARAMETER;\r | |
69 | }\r | |
70 | \r | |
731c67e1 | 71 | *OutNode = (AML_NODE_HEADER *)InternalIterator->CurrentNode;\r |
e2c1104c PG |
72 | \r |
73 | return EFI_SUCCESS;\r | |
74 | }\r | |
75 | \r | |
76 | /** Move the current node of the iterator to the next node,\r | |
77 | according to the iteration mode selected.\r | |
78 | \r | |
79 | If NextNode is not NULL, return the next node.\r | |
80 | \r | |
81 | @param [in] Iterator Pointer to an iterator.\r | |
82 | @param [out] NextNode If not NULL, updated to the next node.\r | |
83 | \r | |
84 | @retval EFI_SUCCESS The function completed successfully.\r | |
85 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
86 | **/\r | |
87 | STATIC\r | |
88 | EFI_STATUS\r | |
89 | EFIAPI\r | |
90 | AmlIteratorGetNextLinear (\r | |
731c67e1 MK |
91 | IN AML_TREE_ITERATOR *Iterator,\r |
92 | OUT AML_NODE_HEADER **NextNode\r | |
e2c1104c PG |
93 | )\r |
94 | {\r | |
731c67e1 | 95 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
e2c1104c | 96 | \r |
731c67e1 | 97 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)Iterator;\r |
e2c1104c PG |
98 | \r |
99 | // CurrentNode can be NULL, but InitialNode cannot.\r | |
100 | if ((InternalIterator == NULL) ||\r | |
101 | (InternalIterator->Mode != EAmlIteratorLinear) ||\r | |
102 | !IS_AML_NODE_VALID (InternalIterator->InitialNode) ||\r | |
731c67e1 MK |
103 | !IS_AML_NODE_VALID (InternalIterator->CurrentNode))\r |
104 | {\r | |
e2c1104c PG |
105 | ASSERT (0);\r |
106 | return EFI_INVALID_PARAMETER;\r | |
107 | }\r | |
108 | \r | |
109 | // Get the next node according to the iteration mode.\r | |
110 | InternalIterator->CurrentNode = AmlGetNextNode (\r | |
111 | InternalIterator->CurrentNode\r | |
112 | );\r | |
113 | \r | |
114 | if (NextNode != NULL) {\r | |
731c67e1 | 115 | *NextNode = (AML_NODE_HEADER *)InternalIterator->CurrentNode;\r |
e2c1104c | 116 | }\r |
731c67e1 | 117 | \r |
e2c1104c PG |
118 | return EFI_SUCCESS;\r |
119 | }\r | |
120 | \r | |
121 | /** Move the current node of the iterator to the previous node,\r | |
122 | according to the iteration mode selected.\r | |
123 | \r | |
124 | If PrevNode is not NULL, return the previous node.\r | |
125 | \r | |
126 | @param [in] Iterator Pointer to an iterator.\r | |
127 | @param [out] PrevNode If not NULL, updated to the previous node.\r | |
128 | \r | |
129 | @retval EFI_SUCCESS The function completed successfully.\r | |
130 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
131 | **/\r | |
132 | STATIC\r | |
133 | EFI_STATUS\r | |
134 | EFIAPI\r | |
135 | AmlIteratorGetPreviousLinear (\r | |
731c67e1 MK |
136 | IN AML_TREE_ITERATOR *Iterator,\r |
137 | OUT AML_NODE_HEADER **PrevNode\r | |
e2c1104c PG |
138 | )\r |
139 | {\r | |
731c67e1 | 140 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
e2c1104c | 141 | \r |
731c67e1 | 142 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)Iterator;\r |
e2c1104c PG |
143 | \r |
144 | // CurrentNode can be NULL, but InitialNode cannot.\r | |
145 | if ((InternalIterator == NULL) ||\r | |
146 | (InternalIterator->Mode != EAmlIteratorLinear) ||\r | |
147 | !IS_AML_NODE_VALID (InternalIterator->InitialNode) ||\r | |
731c67e1 MK |
148 | !IS_AML_NODE_VALID (InternalIterator->CurrentNode))\r |
149 | {\r | |
e2c1104c PG |
150 | ASSERT (0);\r |
151 | return EFI_INVALID_PARAMETER;\r | |
152 | }\r | |
153 | \r | |
154 | // Get the previous node according to the iteration mode.\r | |
155 | InternalIterator->CurrentNode = AmlGetPreviousNode (\r | |
156 | InternalIterator->CurrentNode\r | |
157 | );\r | |
158 | if (PrevNode != NULL) {\r | |
731c67e1 | 159 | *PrevNode = (AML_NODE_HEADER *)InternalIterator->CurrentNode;\r |
e2c1104c | 160 | }\r |
731c67e1 | 161 | \r |
e2c1104c PG |
162 | return EFI_SUCCESS;\r |
163 | }\r | |
164 | \r | |
165 | /** Move the current node of the iterator to the next node,\r | |
166 | according to the iteration mode selected.\r | |
167 | \r | |
168 | If NextNode is not NULL, return the next node.\r | |
169 | \r | |
170 | @param [in] Iterator Pointer to an iterator.\r | |
171 | @param [out] NextNode If not NULL, updated to the next node.\r | |
172 | \r | |
173 | @retval EFI_SUCCESS The function completed successfully.\r | |
174 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
175 | **/\r | |
176 | STATIC\r | |
177 | EFI_STATUS\r | |
178 | EFIAPI\r | |
179 | AmlIteratorGetNextBranch (\r | |
731c67e1 MK |
180 | IN AML_TREE_ITERATOR *Iterator,\r |
181 | OUT AML_NODE_HEADER **NextNode\r | |
e2c1104c PG |
182 | )\r |
183 | {\r | |
731c67e1 MK |
184 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
185 | AML_NODE_HEADER *Node;\r | |
e2c1104c | 186 | \r |
731c67e1 | 187 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)Iterator;\r |
e2c1104c PG |
188 | \r |
189 | // CurrentNode can be NULL, but InitialNode cannot.\r | |
190 | if ((InternalIterator == NULL) ||\r | |
191 | (InternalIterator->Mode != EAmlIteratorBranch) ||\r | |
192 | !IS_AML_NODE_VALID (InternalIterator->InitialNode) ||\r | |
731c67e1 MK |
193 | !IS_AML_NODE_VALID (InternalIterator->CurrentNode))\r |
194 | {\r | |
e2c1104c PG |
195 | ASSERT (0);\r |
196 | return EFI_INVALID_PARAMETER;\r | |
197 | }\r | |
198 | \r | |
199 | Node = AmlGetNextNode (InternalIterator->CurrentNode);\r | |
200 | // Check whether NextNode is a sibling of InitialNode.\r | |
201 | if (AmlGetParent (Node) ==\r | |
731c67e1 MK |
202 | AmlGetParent ((AML_NODE_HEADER *)InternalIterator->InitialNode))\r |
203 | {\r | |
e2c1104c PG |
204 | Node = NULL;\r |
205 | }\r | |
206 | \r | |
207 | InternalIterator->CurrentNode = Node;\r | |
208 | \r | |
209 | if (NextNode != NULL) {\r | |
210 | *NextNode = Node;\r | |
211 | }\r | |
731c67e1 | 212 | \r |
e2c1104c PG |
213 | return EFI_SUCCESS;\r |
214 | }\r | |
215 | \r | |
216 | /** Move the current node of the iterator to the previous node,\r | |
217 | according to the iteration mode selected.\r | |
218 | \r | |
219 | If PrevNode is not NULL, return the previous node.\r | |
220 | \r | |
221 | @param [in] Iterator Pointer to an iterator.\r | |
222 | @param [out] PrevNode If not NULL, updated to the previous node.\r | |
223 | \r | |
224 | @retval EFI_SUCCESS The function completed successfully.\r | |
225 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
226 | **/\r | |
227 | STATIC\r | |
228 | EFI_STATUS\r | |
229 | EFIAPI\r | |
230 | AmlIteratorGetPreviousBranch (\r | |
731c67e1 MK |
231 | IN AML_TREE_ITERATOR *Iterator,\r |
232 | OUT AML_NODE_HEADER **PrevNode\r | |
e2c1104c PG |
233 | )\r |
234 | {\r | |
731c67e1 MK |
235 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
236 | AML_NODE_HEADER *Node;\r | |
e2c1104c | 237 | \r |
731c67e1 | 238 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)Iterator;\r |
e2c1104c PG |
239 | \r |
240 | // CurrentNode can be NULL, but InitialNode cannot.\r | |
241 | if ((InternalIterator == NULL) ||\r | |
242 | (InternalIterator->Mode != EAmlIteratorBranch) ||\r | |
243 | !IS_AML_NODE_VALID (InternalIterator->InitialNode) ||\r | |
731c67e1 MK |
244 | !IS_AML_NODE_VALID (InternalIterator->CurrentNode))\r |
245 | {\r | |
e2c1104c PG |
246 | ASSERT (0);\r |
247 | return EFI_INVALID_PARAMETER;\r | |
248 | }\r | |
249 | \r | |
250 | Node = AmlGetPreviousNode (InternalIterator->CurrentNode);\r | |
251 | // Check whether PreviousNode is a sibling of InitialNode.\r | |
252 | if (AmlGetParent (Node) ==\r | |
731c67e1 MK |
253 | AmlGetParent ((AML_NODE_HEADER *)InternalIterator->InitialNode))\r |
254 | {\r | |
e2c1104c PG |
255 | Node = NULL;\r |
256 | }\r | |
257 | \r | |
258 | InternalIterator->CurrentNode = Node;\r | |
259 | \r | |
260 | if (PrevNode != NULL) {\r | |
261 | *PrevNode = Node;\r | |
262 | }\r | |
731c67e1 | 263 | \r |
e2c1104c PG |
264 | return EFI_SUCCESS;\r |
265 | }\r | |
266 | \r | |
267 | /** Initialize an iterator.\r | |
268 | \r | |
269 | Note: The caller must call AmlDeleteIterator () to free the memory\r | |
270 | allocated for the iterator.\r | |
271 | \r | |
272 | @param [in] Node Pointer to the node.\r | |
273 | @param [in] IteratorMode Selected mode to traverse the tree.\r | |
274 | @param [out] IteratorPtr Pointer holding the created iterator.\r | |
275 | \r | |
276 | @retval EFI_SUCCESS The function completed successfully.\r | |
277 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
278 | @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r | |
279 | **/\r | |
280 | EFI_STATUS\r | |
281 | EFIAPI\r | |
282 | AmlInitializeIterator (\r | |
731c67e1 MK |
283 | IN AML_NODE_HEADER *Node,\r |
284 | IN EAML_ITERATOR_MODE IteratorMode,\r | |
285 | OUT AML_TREE_ITERATOR **IteratorPtr\r | |
e2c1104c PG |
286 | )\r |
287 | {\r | |
731c67e1 | 288 | AML_TREE_ITERATOR_INTERNAL *InternalIterator;\r |
e2c1104c PG |
289 | \r |
290 | if (!IS_AML_NODE_VALID (Node) ||\r | |
291 | (IteratorMode <= EAmlIteratorUnknown) ||\r | |
292 | (IteratorMode >= EAmlIteratorModeMax) ||\r | |
731c67e1 MK |
293 | (IteratorPtr == NULL))\r |
294 | {\r | |
e2c1104c PG |
295 | ASSERT (0);\r |
296 | return EFI_INVALID_PARAMETER;\r | |
297 | }\r | |
298 | \r | |
731c67e1 MK |
299 | *IteratorPtr = NULL;\r |
300 | InternalIterator = (AML_TREE_ITERATOR_INTERNAL *)AllocateZeroPool (\r | |
301 | sizeof (\r | |
302 | AML_TREE_ITERATOR_INTERNAL\r | |
303 | )\r | |
304 | );\r | |
e2c1104c PG |
305 | if (InternalIterator == NULL) {\r |
306 | ASSERT (0);\r | |
307 | return EFI_OUT_OF_RESOURCES;\r | |
308 | }\r | |
309 | \r | |
731c67e1 MK |
310 | InternalIterator->InitialNode = Node;\r |
311 | InternalIterator->CurrentNode = Node;\r | |
312 | InternalIterator->Mode = IteratorMode;\r | |
e2c1104c PG |
313 | InternalIterator->Iterator.GetNode = AmlIteratorGetNode;\r |
314 | \r | |
315 | switch (InternalIterator->Mode) {\r | |
316 | case EAmlIteratorLinear:\r | |
317 | {\r | |
731c67e1 | 318 | InternalIterator->Iterator.GetNext = AmlIteratorGetNextLinear;\r |
e2c1104c PG |
319 | InternalIterator->Iterator.GetPrevious = AmlIteratorGetPreviousLinear;\r |
320 | break;\r | |
321 | }\r | |
322 | case EAmlIteratorBranch:\r | |
323 | {\r | |
731c67e1 | 324 | InternalIterator->Iterator.GetNext = AmlIteratorGetNextBranch;\r |
e2c1104c PG |
325 | InternalIterator->Iterator.GetPrevious = AmlIteratorGetPreviousBranch;\r |
326 | break;\r | |
327 | }\r | |
328 | default:\r | |
329 | {\r | |
330 | ASSERT (0);\r | |
331 | FreePool (InternalIterator);\r | |
332 | return EFI_INVALID_PARAMETER;\r | |
333 | }\r | |
334 | } // switch\r | |
335 | \r | |
336 | *IteratorPtr = &InternalIterator->Iterator;\r | |
337 | \r | |
338 | return EFI_SUCCESS;\r | |
339 | }\r | |
340 | \r | |
341 | /** Delete an iterator.\r | |
342 | \r | |
343 | Note: The caller must have first initialized the iterator with the\r | |
344 | AmlInitializeIterator () function.\r | |
345 | \r | |
346 | @param [in] Iterator Pointer to an iterator.\r | |
347 | \r | |
348 | @retval EFI_SUCCESS The function completed successfully.\r | |
349 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r | |
350 | **/\r | |
351 | EFI_STATUS\r | |
352 | EFIAPI\r | |
353 | AmlDeleteIterator (\r | |
731c67e1 | 354 | IN AML_TREE_ITERATOR *Iterator\r |
e2c1104c PG |
355 | )\r |
356 | {\r | |
357 | if (Iterator == NULL) {\r | |
358 | ASSERT (0);\r | |
359 | return EFI_INVALID_PARAMETER;\r | |
360 | }\r | |
361 | \r | |
362 | FreePool (Iterator);\r | |
363 | \r | |
364 | return EFI_SUCCESS;\r | |
365 | }\r |