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