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