1 /****************************************************************************** 2 * 3 * Module Name: aslxref - Namespace cross-reference 4 * 5 *****************************************************************************/ 6 7 /****************************************************************************** 8 * 9 * 1. Copyright Notice 10 * 11 * Some or all of this work - Copyright (c) 1999 - 2017, Intel Corp. 12 * All rights reserved. 13 * 14 * 2. License 15 * 16 * 2.1. This is your license from Intel Corp. under its intellectual property 17 * rights. You may have additional license terms from the party that provided 18 * you this software, covering your right to use that party's intellectual 19 * property rights. 20 * 21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22 * copy of the source code appearing in this file ("Covered Code") an 23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24 * base code distributed originally by Intel ("Original Intel Code") to copy, 25 * make derivatives, distribute, use and display any portion of the Covered 26 * Code in any form, with the right to sublicense such rights; and 27 * 28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29 * license (with the right to sublicense), under only those claims of Intel 30 * patents that are infringed by the Original Intel Code, to make, use, sell, 31 * offer to sell, and import the Covered Code and derivative works thereof 32 * solely to the minimum extent necessary to exercise the above copyright 33 * license, and in no event shall the patent license extend to any additions 34 * to or modifications of the Original Intel Code. No other license or right 35 * is granted directly or by implication, estoppel or otherwise; 36 * 37 * The above copyright and patent license is granted only if the following 38 * conditions are met: 39 * 40 * 3. Conditions 41 * 42 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43 * Redistribution of source code of any substantial portion of the Covered 44 * Code or modification with rights to further distribute source must include 45 * the above Copyright Notice, the above License, this list of Conditions, 46 * and the following Disclaimer and Export Compliance provision. In addition, 47 * Licensee must cause all Covered Code to which Licensee contributes to 48 * contain a file documenting the changes Licensee made to create that Covered 49 * Code and the date of any change. Licensee must include in that file the 50 * documentation of any changes made by any predecessor Licensee. Licensee 51 * must include a prominent statement that the modification is derived, 52 * directly or indirectly, from Original Intel Code. 53 * 54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55 * Redistribution of source code of any substantial portion of the Covered 56 * Code or modification without rights to further distribute source must 57 * include the following Disclaimer and Export Compliance provision in the 58 * documentation and/or other materials provided with distribution. In 59 * addition, Licensee may not authorize further sublicense of source of any 60 * portion of the Covered Code, and must include terms to the effect that the 61 * license from Licensee to its licensee is limited to the intellectual 62 * property embodied in the software Licensee provides to its licensee, and 63 * not to intellectual property embodied in modifications its licensee may 64 * make. 65 * 66 * 3.3. Redistribution of Executable. Redistribution in executable form of any 67 * substantial portion of the Covered Code or modification must reproduce the 68 * above Copyright Notice, and the following Disclaimer and Export Compliance 69 * provision in the documentation and/or other materials provided with the 70 * distribution. 71 * 72 * 3.4. Intel retains all right, title, and interest in and to the Original 73 * Intel Code. 74 * 75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76 * Intel shall be used in advertising or otherwise to promote the sale, use or 77 * other dealings in products derived from or relating to the Covered Code 78 * without prior written authorization from Intel. 79 * 80 * 4. Disclaimer and Export Compliance 81 * 82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88 * PARTICULAR PURPOSE. 89 * 90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97 * LIMITED REMEDY. 98 * 99 * 4.3. Licensee shall not export, either directly or indirectly, any of this 100 * software or system incorporating such software without first obtaining any 101 * required license or other approval from the U. S. Department of Commerce or 102 * any other agency or department of the United States Government. In the 103 * event Licensee exports any such software from the United States or 104 * re-exports any such software from a foreign destination, Licensee shall 105 * ensure that the distribution and export/re-export of the software is in 106 * compliance with all laws, regulations, orders, or other restrictions of the 107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108 * any of its subsidiaries will export/re-export any technical data, process, 109 * software, or service, directly or indirectly, to any country for which the 110 * United States government or any agency thereof requires an export license, 111 * other governmental approval, or letter of assurance, without first obtaining 112 * such license, approval or letter. 113 * 114 ***************************************************************************** 115 * 116 * Alternatively, you may choose to be licensed under the terms of the 117 * following license: 118 * 119 * Redistribution and use in source and binary forms, with or without 120 * modification, are permitted provided that the following conditions 121 * are met: 122 * 1. Redistributions of source code must retain the above copyright 123 * notice, this list of conditions, and the following disclaimer, 124 * without modification. 125 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 126 * substantially similar to the "NO WARRANTY" disclaimer below 127 * ("Disclaimer") and any redistribution must be conditioned upon 128 * including a substantially similar Disclaimer requirement for further 129 * binary redistribution. 130 * 3. Neither the names of the above-listed copyright holders nor the names 131 * of any contributors may be used to endorse or promote products derived 132 * from this software without specific prior written permission. 133 * 134 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 135 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 136 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 137 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 138 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 139 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 140 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 141 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 142 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 143 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 144 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 145 * 146 * Alternatively, you may choose to be licensed under the terms of the 147 * GNU General Public License ("GPL") version 2 as published by the Free 148 * Software Foundation. 149 * 150 *****************************************************************************/ 151 152 #include <contrib/dev/acpica/compiler/aslcompiler.h> 153 #include "aslcompiler.y.h" 154 #include <contrib/dev/acpica/include/acparser.h> 155 #include <contrib/dev/acpica/include/amlcode.h> 156 #include <contrib/dev/acpica/include/acnamesp.h> 157 #include <contrib/dev/acpica/include/acdispat.h> 158 159 160 #define _COMPONENT ACPI_COMPILER 161 ACPI_MODULE_NAME ("aslxref") 162 163 /* Local prototypes */ 164 165 static ACPI_STATUS 166 XfNamespaceLocateBegin ( 167 ACPI_PARSE_OBJECT *Op, 168 UINT32 Level, 169 void *Context); 170 171 static ACPI_STATUS 172 XfNamespaceLocateEnd ( 173 ACPI_PARSE_OBJECT *Op, 174 UINT32 Level, 175 void *Context); 176 177 static ACPI_PARSE_OBJECT * 178 XfGetParentMethod ( 179 ACPI_PARSE_OBJECT *Op); 180 181 static BOOLEAN 182 XfObjectExists ( 183 char *Name); 184 185 static ACPI_STATUS 186 XfCompareOneNamespaceObject ( 187 ACPI_HANDLE ObjHandle, 188 UINT32 Level, 189 void *Context, 190 void **ReturnValue); 191 192 static void 193 XfCheckFieldRange ( 194 ACPI_PARSE_OBJECT *Op, 195 UINT32 RegionBitLength, 196 UINT32 FieldBitOffset, 197 UINT32 FieldBitLength, 198 UINT32 AccessBitWidth); 199 200 #ifdef __UNDER_DEVELOPMENT 201 static ACPI_PARSE_OBJECT * 202 XfGetParentMethod ( 203 ACPI_PARSE_OBJECT *Op); 204 205 static void 206 XfCheckIllegalReference ( 207 ACPI_PARSE_OBJECT *Op, 208 ACPI_NAMESPACE_NODE *Node); 209 210 static BOOLEAN 211 XfIsObjectParental ( 212 ACPI_PARSE_OBJECT *MethodOp1, 213 ACPI_PARSE_OBJECT *MethodOp2); 214 #endif 215 216 217 /******************************************************************************* 218 * 219 * FUNCTION: XfCrossReferenceNamespace 220 * 221 * PARAMETERS: None 222 * 223 * RETURN: Status 224 * 225 * DESCRIPTION: Perform a cross reference check of the parse tree against the 226 * namespace. Every named referenced within the parse tree 227 * should be get resolved with a namespace lookup. If not, the 228 * original reference in the ASL code is invalid -- i.e., refers 229 * to a non-existent object. 230 * 231 * NOTE: The ASL "External" operator causes the name to be inserted into the 232 * namespace so that references to the external name will be resolved 233 * correctly here. 234 * 235 ******************************************************************************/ 236 237 ACPI_STATUS 238 XfCrossReferenceNamespace ( 239 void) 240 { 241 ACPI_WALK_STATE *WalkState; 242 243 244 /* 245 * Create a new walk state for use when looking up names 246 * within the namespace (Passed as context to the callbacks) 247 */ 248 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); 249 if (!WalkState) 250 { 251 return (AE_NO_MEMORY); 252 } 253 254 /* Walk the entire parse tree */ 255 256 TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_TWICE, 257 XfNamespaceLocateBegin, XfNamespaceLocateEnd, WalkState); 258 259 ACPI_FREE (WalkState); 260 return (AE_OK); 261 } 262 263 264 /******************************************************************************* 265 * 266 * FUNCTION: XfObjectExists 267 * 268 * PARAMETERS: Name - 4 char ACPI name 269 * 270 * RETURN: TRUE if name exists in namespace 271 * 272 * DESCRIPTION: Walk the namespace to find an object 273 * 274 ******************************************************************************/ 275 276 static BOOLEAN 277 XfObjectExists ( 278 char *Name) 279 { 280 ACPI_STATUS Status; 281 282 283 /* Walk entire namespace from the supplied root */ 284 285 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 286 ACPI_UINT32_MAX, FALSE, XfCompareOneNamespaceObject, NULL, 287 Name, NULL); 288 if (Status == AE_CTRL_TRUE) 289 { 290 /* At least one instance of the name was found */ 291 292 return (TRUE); 293 } 294 295 return (FALSE); 296 } 297 298 299 /******************************************************************************* 300 * 301 * FUNCTION: XfCompareOneNamespaceObject 302 * 303 * PARAMETERS: ACPI_WALK_CALLBACK 304 * 305 * RETURN: Status 306 * 307 * DESCRIPTION: Compare name of one object. 308 * 309 ******************************************************************************/ 310 311 static ACPI_STATUS 312 XfCompareOneNamespaceObject ( 313 ACPI_HANDLE ObjHandle, 314 UINT32 Level, 315 void *Context, 316 void **ReturnValue) 317 { 318 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; 319 320 321 /* Simply check the name */ 322 323 if (*((UINT32 *) (Context)) == Node->Name.Integer) 324 { 325 /* Abort walk if we found one instance */ 326 327 return (AE_CTRL_TRUE); 328 } 329 330 return (AE_OK); 331 } 332 333 334 /******************************************************************************* 335 * 336 * FUNCTION: XfCheckFieldRange 337 * 338 * PARAMETERS: RegionBitLength - Length of entire parent region 339 * FieldBitOffset - Start of the field unit (within region) 340 * FieldBitLength - Entire length of field unit 341 * AccessBitWidth - Access width of the field unit 342 * 343 * RETURN: None 344 * 345 * DESCRIPTION: Check one field unit to make sure it fits in the parent 346 * op region. 347 * 348 * Note: AccessBitWidth must be either 8,16,32, or 64 349 * 350 ******************************************************************************/ 351 352 static void 353 XfCheckFieldRange ( 354 ACPI_PARSE_OBJECT *Op, 355 UINT32 RegionBitLength, 356 UINT32 FieldBitOffset, 357 UINT32 FieldBitLength, 358 UINT32 AccessBitWidth) 359 { 360 UINT32 FieldEndBitOffset; 361 362 363 /* 364 * Check each field unit against the region size. The entire 365 * field unit (start offset plus length) must fit within the 366 * region. 367 */ 368 FieldEndBitOffset = FieldBitOffset + FieldBitLength; 369 370 if (FieldEndBitOffset > RegionBitLength) 371 { 372 /* Field definition itself is beyond the end-of-region */ 373 374 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_OFFSET, Op, NULL); 375 return; 376 } 377 378 /* 379 * Now check that the field plus AccessWidth doesn't go beyond 380 * the end-of-region. Assumes AccessBitWidth is a power of 2 381 */ 382 FieldEndBitOffset = ACPI_ROUND_UP (FieldEndBitOffset, AccessBitWidth); 383 384 if (FieldEndBitOffset > RegionBitLength) 385 { 386 /* Field definition combined with the access is beyond EOR */ 387 388 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, Op, NULL); 389 } 390 } 391 392 393 /******************************************************************************* 394 * 395 * FUNCTION: XfGetParentMethod 396 * 397 * PARAMETERS: Op - Parse Op to be checked 398 * 399 * RETURN: Control method Op if found. NULL otherwise 400 * 401 * DESCRIPTION: Find the control method parent of a parse op. Returns NULL if 402 * the input Op is not within a control method. 403 * 404 ******************************************************************************/ 405 406 static ACPI_PARSE_OBJECT * 407 XfGetParentMethod ( 408 ACPI_PARSE_OBJECT *Op) 409 { 410 ACPI_PARSE_OBJECT *NextOp; 411 412 413 NextOp = Op->Asl.Parent; 414 while (NextOp) 415 { 416 if (NextOp->Asl.AmlOpcode == AML_METHOD_OP) 417 { 418 return (NextOp); 419 } 420 421 NextOp = NextOp->Asl.Parent; 422 } 423 424 return (NULL); /* No parent method found */ 425 } 426 427 /******************************************************************************* 428 * 429 * FUNCTION: XfNamespaceLocateBegin 430 * 431 * PARAMETERS: ASL_WALK_CALLBACK 432 * 433 * RETURN: Status 434 * 435 * DESCRIPTION: Descending callback used during cross-reference. For named 436 * object references, attempt to locate the name in the 437 * namespace. 438 * 439 * NOTE: ASL references to named fields within resource descriptors are 440 * resolved to integer values here. Therefore, this step is an 441 * important part of the code generation. We don't know that the 442 * name refers to a resource descriptor until now. 443 * 444 ******************************************************************************/ 445 446 static ACPI_STATUS 447 XfNamespaceLocateBegin ( 448 ACPI_PARSE_OBJECT *Op, 449 UINT32 Level, 450 void *Context) 451 { 452 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; 453 ACPI_NAMESPACE_NODE *Node; 454 ACPI_STATUS Status; 455 ACPI_OBJECT_TYPE ObjectType; 456 char *Path; 457 UINT8 PassedArgs; 458 ACPI_PARSE_OBJECT *NextOp; 459 ACPI_PARSE_OBJECT *OwningOp; 460 ACPI_PARSE_OBJECT *SpaceIdOp; 461 UINT32 MinimumLength; 462 UINT32 Offset; 463 UINT32 FieldBitLength; 464 UINT32 TagBitLength; 465 UINT8 Message = 0; 466 const ACPI_OPCODE_INFO *OpInfo; 467 UINT32 Flags; 468 ASL_METHOD_LOCAL *MethodLocals = NULL; 469 ASL_METHOD_LOCAL *MethodArgs = NULL; 470 int RegisterNumber; 471 UINT32 i; 472 473 474 ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op); 475 476 477 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node) 478 { 479 Node = Op->Asl.Node; 480 481 /* Support for method LocalX/ArgX analysis */ 482 483 if (!Node->MethodLocals) 484 { 485 /* Create local/arg info blocks */ 486 487 MethodLocals = UtLocalCalloc ( 488 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS); 489 Node->MethodLocals = MethodLocals; 490 491 MethodArgs = UtLocalCalloc ( 492 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS); 493 Node->MethodArgs = MethodArgs; 494 495 /* 496 * Get the method argument count 497 * First, get the name node 498 */ 499 NextOp = Op->Asl.Child; 500 501 /* Get the NumArguments node */ 502 503 NextOp = NextOp->Asl.Next; 504 Node->ArgCount = (UINT8) 505 (((UINT8) NextOp->Asl.Value.Integer) & 0x07); 506 507 /* We will track all posible ArgXs */ 508 509 for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) 510 { 511 if (i < Node->ArgCount) 512 { 513 /* Real Args are always "initialized" */ 514 515 MethodArgs[i].Flags = ASL_ARG_INITIALIZED; 516 } 517 else 518 { 519 /* Other ArgXs can be used as locals */ 520 521 MethodArgs[i].Flags = ASL_ARG_IS_LOCAL; 522 } 523 524 MethodArgs[i].Op = Op; 525 } 526 } 527 } 528 529 /* 530 * If this node is the actual declaration of a name 531 * [such as the XXXX name in "Method (XXXX)"], 532 * we are not interested in it here. We only care about names that are 533 * references to other objects within the namespace and the parent objects 534 * of name declarations 535 */ 536 if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) 537 { 538 return_ACPI_STATUS (AE_OK); 539 } 540 541 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 542 543 /* Check method LocalX variables */ 544 545 if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE) 546 { 547 /* Find parent method Op */ 548 549 NextOp = XfGetParentMethod (Op); 550 if (!NextOp) 551 { 552 return_ACPI_STATUS (AE_OK); 553 } 554 555 /* Get method node */ 556 557 Node = NextOp->Asl.Node; 558 559 RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */ 560 MethodLocals = Node->MethodLocals; 561 562 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 563 { 564 /* Local is being initialized */ 565 566 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED; 567 MethodLocals[RegisterNumber].Op = Op; 568 569 return_ACPI_STATUS (AE_OK); 570 } 571 572 /* Mark this Local as referenced */ 573 574 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED; 575 MethodLocals[RegisterNumber].Op = Op; 576 577 return_ACPI_STATUS (AE_OK); 578 } 579 580 /* Check method ArgX variables */ 581 582 if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT) 583 { 584 /* Find parent method Op */ 585 586 NextOp = XfGetParentMethod (Op); 587 if (!NextOp) 588 { 589 return_ACPI_STATUS (AE_OK); 590 } 591 592 /* Get method node */ 593 594 Node = NextOp->Asl.Node; 595 596 /* Get Arg # */ 597 598 RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */ 599 MethodArgs = Node->MethodArgs; 600 601 /* Mark this Arg as referenced */ 602 603 MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED; 604 MethodArgs[RegisterNumber].Op = Op; 605 606 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 607 { 608 /* Arg is being initialized */ 609 610 MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED; 611 } 612 613 return_ACPI_STATUS (AE_OK); 614 } 615 616 /* 617 * After method ArgX and LocalX, we are only interested in opcodes 618 * that have an associated name 619 */ 620 if ((!(OpInfo->Flags & AML_NAMED)) && 621 (!(OpInfo->Flags & AML_CREATE)) && 622 (Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) && 623 (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) && 624 (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) && 625 (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL)) 626 { 627 return_ACPI_STATUS (AE_OK); 628 } 629 630 /* 631 * One special case: CondRefOf operator - we don't care if the name exists 632 * or not at this point, just ignore it, the point of the operator is to 633 * determine if the name exists at runtime. 634 */ 635 if ((Op->Asl.Parent) && 636 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF)) 637 { 638 return_ACPI_STATUS (AE_OK); 639 } 640 641 /* 642 * We must enable the "search-to-root" for single NameSegs, but 643 * we have to be very careful about opening up scopes 644 */ 645 Flags = ACPI_NS_SEARCH_PARENT; 646 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || 647 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || 648 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || 649 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) 650 { 651 /* 652 * These are name references, do not push the scope stack 653 * for them. 654 */ 655 Flags |= ACPI_NS_DONT_OPEN_SCOPE; 656 } 657 658 /* Get the NamePath from the appropriate place */ 659 660 if (OpInfo->Flags & AML_NAMED) 661 { 662 /* For nearly all NAMED operators, the name reference is the first child */ 663 664 Path = Op->Asl.Child->Asl.Value.String; 665 if (Op->Asl.AmlOpcode == AML_ALIAS_OP) 666 { 667 /* 668 * ALIAS is the only oddball opcode, the name declaration 669 * (alias name) is the second operand 670 */ 671 Path = Op->Asl.Child->Asl.Next->Asl.Value.String; 672 } 673 } 674 else if (OpInfo->Flags & AML_CREATE) 675 { 676 /* Name must appear as the last parameter */ 677 678 NextOp = Op->Asl.Child; 679 while (!(NextOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) 680 { 681 NextOp = NextOp->Asl.Next; 682 } 683 684 Path = NextOp->Asl.Value.String; 685 } 686 else 687 { 688 Path = Op->Asl.Value.String; 689 } 690 691 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); 692 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 693 "Type=%s\n", AcpiUtGetTypeName (ObjectType))); 694 695 /* 696 * Lookup the name in the namespace. Name must exist at this point, or it 697 * is an invalid reference. 698 * 699 * The namespace is also used as a lookup table for references to resource 700 * descriptors and the fields within them. 701 */ 702 Gbl_NsLookupCount++; 703 704 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, 705 ACPI_IMODE_EXECUTE, Flags, WalkState, &(Node)); 706 if (ACPI_FAILURE (Status)) 707 { 708 if (Status == AE_NOT_FOUND) 709 { 710 /* 711 * We didn't find the name reference by path -- we can qualify this 712 * a little better before we print an error message 713 */ 714 if (strlen (Path) == ACPI_NAME_SIZE) 715 { 716 /* A simple, one-segment ACPI name */ 717 718 if (XfObjectExists (Path)) 719 { 720 /* 721 * There exists such a name, but we couldn't get to it 722 * from this scope 723 */ 724 AslError (ASL_ERROR, ASL_MSG_NOT_REACHABLE, Op, 725 Op->Asl.ExternalName); 726 } 727 else 728 { 729 /* The name doesn't exist, period */ 730 731 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, 732 Op, Op->Asl.ExternalName); 733 } 734 } 735 else 736 { 737 /* Check for a fully qualified path */ 738 739 if (Path[0] == AML_ROOT_PREFIX) 740 { 741 /* Gave full path, the object does not exist */ 742 743 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, Op, 744 Op->Asl.ExternalName); 745 } 746 else 747 { 748 /* 749 * We can't tell whether it doesn't exist or just 750 * can't be reached. 751 */ 752 AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, 753 Op->Asl.ExternalName); 754 } 755 } 756 757 Status = AE_OK; 758 } 759 760 return_ACPI_STATUS (Status); 761 } 762 763 /* Check for a reference vs. name declaration */ 764 765 if (!(OpInfo->Flags & AML_NAMED) && 766 !(OpInfo->Flags & AML_CREATE)) 767 { 768 /* This node has been referenced, mark it for reference check */ 769 770 Node->Flags |= ANOBJ_IS_REFERENCED; 771 772 #ifdef __UNDER_DEVELOPMENT 773 774 /* Check for an illegal reference */ 775 776 XfCheckIllegalReference (Op, Node); 777 #endif 778 } 779 780 /* Attempt to optimize the NamePath */ 781 782 OptOptimizeNamePath (Op, OpInfo->Flags, WalkState, Path, Node); 783 784 /* 785 * 1) Dereference an alias (A name reference that is an alias) 786 * Aliases are not nested, the alias always points to the final object 787 */ 788 if ((Op->Asl.ParseOpcode != PARSEOP_ALIAS) && 789 (Node->Type == ACPI_TYPE_LOCAL_ALIAS)) 790 { 791 /* This node points back to the original PARSEOP_ALIAS */ 792 793 NextOp = Node->Op; 794 795 /* The first child is the alias target op */ 796 797 NextOp = NextOp->Asl.Child; 798 799 /* That in turn points back to original target alias node */ 800 801 if (NextOp->Asl.Node) 802 { 803 Node = NextOp->Asl.Node; 804 } 805 806 /* Else - forward reference to alias, will be resolved later */ 807 } 808 809 /* 2) Check for a reference to a resource descriptor */ 810 811 if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || 812 (Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) 813 { 814 /* 815 * This was a reference to a field within a resource descriptor. 816 * Extract the associated field offset (either a bit or byte 817 * offset depending on the field type) and change the named 818 * reference into an integer for AML code generation 819 */ 820 Offset = Node->Value; 821 TagBitLength = Node->Length; 822 823 /* 824 * If a field is being created, generate the length (in bits) of 825 * the field. Note: Opcodes other than CreateXxxField and Index 826 * can come through here. For other opcodes, we just need to 827 * convert the resource tag reference to an integer offset. 828 */ 829 switch (Op->Asl.Parent->Asl.AmlOpcode) 830 { 831 case AML_CREATE_FIELD_OP: /* Variable "Length" field, in bits */ 832 /* 833 * We know the length operand is an integer constant because 834 * we know that it contains a reference to a resource 835 * descriptor tag. 836 */ 837 FieldBitLength = (UINT32) Op->Asl.Next->Asl.Value.Integer; 838 break; 839 840 case AML_CREATE_BIT_FIELD_OP: 841 842 FieldBitLength = 1; 843 break; 844 845 case AML_CREATE_BYTE_FIELD_OP: 846 case AML_INDEX_OP: 847 848 FieldBitLength = 8; 849 break; 850 851 case AML_CREATE_WORD_FIELD_OP: 852 853 FieldBitLength = 16; 854 break; 855 856 case AML_CREATE_DWORD_FIELD_OP: 857 858 FieldBitLength = 32; 859 break; 860 861 case AML_CREATE_QWORD_FIELD_OP: 862 863 FieldBitLength = 64; 864 break; 865 866 default: 867 868 FieldBitLength = 0; 869 break; 870 } 871 872 /* Check the field length against the length of the resource tag */ 873 874 if (FieldBitLength) 875 { 876 if (TagBitLength < FieldBitLength) 877 { 878 Message = ASL_MSG_TAG_SMALLER; 879 } 880 else if (TagBitLength > FieldBitLength) 881 { 882 Message = ASL_MSG_TAG_LARGER; 883 } 884 885 if (Message) 886 { 887 sprintf (MsgBuffer, 888 "Size mismatch, Tag: %u bit%s, Field: %u bit%s", 889 TagBitLength, (TagBitLength > 1) ? "s" : "", 890 FieldBitLength, (FieldBitLength > 1) ? "s" : ""); 891 892 AslError (ASL_WARNING, Message, Op, MsgBuffer); 893 } 894 } 895 896 /* Convert the BitOffset to a ByteOffset for certain opcodes */ 897 898 switch (Op->Asl.Parent->Asl.AmlOpcode) 899 { 900 case AML_CREATE_BYTE_FIELD_OP: 901 case AML_CREATE_WORD_FIELD_OP: 902 case AML_CREATE_DWORD_FIELD_OP: 903 case AML_CREATE_QWORD_FIELD_OP: 904 case AML_INDEX_OP: 905 906 Offset = ACPI_DIV_8 (Offset); 907 break; 908 909 default: 910 911 break; 912 } 913 914 /* Now convert this node to an integer whose value is the field offset */ 915 916 Op->Asl.AmlLength = 0; 917 Op->Asl.ParseOpcode = PARSEOP_INTEGER; 918 Op->Asl.Value.Integer = (UINT64) Offset; 919 Op->Asl.CompileFlags |= NODE_IS_RESOURCE_FIELD; 920 921 OpcGenerateAmlOpcode (Op); 922 } 923 924 /* 3) Check for a method invocation */ 925 926 else if ((((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || (Op->Asl.ParseOpcode == PARSEOP_NAMESEG)) && 927 (Node->Type == ACPI_TYPE_METHOD) && 928 (Op->Asl.Parent) && 929 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_METHOD)) || 930 931 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) 932 { 933 /* 934 * A reference to a method within one of these opcodes is not an 935 * invocation of the method, it is simply a reference to the method. 936 * 937 * September 2016: Removed DeRefOf from this list 938 */ 939 if ((Op->Asl.Parent) && 940 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) || 941 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) || 942 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)|| 943 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE))) 944 { 945 return_ACPI_STATUS (AE_OK); 946 } 947 948 /* 949 * There are two types of method invocation: 950 * 1) Invocation with arguments -- the parser recognizes this 951 * as a METHODCALL. 952 * 2) Invocation with no arguments --the parser cannot determine that 953 * this is a method invocation, therefore we have to figure it out 954 * here. 955 */ 956 if (Node->Type != ACPI_TYPE_METHOD) 957 { 958 sprintf (MsgBuffer, "%s is a %s", 959 Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type)); 960 961 AslError (ASL_ERROR, ASL_MSG_NOT_METHOD, Op, MsgBuffer); 962 return_ACPI_STATUS (AE_OK); 963 } 964 965 /* Save the method node in the caller's op */ 966 967 Op->Asl.Node = Node; 968 if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF) 969 { 970 return_ACPI_STATUS (AE_OK); 971 } 972 973 /* 974 * This is a method invocation, with or without arguments. 975 * Count the number of arguments, each appears as a child 976 * under the parent node 977 */ 978 Op->Asl.ParseOpcode = PARSEOP_METHODCALL; 979 UtSetParseOpName (Op); 980 981 PassedArgs = 0; 982 NextOp = Op->Asl.Child; 983 984 while (NextOp) 985 { 986 PassedArgs++; 987 NextOp = NextOp->Asl.Next; 988 } 989 990 if (Node->Value != ASL_EXTERNAL_METHOD && 991 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) 992 { 993 /* 994 * Check the parsed arguments with the number expected by the 995 * method declaration itself 996 */ 997 if (PassedArgs != Node->Value) 998 { 999 sprintf (MsgBuffer, "%s requires %u", Op->Asl.ExternalName, 1000 Node->Value); 1001 1002 if (PassedArgs < Node->Value) 1003 { 1004 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, MsgBuffer); 1005 } 1006 else 1007 { 1008 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_HI, Op, MsgBuffer); 1009 } 1010 } 1011 } 1012 } 1013 1014 /* 4) Check for an ASL Field definition */ 1015 1016 else if ((Op->Asl.Parent) && 1017 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_FIELD) || 1018 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_BANKFIELD))) 1019 { 1020 /* 1021 * Offset checking for fields. If the parent operation region has a 1022 * constant length (known at compile time), we can check fields 1023 * defined in that region against the region length. This will catch 1024 * fields and field units that cannot possibly fit within the region. 1025 * 1026 * Note: Index fields do not directly reference an operation region, 1027 * thus they are not included in this check. 1028 */ 1029 if (Op == Op->Asl.Parent->Asl.Child) 1030 { 1031 /* 1032 * This is the first child of the field node, which is 1033 * the name of the region. Get the parse node for the 1034 * region -- which contains the length of the region. 1035 */ 1036 OwningOp = Node->Op; 1037 Op->Asl.Parent->Asl.ExtraValue = 1038 ACPI_MUL_8 ((UINT32) OwningOp->Asl.Value.Integer); 1039 1040 /* Examine the field access width */ 1041 1042 switch ((UINT8) Op->Asl.Parent->Asl.Value.Integer) 1043 { 1044 case AML_FIELD_ACCESS_ANY: 1045 case AML_FIELD_ACCESS_BYTE: 1046 case AML_FIELD_ACCESS_BUFFER: 1047 default: 1048 1049 MinimumLength = 1; 1050 break; 1051 1052 case AML_FIELD_ACCESS_WORD: 1053 1054 MinimumLength = 2; 1055 break; 1056 1057 case AML_FIELD_ACCESS_DWORD: 1058 1059 MinimumLength = 4; 1060 break; 1061 1062 case AML_FIELD_ACCESS_QWORD: 1063 1064 MinimumLength = 8; 1065 break; 1066 } 1067 1068 /* 1069 * Is the region at least as big as the access width? 1070 * Note: DataTableRegions have 0 length 1071 */ 1072 if (((UINT32) OwningOp->Asl.Value.Integer) && 1073 ((UINT32) OwningOp->Asl.Value.Integer < MinimumLength)) 1074 { 1075 AslError (ASL_ERROR, ASL_MSG_FIELD_ACCESS_WIDTH, Op, NULL); 1076 } 1077 1078 /* 1079 * Check EC/CMOS/SMBUS fields to make sure that the correct 1080 * access type is used (BYTE for EC/CMOS, BUFFER for SMBUS) 1081 */ 1082 SpaceIdOp = OwningOp->Asl.Child->Asl.Next; 1083 switch ((UINT32) SpaceIdOp->Asl.Value.Integer) 1084 { 1085 case ACPI_ADR_SPACE_EC: 1086 case ACPI_ADR_SPACE_CMOS: 1087 case ACPI_ADR_SPACE_GPIO: 1088 1089 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != 1090 AML_FIELD_ACCESS_BYTE) 1091 { 1092 AslError (ASL_ERROR, ASL_MSG_REGION_BYTE_ACCESS, Op, NULL); 1093 } 1094 break; 1095 1096 case ACPI_ADR_SPACE_SMBUS: 1097 case ACPI_ADR_SPACE_IPMI: 1098 case ACPI_ADR_SPACE_GSBUS: 1099 1100 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != 1101 AML_FIELD_ACCESS_BUFFER) 1102 { 1103 AslError (ASL_ERROR, ASL_MSG_REGION_BUFFER_ACCESS, Op, NULL); 1104 } 1105 break; 1106 1107 default: 1108 1109 /* Nothing to do for other address spaces */ 1110 1111 break; 1112 } 1113 } 1114 else 1115 { 1116 /* 1117 * This is one element of the field list. Check to make sure 1118 * that it does not go beyond the end of the parent operation region. 1119 * 1120 * In the code below: 1121 * Op->Asl.Parent->Asl.ExtraValue - Region Length (bits) 1122 * Op->Asl.ExtraValue - Field start offset (bits) 1123 * Op->Asl.Child->Asl.Value.Integer32 - Field length (bits) 1124 * Op->Asl.Child->Asl.ExtraValue - Field access width (bits) 1125 */ 1126 if (Op->Asl.Parent->Asl.ExtraValue && Op->Asl.Child) 1127 { 1128 XfCheckFieldRange (Op, 1129 Op->Asl.Parent->Asl.ExtraValue, 1130 Op->Asl.ExtraValue, 1131 (UINT32) Op->Asl.Child->Asl.Value.Integer, 1132 Op->Asl.Child->Asl.ExtraValue); 1133 } 1134 } 1135 } 1136 1137 /* 5) Check for a connection object */ 1138 #if 0 1139 else if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION) 1140 { 1141 return_ACPI_STATUS (Status); 1142 } 1143 #endif 1144 1145 Op->Asl.Node = Node; 1146 return_ACPI_STATUS (Status); 1147 } 1148 1149 1150 /******************************************************************************* 1151 * 1152 * FUNCTION: XfNamespaceLocateEnd 1153 * 1154 * PARAMETERS: ASL_WALK_CALLBACK 1155 * 1156 * RETURN: Status 1157 * 1158 * DESCRIPTION: Ascending callback used during cross reference. We only 1159 * need to worry about scope management here. 1160 * 1161 ******************************************************************************/ 1162 1163 static ACPI_STATUS 1164 XfNamespaceLocateEnd ( 1165 ACPI_PARSE_OBJECT *Op, 1166 UINT32 Level, 1167 void *Context) 1168 { 1169 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; 1170 const ACPI_OPCODE_INFO *OpInfo; 1171 1172 1173 ACPI_FUNCTION_TRACE (XfNamespaceLocateEnd); 1174 1175 1176 /* We are only interested in opcodes that have an associated name */ 1177 1178 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 1179 if (!(OpInfo->Flags & AML_NAMED)) 1180 { 1181 return_ACPI_STATUS (AE_OK); 1182 } 1183 1184 /* Not interested in name references, we did not open a scope for them */ 1185 1186 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || 1187 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || 1188 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || 1189 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) 1190 { 1191 return_ACPI_STATUS (AE_OK); 1192 } 1193 1194 /* Pop the scope stack if necessary */ 1195 1196 if (AcpiNsOpensScope (AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode))) 1197 { 1198 1199 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 1200 "%s: Popping scope for Op %p\n", 1201 AcpiUtGetTypeName (OpInfo->ObjectType), Op)); 1202 1203 (void) AcpiDsScopeStackPop (WalkState); 1204 } 1205 1206 return_ACPI_STATUS (AE_OK); 1207 } 1208 1209 1210 #ifdef __UNDER_DEVELOPMENT 1211 /******************************************************************************* 1212 * 1213 * FUNCTION: XfIsObjectParental 1214 * 1215 * PARAMETERS: ChildOp - Op to be checked 1216 * PossibleParentOp - Determine if this op is in the family 1217 * 1218 * RETURN: TRUE if ChildOp is a descendent of PossibleParentOp 1219 * 1220 * DESCRIPTION: Determine if an Op is a descendent of another Op. Used to 1221 * detect if a method is declared within another method. 1222 * 1223 ******************************************************************************/ 1224 1225 static BOOLEAN 1226 XfIsObjectParental ( 1227 ACPI_PARSE_OBJECT *ChildOp, 1228 ACPI_PARSE_OBJECT *PossibleParentOp) 1229 { 1230 ACPI_PARSE_OBJECT *ParentOp; 1231 1232 1233 /* Search upwards through the tree for possible parent */ 1234 1235 ParentOp = ChildOp; 1236 while (ParentOp) 1237 { 1238 if (ParentOp == PossibleParentOp) 1239 { 1240 return (TRUE); 1241 } 1242 1243 ParentOp = ParentOp->Asl.Parent; 1244 } 1245 1246 return (FALSE); 1247 } 1248 1249 1250 /******************************************************************************* 1251 * 1252 * FUNCTION: XfGetParentMethod 1253 * 1254 * PARAMETERS: Op - Op to be checked 1255 * 1256 * RETURN: Op for parent method. NULL if object is not within a method. 1257 * 1258 * DESCRIPTION: Determine if an object is within a control method. Used to 1259 * implement special rules for named references from within a 1260 * control method. 1261 * 1262 * NOTE: It would be better to have the parser set a flag in the Op if possible. 1263 * 1264 ******************************************************************************/ 1265 1266 static ACPI_PARSE_OBJECT * 1267 XfGetParentMethod ( 1268 ACPI_PARSE_OBJECT *Op) 1269 { 1270 ACPI_PARSE_OBJECT *ParentOp; 1271 1272 1273 if (!Op) 1274 { 1275 return (NULL); 1276 } 1277 1278 if (Op->Asl.ParseOpcode == PARSEOP_METHOD) 1279 { 1280 return (NULL); 1281 } 1282 1283 /* Walk upwards through the parse tree, up to the root if necessary */ 1284 1285 ParentOp = Op; 1286 while (ParentOp) 1287 { 1288 if (ParentOp->Asl.ParseOpcode == PARSEOP_METHOD) 1289 { 1290 return (ParentOp); 1291 } 1292 1293 ParentOp = ParentOp->Asl.Parent; 1294 } 1295 1296 /* Object is not within a method */ 1297 1298 return (NULL); 1299 } 1300 1301 1302 /******************************************************************************* 1303 * 1304 * FUNCTION: XfCheckIllegalReference 1305 * 1306 * PARAMETERS: Op - Op referring to the target 1307 * TargetNode - Target of the reference 1308 * 1309 * RETURN: None. Emits error message for an illegal reference 1310 * 1311 * DESCRIPTION: Determine if a named reference is legal. A "named" reference 1312 * is something like: Store(ABCD, ...), where ABCD is an AML 1313 * Nameseg or Namepath. 1314 * 1315 * NOTE: Caller must ensure that the name Op is in fact a reference, and not 1316 * an actual name declaration (creation of a named object). 1317 * 1318 ******************************************************************************/ 1319 1320 static void 1321 XfCheckIllegalReference ( 1322 ACPI_PARSE_OBJECT *Op, 1323 ACPI_NAMESPACE_NODE *TargetNode) 1324 { 1325 ACPI_PARSE_OBJECT *MethodOp1; 1326 ACPI_PARSE_OBJECT *MethodOp2; 1327 ACPI_PARSE_OBJECT *TargetOp; 1328 1329 1330 /* 1331 * Check for an illegal reference to a named object: 1332 * 1333 * 1) References from one control method to another, non-parent 1334 * method are not allowed, they will fail at runtime. 1335 * 1336 * 2) Forward references within a control method are not allowed. 1337 * AML interpreters use a one-pass parse of control methods 1338 * so these forward references will fail at runtime. 1339 */ 1340 TargetOp = TargetNode->Op; 1341 1342 MethodOp1 = XfGetParentMethod (Op); 1343 MethodOp2 = XfGetParentMethod (TargetOp); 1344 1345 /* Are both objects within control method(s)? */ 1346 1347 if (!MethodOp1 || !MethodOp2) 1348 { 1349 return; 1350 } 1351 1352 /* Objects not in the same method? */ 1353 1354 if (MethodOp1 != MethodOp2) 1355 { 1356 /* 1357 * 1) Cross-method named reference 1358 * 1359 * This is OK if and only if the target reference is within in a 1360 * method that is a parent of current method 1361 */ 1362 if (!XfIsObjectParental (MethodOp1, MethodOp2)) 1363 { 1364 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_METHOD_REF, Op, 1365 Op->Asl.ExternalName); 1366 } 1367 } 1368 1369 /* 1370 * 2) Both reference and target are in the same method. Check if this is 1371 * an (illegal) forward reference by examining the exact source code 1372 * location of each (the referenced object and the object declaration). 1373 * This is a bit nasty, yet effective. 1374 */ 1375 else if (Op->Asl.LogicalByteOffset < TargetOp->Asl.LogicalByteOffset) 1376 { 1377 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, 1378 Op->Asl.ExternalName); 1379 } 1380 1381 } 1382 #endif 1383