]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
Add missing parameter in functions header.
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / AcpiTableDxe / AmlNamespace.c
CommitLineData
3dc8585e
JY
1/** @file\r
2 ACPI Sdt Protocol Driver\r
3\r
4 Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "AcpiTable.h"\r
16\r
17/**\r
18 Construct node list according to the AML handle.\r
19 \r
20 @param[in] AmlHandle AML handle.\r
21 @param[in] AmlRootNodeList AML root node list.\r
22 @param[in] AmlParentNodeList AML parent node list.\r
23 \r
24 @retval EFI_SUCCESS Success.\r
25 @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.\r
26**/\r
27EFI_STATUS\r
28AmlConstructNodeList (\r
29 IN EFI_AML_HANDLE *AmlHandle,\r
30 IN EFI_AML_NODE_LIST *AmlRootNodeList,\r
31 IN EFI_AML_NODE_LIST *AmlParentNodeList\r
32 );\r
33\r
34/**\r
35 Create AML Node.\r
36 \r
37 @param[in] NameSeg AML NameSeg.\r
38 @param[in] Parent AML parent node list.\r
39 @param[in] AmlByteEncoding AML Byte Encoding.\r
40 \r
41 @return AML Node.\r
42**/\r
43EFI_AML_NODE_LIST *\r
44AmlCreateNode (\r
45 IN UINT8 *NameSeg,\r
46 IN EFI_AML_NODE_LIST *Parent,\r
47 IN AML_BYTE_ENCODING *AmlByteEncoding\r
48 )\r
49{\r
50 EFI_AML_NODE_LIST *AmlNodeList;\r
51\r
52 AmlNodeList = AllocatePool (sizeof(*AmlNodeList));\r
53 ASSERT (AmlNodeList != NULL);\r
54\r
55 AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE;\r
56 CopyMem (AmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE);\r
57 AmlNodeList->Buffer = NULL;\r
58 AmlNodeList->Size = 0;\r
59 InitializeListHead (&AmlNodeList->Link);\r
60 InitializeListHead (&AmlNodeList->Children);\r
61 AmlNodeList->Parent = Parent;\r
62 AmlNodeList->AmlByteEncoding = AmlByteEncoding;\r
63\r
64 return AmlNodeList;\r
65}\r
66\r
67/**\r
68 Find the AML NameSeg in the children of AmlParentNodeList.\r
69 \r
70 @param[in] NameSeg AML NameSeg.\r
71 @param[in] AmlParentNodeList AML parent node list.\r
72 @param[in] Create TRUE means to create node if not found.\r
73 \r
74 @return AmlChildNode whoes name is same as NameSeg.\r
75**/\r
76EFI_AML_NODE_LIST *\r
77AmlFindNodeInThis (\r
78 IN UINT8 *NameSeg,\r
79 IN EFI_AML_NODE_LIST *AmlParentNodeList,\r
80 IN BOOLEAN Create\r
81 )\r
82{\r
83 EFI_AML_NODE_LIST *CurrentAmlNodeList;\r
84 LIST_ENTRY *CurrentLink;\r
85 LIST_ENTRY *StartLink;\r
86 EFI_AML_NODE_LIST *AmlNodeList;\r
87\r
88 StartLink = &AmlParentNodeList->Children;\r
89 CurrentLink = StartLink->ForwardLink;\r
90\r
91 while (CurrentLink != StartLink) {\r
92 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);\r
93 //\r
94 // AML name is same as the one stored\r
95 //\r
96 if (CompareMem (CurrentAmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE) == 0) {\r
97 //\r
98 // Good! Found it\r
99 //\r
100 return CurrentAmlNodeList;\r
101 }\r
102 CurrentLink = CurrentLink->ForwardLink;\r
103 }\r
104\r
105 //\r
106 // Not found\r
107 //\r
108 if (!Create) {\r
109 return NULL;\r
110 }\r
111\r
112 //\r
113 // Create new node with NULL buffer - it means namespace not be returned.\r
114 //\r
115 AmlNodeList = AmlCreateNode (NameSeg, AmlParentNodeList, NULL);\r
116 InsertTailList (&AmlParentNodeList->Children, &AmlNodeList->Link);\r
117\r
118 return AmlNodeList;\r
119}\r
120\r
121/**\r
122 Find the AML NameString in the children of AmlParentNodeList or AmlRootNodeList.\r
123 \r
124 @param[in] NameString AML NameString.\r
125 @param[in] AmlRootNodeList AML root node list.\r
126 @param[in] AmlParentNodeList AML parent node list.\r
127 @param[in] Create TRUE means to create node if not found.\r
128 \r
129 @return AmlChildNode whoes name is same as NameSeg.\r
130**/\r
131EFI_AML_NODE_LIST *\r
132AmlFindNodeInTheTree (\r
133 IN UINT8 *NameString,\r
134 IN EFI_AML_NODE_LIST *AmlRootNodeList,\r
135 IN EFI_AML_NODE_LIST *AmlParentNodeList,\r
136 IN BOOLEAN Create\r
137 )\r
138{\r
139 UINT8 *Buffer;\r
140 EFI_AML_NODE_LIST *AmlNodeList;\r
141 EFI_AML_NODE_LIST *AmlCurrentNodeList;\r
142 UINT8 Index;\r
143 UINT8 SegCount;\r
144\r
145 Buffer = NameString;\r
146\r
147 //\r
148 // Handle root or parent prefix\r
149 //\r
150 if (*Buffer == AML_ROOT_CHAR) {\r
151 AmlCurrentNodeList = AmlRootNodeList;\r
152 Buffer += 1;\r
153 } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {\r
154 AmlCurrentNodeList = AmlParentNodeList;\r
155 do {\r
156 if (AmlCurrentNodeList->Parent != NULL) {\r
157 AmlCurrentNodeList = AmlCurrentNodeList->Parent;\r
158 } else {\r
159 //\r
160 // Only root has no parent\r
161 //\r
162 ASSERT (AmlCurrentNodeList == AmlRootNodeList);\r
163 }\r
164 Buffer += 1;\r
165 } while (*Buffer == AML_PARENT_PREFIX_CHAR);\r
166 } else {\r
167 AmlCurrentNodeList = AmlParentNodeList;\r
168 }\r
169 \r
170 //\r
171 // Handle name segment\r
172 //\r
173 if (*Buffer == AML_DUAL_NAME_PREFIX) {\r
174 Buffer += 1;\r
175 SegCount = 2;\r
176 } else if (*Buffer == AML_MULTI_NAME_PREFIX) {\r
177 Buffer += 1;\r
178 SegCount = *Buffer;\r
179 Buffer += 1;\r
180 } else if (*Buffer == 0) {\r
181 //\r
182 // NULL name, only for Root\r
183 //\r
184 ASSERT (AmlCurrentNodeList == AmlRootNodeList);\r
185 return AmlCurrentNodeList;\r
186 } else {\r
187 SegCount = 1;\r
188 }\r
189\r
190 //\r
191 // Handle NamePath\r
192 //\r
193 Index = 0;\r
194 do {\r
195 AmlNodeList = AmlFindNodeInThis (Buffer, AmlCurrentNodeList, Create);\r
196 if (AmlNodeList == NULL) {\r
197 return NULL;\r
198 }\r
199 AmlCurrentNodeList = AmlNodeList;\r
200 Buffer += AML_NAME_SEG_SIZE;\r
201 Index ++;\r
202 } while (Index < SegCount);\r
203\r
204 return AmlNodeList;\r
205}\r
206\r
207/**\r
208 Insert the NameString to the AmlNodeList.\r
209 \r
210 @param[in] NameString AML NameString.\r
211 @param[in] Buffer Buffer for the Node.\r
212 @param[in] Size Size for the Node.\r
213 @param[in] AmlRootNodeList AML root node list.\r
214 @param[in] AmlParentNodeList AML parent node list.\r
215 \r
216 @return AmlChildNode whoes name is NameString.\r
217**/\r
218EFI_AML_NODE_LIST *\r
219AmlInsertNodeToTree (\r
220 IN UINT8 *NameString,\r
221 IN VOID *Buffer,\r
222 IN UINTN Size,\r
223 IN EFI_AML_NODE_LIST *AmlRootNodeList,\r
224 IN EFI_AML_NODE_LIST *AmlParentNodeList\r
225 )\r
226{\r
227 EFI_AML_NODE_LIST *AmlNodeList;\r
228\r
229 AmlNodeList = AmlFindNodeInTheTree (\r
230 NameString,\r
231 AmlRootNodeList,\r
232 AmlParentNodeList,\r
233 TRUE // Find and Create\r
234 );\r
235 ASSERT (AmlNodeList != NULL);\r
236 if (AmlNodeList == NULL) {\r
237 return NULL;\r
238 }\r
239\r
240 //\r
241 // Check buffer\r
242 //\r
243 if (AmlNodeList->Buffer == NULL) {\r
244 //\r
245 // NULL means new added one or SCOPE_OP\r
246 //\r
247 if (*(UINT8 *)Buffer != AML_SCOPE_OP) {\r
248 //\r
249 // We need check if new one is SCOPE_OP, because SCOPE_OP just means namespace, not a real device.\r
250 // We should not return SCOPE_OP.\r
251 //\r
252 AmlNodeList->Buffer = Buffer;\r
253 AmlNodeList->Size = Size;\r
254 AmlNodeList->AmlByteEncoding = AmlSearchByOpByte (Buffer);\r
255 }\r
256 return AmlNodeList;\r
257 }\r
258\r
259 //\r
260 // Already added\r
261 //\r
262 if (*(UINT8 *)Buffer == AML_SCOPE_OP) {\r
263 //\r
264 // The new one is SCOPE_OP, OK just return;\r
265 //\r
266 return AmlNodeList;\r
267 }\r
268\r
269 //\r
270 // Oops!!!, There must be something wrong.\r
271 //\r
272 DEBUG ((EFI_D_ERROR, "AML: Override Happen - %a!\n", NameString));\r
273 DEBUG ((EFI_D_ERROR, "AML: Existing Node - %x\n", AmlNodeList->Buffer));\r
274 DEBUG ((EFI_D_ERROR, "AML: New Buffer - %x\n", Buffer));\r
275\r
276 return NULL;\r
277}\r
278\r
279/**\r
280 Construct child node list according to the AML handle.\r
281 \r
282 @param[in] AmlHandle AML handle.\r
283 @param[in] AmlRootNodeList AML root node list.\r
284 @param[in] AmlParentNodeList AML parent node list.\r
285 \r
286 @retval EFI_SUCCESS Success.\r
287 @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.\r
288**/\r
289EFI_STATUS\r
290AmlConstructNodeListForChild (\r
291 IN EFI_AML_HANDLE *AmlHandle,\r
292 IN EFI_AML_NODE_LIST *AmlRootNodeList,\r
293 IN EFI_AML_NODE_LIST *AmlParentNodeList\r
294 )\r
295{\r
296 AML_BYTE_ENCODING *AmlByteEncoding;\r
297 UINT8 *Buffer;\r
298 UINTN BufferSize;\r
299 UINT8 *CurrentBuffer;\r
300 EFI_AML_HANDLE *AmlChildHandle;\r
301 EFI_STATUS Status;\r
302\r
303 AmlByteEncoding = AmlHandle->AmlByteEncoding;\r
304 Buffer = AmlHandle->Buffer;\r
305 BufferSize = AmlHandle->Size;\r
306\r
307 //\r
308 // Check if we need recursively add node\r
309 //\r
310 if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {\r
311 //\r
312 // No more node need to be added\r
313 //\r
314 return EFI_SUCCESS;\r
315 }\r
316\r
317 //\r
318 // Do we need add node within METHOD?\r
319 // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.\r
320 //\r
321\r
322 //\r
323 // Now, we get the last node.\r
324 //\r
325 Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);\r
326 if (EFI_ERROR (Status)) {\r
327 return EFI_INVALID_PARAMETER;\r
328 }\r
329\r
330 //\r
331 // Go through all the reset buffer.\r
332 //\r
333 while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {\r
334 //\r
335 // Find the child node.\r
336 //\r
337 Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);\r
338 if (EFI_ERROR (Status)) {\r
339 //\r
340 // No child found, break now.\r
341 //\r
342 break;\r
343 }\r
344\r
345 //\r
346 // Good, find the child. Construct node recursively\r
347 //\r
348 Status = AmlConstructNodeList (\r
349 AmlChildHandle,\r
350 AmlRootNodeList,\r
351 AmlParentNodeList\r
352 );\r
353 if (EFI_ERROR (Status)) {\r
354 break;\r
355 }\r
356\r
357 //\r
358 // Parse next one\r
359 //\r
360 CurrentBuffer += AmlChildHandle->Size;\r
361\r
362 Close ((EFI_ACPI_HANDLE)AmlChildHandle);\r
363 }\r
364\r
365 return EFI_SUCCESS;\r
366}\r
367\r
368/**\r
369 Construct node list according to the AML handle.\r
370 \r
371 @param[in] AmlHandle AML handle.\r
372 @param[in] AmlRootNodeList AML root node list.\r
373 @param[in] AmlParentNodeList AML parent node list.\r
374 \r
375 @retval EFI_SUCCESS Success.\r
376 @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.\r
377**/\r
378EFI_STATUS\r
379AmlConstructNodeList (\r
380 IN EFI_AML_HANDLE *AmlHandle,\r
381 IN EFI_AML_NODE_LIST *AmlRootNodeList,\r
382 IN EFI_AML_NODE_LIST *AmlParentNodeList\r
383 )\r
384{\r
385 VOID *NameString;\r
386 EFI_AML_NODE_LIST *AmlNodeList;\r
387\r
388 //\r
389 // 1. Check if there is need to construct node for this OpCode.\r
390 //\r
391 if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {\r
392 //\r
393 // No need to construct node, so we just skip this OpCode.\r
394 //\r
395 return EFI_SUCCESS;\r
396 }\r
397\r
398 //\r
399 // 2. Now, we need construct node for this OpCode.\r
400 //\r
401 NameString = AmlGetObjectName (AmlHandle);\r
402 if (NameString == NULL) {\r
403 return EFI_INVALID_PARAMETER;\r
404 }\r
405\r
406 //\r
407 // Now, we need to insert node to the node list.\r
408 // NOTE: The name here could be AML NameString. So the callee need parse it.\r
409 //\r
410 AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);\r
411 ASSERT (AmlNodeList != NULL);\r
412\r
413 //\r
414 // 3. Ok, we need to parse the object list to see if there are more node to be added.\r
415 //\r
416 return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);\r
417}\r
418\r
419/**\r
420 Destruct node list\r
421 \r
422 @param[in] AmlParentNodeList AML parent node list.\r
423**/\r
424VOID\r
425AmlDestructNodeList (\r
426 IN EFI_AML_NODE_LIST *AmlParentNodeList\r
427 )\r
428{\r
429 EFI_AML_NODE_LIST *CurrentAmlNodeList;\r
430 LIST_ENTRY *CurrentLink;\r
431 LIST_ENTRY *StartLink;\r
432\r
433 //\r
434 // Get the children link\r
435 //\r
436 StartLink = &AmlParentNodeList->Children;\r
437 CurrentLink = StartLink->ForwardLink;\r
438\r
439 //\r
440 // Go through all the children\r
441 //\r
442 while (CurrentLink != StartLink) {\r
443 //\r
444 // Destruct the child's list recursively\r
445 //\r
446 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);\r
447 CurrentLink = CurrentLink->ForwardLink;\r
448\r
449 //\r
450 // Remove this child from list and free the node\r
451 //\r
452 RemoveEntryList (&(CurrentAmlNodeList->Link));\r
453\r
454 AmlDestructNodeList (CurrentAmlNodeList);\r
455 }\r
456\r
457 //\r
458 // Done.\r
459 //\r
460 FreePool (AmlParentNodeList);\r
461 return ;\r
462}\r
463\r
464/**\r
465 Dump node list\r
466 \r
467 @param[in] AmlParentNodeList AML parent node list.\r
468 @param[in] Level Output debug level.\r
469**/\r
470VOID\r
471AmlDumpNodeInfo (\r
472 IN EFI_AML_NODE_LIST *AmlParentNodeList,\r
473 IN UINTN Level\r
474 )\r
475{\r
476 EFI_AML_NODE_LIST *CurrentAmlNodeList;\r
477 volatile LIST_ENTRY *CurrentLink;\r
478 UINTN Index;\r
479\r
480 CurrentLink = AmlParentNodeList->Children.ForwardLink;\r
481\r
482 if (Level == 0) {\r
483 DEBUG ((EFI_D_ERROR, "\\"));\r
484 } else {\r
485 for (Index = 0; Index < Level; Index++) {\r
486 DEBUG ((EFI_D_ERROR, " "));\r
487 }\r
488 AmlPrintNameSeg (AmlParentNodeList->Name);\r
489 }\r
490 DEBUG ((EFI_D_ERROR, "\n"));\r
491\r
492 while (CurrentLink != &AmlParentNodeList->Children) {\r
493 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);\r
494 AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);\r
495 CurrentLink = CurrentLink->ForwardLink;\r
496 }\r
497\r
498 return ;\r
499}\r
500\r
501/**\r
502 Returns the handle of the ACPI object representing the specified ACPI AML path\r
503 \r
504 @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.\r
505 @param[in] AmlPath Points to the ACPI AML path.\r
506 @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to\r
507 HandleIn.\r
508 @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.\r
509 FALSE means to find AML path from this Node (The HandleIn).\r
510 \r
511 @retval EFI_SUCCESS Success\r
512 @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object. \r
513**/\r
514EFI_STATUS\r
515AmlFindPath (\r
516 IN EFI_AML_HANDLE *AmlHandle,\r
517 IN UINT8 *AmlPath,\r
518 OUT VOID **Buffer,\r
519 IN BOOLEAN FromRoot\r
520 )\r
521{\r
522 EFI_AML_NODE_LIST *AmlRootNodeList;\r
523 EFI_STATUS Status;\r
524 EFI_AML_NODE_LIST *AmlNodeList;\r
525 UINT8 RootNameSeg[AML_NAME_SEG_SIZE];\r
526 EFI_AML_NODE_LIST *CurrentAmlNodeList;\r
527 LIST_ENTRY *CurrentLink;\r
528\r
529 //\r
530 // 1. create tree\r
531 //\r
532\r
533 //\r
534 // Create root handle\r
535 //\r
536 RootNameSeg[0] = AML_ROOT_CHAR;\r
537 RootNameSeg[1] = 0;\r
538 AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);\r
539\r
540 Status = AmlConstructNodeList (\r
541 AmlHandle,\r
542 AmlRootNodeList, // Root\r
543 AmlRootNodeList // Parent\r
544 );\r
545 if (EFI_ERROR (Status)) {\r
546 return EFI_INVALID_PARAMETER;\r
547 }\r
548\r
549 DEBUG_CODE_BEGIN ();\r
550 DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));\r
551 AmlDumpNodeInfo (AmlRootNodeList, 0);\r
552 DEBUG_CODE_END ();\r
553\r
554 //\r
555 // 2. Search the node in the tree\r
556 //\r
557 if (FromRoot) {\r
558 //\r
559 // Search from Root\r
560 //\r
561 CurrentAmlNodeList = AmlRootNodeList;\r
562 } else {\r
563 //\r
564 // Search from this node, NOT ROOT.\r
565 // Since we insert node to ROOT one by one, we just get the first node and search from it.\r
566 //\r
567 CurrentLink = AmlRootNodeList->Children.ForwardLink;\r
568 if (CurrentLink != &AmlRootNodeList->Children) {\r
569 //\r
570 // First node\r
571 //\r
572 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);\r
573 } else {\r
574 //\r
575 // No child\r
576 //\r
577 CurrentAmlNodeList = NULL;\r
578 }\r
579 }\r
580\r
581 //\r
582 // Search\r
583 //\r
584 if (CurrentAmlNodeList != NULL) {\r
585 DEBUG_CODE_BEGIN ();\r
586 DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));\r
587 AmlPrintNameSeg (CurrentAmlNodeList->Name);\r
588 DEBUG ((EFI_D_ERROR, "\n"));\r
589 DEBUG_CODE_END ();\r
590 AmlNodeList = AmlFindNodeInTheTree (\r
591 AmlPath,\r
592 AmlRootNodeList, // Root\r
593 CurrentAmlNodeList, // Parent\r
594 FALSE\r
595 );\r
596 } else {\r
597 AmlNodeList = NULL;\r
598 }\r
599\r
600 *Buffer = NULL;\r
601 Status = EFI_SUCCESS;\r
602 if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {\r
603 *Buffer = AmlNodeList->Buffer;\r
604 }\r
605\r
606 //\r
607 // 3. free the tree\r
608 //\r
609 AmlDestructNodeList (AmlRootNodeList);\r
610\r
611 return Status;\r
612}\r