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