1 /** @file 2 ACPI Sdt Protocol Driver 3 4 Copyright (c) 2010 - 2016, 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 // 16 // Includes 17 // 18 #include "AcpiTable.h" 19 20 GLOBAL_REMOVE_IF_UNREFERENCED 21 EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = { 22 EFI_ACPI_TABLE_VERSION_NONE, 23 GetAcpiTable2, 24 RegisterNotify, 25 Open, 26 OpenSdt, 27 Close, 28 GetChild, 29 GetOption, 30 SetOption, 31 FindPath 32 }; 33 34 /** 35 This function returns ACPI Table instance. 36 37 @return AcpiTableInstance 38 **/ 39 EFI_ACPI_TABLE_INSTANCE * 40 SdtGetAcpiTableInstance ( 41 VOID 42 ) 43 { 44 return mPrivateData; 45 } 46 47 /** 48 This function finds the table specified by the buffer. 49 50 @param[in] Buffer Table buffer to find. 51 52 @return ACPI table list. 53 **/ 54 EFI_ACPI_TABLE_LIST * 55 FindTableByBuffer ( 56 IN VOID *Buffer 57 ) 58 { 59 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; 60 LIST_ENTRY *CurrentLink; 61 EFI_ACPI_TABLE_LIST *CurrentTableList; 62 LIST_ENTRY *StartLink; 63 64 // 65 // Get the instance of the ACPI Table 66 // 67 AcpiTableInstance = SdtGetAcpiTableInstance (); 68 69 // 70 // Find the notify 71 // 72 StartLink = &AcpiTableInstance->TableList; 73 CurrentLink = StartLink->ForwardLink; 74 75 while (CurrentLink != StartLink) { 76 CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink); 77 if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) && 78 ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) { 79 // 80 // Good! Found Table. 81 // 82 return CurrentTableList; 83 } 84 85 CurrentLink = CurrentLink->ForwardLink; 86 } 87 88 return NULL; 89 } 90 91 /** 92 This function updates AML table checksum. 93 It will search the ACPI table installed by ACPI_TABLE protocol. 94 95 @param[in] Buffer A piece of AML code buffer pointer. 96 97 @retval EFI_SUCCESS The table holds the AML buffer is found, and checksum is updated. 98 @retval EFI_NOT_FOUND The table holds the AML buffer is not found. 99 **/ 100 EFI_STATUS 101 SdtUpdateAmlChecksum ( 102 IN VOID *Buffer 103 ) 104 { 105 EFI_ACPI_TABLE_LIST *CurrentTableList; 106 107 CurrentTableList = FindTableByBuffer (Buffer); 108 if (CurrentTableList == NULL) { 109 return EFI_NOT_FOUND; 110 } 111 112 AcpiPlatformChecksum ( 113 (VOID *)CurrentTableList->Table, 114 CurrentTableList->Table->Length, 115 OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum) 116 ); 117 return EFI_SUCCESS; 118 } 119 120 /** 121 This function finds MAX AML buffer size. 122 It will search the ACPI table installed by ACPI_TABLE protocol. 123 124 @param[in] Buffer A piece of AML code buffer pointer. 125 @param[out] MaxSize On return it holds the MAX size of buffer. 126 127 @retval EFI_SUCCESS The table holds the AML buffer is found, and MAX size if returned. 128 @retval EFI_NOT_FOUND The table holds the AML buffer is not found. 129 **/ 130 EFI_STATUS 131 SdtGetMaxAmlBufferSize ( 132 IN VOID *Buffer, 133 OUT UINTN *MaxSize 134 ) 135 { 136 EFI_ACPI_TABLE_LIST *CurrentTableList; 137 138 CurrentTableList = FindTableByBuffer (Buffer); 139 if (CurrentTableList == NULL) { 140 return EFI_NOT_FOUND; 141 } 142 143 *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer; 144 return EFI_SUCCESS; 145 } 146 147 /** 148 This function invokes ACPI notification. 149 150 @param[in] AcpiTableInstance Instance to AcpiTable 151 @param[in] Version Version(s) to set. 152 @param[in] Handle Handle of the table. 153 **/ 154 VOID 155 SdtNotifyAcpiList ( 156 IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance, 157 IN EFI_ACPI_TABLE_VERSION Version, 158 IN UINTN Handle 159 ) 160 { 161 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; 162 LIST_ENTRY *CurrentLink; 163 LIST_ENTRY *StartLink; 164 EFI_ACPI_TABLE_LIST *Table; 165 EFI_STATUS Status; 166 167 // 168 // We should not use Table buffer, because it is user input buffer. 169 // 170 Status = FindTableByHandle ( 171 Handle, 172 &AcpiTableInstance->TableList, 173 &Table 174 ); 175 ASSERT_EFI_ERROR (Status); 176 177 // 178 // Find the notify 179 // 180 StartLink = &AcpiTableInstance->NotifyList; 181 CurrentLink = StartLink->ForwardLink; 182 183 while (CurrentLink != StartLink) { 184 CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink); 185 186 // 187 // Inovke notification 188 // 189 CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle); 190 191 CurrentLink = CurrentLink->ForwardLink; 192 } 193 194 return ; 195 } 196 197 /** 198 Returns a requested ACPI table. 199 200 The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated 201 with the Index that was input. The following structures are not considered elements in the list of 202 ACPI tables: 203 - Root System Description Pointer (RSD_PTR) 204 - Root System Description Table (RSDT) 205 - Extended System Description Table (XSDT) 206 Version is updated with a bit map containing all the versions of ACPI of which the table is a 207 member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface, 208 the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion. 209 210 @param[in] Index The zero-based index of the table to retrieve. 211 @param[out] Table Pointer for returning the table buffer. 212 @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type 213 EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the 214 EFI_ACPI_SDT_PROTOCOL. 215 @param[out] TableKey On return, points to the table key for the specified ACPI system definition table. 216 This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL. 217 The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable() 218 to uninstall the table. 219 @retval EFI_SUCCESS The function completed successfully. 220 @retval EFI_NOT_FOUND The requested index is too large and a table was not found. 221 **/ 222 EFI_STATUS 223 EFIAPI 224 GetAcpiTable2 ( 225 IN UINTN Index, 226 OUT EFI_ACPI_SDT_HEADER **Table, 227 OUT EFI_ACPI_TABLE_VERSION *Version, 228 OUT UINTN *TableKey 229 ) 230 { 231 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; 232 UINTN TableIndex; 233 LIST_ENTRY *CurrentLink; 234 LIST_ENTRY *StartLink; 235 EFI_ACPI_TABLE_LIST *CurrentTable; 236 237 ASSERT (Table != NULL); 238 ASSERT (Version != NULL); 239 ASSERT (TableKey != NULL); 240 241 // 242 // Get the instance of the ACPI Table 243 // 244 AcpiTableInstance = SdtGetAcpiTableInstance (); 245 246 // 247 // Find the table 248 // 249 StartLink = &AcpiTableInstance->TableList; 250 CurrentLink = StartLink->ForwardLink; 251 TableIndex = 0; 252 253 while (CurrentLink != StartLink) { 254 if (TableIndex == Index) { 255 break; 256 } 257 // 258 // Next one 259 // 260 CurrentLink = CurrentLink->ForwardLink; 261 TableIndex ++; 262 } 263 264 if ((TableIndex != Index) || (CurrentLink == StartLink)) { 265 return EFI_NOT_FOUND; 266 } 267 268 // 269 // Get handle and version 270 // 271 CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink); 272 *TableKey = CurrentTable->Handle; 273 *Version = CurrentTable->Version; 274 *Table = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table; 275 276 return EFI_SUCCESS; 277 } 278 279 /** 280 Register a callback when an ACPI table is installed. 281 282 This function registers a function which will be called whenever a new ACPI table is installed. 283 284 @param[in] Notification Points to the callback function to be registered 285 **/ 286 VOID 287 SdtRegisterNotify ( 288 IN EFI_ACPI_NOTIFICATION_FN Notification 289 ) 290 { 291 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; 292 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; 293 294 // 295 // Get the instance of the ACPI Table 296 // 297 AcpiTableInstance = SdtGetAcpiTableInstance (); 298 299 // 300 // Create a new list entry 301 // 302 CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST)); 303 ASSERT (CurrentNotifyList != NULL); 304 305 // 306 // Initialize the table contents 307 // 308 CurrentNotifyList->Signature = EFI_ACPI_NOTIFY_LIST_SIGNATURE; 309 CurrentNotifyList->Notification = Notification; 310 311 // 312 // Add the table to the current list of tables 313 // 314 InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link); 315 316 return ; 317 } 318 319 /** 320 Unregister a callback when an ACPI table is installed. 321 322 This function unregisters a function which will be called whenever a new ACPI table is installed. 323 324 @param[in] Notification Points to the callback function to be unregistered. 325 326 @retval EFI_SUCCESS Callback successfully unregistered. 327 @retval EFI_INVALID_PARAMETER Notification does not match a known registration function. 328 **/ 329 EFI_STATUS 330 SdtUnregisterNotify ( 331 IN EFI_ACPI_NOTIFICATION_FN Notification 332 ) 333 { 334 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; 335 EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; 336 LIST_ENTRY *CurrentLink; 337 LIST_ENTRY *StartLink; 338 339 // 340 // Get the instance of the ACPI Table 341 // 342 AcpiTableInstance = SdtGetAcpiTableInstance (); 343 344 // 345 // Find the notify 346 // 347 StartLink = &AcpiTableInstance->NotifyList; 348 CurrentLink = StartLink->ForwardLink; 349 350 while (CurrentLink != StartLink) { 351 CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink); 352 if (CurrentNotifyList->Notification == Notification) { 353 // 354 // Good! Found notification. 355 // 356 // Remove it from list and free the node. 357 // 358 RemoveEntryList (&(CurrentNotifyList->Link)); 359 FreePool (CurrentNotifyList); 360 return EFI_SUCCESS; 361 } 362 363 CurrentLink = CurrentLink->ForwardLink; 364 } 365 366 // 367 // Not found! 368 // 369 return EFI_INVALID_PARAMETER; 370 } 371 372 /** 373 Register or unregister a callback when an ACPI table is installed. 374 375 This function registers or unregisters a function which will be called whenever a new ACPI table is 376 installed. 377 378 @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified 379 function will be unregistered. 380 @param[in] Notification Points to the callback function to be registered or unregistered. 381 382 @retval EFI_SUCCESS Callback successfully registered or unregistered. 383 @retval EFI_INVALID_PARAMETER Notification is NULL 384 @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function. 385 **/ 386 EFI_STATUS 387 EFIAPI 388 RegisterNotify ( 389 IN BOOLEAN Register, 390 IN EFI_ACPI_NOTIFICATION_FN Notification 391 ) 392 { 393 // 394 // Check for invalid input parameters 395 // 396 if (Notification == NULL) { 397 return EFI_INVALID_PARAMETER; 398 } 399 400 if (Register) { 401 // 402 // Register a new notify 403 // 404 SdtRegisterNotify (Notification); 405 return EFI_SUCCESS; 406 } else { 407 // 408 // Unregister an old notify 409 // 410 return SdtUnregisterNotify (Notification); 411 } 412 } 413 414 /** 415 Create a handle for the first ACPI opcode in an ACPI system description table. 416 417 @param[in] TableKey The table key for the ACPI table, as returned by GetTable(). 418 @param[out] Handle On return, points to the newly created ACPI handle. 419 420 @retval EFI_SUCCESS Handle created successfully. 421 @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. 422 **/ 423 EFI_STATUS 424 SdtOpenSdtTable ( 425 IN UINTN TableKey, 426 OUT EFI_ACPI_HANDLE *Handle 427 ) 428 { 429 EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; 430 EFI_STATUS Status; 431 EFI_ACPI_TABLE_LIST *Table; 432 EFI_AML_HANDLE *AmlHandle; 433 434 // 435 // Get the instance of the ACPI Table 436 // 437 AcpiTableInstance = SdtGetAcpiTableInstance (); 438 439 // 440 // Find the table 441 // 442 Status = FindTableByHandle ( 443 TableKey, 444 &AcpiTableInstance->TableList, 445 &Table 446 ); 447 if (EFI_ERROR (Status)) { 448 return EFI_NOT_FOUND; 449 } 450 451 AmlHandle = AllocatePool (sizeof(*AmlHandle)); 452 ASSERT (AmlHandle != NULL); 453 AmlHandle->Signature = EFI_AML_ROOT_HANDLE_SIGNATURE; 454 AmlHandle->Buffer = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER)); 455 AmlHandle->Size = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER); 456 AmlHandle->AmlByteEncoding = NULL; 457 AmlHandle->Modified = FALSE; 458 459 // 460 // return the ACPI handle 461 // 462 *Handle = (EFI_ACPI_HANDLE)AmlHandle; 463 464 return EFI_SUCCESS; 465 } 466 467 /** 468 Create a handle for the first ACPI opcode in an ACPI system description table. 469 470 @param[in] TableKey The table key for the ACPI table, as returned by GetTable(). 471 @param[out] Handle On return, points to the newly created ACPI handle. 472 473 @retval EFI_SUCCESS Handle created successfully. 474 @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. 475 **/ 476 EFI_STATUS 477 EFIAPI 478 OpenSdt ( 479 IN UINTN TableKey, 480 OUT EFI_ACPI_HANDLE *Handle 481 ) 482 { 483 if (Handle == NULL) { 484 return EFI_INVALID_PARAMETER; 485 } 486 487 return SdtOpenSdtTable (TableKey, Handle); 488 } 489 490 /** 491 Create a handle from an ACPI opcode 492 493 @param[in] Buffer Points to the ACPI opcode. 494 @param[in] BufferSize Max buffer size. 495 @param[out] Handle Upon return, holds the handle. 496 497 @retval EFI_SUCCESS Success 498 @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an 499 invalid opcode. 500 501 **/ 502 EFI_STATUS 503 SdtOpenEx ( 504 IN VOID *Buffer, 505 IN UINTN BufferSize, 506 OUT EFI_ACPI_HANDLE *Handle 507 ) 508 { 509 AML_BYTE_ENCODING *AmlByteEncoding; 510 EFI_AML_HANDLE *AmlHandle; 511 512 AmlByteEncoding = AmlSearchByOpByte (Buffer); 513 if (AmlByteEncoding == NULL) { 514 return EFI_INVALID_PARAMETER; 515 } 516 517 // 518 // Do not open NameString as handle 519 // 520 if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) { 521 return EFI_INVALID_PARAMETER; 522 } 523 524 // 525 // Good, find it 526 // 527 AmlHandle = AllocatePool (sizeof(*AmlHandle)); 528 ASSERT (AmlHandle != NULL); 529 530 AmlHandle->Signature = EFI_AML_HANDLE_SIGNATURE; 531 AmlHandle->Buffer = Buffer; 532 AmlHandle->AmlByteEncoding = AmlByteEncoding; 533 AmlHandle->Modified = FALSE; 534 535 AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize); 536 if (AmlHandle->Size == 0) { 537 FreePool (AmlHandle); 538 return EFI_INVALID_PARAMETER; 539 } 540 541 *Handle = (EFI_ACPI_HANDLE)AmlHandle; 542 543 return EFI_SUCCESS; 544 } 545 546 /** 547 Create a handle from an ACPI opcode 548 549 @param[in] Buffer Points to the ACPI opcode. 550 @param[out] Handle Upon return, holds the handle. 551 552 @retval EFI_SUCCESS Success 553 @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an 554 invalid opcode. 555 556 **/ 557 EFI_STATUS 558 EFIAPI 559 Open ( 560 IN VOID *Buffer, 561 OUT EFI_ACPI_HANDLE *Handle 562 ) 563 { 564 EFI_STATUS Status; 565 UINTN MaxSize; 566 567 MaxSize = 0; 568 569 // 570 // Check for invalid input parameters 571 // 572 if (Buffer == NULL || Handle == NULL) { 573 return EFI_INVALID_PARAMETER; 574 } 575 576 Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize); 577 if (EFI_ERROR (Status)) { 578 return EFI_INVALID_PARAMETER; 579 } 580 581 return SdtOpenEx (Buffer, MaxSize, Handle); 582 } 583 584 /** 585 Close an ACPI handle. 586 587 @param[in] Handle Returns the handle. 588 589 @retval EFI_SUCCESS Success 590 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. 591 **/ 592 EFI_STATUS 593 EFIAPI 594 Close ( 595 IN EFI_ACPI_HANDLE Handle 596 ) 597 { 598 EFI_AML_HANDLE *AmlHandle; 599 EFI_STATUS Status; 600 601 // 602 // Check for invalid input parameters 603 // 604 if (Handle == NULL) { 605 return EFI_INVALID_PARAMETER; 606 } 607 608 AmlHandle = (EFI_AML_HANDLE *)Handle; 609 if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) && 610 (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) { 611 return EFI_INVALID_PARAMETER; 612 } 613 614 // 615 // Update Checksum only if modified 616 // 617 if (AmlHandle->Modified) { 618 Status = SdtUpdateAmlChecksum (AmlHandle->Buffer); 619 if (EFI_ERROR (Status)) { 620 return EFI_INVALID_PARAMETER; 621 } 622 } 623 624 FreePool (AmlHandle); 625 626 return EFI_SUCCESS; 627 } 628 629 /** 630 Retrieve information about an ACPI object. 631 632 @param[in] Handle ACPI object handle. 633 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right 634 in the ACPI encoding, with index 0 always being the ACPI opcode. 635 @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists 636 for the specified index. 637 @param[out] Data Upon return, points to the pointer to the data. 638 @param[out] DataSize Upon return, points to the size of Data. 639 640 @retval EFI_SUCCESS Success. 641 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. 642 **/ 643 EFI_STATUS 644 EFIAPI 645 GetOption ( 646 IN EFI_ACPI_HANDLE Handle, 647 IN UINTN Index, 648 OUT EFI_ACPI_DATA_TYPE *DataType, 649 OUT CONST VOID **Data, 650 OUT UINTN *DataSize 651 ) 652 { 653 EFI_AML_HANDLE *AmlHandle; 654 AML_BYTE_ENCODING *AmlByteEncoding; 655 EFI_STATUS Status; 656 657 ASSERT (DataType != NULL); 658 ASSERT (Data != NULL); 659 ASSERT (DataSize != NULL); 660 661 // 662 // Check for invalid input parameters 663 // 664 if (Handle == NULL) { 665 return EFI_INVALID_PARAMETER; 666 } 667 668 AmlHandle = (EFI_AML_HANDLE *)Handle; 669 // 670 // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle 671 // 672 if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) { 673 return EFI_INVALID_PARAMETER; 674 } 675 676 AmlByteEncoding = AmlHandle->AmlByteEncoding; 677 if (Index > AmlByteEncoding->MaxIndex) { 678 *DataType = EFI_ACPI_DATA_TYPE_NONE; 679 return EFI_SUCCESS; 680 } 681 682 // 683 // Parse option 684 // 685 Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize); 686 if (EFI_ERROR (Status)) { 687 return EFI_INVALID_PARAMETER; 688 } 689 690 return EFI_SUCCESS; 691 } 692 693 /** 694 Change information about an ACPI object. 695 696 @param[in] Handle ACPI object handle. 697 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right 698 in the ACPI encoding, with index 0 always being the ACPI opcode. 699 @param[in] Data Points to the data. 700 @param[in] DataSize The size of the Data. 701 702 @retval EFI_SUCCESS Success 703 @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. 704 @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by 705 the option. 706 707 **/ 708 EFI_STATUS 709 EFIAPI 710 SetOption ( 711 IN EFI_ACPI_HANDLE Handle, 712 IN UINTN Index, 713 IN CONST VOID *Data, 714 IN UINTN DataSize 715 ) 716 { 717 EFI_AML_HANDLE *AmlHandle; 718 AML_BYTE_ENCODING *AmlByteEncoding; 719 EFI_STATUS Status; 720 EFI_ACPI_DATA_TYPE DataType; 721 VOID *OrgData; 722 UINTN OrgDataSize; 723 724 ASSERT (Data != NULL); 725 726 // 727 // Check for invalid input parameters 728 // 729 if (Handle == NULL) { 730 return EFI_INVALID_PARAMETER; 731 } 732 733 AmlHandle = (EFI_AML_HANDLE *)Handle; 734 // 735 // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle 736 // 737 if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) { 738 return EFI_INVALID_PARAMETER; 739 } 740 AmlByteEncoding = AmlHandle->AmlByteEncoding; 741 742 if (Index > AmlByteEncoding->MaxIndex) { 743 return EFI_INVALID_PARAMETER; 744 } 745 746 // 747 // Parse option 748 // 749 Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize); 750 if (EFI_ERROR (Status)) { 751 return EFI_INVALID_PARAMETER; 752 } 753 if (DataType == EFI_ACPI_DATA_TYPE_NONE) { 754 return EFI_INVALID_PARAMETER; 755 } 756 757 if (DataSize > OrgDataSize) { 758 return EFI_BAD_BUFFER_SIZE; 759 } 760 761 // 762 // Update 763 // 764 CopyMem (OrgData, Data, DataSize); 765 AmlHandle->Modified = TRUE; 766 767 return EFI_SUCCESS; 768 } 769 770 /** 771 Return the child ACPI objects. 772 773 @param[in] ParentHandle Parent handle. 774 @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first 775 handle. On return, points to the next returned ACPI handle or NULL if there are no 776 child objects. 777 778 @retval EFI_SUCCESS Success 779 @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object. 780 **/ 781 EFI_STATUS 782 EFIAPI 783 GetChild ( 784 IN EFI_ACPI_HANDLE ParentHandle, 785 IN OUT EFI_ACPI_HANDLE *Handle 786 ) 787 { 788 EFI_AML_HANDLE *AmlParentHandle; 789 EFI_AML_HANDLE *AmlHandle; 790 VOID *Buffer; 791 EFI_STATUS Status; 792 793 ASSERT (Handle != NULL); 794 795 // 796 // Check for invalid input parameters 797 // 798 if (ParentHandle == NULL) { 799 return EFI_INVALID_PARAMETER; 800 } 801 802 AmlHandle = *Handle; 803 if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) { 804 return EFI_INVALID_PARAMETER; 805 } 806 807 AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle; 808 if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) { 809 // 810 // Root handle 811 // 812 Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer); 813 } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) { 814 // 815 // Non-root handle 816 // 817 Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer); 818 } else { 819 // 820 // Invalid 821 // 822 return EFI_INVALID_PARAMETER; 823 } 824 825 if (EFI_ERROR (Status)) { 826 return EFI_INVALID_PARAMETER; 827 } 828 if (Buffer == NULL) { 829 *Handle = NULL; 830 return EFI_SUCCESS; 831 } 832 return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle); 833 } 834 835 /** 836 Returns the handle of the ACPI object representing the specified ACPI path 837 838 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. 839 @param[in] AmlPath Points to the AML path. 840 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to 841 HandleIn. 842 843 @retval EFI_SUCCESS Success 844 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. 845 **/ 846 EFI_STATUS 847 SdtFindPathFromNonRoot ( 848 IN EFI_ACPI_HANDLE HandleIn, 849 IN UINT8 *AmlPath, 850 OUT EFI_ACPI_HANDLE *HandleOut 851 ) 852 { 853 EFI_AML_HANDLE *AmlHandle; 854 VOID *Buffer; 855 EFI_STATUS Status; 856 857 Buffer = NULL; 858 AmlHandle = (EFI_AML_HANDLE *)HandleIn; 859 860 // 861 // For non-root handle, we need search from THIS node instead of ROOT. 862 // 863 Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE); 864 if (EFI_ERROR (Status)) { 865 return EFI_INVALID_PARAMETER; 866 } 867 if (Buffer == NULL) { 868 *HandleOut = NULL; 869 return EFI_SUCCESS; 870 } 871 return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut); 872 } 873 874 /** 875 Duplicate AML handle. 876 877 @param[in] AmlHandle Handle to be duplicated. 878 879 @return Duplicated AML handle. 880 **/ 881 EFI_AML_HANDLE * 882 SdtDuplicateHandle ( 883 IN EFI_AML_HANDLE *AmlHandle 884 ) 885 { 886 EFI_AML_HANDLE *DstAmlHandle; 887 888 DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle)); 889 ASSERT (DstAmlHandle != NULL); 890 CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle)); 891 892 return DstAmlHandle; 893 } 894 895 /** 896 Returns the handle of the ACPI object representing the specified ACPI path 897 898 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. 899 @param[in] AmlPath Points to the AML path. 900 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to 901 HandleIn. 902 903 @retval EFI_SUCCESS Success 904 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. 905 **/ 906 EFI_STATUS 907 SdtFindPathFromRoot ( 908 IN EFI_ACPI_HANDLE HandleIn, 909 IN UINT8 *AmlPath, 910 OUT EFI_ACPI_HANDLE *HandleOut 911 ) 912 { 913 EFI_ACPI_HANDLE ChildHandle; 914 EFI_AML_HANDLE *AmlHandle; 915 EFI_STATUS Status; 916 VOID *Buffer; 917 918 Buffer = NULL; 919 AmlHandle = (EFI_AML_HANDLE *)HandleIn; 920 921 // 922 // Handle case that AcpiPath is Root 923 // 924 if (AmlIsRootPath (AmlPath)) { 925 // 926 // Duplicate RootHandle 927 // 928 *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle); 929 return EFI_SUCCESS; 930 } 931 932 // 933 // Let children find it. 934 // 935 ChildHandle = NULL; 936 while (TRUE) { 937 Status = GetChild (HandleIn, &ChildHandle); 938 if (EFI_ERROR (Status)) { 939 return EFI_INVALID_PARAMETER; 940 } 941 942 if (ChildHandle == NULL) { 943 // 944 // Not found 945 // 946 *HandleOut = NULL; 947 return EFI_SUCCESS; 948 } 949 950 // 951 // More child 952 // 953 AmlHandle = (EFI_AML_HANDLE *)ChildHandle; 954 Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE); 955 if (EFI_ERROR (Status)) { 956 return EFI_INVALID_PARAMETER; 957 } 958 959 if (Buffer != NULL) { 960 // 961 // Great! Find it, open 962 // 963 Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut); 964 if (!EFI_ERROR (Status)) { 965 return EFI_SUCCESS; 966 } 967 // 968 // Not success, try next one 969 // 970 } 971 } 972 973 // 974 // Should not run here 975 // 976 } 977 978 /** 979 Returns the handle of the ACPI object representing the specified ACPI path 980 981 @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. 982 @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format. 983 @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to 984 HandleIn. 985 986 @retval EFI_SUCCESS Success 987 @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. 988 **/ 989 EFI_STATUS 990 EFIAPI 991 FindPath ( 992 IN EFI_ACPI_HANDLE HandleIn, 993 IN VOID *AcpiPath, 994 OUT EFI_ACPI_HANDLE *HandleOut 995 ) 996 { 997 EFI_AML_HANDLE *AmlHandle; 998 EFI_STATUS Status; 999 UINT8 *AmlPath; 1000 1001 // 1002 // Check for invalid input parameters 1003 // 1004 if (HandleIn == NULL) { 1005 return EFI_INVALID_PARAMETER; 1006 } 1007 1008 AmlHandle = (EFI_AML_HANDLE *)HandleIn; 1009 1010 // 1011 // Convert ASL path to AML path 1012 // 1013 AmlPath = AmlNameFromAslName (AcpiPath); 1014 if (AmlPath == NULL) { 1015 return EFI_INVALID_PARAMETER; 1016 } 1017 1018 DEBUG_CODE_BEGIN (); 1019 DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - ")); 1020 AmlPrintNameString (AmlPath); 1021 DEBUG ((EFI_D_ERROR, "\n")); 1022 DEBUG_CODE_END (); 1023 1024 if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) { 1025 // 1026 // Root Handle 1027 // 1028 Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut); 1029 } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) { 1030 // 1031 // Non-Root handle 1032 // 1033 Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut); 1034 } else { 1035 Status = EFI_INVALID_PARAMETER; 1036 } 1037 1038 FreePool (AmlPath); 1039 1040 return Status; 1041 } 1042 1043 /** 1044 This function initializes AcpiSdt protocol in ACPI table instance. 1045 1046 @param[in] AcpiTableInstance Instance to construct 1047 **/ 1048 VOID 1049 SdtAcpiTableAcpiSdtConstructor ( 1050 IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance 1051 ) 1052 { 1053 1054 InitializeListHead (&AcpiTableInstance->NotifyList); 1055 CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate)); 1056 AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions); 1057 1058 return ; 1059 } 1060