1 /****************************************************************************** 2 * 3 * Module Name: aslxref - Namespace cross-reference 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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 MERCHANTIBILITY 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 "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "acparser.h" 47 #include "amlcode.h" 48 #include "acnamesp.h" 49 #include "acdispat.h" 50 51 52 #define _COMPONENT ACPI_COMPILER 53 ACPI_MODULE_NAME ("aslxref") 54 55 /* Local prototypes */ 56 57 static ACPI_STATUS 58 XfNamespaceLocateBegin ( 59 ACPI_PARSE_OBJECT *Op, 60 UINT32 Level, 61 void *Context); 62 63 static ACPI_STATUS 64 XfNamespaceLocateEnd ( 65 ACPI_PARSE_OBJECT *Op, 66 UINT32 Level, 67 void *Context); 68 69 static BOOLEAN 70 XfValidateCrossReference ( 71 ACPI_PARSE_OBJECT *Op, 72 const ACPI_OPCODE_INFO *OpInfo, 73 ACPI_NAMESPACE_NODE *Node); 74 75 static BOOLEAN 76 XfObjectExists ( 77 char *Name); 78 79 static ACPI_STATUS 80 XfCompareOneNamespaceObject ( 81 ACPI_HANDLE ObjHandle, 82 UINT32 Level, 83 void *Context, 84 void **ReturnValue); 85 86 static void 87 XfCheckFieldRange ( 88 ACPI_PARSE_OBJECT *Op, 89 UINT32 RegionBitLength, 90 UINT32 FieldBitOffset, 91 UINT32 FieldBitLength, 92 UINT32 AccessBitWidth); 93 94 95 /******************************************************************************* 96 * 97 * FUNCTION: XfCrossReferenceNamespace 98 * 99 * PARAMETERS: None 100 * 101 * RETURN: Status 102 * 103 * DESCRIPTION: Perform a cross reference check of the parse tree against the 104 * namespace. Every named referenced within the parse tree 105 * should be get resolved with a namespace lookup. If not, the 106 * original reference in the ASL code is invalid -- i.e., refers 107 * to a non-existent object. 108 * 109 * NOTE: The ASL "External" operator causes the name to be inserted into the 110 * namespace so that references to the external name will be resolved 111 * correctly here. 112 * 113 ******************************************************************************/ 114 115 ACPI_STATUS 116 XfCrossReferenceNamespace ( 117 void) 118 { 119 ACPI_WALK_STATE *WalkState; 120 121 122 /* 123 * Create a new walk state for use when looking up names 124 * within the namespace (Passed as context to the callbacks) 125 */ 126 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); 127 if (!WalkState) 128 { 129 return (AE_NO_MEMORY); 130 } 131 132 /* Walk the entire parse tree */ 133 134 TrWalkParseTree (AslGbl_ParseTreeRoot, ASL_WALK_VISIT_TWICE, 135 XfNamespaceLocateBegin, XfNamespaceLocateEnd, WalkState); 136 137 ACPI_FREE (WalkState); 138 return (AE_OK); 139 } 140 141 142 /******************************************************************************* 143 * 144 * FUNCTION: XfObjectExists 145 * 146 * PARAMETERS: Name - 4 char ACPI name 147 * 148 * RETURN: TRUE if name exists in namespace 149 * 150 * DESCRIPTION: Walk the namespace to find an object 151 * 152 ******************************************************************************/ 153 154 static BOOLEAN 155 XfObjectExists ( 156 char *Name) 157 { 158 ACPI_STATUS Status; 159 160 161 /* Walk entire namespace from the supplied root */ 162 163 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 164 ACPI_UINT32_MAX, FALSE, XfCompareOneNamespaceObject, NULL, 165 Name, NULL); 166 if (Status == AE_CTRL_TRUE) 167 { 168 /* At least one instance of the name was found */ 169 170 return (TRUE); 171 } 172 173 return (FALSE); 174 } 175 176 177 /******************************************************************************* 178 * 179 * FUNCTION: XfCompareOneNamespaceObject 180 * 181 * PARAMETERS: ACPI_WALK_CALLBACK 182 * 183 * RETURN: Status 184 * 185 * DESCRIPTION: Compare name of one object. 186 * 187 ******************************************************************************/ 188 189 static ACPI_STATUS 190 XfCompareOneNamespaceObject ( 191 ACPI_HANDLE ObjHandle, 192 UINT32 Level, 193 void *Context, 194 void **ReturnValue) 195 { 196 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; 197 198 199 /* Simply check the name */ 200 201 if (*((UINT32 *) (Context)) == Node->Name.Integer) 202 { 203 /* Abort walk if we found one instance */ 204 205 return (AE_CTRL_TRUE); 206 } 207 208 return (AE_OK); 209 } 210 211 212 /******************************************************************************* 213 * 214 * FUNCTION: XfCheckFieldRange 215 * 216 * PARAMETERS: RegionBitLength - Length of entire parent region 217 * FieldBitOffset - Start of the field unit (within region) 218 * FieldBitLength - Entire length of field unit 219 * AccessBitWidth - Access width of the field unit 220 * 221 * RETURN: None 222 * 223 * DESCRIPTION: Check one field unit to make sure it fits in the parent 224 * op region. 225 * 226 * Note: AccessBitWidth must be either 8,16,32, or 64 227 * 228 ******************************************************************************/ 229 230 static void 231 XfCheckFieldRange ( 232 ACPI_PARSE_OBJECT *Op, 233 UINT32 RegionBitLength, 234 UINT32 FieldBitOffset, 235 UINT32 FieldBitLength, 236 UINT32 AccessBitWidth) 237 { 238 UINT32 FieldEndBitOffset; 239 240 241 /* 242 * Check each field unit against the region size. The entire 243 * field unit (start offset plus length) must fit within the 244 * region. 245 */ 246 FieldEndBitOffset = FieldBitOffset + FieldBitLength; 247 248 if (FieldEndBitOffset > RegionBitLength) 249 { 250 /* Field definition itself is beyond the end-of-region */ 251 252 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_OFFSET, Op, NULL); 253 return; 254 } 255 256 /* 257 * Now check that the field plus AccessWidth doesn't go beyond 258 * the end-of-region. Assumes AccessBitWidth is a power of 2 259 */ 260 FieldEndBitOffset = ACPI_ROUND_UP (FieldEndBitOffset, AccessBitWidth); 261 262 if (FieldEndBitOffset > RegionBitLength) 263 { 264 /* Field definition combined with the access is beyond EOR */ 265 266 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, Op, NULL); 267 } 268 } 269 270 271 /******************************************************************************* 272 * 273 * FUNCTION: XfNamespaceLocateBegin 274 * 275 * PARAMETERS: ASL_WALK_CALLBACK 276 * 277 * RETURN: Status 278 * 279 * DESCRIPTION: Descending callback used during cross-reference. For named 280 * object references, attempt to locate the name in the 281 * namespace. 282 * 283 * NOTE: ASL references to named fields within resource descriptors are 284 * resolved to integer values here. Therefore, this step is an 285 * important part of the code generation. We don't know that the 286 * name refers to a resource descriptor until now. 287 * 288 ******************************************************************************/ 289 290 static ACPI_STATUS 291 XfNamespaceLocateBegin ( 292 ACPI_PARSE_OBJECT *Op, 293 UINT32 Level, 294 void *Context) 295 { 296 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; 297 ACPI_NAMESPACE_NODE *Node; 298 ACPI_STATUS Status; 299 ACPI_OBJECT_TYPE ObjectType; 300 char *Path; 301 UINT8 PassedArgs; 302 ACPI_PARSE_OBJECT *NextOp; 303 ACPI_PARSE_OBJECT *OwningOp; 304 ACPI_PARSE_OBJECT *SpaceIdOp; 305 UINT32 MinimumLength; 306 UINT32 Offset; 307 UINT32 FieldBitLength; 308 UINT32 TagBitLength; 309 UINT8 Message = 0; 310 const ACPI_OPCODE_INFO *OpInfo; 311 UINT32 Flags; 312 ASL_METHOD_LOCAL *MethodLocals = NULL; 313 ASL_METHOD_LOCAL *MethodArgs = NULL; 314 int RegisterNumber; 315 UINT32 i; 316 ACPI_NAMESPACE_NODE *DeclarationParentMethod; 317 ACPI_PARSE_OBJECT *ReferenceParentMethod; 318 319 320 ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op); 321 322 323 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node) 324 { 325 Node = Op->Asl.Node; 326 327 /* Support for method LocalX/ArgX analysis */ 328 329 if (!Node->MethodLocals) 330 { 331 /* Create local/arg info blocks */ 332 333 MethodLocals = UtLocalCalloc ( 334 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS); 335 Node->MethodLocals = MethodLocals; 336 337 MethodArgs = UtLocalCalloc ( 338 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS); 339 Node->MethodArgs = MethodArgs; 340 341 /* 342 * Get the method argument count 343 * First, get the name node 344 */ 345 NextOp = Op->Asl.Child; 346 347 /* Get the NumArguments node */ 348 349 NextOp = NextOp->Asl.Next; 350 Node->ArgCount = (UINT8) 351 (((UINT8) NextOp->Asl.Value.Integer) & 0x07); 352 353 /* We will track all possible ArgXs */ 354 355 for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) 356 { 357 if (i < Node->ArgCount) 358 { 359 /* Real Args are always "initialized" */ 360 361 MethodArgs[i].Flags = ASL_ARG_INITIALIZED; 362 } 363 else 364 { 365 /* Other ArgXs can be used as locals */ 366 367 MethodArgs[i].Flags = ASL_ARG_IS_LOCAL; 368 } 369 370 MethodArgs[i].Op = Op; 371 } 372 } 373 } 374 375 /* 376 * If this node is the actual declaration of a name 377 * [such as the XXXX name in "Method (XXXX)"], 378 * we are not interested in it here. We only care about names that are 379 * references to other objects within the namespace and the parent objects 380 * of name declarations 381 */ 382 if (Op->Asl.CompileFlags & OP_IS_NAME_DECLARATION) 383 { 384 return_ACPI_STATUS (AE_OK); 385 } 386 387 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 388 389 /* Check method LocalX variables */ 390 391 if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE) 392 { 393 /* Find parent method Op */ 394 395 NextOp = UtGetParentMethodOp (Op); 396 if (!NextOp) 397 { 398 return_ACPI_STATUS (AE_OK); 399 } 400 401 /* Get method node */ 402 403 Node = NextOp->Asl.Node; 404 405 RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */ 406 MethodLocals = Node->MethodLocals; 407 408 if (Op->Asl.CompileFlags & OP_IS_TARGET) 409 { 410 /* Local is being initialized */ 411 412 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED; 413 MethodLocals[RegisterNumber].Op = Op; 414 415 return_ACPI_STATUS (AE_OK); 416 } 417 418 /* Mark this Local as referenced */ 419 420 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED; 421 MethodLocals[RegisterNumber].Op = Op; 422 423 return_ACPI_STATUS (AE_OK); 424 } 425 426 /* Check method ArgX variables */ 427 428 if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT) 429 { 430 /* Find parent method Op */ 431 432 NextOp = UtGetParentMethodOp (Op); 433 if (!NextOp) 434 { 435 return_ACPI_STATUS (AE_OK); 436 } 437 438 /* Get method node */ 439 440 Node = NextOp->Asl.Node; 441 442 /* Get Arg # */ 443 444 RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */ 445 MethodArgs = Node->MethodArgs; 446 447 /* Mark this Arg as referenced */ 448 449 MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED; 450 MethodArgs[RegisterNumber].Op = Op; 451 452 if (Op->Asl.CompileFlags & OP_IS_TARGET) 453 { 454 /* Arg is being initialized */ 455 456 MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED; 457 } 458 459 return_ACPI_STATUS (AE_OK); 460 } 461 462 /* 463 * After method ArgX and LocalX, we are only interested in opcodes 464 * that have an associated name 465 */ 466 if ((!(OpInfo->Flags & AML_NAMED)) && 467 (!(OpInfo->Flags & AML_CREATE)) && 468 (Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) && 469 (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) && 470 (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) && 471 (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL)) 472 { 473 return_ACPI_STATUS (AE_OK); 474 } 475 476 /* 477 * One special case: CondRefOf operator - we don't care if the name exists 478 * or not at this point, just ignore it, the point of the operator is to 479 * determine if the name exists at runtime. 480 */ 481 if ((Op->Asl.Parent) && 482 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF)) 483 { 484 return_ACPI_STATUS (AE_OK); 485 } 486 487 /* 488 * We must enable the "search-to-root" for single NameSegs, but 489 * we have to be very careful about opening up scopes 490 */ 491 Flags = ACPI_NS_SEARCH_PARENT; 492 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || 493 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || 494 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || 495 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) 496 { 497 /* 498 * These are name references, do not push the scope stack 499 * for them. 500 */ 501 Flags |= ACPI_NS_DONT_OPEN_SCOPE; 502 } 503 504 /* Get the NamePath from the appropriate place */ 505 506 if (OpInfo->Flags & AML_NAMED) 507 { 508 /* For nearly all NAMED operators, the name reference is the first child */ 509 510 Path = Op->Asl.Child->Asl.Value.String; 511 if (Op->Asl.AmlOpcode == AML_ALIAS_OP) 512 { 513 /* 514 * ALIAS is the only oddball opcode, the name declaration 515 * (alias name) is the second operand 516 */ 517 Path = Op->Asl.Child->Asl.Next->Asl.Value.String; 518 } 519 } 520 else if (OpInfo->Flags & AML_CREATE) 521 { 522 /* Name must appear as the last parameter */ 523 524 NextOp = Op->Asl.Child; 525 while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION)) 526 { 527 NextOp = NextOp->Asl.Next; 528 } 529 530 Path = NextOp->Asl.Value.String; 531 } 532 else 533 { 534 Path = Op->Asl.Value.String; 535 } 536 537 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); 538 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 539 "Type=%s\n", AcpiUtGetTypeName (ObjectType))); 540 541 /* 542 * Lookup the name in the namespace. Name must exist at this point, or it 543 * is an invalid reference. 544 * 545 * The namespace is also used as a lookup table for references to resource 546 * descriptors and the fields within them. 547 */ 548 AslGbl_NsLookupCount++; 549 550 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, 551 ACPI_IMODE_EXECUTE, Flags, WalkState, &Node); 552 if (ACPI_FAILURE (Status)) 553 { 554 if (Status == AE_NOT_FOUND) 555 { 556 /* 557 * We didn't find the name reference by path -- we can qualify this 558 * a little better before we print an error message 559 */ 560 if (strlen (Path) == ACPI_NAMESEG_SIZE) 561 { 562 /* A simple, one-segment ACPI name */ 563 564 if (XfObjectExists (Path)) 565 { 566 /* 567 * There exists such a name, but we couldn't get to it 568 * from this scope 569 */ 570 AslError (ASL_ERROR, ASL_MSG_NOT_REACHABLE, Op, 571 Op->Asl.ExternalName); 572 } 573 else 574 { 575 /* The name doesn't exist, period */ 576 577 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, 578 Op, Op->Asl.ExternalName); 579 } 580 } 581 else 582 { 583 /* The NamePath contains multiple NameSegs */ 584 585 if ((OpInfo->Flags & AML_CREATE) || 586 (OpInfo->ObjectType == ACPI_TYPE_LOCAL_ALIAS)) 587 { 588 /* 589 * The new name is the last parameter. For the 590 * CreateXXXXField and Alias operators 591 */ 592 NextOp = Op->Asl.Child; 593 while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION)) 594 { 595 NextOp = NextOp->Asl.Next; 596 } 597 598 AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, NextOp, 599 NextOp->Asl.ExternalName); 600 } 601 else if (OpInfo->Flags & AML_NAMED) 602 { 603 /* The new name is the first parameter */ 604 605 AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, Op, 606 Op->Asl.ExternalName); 607 } 608 else if (Path[0] == AML_ROOT_PREFIX) 609 { 610 /* Full namepath from root, the object does not exist */ 611 612 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, Op, 613 Op->Asl.ExternalName); 614 } 615 else 616 { 617 /* 618 * Generic "not found" error. Cannot determine whether it 619 * doesn't exist or just can't be reached. However, we 620 * can differentiate between a NameSeg vs. NamePath. 621 */ 622 if (strlen (Op->Asl.ExternalName) == ACPI_NAMESEG_SIZE) 623 { 624 AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, 625 Op->Asl.ExternalName); 626 } 627 else 628 { 629 AslError (ASL_ERROR, ASL_MSG_NAMEPATH_NOT_EXIST, Op, 630 Op->Asl.ExternalName); 631 } 632 } 633 } 634 635 Status = AE_OK; 636 } 637 638 return_ACPI_STATUS (Status); 639 } 640 641 /* Check for an attempt to access an object in another method */ 642 643 if (!XfValidateCrossReference (Op, OpInfo, Node)) 644 { 645 AslError (ASL_ERROR, ASL_MSG_TEMPORARY_OBJECT, Op, 646 Op->Asl.ExternalName); 647 return_ACPI_STATUS (Status); 648 } 649 650 /* Object was found above, check for an illegal forward reference */ 651 652 if (Op->Asl.CompileFlags & OP_NOT_FOUND_DURING_LOAD) 653 { 654 /* 655 * During the load phase, this Op was flagged as a possible 656 * illegal forward reference. In other words, Op is a name path or 657 * name segment that refers to a named object declared after the 658 * reference. In this scinario, Node refers to the actual declaration 659 * and Op is a parse node that references the named object. 660 * 661 * Note: 662 * 663 * Object references inside of control methods are allowed to 664 * refer to objects declared outside of control methods. 665 * 666 * If the declaration and reference are both contained inside of the 667 * same method or outside of any method, this is a forward reference 668 * and should be reported as a compiler error. 669 */ 670 DeclarationParentMethod = UtGetParentMethodNode (Node); 671 ReferenceParentMethod = UtGetParentMethodOp (Op); 672 673 /* case 1: declaration and reference are both outside of method */ 674 675 if (!ReferenceParentMethod && !DeclarationParentMethod) 676 { 677 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, 678 Op->Asl.ExternalName); 679 } 680 681 /* case 2: declaration and reference are both inside of the same method */ 682 683 else if (ReferenceParentMethod && DeclarationParentMethod && 684 ReferenceParentMethod == DeclarationParentMethod->Op) 685 { 686 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, 687 Op->Asl.ExternalName); 688 } 689 } 690 691 /* Check for a reference vs. name declaration */ 692 693 if (!(OpInfo->Flags & AML_NAMED) && 694 !(OpInfo->Flags & AML_CREATE)) 695 { 696 /* This node has been referenced, mark it for reference check */ 697 698 Node->Flags |= ANOBJ_IS_REFERENCED; 699 } 700 701 /* Attempt to optimize the NamePath */ 702 703 OptOptimizeNamePath (Op, OpInfo->Flags, WalkState, Path, Node); 704 705 /* 706 * 1) Dereference an alias (A name reference that is an alias) 707 * Aliases are not nested, the alias always points to the final object 708 */ 709 if ((Op->Asl.ParseOpcode != PARSEOP_ALIAS) && 710 (Node->Type == ACPI_TYPE_LOCAL_ALIAS)) 711 { 712 /* This node points back to the original PARSEOP_ALIAS */ 713 714 NextOp = Node->Op; 715 716 /* The first child is the alias target op */ 717 718 NextOp = NextOp->Asl.Child; 719 720 /* That in turn points back to original target alias node */ 721 722 if (NextOp->Asl.Node) 723 { 724 Node = NextOp->Asl.Node; 725 } 726 727 /* Else - forward reference to alias, will be resolved later */ 728 } 729 730 /* 2) Check for a reference to a resource descriptor */ 731 732 if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || 733 (Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) 734 { 735 /* 736 * This was a reference to a field within a resource descriptor. 737 * Extract the associated field offset (either a bit or byte 738 * offset depending on the field type) and change the named 739 * reference into an integer for AML code generation 740 */ 741 Offset = Node->Value; 742 TagBitLength = Node->Length; 743 744 /* 745 * If a field is being created, generate the length (in bits) of 746 * the field. Note: Opcodes other than CreateXxxField and Index 747 * can come through here. For other opcodes, we just need to 748 * convert the resource tag reference to an integer offset. 749 */ 750 switch (Op->Asl.Parent->Asl.AmlOpcode) 751 { 752 case AML_CREATE_FIELD_OP: /* Variable "Length" field, in bits */ 753 /* 754 * We know the length operand is an integer constant because 755 * we know that it contains a reference to a resource 756 * descriptor tag. 757 */ 758 FieldBitLength = (UINT32) Op->Asl.Next->Asl.Value.Integer; 759 break; 760 761 case AML_CREATE_BIT_FIELD_OP: 762 763 FieldBitLength = 1; 764 break; 765 766 case AML_CREATE_BYTE_FIELD_OP: 767 case AML_INDEX_OP: 768 769 FieldBitLength = 8; 770 break; 771 772 case AML_CREATE_WORD_FIELD_OP: 773 774 FieldBitLength = 16; 775 break; 776 777 case AML_CREATE_DWORD_FIELD_OP: 778 779 FieldBitLength = 32; 780 break; 781 782 case AML_CREATE_QWORD_FIELD_OP: 783 784 FieldBitLength = 64; 785 break; 786 787 default: 788 789 FieldBitLength = 0; 790 break; 791 } 792 793 /* Check the field length against the length of the resource tag */ 794 795 if (FieldBitLength) 796 { 797 if (TagBitLength < FieldBitLength) 798 { 799 Message = ASL_MSG_TAG_SMALLER; 800 } 801 else if (TagBitLength > FieldBitLength) 802 { 803 Message = ASL_MSG_TAG_LARGER; 804 } 805 806 if (Message) 807 { 808 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), 809 "Size mismatch, Tag: %u bit%s, Field: %u bit%s", 810 TagBitLength, (TagBitLength > 1) ? "s" : "", 811 FieldBitLength, (FieldBitLength > 1) ? "s" : ""); 812 813 AslError (ASL_WARNING, Message, Op, AslGbl_MsgBuffer); 814 } 815 } 816 817 /* Convert the BitOffset to a ByteOffset for certain opcodes */ 818 819 switch (Op->Asl.Parent->Asl.AmlOpcode) 820 { 821 case AML_CREATE_BYTE_FIELD_OP: 822 case AML_CREATE_WORD_FIELD_OP: 823 case AML_CREATE_DWORD_FIELD_OP: 824 case AML_CREATE_QWORD_FIELD_OP: 825 case AML_INDEX_OP: 826 827 Offset = ACPI_DIV_8 (Offset); 828 break; 829 830 default: 831 832 break; 833 } 834 835 /* Now convert this node to an integer whose value is the field offset */ 836 837 Op->Asl.AmlLength = 0; 838 Op->Asl.ParseOpcode = PARSEOP_INTEGER; 839 Op->Asl.Value.Integer = (UINT64) Offset; 840 Op->Asl.CompileFlags |= OP_IS_RESOURCE_FIELD; 841 842 OpcGenerateAmlOpcode (Op); 843 } 844 845 /* 3) Check for a method invocation */ 846 847 else if ((((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || (Op->Asl.ParseOpcode == PARSEOP_NAMESEG)) && 848 (Node->Type == ACPI_TYPE_METHOD) && 849 (Op->Asl.Parent) && 850 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_METHOD)) || 851 852 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) 853 { 854 /* 855 * A reference to a method within one of these opcodes is not an 856 * invocation of the method, it is simply a reference to the method. 857 * 858 * September 2016: Removed DeRefOf from this list 859 */ 860 if ((Op->Asl.Parent) && 861 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) || 862 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) || 863 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)|| 864 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE))) 865 { 866 return_ACPI_STATUS (AE_OK); 867 } 868 869 /* 870 * There are two types of method invocation: 871 * 1) Invocation with arguments -- the parser recognizes this 872 * as a METHODCALL. 873 * 2) Invocation with no arguments --the parser cannot determine that 874 * this is a method invocation, therefore we have to figure it out 875 * here. 876 */ 877 if (Node->Type != ACPI_TYPE_METHOD) 878 { 879 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "%s is a %s", 880 Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type)); 881 882 AslError (ASL_ERROR, ASL_MSG_NOT_METHOD, Op, AslGbl_MsgBuffer); 883 return_ACPI_STATUS (AE_OK); 884 } 885 886 /* Save the method node in the caller's op */ 887 888 Op->Asl.Node = Node; 889 if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF) 890 { 891 return_ACPI_STATUS (AE_OK); 892 } 893 894 /* 895 * This is a method invocation, with or without arguments. 896 * Count the number of arguments, each appears as a child 897 * under the parent node 898 */ 899 Op->Asl.ParseOpcode = PARSEOP_METHODCALL; 900 UtSetParseOpName (Op); 901 902 PassedArgs = 0; 903 NextOp = Op->Asl.Child; 904 905 while (NextOp) 906 { 907 PassedArgs++; 908 NextOp = NextOp->Asl.Next; 909 } 910 911 if (Node->Value != ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS && 912 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) 913 { 914 /* 915 * Check the parsed arguments with the number expected by the 916 * method declaration itself 917 */ 918 if (PassedArgs != Node->Value) 919 { 920 if (Node->Flags & ANOBJ_IS_EXTERNAL) 921 { 922 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), 923 "according to previous use, %s requires %u", 924 Op->Asl.ExternalName, Node->Value); 925 } 926 else 927 { 928 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), 929 "%s requires %u", Op->Asl.ExternalName, 930 Node->Value); 931 } 932 933 if (PassedArgs < Node->Value) 934 { 935 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, AslGbl_MsgBuffer); 936 } 937 else 938 { 939 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_HI, Op, AslGbl_MsgBuffer); 940 } 941 } 942 } 943 944 /* 945 * At this point, a method call to an external method has been 946 * detected. As of 11/19/2019, iASL does not support parameter counts 947 * for methods declared as external. Therefore, save the parameter 948 * count of the first method call and use this count check other 949 * method calls to ensure that the methods are being called with the 950 * same amount of parameters. 951 */ 952 else if (Node->Type == ACPI_TYPE_METHOD && 953 (Node->Flags & ANOBJ_IS_EXTERNAL) && 954 Node->Value == ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS && 955 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) 956 { 957 Node->Value = PassedArgs; 958 } 959 } 960 961 /* 4) Check for an ASL Field definition */ 962 963 else if ((Op->Asl.Parent) && 964 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_FIELD) || 965 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_BANKFIELD))) 966 { 967 /* 968 * Offset checking for fields. If the parent operation region has a 969 * constant length (known at compile time), we can check fields 970 * defined in that region against the region length. This will catch 971 * fields and field units that cannot possibly fit within the region. 972 * 973 * Note: Index fields do not directly reference an operation region, 974 * thus they are not included in this check. 975 */ 976 if (Op == Op->Asl.Parent->Asl.Child) 977 { 978 /* 979 * This is the first child of the field node, which is 980 * the name of the region. Get the parse node for the 981 * region -- which contains the length of the region. 982 */ 983 OwningOp = Node->Op; 984 Op->Asl.Parent->Asl.ExtraValue = 985 ACPI_MUL_8 ((UINT32) OwningOp->Asl.Value.Integer); 986 987 /* Examine the field access width */ 988 989 switch ((UINT8) Op->Asl.Parent->Asl.Value.Integer) 990 { 991 case AML_FIELD_ACCESS_ANY: 992 case AML_FIELD_ACCESS_BYTE: 993 case AML_FIELD_ACCESS_BUFFER: 994 default: 995 996 MinimumLength = 1; 997 break; 998 999 case AML_FIELD_ACCESS_WORD: 1000 1001 MinimumLength = 2; 1002 break; 1003 1004 case AML_FIELD_ACCESS_DWORD: 1005 1006 MinimumLength = 4; 1007 break; 1008 1009 case AML_FIELD_ACCESS_QWORD: 1010 1011 MinimumLength = 8; 1012 break; 1013 } 1014 1015 /* 1016 * Is the region at least as big as the access width? 1017 * Note: DataTableRegions have 0 length 1018 */ 1019 if (((UINT32) OwningOp->Asl.Value.Integer) && 1020 ((UINT32) OwningOp->Asl.Value.Integer < MinimumLength)) 1021 { 1022 AslError (ASL_ERROR, ASL_MSG_FIELD_ACCESS_WIDTH, Op, NULL); 1023 } 1024 1025 /* 1026 * Check EC/CMOS/SMBUS fields to make sure that the correct 1027 * access type is used (BYTE for EC/CMOS, BUFFER for SMBUS) 1028 */ 1029 SpaceIdOp = OwningOp->Asl.Child->Asl.Next; 1030 switch ((UINT32) SpaceIdOp->Asl.Value.Integer) 1031 { 1032 case ACPI_ADR_SPACE_EC: 1033 case ACPI_ADR_SPACE_CMOS: 1034 case ACPI_ADR_SPACE_GPIO: 1035 1036 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != 1037 AML_FIELD_ACCESS_BYTE) 1038 { 1039 AslError (ASL_ERROR, ASL_MSG_REGION_BYTE_ACCESS, Op, NULL); 1040 } 1041 break; 1042 1043 case ACPI_ADR_SPACE_SMBUS: 1044 case ACPI_ADR_SPACE_IPMI: 1045 case ACPI_ADR_SPACE_GSBUS: 1046 1047 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != 1048 AML_FIELD_ACCESS_BUFFER) 1049 { 1050 AslError (ASL_ERROR, ASL_MSG_REGION_BUFFER_ACCESS, Op, NULL); 1051 } 1052 break; 1053 1054 default: 1055 1056 /* Nothing to do for other address spaces */ 1057 1058 break; 1059 } 1060 } 1061 else 1062 { 1063 /* 1064 * This is one element of the field list. Check to make sure 1065 * that it does not go beyond the end of the parent operation region. 1066 * 1067 * In the code below: 1068 * Op->Asl.Parent->Asl.ExtraValue - Region Length (bits) 1069 * Op->Asl.ExtraValue - Field start offset (bits) 1070 * Op->Asl.Child->Asl.Value.Integer32 - Field length (bits) 1071 * Op->Asl.Child->Asl.ExtraValue - Field access width (bits) 1072 */ 1073 if (Op->Asl.Parent->Asl.ExtraValue && Op->Asl.Child) 1074 { 1075 XfCheckFieldRange (Op, 1076 Op->Asl.Parent->Asl.ExtraValue, 1077 Op->Asl.ExtraValue, 1078 (UINT32) Op->Asl.Child->Asl.Value.Integer, 1079 Op->Asl.Child->Asl.ExtraValue); 1080 } 1081 } 1082 } 1083 1084 /* 1085 * 5) Check for external resolution 1086 * By this point, everything should be loaded in the namespace. If a 1087 * namespace lookup results in a namespace node that is an external, it 1088 * means that this named object was not defined in the input ASL. This 1089 * causes issues because there are plenty of incidents where developers 1090 * use the external keyword to suppress compiler errors about undefined 1091 * objects. Note: this only applies when compiling multiple definition 1092 * blocks. 1093 */ 1094 if (AslGbl_ParseTreeRoot->Asl.Child && AslGbl_ParseTreeRoot->Asl.Child->Asl.Next && 1095 (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL && 1096 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) && 1097 (Node->Flags & ANOBJ_IS_EXTERNAL)) 1098 { 1099 AslError (ASL_ERROR, ASL_MSG_UNDEFINED_EXTERNAL, Op, NULL); 1100 } 1101 1102 /* 5) Check for a connection object */ 1103 #if 0 1104 else if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION) 1105 { 1106 return_ACPI_STATUS (Status); 1107 } 1108 #endif 1109 1110 Op->Asl.Node = Node; 1111 return_ACPI_STATUS (Status); 1112 } 1113 1114 1115 /******************************************************************************* 1116 * 1117 * FUNCTION: XfNamespaceLocateEnd 1118 * 1119 * PARAMETERS: ASL_WALK_CALLBACK 1120 * 1121 * RETURN: Status 1122 * 1123 * DESCRIPTION: Ascending callback used during cross reference. We only 1124 * need to worry about scope management here. 1125 * 1126 ******************************************************************************/ 1127 1128 static ACPI_STATUS 1129 XfNamespaceLocateEnd ( 1130 ACPI_PARSE_OBJECT *Op, 1131 UINT32 Level, 1132 void *Context) 1133 { 1134 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; 1135 const ACPI_OPCODE_INFO *OpInfo; 1136 1137 1138 ACPI_FUNCTION_TRACE (XfNamespaceLocateEnd); 1139 1140 1141 /* We are only interested in opcodes that have an associated name */ 1142 1143 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 1144 if (!(OpInfo->Flags & AML_NAMED)) 1145 { 1146 return_ACPI_STATUS (AE_OK); 1147 } 1148 1149 /* Not interested in name references, we did not open a scope for them */ 1150 1151 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || 1152 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || 1153 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || 1154 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) 1155 { 1156 return_ACPI_STATUS (AE_OK); 1157 } 1158 1159 /* Pop the scope stack if necessary */ 1160 1161 if (AcpiNsOpensScope (AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode))) 1162 { 1163 1164 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 1165 "%s: Popping scope for Op %p\n", 1166 AcpiUtGetTypeName (OpInfo->ObjectType), Op)); 1167 1168 (void) AcpiDsScopeStackPop (WalkState); 1169 } 1170 1171 return_ACPI_STATUS (AE_OK); 1172 } 1173 1174 1175 /******************************************************************************* 1176 * 1177 * FUNCTION: XfValidateCrossReference 1178 * 1179 * PARAMETERS: Op - Parse Op that references the object 1180 * OpInfo - Parse Op info struct 1181 * Node - Node for the referenced object 1182 * 1183 * RETURN: TRUE if the reference is legal, FALSE otherwise 1184 * 1185 * DESCRIPTION: Determine if a reference to another object is allowed. 1186 * 1187 * EXAMPLE: 1188 * Method (A) {Name (INT1, 1)} Declaration of object INT1 1189 * Method (B) (Store (2, \A.INT1)} Illegal reference to object INT1 1190 * (INT1 is temporary, valid only during 1191 * execution of A) 1192 * 1193 * NOTES: 1194 * A null pointer returned by either UtGetParentMethodOp or 1195 * UtGetParentMethodNode indicates that the parameter object is not 1196 * within a control method. 1197 * 1198 * Five cases are handled: Case(Op, Node) 1199 * 1) Case(0,0): Op is not within a method, Node is not --> OK 1200 * 2) Case(0,1): Op is not within a method, but Node is --> Illegal 1201 * 3) Case(1,0): Op is within a method, Node is not --> OK 1202 * 4) Case(1,1): Both are within the same method --> OK 1203 * 5) Case(1,1): Both are in methods, but not same method --> Illegal 1204 * 1205 ******************************************************************************/ 1206 1207 static BOOLEAN 1208 XfValidateCrossReference ( 1209 ACPI_PARSE_OBJECT *Op, 1210 const ACPI_OPCODE_INFO *OpInfo, 1211 ACPI_NAMESPACE_NODE *Node) 1212 { 1213 ACPI_PARSE_OBJECT *ReferencingMethodOp; 1214 ACPI_NAMESPACE_NODE *ReferencedMethodNode; 1215 1216 1217 /* Ignore actual named (and related) object declarations */ 1218 1219 if (OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_DEFER | AML_HAS_ARGS)) 1220 { 1221 return (TRUE); 1222 } 1223 1224 /* 1225 * 1) Search upwards in parse tree for owner of the referencing object 1226 * 2) Search upwards in namespace to find the owner of the referenced object 1227 */ 1228 ReferencingMethodOp = UtGetParentMethodOp (Op); 1229 ReferencedMethodNode = UtGetParentMethodNode (Node); 1230 1231 if (!ReferencingMethodOp && !ReferencedMethodNode) 1232 { 1233 /* 1234 * 1) Case (0,0): Both Op and Node are not within methods 1235 * --> OK 1236 */ 1237 return (TRUE); 1238 } 1239 1240 if (!ReferencingMethodOp && ReferencedMethodNode) 1241 { 1242 /* 1243 * 2) Case (0,1): Op is not in a method, but Node is within a 1244 * method --> illegal 1245 */ 1246 return (FALSE); 1247 } 1248 else if (ReferencingMethodOp && !ReferencedMethodNode) 1249 { 1250 /* 1251 * 3) Case (1,0): Op is within a method, but Node is not 1252 * --> OK 1253 */ 1254 return (TRUE); 1255 } 1256 else if (ReferencingMethodOp->Asl.Node == ReferencedMethodNode) 1257 { 1258 /* 1259 * 4) Case (1,1): Both Op and Node are within the same method 1260 * --> OK 1261 */ 1262 return (TRUE); 1263 } 1264 else 1265 { 1266 /* 1267 * 5) Case (1,1), Op and Node are in different methods 1268 * --> Illegal 1269 */ 1270 return (FALSE); 1271 } 1272 } 1273