1/****************************************************************************** 2 * 3 * Module Name: adwalk - Application-level disassembler parse tree walk routines 4 * 5 *****************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2023, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44#include "acpi.h" 45#include "accommon.h" 46#include "acparser.h" 47#include "amlcode.h" 48#include "acdisasm.h" 49#include "acdispat.h" 50#include "acnamesp.h" 51#include "acapps.h" 52 53 54#define _COMPONENT ACPI_TOOLS 55 ACPI_MODULE_NAME ("adwalk") 56 57/* 58 * aslmap - opcode mappings and reserved method names 59 */ 60ACPI_OBJECT_TYPE 61AslMapNamedOpcodeToDataType ( 62 UINT16 Opcode); 63 64/* Local prototypes */ 65 66static ACPI_STATUS 67AcpiDmFindOrphanDescending ( 68 ACPI_PARSE_OBJECT *Op, 69 UINT32 Level, 70 void *Context); 71 72static ACPI_STATUS 73AcpiDmDumpDescending ( 74 ACPI_PARSE_OBJECT *Op, 75 UINT32 Level, 76 void *Context); 77 78static ACPI_STATUS 79AcpiDmXrefDescendingOp ( 80 ACPI_PARSE_OBJECT *Op, 81 UINT32 Level, 82 void *Context); 83 84static ACPI_STATUS 85AcpiDmCommonAscendingOp ( 86 ACPI_PARSE_OBJECT *Op, 87 UINT32 Level, 88 void *Context); 89 90static ACPI_STATUS 91AcpiDmLoadDescendingOp ( 92 ACPI_PARSE_OBJECT *Op, 93 UINT32 Level, 94 void *Context); 95 96static UINT32 97AcpiDmInspectPossibleArgs ( 98 UINT32 CurrentOpArgCount, 99 UINT32 TargetCount, 100 ACPI_PARSE_OBJECT *Op); 101 102static ACPI_STATUS 103AcpiDmCommonDescendingOp ( 104 ACPI_PARSE_OBJECT *Op, 105 UINT32 Level, 106 void *Context); 107 108static ACPI_STATUS 109AcpiDmProcessResourceDescriptors ( 110 ACPI_PARSE_OBJECT *Op, 111 UINT32 Level, 112 void *Context); 113 114/******************************************************************************* 115 * 116 * FUNCTION: AcpiDmDumpTree 117 * 118 * PARAMETERS: Origin - Starting object 119 * 120 * RETURN: None 121 * 122 * DESCRIPTION: Parse tree walk to format and output the nodes 123 * 124 ******************************************************************************/ 125 126void 127AcpiDmDumpTree ( 128 ACPI_PARSE_OBJECT *Origin) 129{ 130 ACPI_OP_WALK_INFO Info; 131 132 133 if (!Origin) 134 { 135 return; 136 } 137 138 AcpiOsPrintf ("/*\nAML Parse Tree\n\n"); 139 Info.Flags = 0; 140 Info.Count = 0; 141 Info.Level = 0; 142 Info.WalkState = NULL; 143 144 AcpiDmWalkParseTree (Origin, AcpiDmDumpDescending, NULL, &Info); 145 AcpiOsPrintf ("*/\n\n"); 146} 147 148 149/******************************************************************************* 150 * 151 * FUNCTION: AcpiDmFindOrphanMethods 152 * 153 * PARAMETERS: Origin - Starting object 154 * 155 * RETURN: None 156 * 157 * DESCRIPTION: Parse tree walk to find "orphaned" method invocations -- methods 158 * that are not resolved in the namespace 159 * 160 ******************************************************************************/ 161 162void 163AcpiDmFindOrphanMethods ( 164 ACPI_PARSE_OBJECT *Origin) 165{ 166 ACPI_OP_WALK_INFO Info; 167 168 169 if (!Origin) 170 { 171 return; 172 } 173 174 Info.Flags = 0; 175 Info.Level = 0; 176 Info.WalkState = NULL; 177 178 AcpiDmWalkParseTree (Origin, AcpiDmFindOrphanDescending, NULL, &Info); 179} 180 181 182/******************************************************************************* 183 * 184 * FUNCTION: AcpiDmFinishNamespaceLoad 185 * 186 * PARAMETERS: ParseTreeRoot - Root of the parse tree 187 * NamespaceRoot - Root of the internal namespace 188 * OwnerId - OwnerId of the table to be disassembled 189 * 190 * RETURN: None 191 * 192 * DESCRIPTION: Load all namespace items that are created within control 193 * methods. Used before namespace cross reference 194 * 195 ******************************************************************************/ 196 197void 198AcpiDmFinishNamespaceLoad ( 199 ACPI_PARSE_OBJECT *ParseTreeRoot, 200 ACPI_NAMESPACE_NODE *NamespaceRoot, 201 ACPI_OWNER_ID OwnerId) 202{ 203 ACPI_STATUS Status; 204 ACPI_OP_WALK_INFO Info; 205 ACPI_WALK_STATE *WalkState; 206 207 208 if (!ParseTreeRoot) 209 { 210 return; 211 } 212 213 /* Create and initialize a new walk state */ 214 215 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL); 216 if (!WalkState) 217 { 218 return; 219 } 220 221 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, 222 WalkState); 223 if (ACPI_FAILURE (Status)) 224 { 225 return; 226 } 227 228 Info.Flags = 0; 229 Info.Level = 0; 230 Info.WalkState = WalkState; 231 232 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmLoadDescendingOp, 233 AcpiDmCommonAscendingOp, &Info); 234 ACPI_FREE (WalkState); 235} 236 237 238/******************************************************************************* 239 * 240 * FUNCTION: AcpiDmCrossReferenceNamespace 241 * 242 * PARAMETERS: ParseTreeRoot - Root of the parse tree 243 * NamespaceRoot - Root of the internal namespace 244 * OwnerId - OwnerId of the table to be disassembled 245 * 246 * RETURN: None 247 * 248 * DESCRIPTION: Cross reference the namespace to create externals 249 * 250 ******************************************************************************/ 251 252void 253AcpiDmCrossReferenceNamespace ( 254 ACPI_PARSE_OBJECT *ParseTreeRoot, 255 ACPI_NAMESPACE_NODE *NamespaceRoot, 256 ACPI_OWNER_ID OwnerId) 257{ 258 ACPI_STATUS Status; 259 ACPI_OP_WALK_INFO Info; 260 ACPI_WALK_STATE *WalkState; 261 262 263 if (!ParseTreeRoot) 264 { 265 return; 266 } 267 268 /* Create and initialize a new walk state */ 269 270 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL); 271 if (!WalkState) 272 { 273 return; 274 } 275 276 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, 277 WalkState); 278 if (ACPI_FAILURE (Status)) 279 { 280 return; 281 } 282 283 Info.Flags = 0; 284 Info.Level = 0; 285 Info.WalkState = WalkState; 286 287 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmXrefDescendingOp, 288 AcpiDmCommonAscendingOp, &Info); 289 ACPI_FREE (WalkState); 290} 291 292 293/******************************************************************************* 294 * 295 * FUNCTION: AcpiDmConvertParseObjects 296 * 297 * PARAMETERS: ParseTreeRoot - Root of the parse tree 298 * NamespaceRoot - Root of the internal namespace 299 * 300 * RETURN: None 301 * 302 * DESCRIPTION: Begin parse tree walk to perform conversions needed for 303 * disassembly. These include resource descriptors and switch/case 304 * operations. 305 * 306 ******************************************************************************/ 307 308void 309AcpiDmConvertParseObjects ( 310 ACPI_PARSE_OBJECT *ParseTreeRoot, 311 ACPI_NAMESPACE_NODE *NamespaceRoot) 312{ 313 ACPI_STATUS Status; 314 ACPI_OP_WALK_INFO Info; 315 ACPI_WALK_STATE *WalkState; 316 317 318 if (!ParseTreeRoot) 319 { 320 return; 321 } 322 323 /* Create and initialize a new walk state */ 324 325 WalkState = AcpiDsCreateWalkState (0, ParseTreeRoot, NULL, NULL); 326 if (!WalkState) 327 { 328 return; 329 } 330 331 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, 332 WalkState); 333 if (ACPI_FAILURE (Status)) 334 { 335 ACPI_FREE (WalkState); 336 return; 337 } 338 339 Info.Flags = 0; 340 Info.Level = 0; 341 Info.WalkState = WalkState; 342 343 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmCommonDescendingOp, 344 AcpiDmCommonAscendingOp, &Info); 345 ACPI_FREE (WalkState); 346 347 if (AcpiGbl_TempListHead) { 348 AcpiDmClearTempList(); 349 } 350 351 return; 352} 353 354 355/******************************************************************************* 356 * 357 * FUNCTION: AcpiDmDumpDescending 358 * 359 * PARAMETERS: ASL_WALK_CALLBACK 360 * 361 * RETURN: Status 362 * 363 * DESCRIPTION: Format and print contents of one parse Op. 364 * 365 ******************************************************************************/ 366 367static ACPI_STATUS 368AcpiDmDumpDescending ( 369 ACPI_PARSE_OBJECT *Op, 370 UINT32 Level, 371 void *Context) 372{ 373 ACPI_OP_WALK_INFO *Info = Context; 374 char *Path; 375 ACPI_STATUS Status; 376 377 378 if (!Op) 379 { 380 return (AE_OK); 381 } 382 383 /* Most of the information (count, level, name) here */ 384 385 Info->Count++; 386 AcpiOsPrintf ("% 5d [%2.2d] ", Info->Count, Level); 387 AcpiDmIndent (Level); 388 AcpiOsPrintf ("%-28s", AcpiPsGetOpcodeName (Op->Common.AmlOpcode)); 389 390 /* Extra info is helpful */ 391 392 switch (Op->Common.AmlOpcode) 393 { 394 case AML_BYTE_OP: 395 396 AcpiOsPrintf ("%2.2X", (UINT32) Op->Common.Value.Integer); 397 break; 398 399 case AML_WORD_OP: 400 401 AcpiOsPrintf ("%4.4X", (UINT32) Op->Common.Value.Integer); 402 break; 403 404 case AML_DWORD_OP: 405 406 AcpiOsPrintf ("%8.8X", (UINT32) Op->Common.Value.Integer); 407 break; 408 409 case AML_QWORD_OP: 410 411 AcpiOsPrintf ("%8.8X%8.8X", ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); 412 break; 413 414 case AML_INT_NAMEPATH_OP: 415 416 if (Op->Common.Value.String) 417 { 418 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Op->Common.Value.String, 419 NULL, &Path); 420 if (ACPI_SUCCESS (Status)) 421 { 422 AcpiOsPrintf ("%s %p", Path, Op->Common.Node); 423 ACPI_FREE (Path); 424 } 425 else 426 { 427 AcpiOsPrintf ("Could not externalize pathname for node [%4.4s]", 428 Op->Common.Node->Name.Ascii); 429 } 430 } 431 else 432 { 433 AcpiOsPrintf ("[NULL]"); 434 } 435 break; 436 437 case AML_NAME_OP: 438 case AML_METHOD_OP: 439 case AML_DEVICE_OP: 440 441 AcpiOsPrintf ("%4.4s", 442 ACPI_CAST_PTR (char, &Op->Named.Name)); 443 break; 444 445 case AML_INT_NAMEDFIELD_OP: 446 447 AcpiOsPrintf ("%4.4s Length: (bits) %8.8X%8.8X (bytes) %8.8X%8.8X", 448 ACPI_CAST_PTR (char, &Op->Named.Name), 449 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer), 450 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer / 8)); 451 break; 452 453 454 default: 455 456 break; 457 } 458 459 AcpiOsPrintf ("\n"); 460 return (AE_OK); 461} 462 463 464/******************************************************************************* 465 * 466 * FUNCTION: AcpiDmFindOrphanDescending 467 * 468 * PARAMETERS: ASL_WALK_CALLBACK 469 * 470 * RETURN: Status 471 * 472 * DESCRIPTION: Check namepath Ops for orphaned method invocations 473 * 474 * Note: Parts of this are experimental, under possible further development. 475 * 476 ******************************************************************************/ 477 478static ACPI_STATUS 479AcpiDmFindOrphanDescending ( 480 ACPI_PARSE_OBJECT *Op, 481 UINT32 Level, 482 void *Context) 483{ 484 const ACPI_OPCODE_INFO *OpInfo; 485 ACPI_PARSE_OBJECT *ChildOp; 486 ACPI_PARSE_OBJECT *NextOp; 487 ACPI_PARSE_OBJECT *ParentOp; 488 UINT32 ArgCount; 489 490 491 if (!Op) 492 { 493 return (AE_OK); 494 } 495 496#ifdef ACPI_UNDER_DEVELOPMENT 497 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 498#endif 499 500 switch (Op->Common.AmlOpcode) 501 { 502#ifdef ACPI_UNDER_DEVELOPMENT 503 case AML_ADD_OP: 504 505 ChildOp = Op->Common.Value.Arg; 506 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 507 !ChildOp->Common.Node) 508 { 509 AcpiNsExternalizeName (ACPI_UINT32_MAX, ChildOp->Common.Value.String, 510 NULL, &Path); 511 AcpiOsPrintf ("/* %-16s A-NAMEPATH: %s */\n", 512 Op->Common.AmlOpName, Path); 513 ACPI_FREE (Path); 514 515 NextOp = Op->Common.Next; 516 if (!NextOp) 517 { 518 /* This NamePath has no args, assume it is an integer */ 519 520 AcpiDmAddOpToExternalList (ChildOp, 521 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); 522 return (AE_OK); 523 } 524 525 ArgCount = AcpiDmInspectPossibleArgs (3, 1, NextOp); 526 AcpiOsPrintf ("/* A-CHILDREN: %u Actual %u */\n", 527 ArgCount, AcpiDmCountChildren (Op)); 528 529 if (ArgCount < 1) 530 { 531 /* One Arg means this is just a Store(Name,Target) */ 532 533 AcpiDmAddOpToExternalList (ChildOp, 534 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); 535 return (AE_OK); 536 } 537 538 AcpiDmAddOpToExternalList (ChildOp, 539 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); 540 } 541 break; 542 543#endif 544 545 case AML_STORE_OP: 546 547 ChildOp = Op->Common.Value.Arg; 548 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 549 !ChildOp->Common.Node) 550 { 551 NextOp = Op->Common.Next; 552 if (!NextOp) 553 { 554 /* This NamePath has no args, assume it is an integer */ 555 556 AcpiDmAddOpToExternalList (ChildOp, 557 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); 558 return (AE_OK); 559 } 560 561 ArgCount = AcpiDmInspectPossibleArgs (2, 1, NextOp); 562 if (ArgCount <= 1) 563 { 564 /* One Arg means this is just a Store(Name,Target) */ 565 566 AcpiDmAddOpToExternalList (ChildOp, 567 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, ArgCount, 0); 568 return (AE_OK); 569 } 570 571 AcpiDmAddOpToExternalList (ChildOp, 572 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); 573 } 574 break; 575 576 case AML_INT_NAMEPATH_OP: 577 578 /* Must examine parent to see if this namepath is an argument */ 579 580 ParentOp = Op->Common.Parent; 581 OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode); 582 583 if ((OpInfo->Class != AML_CLASS_EXECUTE) && 584 (OpInfo->Class != AML_CLASS_CREATE) && 585 (OpInfo->ObjectType != ACPI_TYPE_LOCAL_ALIAS) && 586 (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) && 587 !Op->Common.Node) 588 { 589 ArgCount = AcpiDmInspectPossibleArgs (0, 0, Op); 590 591 /* 592 * Check if namepath is a predicate for if/while or lone parameter to 593 * a return. 594 */ 595 if (ArgCount == 0) 596 { 597 if (((ParentOp->Common.AmlOpcode == AML_IF_OP) || 598 (ParentOp->Common.AmlOpcode == AML_WHILE_OP) || 599 (ParentOp->Common.AmlOpcode == AML_RETURN_OP)) && 600 601 /* And namepath is the first argument */ 602 (ParentOp->Common.Value.Arg == Op)) 603 { 604 AcpiDmAddOpToExternalList (Op, 605 Op->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0); 606 break; 607 } 608 } 609 610 /* 611 * This is a standalone namestring (not a parameter to another 612 * operator) - it *must* be a method invocation, nothing else is 613 * grammatically possible. 614 */ 615 AcpiDmAddOpToExternalList (Op, 616 Op->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0); 617 } 618 break; 619 620 default: 621 622 break; 623 } 624 625 return (AE_OK); 626} 627 628 629/******************************************************************************* 630 * 631 * FUNCTION: AcpiDmLoadDescendingOp 632 * 633 * PARAMETERS: ASL_WALK_CALLBACK 634 * 635 * RETURN: Status 636 * 637 * DESCRIPTION: Descending handler for namespace control method object load 638 * 639 ******************************************************************************/ 640 641static ACPI_STATUS 642AcpiDmLoadDescendingOp ( 643 ACPI_PARSE_OBJECT *Op, 644 UINT32 Level, 645 void *Context) 646{ 647 ACPI_OP_WALK_INFO *Info = Context; 648 const ACPI_OPCODE_INFO *OpInfo; 649 ACPI_WALK_STATE *WalkState; 650 ACPI_OBJECT_TYPE ObjectType; 651 ACPI_STATUS Status; 652 char *Path = NULL; 653 ACPI_PARSE_OBJECT *NextOp; 654 ACPI_NAMESPACE_NODE *Node; 655 char FieldPath[5]; 656 BOOLEAN PreDefined = FALSE; 657 UINT8 PreDefineIndex = 0; 658 659 660 WalkState = Info->WalkState; 661 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 662 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); 663 664 /* Only interested in operators that create new names */ 665 666 if (!(OpInfo->Flags & AML_NAMED) && 667 !(OpInfo->Flags & AML_CREATE)) 668 { 669 goto Exit; 670 } 671 672 /* Get the NamePath from the appropriate place */ 673 674 if (OpInfo->Flags & AML_NAMED) 675 { 676 /* For all named operators, get the new name */ 677 678 Path = Op->Named.Path; 679 680 if (!Path && Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) 681 { 682 *ACPI_CAST_PTR (UINT32, &FieldPath[0]) = Op->Named.Name; 683 FieldPath[4] = 0; 684 Path = FieldPath; 685 } 686 } 687 else if (OpInfo->Flags & AML_CREATE) 688 { 689 /* New name is the last child */ 690 691 NextOp = Op->Common.Value.Arg; 692 693 while (NextOp->Common.Next) 694 { 695 NextOp = NextOp->Common.Next; 696 } 697 698 Path = NextOp->Common.Value.String; 699 } 700 701 if (!Path) 702 { 703 goto Exit; 704 } 705 706 /* Insert the name into the namespace */ 707 708 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, 709 ACPI_IMODE_LOAD_PASS2, ACPI_NS_DONT_OPEN_SCOPE, 710 WalkState, &Node); 711 712 Op->Common.Node = Node; 713 714 if (ACPI_SUCCESS (Status)) 715 { 716 /* Check if it's a predefined node */ 717 718 while (AcpiGbl_PreDefinedNames[PreDefineIndex].Name) 719 { 720 if (ACPI_COMPARE_NAMESEG (Node->Name.Ascii, 721 AcpiGbl_PreDefinedNames[PreDefineIndex].Name)) 722 { 723 PreDefined = TRUE; 724 break; 725 } 726 727 PreDefineIndex++; 728 } 729 730 /* 731 * Set node owner id if it satisfies all the following conditions: 732 * 1) Not a predefined node, _SB_ etc 733 * 2) Not the root node 734 * 3) Not a node created by Scope 735 */ 736 if (!PreDefined && 737 (Node != AcpiGbl_RootNode) && 738 (Op->Common.AmlOpcode != AML_SCOPE_OP)) 739 { 740 Node->OwnerId = WalkState->OwnerId; 741 } 742 } 743 744 745Exit: 746 747 if (AcpiNsOpensScope (ObjectType)) 748 { 749 if (Op->Common.Node) 750 { 751 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, 752 WalkState); 753 if (ACPI_FAILURE (Status)) 754 { 755 return (Status); 756 } 757 } 758 } 759 760 return (AE_OK); 761} 762 763 764/******************************************************************************* 765 * 766 * FUNCTION: AcpiDmXrefDescendingOp 767 * 768 * PARAMETERS: ASL_WALK_CALLBACK 769 * 770 * RETURN: Status 771 * 772 * DESCRIPTION: Descending handler for namespace cross reference 773 * 774 ******************************************************************************/ 775 776static ACPI_STATUS 777AcpiDmXrefDescendingOp ( 778 ACPI_PARSE_OBJECT *Op, 779 UINT32 Level, 780 void *Context) 781{ 782 ACPI_OP_WALK_INFO *Info = Context; 783 const ACPI_OPCODE_INFO *OpInfo; 784 ACPI_WALK_STATE *WalkState; 785 ACPI_OBJECT_TYPE ObjectType; 786 ACPI_OBJECT_TYPE ObjectType2; 787 ACPI_STATUS Status; 788 char *Path = NULL; 789 ACPI_PARSE_OBJECT *NextOp; 790 ACPI_NAMESPACE_NODE *Node; 791 ACPI_OPERAND_OBJECT *Object; 792 UINT32 ParamCount = 0; 793 char *Pathname; 794 UINT16 Flags = 0; 795 796 797 WalkState = Info->WalkState; 798 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 799 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); 800 801 if ((!(OpInfo->Flags & AML_NAMED)) && 802 (!(OpInfo->Flags & AML_CREATE)) && 803 (Op->Common.AmlOpcode != AML_INT_NAMEPATH_OP) && 804 (Op->Common.AmlOpcode != AML_NOTIFY_OP)) 805 { 806 goto Exit; 807 } 808 809 /* Get the NamePath from the appropriate place */ 810 811 if (OpInfo->Flags & AML_NAMED) 812 { 813 /* 814 * Only these two operators (Alias, Scope) refer to an existing 815 * name, it is the first argument 816 */ 817 if (Op->Common.AmlOpcode == AML_ALIAS_OP) 818 { 819 ObjectType = ACPI_TYPE_ANY; 820 821 NextOp = Op->Common.Value.Arg; 822 NextOp = NextOp->Common.Value.Arg; 823 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) 824 { 825 Path = NextOp->Common.Value.String; 826 } 827 } 828 else if (Op->Common.AmlOpcode == AML_SCOPE_OP || 829 Op->Common.AmlOpcode == AML_EXTERNAL_OP) 830 { 831 Path = Op->Named.Path; 832 } 833 } 834 else if (OpInfo->Flags & AML_CREATE) 835 { 836 /* Referenced Buffer Name is the first child */ 837 838 ObjectType = ACPI_TYPE_BUFFER; /* Change from TYPE_BUFFER_FIELD */ 839 840 NextOp = Op->Common.Value.Arg; 841 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) 842 { 843 Path = NextOp->Common.Value.String; 844 } 845 } 846 else if (Op->Common.AmlOpcode == AML_NOTIFY_OP) 847 { 848 Path = Op->Common.Value.Arg->Asl.Value.String; 849 } 850 else 851 { 852 Path = Op->Common.Value.String; 853 } 854 855 if (!Path) 856 { 857 goto Exit; 858 } 859 860 /* 861 * Lookup the name in the namespace. Name must exist at this point, or it 862 * is an invalid reference. 863 * 864 * The namespace is also used as a lookup table for references to resource 865 * descriptors and the fields within them. 866 */ 867 Node = NULL; 868 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY, 869 ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, 870 WalkState, &Node); 871 872 if (ACPI_SUCCESS (Status) && (Node->Flags & ANOBJ_IS_EXTERNAL)) 873 { 874 /* Node was created by an External() statement */ 875 876 Status = AE_NOT_FOUND; 877 } 878 879 if (ACPI_FAILURE (Status)) 880 { 881 if (Status == AE_NOT_FOUND) 882 { 883 /* 884 * Add this symbol as an external declaration, except if the 885 * parent is a CondRefOf operator. For this operator, we do not 886 * need an external, nor do we want one, since this can cause 887 * disassembly problems if the symbol is actually a control 888 * method. 889 */ 890 if (!(Op->Asl.Parent && 891 (Op->Asl.Parent->Asl.AmlOpcode == AML_CONDITIONAL_REF_OF_OP))) 892 { 893 if (Node) 894 { 895 AcpiDmAddNodeToExternalList (Node, 896 (UINT8) ObjectType, 7, Flags); 897 } 898 else 899 { 900 AcpiDmAddOpToExternalList (Op, Path, 901 (UINT8) ObjectType, 7, Flags); 902 } 903 } 904 } 905 } 906 907 /* 908 * Found the node, but check if it came from an external table. 909 * Add it to external list. Note: Node->OwnerId == 0 indicates 910 * one of the built-in ACPI Names (_OS_ etc.) which can safely 911 * be ignored. 912 */ 913 else if (Node->OwnerId && 914 (WalkState->OwnerId != Node->OwnerId)) 915 { 916 ObjectType2 = ObjectType; 917 918 Object = AcpiNsGetAttachedObject (Node); 919 if (Object) 920 { 921 ObjectType2 = Object->Common.Type; 922 if (ObjectType2 == ACPI_TYPE_METHOD) 923 { 924 ParamCount = Object->Method.ParamCount; 925 } 926 } 927 928 Pathname = AcpiNsGetExternalPathname (Node); 929 if (!Pathname) 930 { 931 return (AE_NO_MEMORY); 932 } 933 934 AcpiDmAddNodeToExternalList (Node, (UINT8) ObjectType2, 935 ParamCount, ACPI_EXT_RESOLVED_REFERENCE); 936 937 ACPI_FREE (Pathname); 938 Op->Common.Node = Node; 939 } 940 else 941 { 942 Op->Common.Node = Node; 943 } 944 945 946Exit: 947 /* Open new scope if necessary */ 948 949 if (AcpiNsOpensScope (ObjectType)) 950 { 951 if (Op->Common.Node) 952 { 953 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, 954 WalkState); 955 if (ACPI_FAILURE (Status)) 956 { 957 return (Status); 958 } 959 } 960 } 961 962 return (AE_OK); 963} 964 965/******************************************************************************* 966 * 967 * FUNCTION: AcpiDmCommonDescendingOp 968 * 969 * PARAMETERS: ASL_WALK_CALLBACK 970 * 971 * RETURN: ACPI_STATUS 972 * 973 * DESCRIPTION: Perform parse tree preprocessing before main disassembly walk. 974 * 975 ******************************************************************************/ 976 977static ACPI_STATUS 978AcpiDmCommonDescendingOp ( 979 ACPI_PARSE_OBJECT *Op, 980 UINT32 Level, 981 void *Context) 982{ 983 ACPI_STATUS Status; 984 985 986 /* Resource descriptor conversion */ 987 988 Status = AcpiDmProcessResourceDescriptors (Op, Level, Context); 989 if (ACPI_FAILURE (Status)) 990 { 991 return (Status); 992 } 993 994 /* Switch/Case conversion */ 995 996 Status = AcpiDmProcessSwitch (Op); 997 return (Status); 998} 999 1000 1001/******************************************************************************* 1002 * 1003 * FUNCTION: AcpiDmProcessResourceDescriptors 1004 * 1005 * PARAMETERS: ASL_WALK_CALLBACK 1006 * 1007 * RETURN: ACPI_STATUS 1008 * 1009 * DESCRIPTION: Convert fixed-offset references to resource descriptors to 1010 * symbolic references. Should only be called after namespace has 1011 * been cross referenced. 1012 * 1013 ******************************************************************************/ 1014 1015static ACPI_STATUS 1016AcpiDmProcessResourceDescriptors ( 1017 ACPI_PARSE_OBJECT *Op, 1018 UINT32 Level, 1019 void *Context) 1020{ 1021 ACPI_OP_WALK_INFO *Info = Context; 1022 const ACPI_OPCODE_INFO *OpInfo; 1023 ACPI_WALK_STATE *WalkState; 1024 ACPI_OBJECT_TYPE ObjectType; 1025 ACPI_STATUS Status; 1026 1027 1028 WalkState = Info->WalkState; 1029 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 1030 1031 /* Open new scope if necessary */ 1032 1033 ObjectType = OpInfo->ObjectType; 1034 if (AcpiNsOpensScope (ObjectType)) 1035 { 1036 if (Op->Common.Node) 1037 { 1038 1039 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, 1040 WalkState); 1041 if (ACPI_FAILURE (Status)) 1042 { 1043 return (Status); 1044 } 1045 } 1046 } 1047 1048 /* 1049 * Check if this operator contains a reference to a resource descriptor. 1050 * If so, convert the reference into a symbolic reference. 1051 */ 1052 AcpiDmCheckResourceReference (Op, WalkState); 1053 return (AE_OK); 1054} 1055 1056/******************************************************************************* 1057 * 1058 * FUNCTION: AcpiDmCommonAscendingOp 1059 * 1060 * PARAMETERS: ASL_WALK_CALLBACK 1061 * 1062 * RETURN: None 1063 * 1064 * DESCRIPTION: Ascending handler for combined parse/namespace walks. Closes 1065 * scope if necessary. 1066 * 1067 ******************************************************************************/ 1068 1069static ACPI_STATUS 1070AcpiDmCommonAscendingOp ( 1071 ACPI_PARSE_OBJECT *Op, 1072 UINT32 Level, 1073 void *Context) 1074{ 1075 ACPI_OP_WALK_INFO *Info = Context; 1076 ACPI_OBJECT_TYPE ObjectType; 1077 1078 1079 /* Close scope if necessary */ 1080 1081 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); 1082 1083 if (AcpiNsOpensScope (ObjectType)) 1084 { 1085 (void) AcpiDsScopeStackPop (Info->WalkState); 1086 } 1087 1088 return (AE_OK); 1089} 1090 1091/******************************************************************************* 1092 * 1093 * FUNCTION: AcpiDmInspectPossibleArgs 1094 * 1095 * PARAMETERS: CurrentOpArgCount - Which arg of the current op was the 1096 * possible method invocation found 1097 * TargetCount - Number of targets (0,1,2) for this op 1098 * Op - Parse op 1099 * 1100 * RETURN: Status 1101 * 1102 * DESCRIPTION: Examine following args and next ops for possible arguments 1103 * for an unrecognized method invocation. 1104 * 1105 ******************************************************************************/ 1106 1107static UINT32 1108AcpiDmInspectPossibleArgs ( 1109 UINT32 CurrentOpArgCount, 1110 UINT32 TargetCount, 1111 ACPI_PARSE_OBJECT *Op) 1112{ 1113 const ACPI_OPCODE_INFO *OpInfo; 1114 UINT32 i; 1115 UINT32 ArgumentCount = 0; 1116 ACPI_PARSE_OBJECT *NextOp; 1117 ACPI_PARSE_OBJECT *ExecuteOp; 1118 1119 1120 if (!Op) 1121 { 1122 return (0); 1123 } 1124 1125 /* Lookahead for the maximum number of possible arguments */ 1126 1127 NextOp = Op->Common.Next; 1128 1129 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && NextOp; i++) 1130 { 1131 OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode); 1132 1133 /* Any one of these operators is "very probably" not a method arg */ 1134 1135 if ((NextOp->Common.AmlOpcode == AML_STORE_OP) || 1136 (NextOp->Common.AmlOpcode == AML_NOTIFY_OP) || 1137 (OpInfo->Class == AML_CLASS_CONTROL) || 1138 (OpInfo->Class == AML_CLASS_CREATE) || 1139 (OpInfo->Class == AML_CLASS_NAMED_OBJECT)) 1140 { 1141 break; 1142 } 1143 1144 if (OpInfo->Class == AML_CLASS_EXECUTE) 1145 { 1146 /* Probable that this is method arg if there is no target */ 1147 1148 ExecuteOp = NextOp->Common.Value.Arg; 1149 while (ExecuteOp) 1150 { 1151 if ((ExecuteOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 1152 (ExecuteOp->Common.Value.Arg == NULL)) 1153 { 1154 /* No target, could be a method arg */ 1155 1156 break; 1157 } 1158 1159 if (NextOp->Common.AmlOpcode == AML_REF_OF_OP) 1160 { 1161 break; 1162 } 1163 1164 ExecuteOp = ExecuteOp->Common.Next; 1165 } 1166 1167 if (!ExecuteOp) 1168 { 1169 /* Has a target, not method arg */ 1170 1171 return (ArgumentCount); 1172 } 1173 } 1174 1175 ArgumentCount++; 1176 NextOp = NextOp->Common.Next; 1177 } 1178 1179 return (ArgumentCount); 1180} 1181