1 /** @file
2 ACPI Sdt Protocol Driver
3
4 Copyright (c) 2010 - 2014, 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 *
AmlCreateNode(IN UINT8 * NameSeg,IN EFI_AML_NODE_LIST * Parent,IN AML_BYTE_ENCODING * AmlByteEncoding)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 *
AmlFindNodeInThis(IN UINT8 * NameSeg,IN EFI_AML_NODE_LIST * AmlParentNodeList,IN BOOLEAN Create)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 *
AmlFindNodeInTheTree(IN UINT8 * NameString,IN EFI_AML_NODE_LIST * AmlRootNodeList,IN EFI_AML_NODE_LIST * AmlParentNodeList,IN BOOLEAN Create)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 *
AmlInsertNodeToTree(IN UINT8 * NameString,IN VOID * Buffer,IN UINTN Size,IN EFI_AML_NODE_LIST * AmlRootNodeList,IN EFI_AML_NODE_LIST * AmlParentNodeList)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
AmlConstructNodeListForChild(IN EFI_AML_HANDLE * AmlHandle,IN EFI_AML_NODE_LIST * AmlRootNodeList,IN EFI_AML_NODE_LIST * AmlParentNodeList)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 CurrentBuffer = NULL;
304 AmlChildHandle = NULL;
305 AmlByteEncoding = AmlHandle->AmlByteEncoding;
306 Buffer = AmlHandle->Buffer;
307 BufferSize = AmlHandle->Size;
308
309 //
310 // Check if we need recursively add node
311 //
312 if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
313 //
314 // No more node need to be added
315 //
316 return EFI_SUCCESS;
317 }
318
319 //
320 // Do we need add node within METHOD?
321 // Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
322 //
323
324 //
325 // Now, we get the last node.
326 //
327 Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);
328 if (EFI_ERROR (Status)) {
329 return EFI_INVALID_PARAMETER;
330 }
331
332 //
333 // Go through all the reset buffer.
334 //
335 while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {
336 //
337 // Find the child node.
338 //
339 Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);
340 if (EFI_ERROR (Status)) {
341 //
342 // No child found, break now.
343 //
344 break;
345 }
346
347 //
348 // Good, find the child. Construct node recursively
349 //
350 Status = AmlConstructNodeList (
351 AmlChildHandle,
352 AmlRootNodeList,
353 AmlParentNodeList
354 );
355 if (EFI_ERROR (Status)) {
356 break;
357 }
358
359 //
360 // Parse next one
361 //
362 CurrentBuffer += AmlChildHandle->Size;
363
364 Close ((EFI_ACPI_HANDLE)AmlChildHandle);
365 }
366
367 return EFI_SUCCESS;
368 }
369
370 /**
371 Construct node list according to the AML handle.
372
373 @param[in] AmlHandle AML handle.
374 @param[in] AmlRootNodeList AML root node list.
375 @param[in] AmlParentNodeList AML parent node list.
376
377 @retval EFI_SUCCESS Success.
378 @retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
379 **/
380 EFI_STATUS
AmlConstructNodeList(IN EFI_AML_HANDLE * AmlHandle,IN EFI_AML_NODE_LIST * AmlRootNodeList,IN EFI_AML_NODE_LIST * AmlParentNodeList)381 AmlConstructNodeList (
382 IN EFI_AML_HANDLE *AmlHandle,
383 IN EFI_AML_NODE_LIST *AmlRootNodeList,
384 IN EFI_AML_NODE_LIST *AmlParentNodeList
385 )
386 {
387 VOID *NameString;
388 EFI_AML_NODE_LIST *AmlNodeList;
389
390 //
391 // 1. Check if there is need to construct node for this OpCode.
392 //
393 if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {
394 //
395 // No need to construct node, so we just skip this OpCode.
396 //
397 return EFI_SUCCESS;
398 }
399
400 //
401 // 2. Now, we need construct node for this OpCode.
402 //
403 NameString = AmlGetObjectName (AmlHandle);
404 if (NameString == NULL) {
405 return EFI_INVALID_PARAMETER;
406 }
407
408 //
409 // Now, we need to insert node to the node list.
410 // NOTE: The name here could be AML NameString. So the callee need parse it.
411 //
412 AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);
413 ASSERT (AmlNodeList != NULL);
414
415 //
416 // 3. Ok, we need to parse the object list to see if there are more node to be added.
417 //
418 return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);
419 }
420
421 /**
422 Destruct node list
423
424 @param[in] AmlParentNodeList AML parent node list.
425 **/
426 VOID
AmlDestructNodeList(IN EFI_AML_NODE_LIST * AmlParentNodeList)427 AmlDestructNodeList (
428 IN EFI_AML_NODE_LIST *AmlParentNodeList
429 )
430 {
431 EFI_AML_NODE_LIST *CurrentAmlNodeList;
432 LIST_ENTRY *CurrentLink;
433 LIST_ENTRY *StartLink;
434
435 //
436 // Get the children link
437 //
438 StartLink = &AmlParentNodeList->Children;
439 CurrentLink = StartLink->ForwardLink;
440
441 //
442 // Go through all the children
443 //
444 while (CurrentLink != StartLink) {
445 //
446 // Destruct the child's list recursively
447 //
448 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
449 CurrentLink = CurrentLink->ForwardLink;
450
451 //
452 // Remove this child from list and free the node
453 //
454 RemoveEntryList (&(CurrentAmlNodeList->Link));
455
456 AmlDestructNodeList (CurrentAmlNodeList);
457 }
458
459 //
460 // Done.
461 //
462 FreePool (AmlParentNodeList);
463 return ;
464 }
465
466 /**
467 Dump node list
468
469 @param[in] AmlParentNodeList AML parent node list.
470 @param[in] Level Output debug level.
471 **/
472 VOID
AmlDumpNodeInfo(IN EFI_AML_NODE_LIST * AmlParentNodeList,IN UINTN Level)473 AmlDumpNodeInfo (
474 IN EFI_AML_NODE_LIST *AmlParentNodeList,
475 IN UINTN Level
476 )
477 {
478 EFI_AML_NODE_LIST *CurrentAmlNodeList;
479 volatile LIST_ENTRY *CurrentLink;
480 UINTN Index;
481
482 CurrentLink = AmlParentNodeList->Children.ForwardLink;
483
484 if (Level == 0) {
485 DEBUG ((EFI_D_ERROR, "\\"));
486 } else {
487 for (Index = 0; Index < Level; Index++) {
488 DEBUG ((EFI_D_ERROR, " "));
489 }
490 AmlPrintNameSeg (AmlParentNodeList->Name);
491 }
492 DEBUG ((EFI_D_ERROR, "\n"));
493
494 while (CurrentLink != &AmlParentNodeList->Children) {
495 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
496 AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);
497 CurrentLink = CurrentLink->ForwardLink;
498 }
499
500 return ;
501 }
502
503 /**
504 Returns the handle of the ACPI object representing the specified ACPI AML path
505
506 @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
507 @param[in] AmlPath Points to the ACPI AML path.
508 @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
509 HandleIn.
510 @param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
511 FALSE means to find AML path from this Node (The HandleIn).
512
513 @retval EFI_SUCCESS Success
514 @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
515 **/
516 EFI_STATUS
AmlFindPath(IN EFI_AML_HANDLE * AmlHandle,IN UINT8 * AmlPath,OUT VOID ** Buffer,IN BOOLEAN FromRoot)517 AmlFindPath (
518 IN EFI_AML_HANDLE *AmlHandle,
519 IN UINT8 *AmlPath,
520 OUT VOID **Buffer,
521 IN BOOLEAN FromRoot
522 )
523 {
524 EFI_AML_NODE_LIST *AmlRootNodeList;
525 EFI_STATUS Status;
526 EFI_AML_NODE_LIST *AmlNodeList;
527 UINT8 RootNameSeg[AML_NAME_SEG_SIZE];
528 EFI_AML_NODE_LIST *CurrentAmlNodeList;
529 LIST_ENTRY *CurrentLink;
530
531 //
532 // 1. create tree
533 //
534
535 //
536 // Create root handle
537 //
538 RootNameSeg[0] = AML_ROOT_CHAR;
539 RootNameSeg[1] = 0;
540 AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);
541
542 Status = AmlConstructNodeList (
543 AmlHandle,
544 AmlRootNodeList, // Root
545 AmlRootNodeList // Parent
546 );
547 if (EFI_ERROR (Status)) {
548 return EFI_INVALID_PARAMETER;
549 }
550
551 DEBUG_CODE_BEGIN ();
552 DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));
553 AmlDumpNodeInfo (AmlRootNodeList, 0);
554 DEBUG_CODE_END ();
555
556 //
557 // 2. Search the node in the tree
558 //
559 if (FromRoot) {
560 //
561 // Search from Root
562 //
563 CurrentAmlNodeList = AmlRootNodeList;
564 } else {
565 //
566 // Search from this node, NOT ROOT.
567 // Since we insert node to ROOT one by one, we just get the first node and search from it.
568 //
569 CurrentLink = AmlRootNodeList->Children.ForwardLink;
570 if (CurrentLink != &AmlRootNodeList->Children) {
571 //
572 // First node
573 //
574 CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
575 } else {
576 //
577 // No child
578 //
579 CurrentAmlNodeList = NULL;
580 }
581 }
582
583 //
584 // Search
585 //
586 if (CurrentAmlNodeList != NULL) {
587 DEBUG_CODE_BEGIN ();
588 DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));
589 AmlPrintNameSeg (CurrentAmlNodeList->Name);
590 DEBUG ((EFI_D_ERROR, "\n"));
591 DEBUG_CODE_END ();
592 AmlNodeList = AmlFindNodeInTheTree (
593 AmlPath,
594 AmlRootNodeList, // Root
595 CurrentAmlNodeList, // Parent
596 FALSE
597 );
598 } else {
599 AmlNodeList = NULL;
600 }
601
602 *Buffer = NULL;
603 Status = EFI_SUCCESS;
604 if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {
605 *Buffer = AmlNodeList->Buffer;
606 }
607
608 //
609 // 3. free the tree
610 //
611 AmlDestructNodeList (AmlRootNodeList);
612
613 return Status;
614 }
615