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