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 * 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 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 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 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 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 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