1 /****************************************************************************** 2 * 3 * Module Name: asloperands - AML operand processing 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2026, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "amlcode.h" 47 48 #define _COMPONENT ACPI_COMPILER 49 ACPI_MODULE_NAME ("asloperands") 50 51 /* Local prototypes */ 52 53 static void 54 OpnDoField ( 55 ACPI_PARSE_OBJECT *Op); 56 57 static void 58 OpnDoBankField ( 59 ACPI_PARSE_OBJECT *Op); 60 61 static void 62 OpnDoBuffer ( 63 ACPI_PARSE_OBJECT *Op); 64 65 static void 66 OpnDoDefinitionBlock ( 67 ACPI_PARSE_OBJECT *Op); 68 69 static void 70 OpnDoFieldCommon ( 71 ACPI_PARSE_OBJECT *FieldOp, 72 ACPI_PARSE_OBJECT *Op); 73 74 static void 75 OpnDoIndexField ( 76 ACPI_PARSE_OBJECT *Op); 77 78 static void 79 OpnDoLoadTable ( 80 ACPI_PARSE_OBJECT *Op); 81 82 static void 83 OpnDoMethod ( 84 ACPI_PARSE_OBJECT *Op); 85 86 static void 87 OpnDoMutex ( 88 ACPI_PARSE_OBJECT *Op); 89 90 static void 91 OpnDoRegion ( 92 ACPI_PARSE_OBJECT *Op); 93 94 static void 95 OpnAttachNameToNode ( 96 ACPI_PARSE_OBJECT *Op); 97 98 99 /******************************************************************************* 100 * 101 * FUNCTION: OpnDoMutex 102 * 103 * PARAMETERS: Op - The parent parse node 104 * 105 * RETURN: None 106 * 107 * DESCRIPTION: Construct the operands for the MUTEX ASL keyword. 108 * 109 ******************************************************************************/ 110 111 static void 112 OpnDoMutex ( 113 ACPI_PARSE_OBJECT *Op) 114 { 115 ACPI_PARSE_OBJECT *Next; 116 117 118 Next = Op->Asl.Child; 119 Next = Next->Asl.Next; 120 121 if (Next->Asl.Value.Integer > 15) 122 { 123 AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL); 124 } 125 return; 126 } 127 128 129 /******************************************************************************* 130 * 131 * FUNCTION: OpnDoMethod 132 * 133 * PARAMETERS: Op - The parent parse node 134 * 135 * RETURN: None 136 * 137 * DESCRIPTION: Construct the operands for the METHOD ASL keyword. 138 * 139 ******************************************************************************/ 140 141 static void 142 OpnDoMethod ( 143 ACPI_PARSE_OBJECT *Op) 144 { 145 ACPI_PARSE_OBJECT *Next; 146 147 /* Optional arguments for this opcode with defaults */ 148 149 UINT8 NumArgs = 0; 150 UINT8 Serialized = 0; 151 UINT8 Concurrency = 0; 152 UINT8 MethodFlags; 153 154 155 /* Opcode and package length first */ 156 /* Method name */ 157 158 Next = Op->Asl.Child; 159 160 /* Num args */ 161 162 Next = Next->Asl.Next; 163 if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) 164 { 165 NumArgs = (UINT8) Next->Asl.Value.Integer; 166 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 167 } 168 169 /* Serialized Flag */ 170 171 Next = Next->Asl.Next; 172 if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) 173 { 174 Serialized = (UINT8) Next->Asl.Value.Integer; 175 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 176 } 177 178 /* Concurrency value (valid values are 0-15) */ 179 180 Next = Next->Asl.Next; 181 if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) 182 { 183 /* This is a ByteConstExpr, so eval the constant now */ 184 185 OpcAmlConstantWalk (Next, 0, NULL); 186 187 if (Next->Asl.Value.Integer > 15) 188 { 189 AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL); 190 } 191 192 Concurrency = (UINT8) Next->Asl.Value.Integer; 193 } 194 195 /* Put the bits in their proper places */ 196 197 MethodFlags = (UINT8) 198 ((NumArgs & 0x7) | 199 ((Serialized & 0x1) << 3) | 200 ((Concurrency & 0xF) << 4)); 201 202 /* Use the last node for the combined flags byte */ 203 204 Next->Asl.Value.Integer = MethodFlags; 205 Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 206 Next->Asl.AmlLength = 1; 207 Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; 208 209 /* Save the arg count in the first node */ 210 211 Op->Asl.Extra = NumArgs; 212 } 213 214 215 /******************************************************************************* 216 * 217 * FUNCTION: OpnDoFieldCommon 218 * 219 * PARAMETERS: FieldOp - Node for an ASL field 220 * Op - The parent parse node 221 * 222 * RETURN: None 223 * 224 * DESCRIPTION: Construct the AML operands for the various field keywords, 225 * FIELD, BANKFIELD, INDEXFIELD 226 * 227 ******************************************************************************/ 228 229 static void 230 OpnDoFieldCommon ( 231 ACPI_PARSE_OBJECT *FieldOp, 232 ACPI_PARSE_OBJECT *Op) 233 { 234 ACPI_PARSE_OBJECT *Next; 235 ACPI_PARSE_OBJECT *PkgLengthNode; 236 UINT32 CurrentBitOffset; 237 UINT32 NewBitOffset; 238 UINT8 AccessType; 239 UINT8 LockRule; 240 UINT8 UpdateRule; 241 UINT8 FieldFlags; 242 UINT32 MinimumLength; 243 244 245 /* AccessType -- not optional, so no need to check for DEFAULT_ARG */ 246 247 AccessType = (UINT8) Op->Asl.Value.Integer; 248 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 249 250 /* Set the access type in the parent (field) node for use later */ 251 252 FieldOp->Asl.Value.Integer = AccessType; 253 254 /* LockRule -- not optional, so no need to check for DEFAULT_ARG */ 255 256 Next = Op->Asl.Next; 257 LockRule = (UINT8) Next->Asl.Value.Integer; 258 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 259 260 /* UpdateRule -- not optional, so no need to check for DEFAULT_ARG */ 261 262 Next = Next->Asl.Next; 263 UpdateRule = (UINT8) Next->Asl.Value.Integer; 264 265 /* 266 * Generate the flags byte. The various fields are already 267 * in the right bit position via translation from the 268 * keywords by the parser. 269 */ 270 FieldFlags = (UINT8) (AccessType | LockRule | UpdateRule); 271 272 /* Use the previous node to be the FieldFlags node */ 273 274 /* Set the node to RAW_DATA */ 275 276 Next->Asl.Value.Integer = FieldFlags; 277 Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 278 Next->Asl.AmlLength = 1; 279 Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; 280 281 /* Process the FieldUnitList */ 282 283 Next = Next->Asl.Next; 284 CurrentBitOffset = 0; 285 286 while (Next) 287 { 288 /* Save the offset of this field unit */ 289 290 Next->Asl.ExtraValue = CurrentBitOffset; 291 292 switch (Next->Asl.ParseOpcode) 293 { 294 case PARSEOP_ACCESSAS: 295 296 PkgLengthNode = Next->Asl.Child; 297 AccessType = (UINT8) PkgLengthNode->Asl.Value.Integer; 298 299 /* Nothing additional to do */ 300 break; 301 302 case PARSEOP_OFFSET: 303 304 /* New offset into the field */ 305 306 PkgLengthNode = Next->Asl.Child; 307 NewBitOffset = ((UINT32) PkgLengthNode->Asl.Value.Integer) * 8; 308 309 /* 310 * Examine the specified offset in relation to the 311 * current offset counter. 312 */ 313 if (NewBitOffset < CurrentBitOffset) 314 { 315 /* 316 * Not allowed to specify a backwards offset! 317 * Issue error and ignore this node. 318 */ 319 AslError (ASL_ERROR, ASL_MSG_BACKWARDS_OFFSET, PkgLengthNode, 320 NULL); 321 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 322 PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 323 } 324 #ifdef _OBSOLETE_CODE 325 /* 326 * January 2022: removed this check due to complaints by users 327 * for too many (invalid) remarks. 328 */ 329 else if (NewBitOffset == CurrentBitOffset) 330 { 331 /* 332 * This Offset() operator is redundant and not needed, 333 * because the offset value is the same as the current 334 * offset. 335 */ 336 AslError (ASL_REMARK, ASL_MSG_OFFSET, PkgLengthNode, NULL); 337 338 if (AslGbl_OptimizeTrivialParseNodes) 339 { 340 /* 341 * Optimize this Offset() operator by removing/ignoring 342 * it. Set the related nodes to default. 343 */ 344 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 345 PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 346 347 AslError (ASL_OPTIMIZATION, ASL_MSG_OFFSET, PkgLengthNode, 348 "Optimizer has removed statement"); 349 } 350 else 351 { 352 /* Optimization is disabled, treat as a valid Offset */ 353 354 PkgLengthNode->Asl.Value.Integer = 355 NewBitOffset - CurrentBitOffset; 356 CurrentBitOffset = NewBitOffset; 357 } 358 } 359 #endif 360 else 361 { 362 /* 363 * Valid new offset - set the value to be inserted into the AML 364 * and update the offset counter. 365 */ 366 PkgLengthNode->Asl.Value.Integer = 367 NewBitOffset - CurrentBitOffset; 368 CurrentBitOffset = NewBitOffset; 369 } 370 break; 371 372 case PARSEOP_NAMESEG: 373 case PARSEOP_RESERVED_BYTES: 374 375 /* Named or reserved field entry */ 376 377 PkgLengthNode = Next->Asl.Child; 378 NewBitOffset = (UINT32) PkgLengthNode->Asl.Value.Integer; 379 CurrentBitOffset += NewBitOffset; 380 381 if ((NewBitOffset == 0) && 382 (Next->Asl.ParseOpcode == PARSEOP_RESERVED_BYTES) && 383 AslGbl_OptimizeTrivialParseNodes) 384 { 385 /* 386 * Unnamed field with a bit length of zero. We can 387 * safely just ignore this. However, we will not ignore 388 * a named field of zero length, we don't want to just 389 * toss out a name. 390 */ 391 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 392 PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 393 break; 394 } 395 396 /* Save the current AccessAs value for error checking later */ 397 398 switch (AccessType) 399 { 400 case AML_FIELD_ACCESS_ANY: 401 case AML_FIELD_ACCESS_BYTE: 402 case AML_FIELD_ACCESS_BUFFER: 403 default: 404 405 MinimumLength = 8; 406 break; 407 408 case AML_FIELD_ACCESS_WORD: 409 MinimumLength = 16; 410 break; 411 412 case AML_FIELD_ACCESS_DWORD: 413 MinimumLength = 32; 414 break; 415 416 case AML_FIELD_ACCESS_QWORD: 417 MinimumLength = 64; 418 break; 419 } 420 421 PkgLengthNode->Asl.ExtraValue = MinimumLength; 422 break; 423 424 default: 425 426 /* All supported field opcodes must appear above */ 427 428 break; 429 } 430 431 /* Move on to next entry in the field list */ 432 433 Next = Next->Asl.Next; 434 } 435 } 436 437 438 /******************************************************************************* 439 * 440 * FUNCTION: OpnDoField 441 * 442 * PARAMETERS: Op - The parent parse node 443 * 444 * RETURN: None 445 * 446 * DESCRIPTION: Construct the AML operands for the FIELD ASL keyword 447 * 448 ******************************************************************************/ 449 450 static void 451 OpnDoField ( 452 ACPI_PARSE_OBJECT *Op) 453 { 454 ACPI_PARSE_OBJECT *Next; 455 456 457 /* Opcode is parent node */ 458 /* First child is field name */ 459 460 Next = Op->Asl.Child; 461 462 /* Second child is the AccessType */ 463 464 OpnDoFieldCommon (Op, Next->Asl.Next); 465 } 466 467 468 /******************************************************************************* 469 * 470 * FUNCTION: OpnDoIndexField 471 * 472 * PARAMETERS: Op - The parent parse node 473 * 474 * RETURN: None 475 * 476 * DESCRIPTION: Construct the AML operands for the INDEXFIELD ASL keyword 477 * 478 ******************************************************************************/ 479 480 static void 481 OpnDoIndexField ( 482 ACPI_PARSE_OBJECT *Op) 483 { 484 ACPI_PARSE_OBJECT *Next; 485 486 487 /* Opcode is parent node */ 488 /* First child is the index name */ 489 490 Next = Op->Asl.Child; 491 492 /* Second child is the data name */ 493 494 Next = Next->Asl.Next; 495 496 /* Third child is the AccessType */ 497 498 OpnDoFieldCommon (Op, Next->Asl.Next); 499 } 500 501 502 /******************************************************************************* 503 * 504 * FUNCTION: OpnDoBankField 505 * 506 * PARAMETERS: Op - The parent parse node 507 * 508 * RETURN: None 509 * 510 * DESCRIPTION: Construct the AML operands for the BANKFIELD ASL keyword 511 * 512 ******************************************************************************/ 513 514 static void 515 OpnDoBankField ( 516 ACPI_PARSE_OBJECT *Op) 517 { 518 ACPI_PARSE_OBJECT *Next; 519 520 521 /* Opcode is parent node */ 522 /* First child is the region name */ 523 524 Next = Op->Asl.Child; 525 526 /* Second child is the bank name */ 527 528 Next = Next->Asl.Next; 529 530 /* Third child is the bank value */ 531 532 Next = Next->Asl.Next; 533 534 /* Fourth child is the AccessType */ 535 536 OpnDoFieldCommon (Op, Next->Asl.Next); 537 } 538 539 540 /******************************************************************************* 541 * 542 * FUNCTION: OpnDoRegion 543 * 544 * PARAMETERS: Op - The parent parse node 545 * 546 * RETURN: None 547 * 548 * DESCRIPTION: Tries to get the length of the region. Can only do this at 549 * compile time if the length is a constant. 550 * 551 ******************************************************************************/ 552 553 static void 554 OpnDoRegion ( 555 ACPI_PARSE_OBJECT *Op) 556 { 557 ACPI_PARSE_OBJECT *Next; 558 ACPI_ADR_SPACE_TYPE SpaceId; 559 560 561 /* Opcode is parent node */ 562 /* First child is the region name */ 563 564 Next = Op->Asl.Child; 565 566 /* Second child is the space ID */ 567 568 Next = Next->Asl.Next; 569 SpaceId = (ACPI_ADR_SPACE_TYPE) Next->Common.Value.Integer; 570 571 /* Third child is the region offset */ 572 573 Next = Next->Asl.Next; 574 575 /* Fourth child is the region length */ 576 577 Next = Next->Asl.Next; 578 if (Next->Asl.ParseOpcode == PARSEOP_INTEGER) 579 { 580 /* Check for zero length */ 581 582 Op->Asl.Value.Integer = Next->Asl.Value.Integer; 583 if (!Op->Asl.Value.Integer && (SpaceId < ACPI_NUM_PREDEFINED_REGIONS)) 584 { 585 AslError (ASL_ERROR, ASL_MSG_REGION_LENGTH, Op, NULL); 586 } 587 } 588 else 589 { 590 Op->Asl.Value.Integer = ACPI_UINT64_MAX; 591 } 592 } 593 594 595 /******************************************************************************* 596 * 597 * FUNCTION: OpnDoBuffer 598 * 599 * PARAMETERS: Op - The parent parse node 600 * 601 * RETURN: None 602 * 603 * DESCRIPTION: Construct the AML operands for the BUFFER ASL keyword. We 604 * build a single raw byte buffer from the initialization nodes, 605 * each parse node contains a buffer byte. 606 * 607 ******************************************************************************/ 608 609 static void 610 OpnDoBuffer ( 611 ACPI_PARSE_OBJECT *Op) 612 { 613 ACPI_PARSE_OBJECT *InitializerOp; 614 ACPI_PARSE_OBJECT *BufferLengthOp; 615 616 /* Optional arguments for this opcode with defaults */ 617 618 UINT32 BufferLength = 0; 619 620 621 /* Opcode and package length first */ 622 /* Buffer Length is next, followed by the initializer list */ 623 624 BufferLengthOp = Op->Asl.Child; 625 InitializerOp = BufferLengthOp->Asl.Next; 626 627 /* 628 * If the BufferLength is not an INTEGER or was not specified in the ASL 629 * (DEFAULT_ARG), it is a TermArg that is 630 * evaluated at run-time, and we are therefore finished. 631 */ 632 if ((BufferLengthOp->Asl.ParseOpcode != PARSEOP_INTEGER) && 633 (BufferLengthOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) 634 { 635 return; 636 } 637 638 /* 639 * We want to count the number of items in the initializer list, because if 640 * it is larger than the buffer length, we will define the buffer size 641 * to be the size of the initializer list (as per the ACPI Specification) 642 */ 643 switch (InitializerOp->Asl.ParseOpcode) 644 { 645 case PARSEOP_INTEGER: 646 case PARSEOP_BYTECONST: 647 case PARSEOP_WORDCONST: 648 case PARSEOP_DWORDCONST: 649 650 /* The peer list contains the byte list (if any...) */ 651 652 while (InitializerOp) 653 { 654 /* For buffers, this is a list of raw bytes */ 655 656 InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 657 InitializerOp->Asl.AmlLength = 1; 658 InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; 659 660 BufferLength++; 661 InitializerOp = ASL_GET_PEER_NODE (InitializerOp); 662 } 663 break; 664 665 case PARSEOP_STRING_LITERAL: 666 667 /* 668 * Only one initializer, the string. Buffer must be big enough to hold 669 * the string plus the null termination byte 670 */ 671 BufferLength = strlen (InitializerOp->Asl.Value.String) + 1; 672 673 InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; 674 InitializerOp->Asl.AmlLength = BufferLength; 675 InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; 676 break; 677 678 case PARSEOP_RAW_DATA: 679 680 /* Buffer nodes are already initialized (e.g. Unicode operator) */ 681 return; 682 683 case PARSEOP_DEFAULT_ARG: 684 break; 685 686 default: 687 688 AslError (ASL_ERROR, ASL_MSG_INVALID_OPERAND, InitializerOp, 689 "Unknown buffer initializer opcode"); 690 printf ("Unknown buffer initializer opcode [%s]\n", 691 UtGetOpName (InitializerOp->Asl.ParseOpcode)); 692 return; 693 } 694 695 /* Check if initializer list is longer than the buffer length */ 696 697 if (BufferLengthOp->Asl.Value.Integer > BufferLength) 698 { 699 BufferLength = (UINT32) BufferLengthOp->Asl.Value.Integer; 700 } 701 702 if (!BufferLength) 703 { 704 /* No length AND no items -- issue notice */ 705 706 AslError (ASL_REMARK, ASL_MSG_BUFFER_LENGTH, BufferLengthOp, NULL); 707 708 /* But go ahead and put the buffer length of zero into the AML */ 709 } 710 711 /* 712 * Just set the buffer size node to be the buffer length, regardless 713 * of whether it was previously an integer or a default_arg placeholder 714 */ 715 BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; 716 BufferLengthOp->Asl.AmlOpcode = AML_DWORD_OP; 717 BufferLengthOp->Asl.Value.Integer = BufferLength; 718 719 (void) OpcSetOptimalIntegerSize (BufferLengthOp); 720 UtSetParseOpName (BufferLengthOp); 721 722 /* Remaining nodes are handled via the tree walk */ 723 } 724 725 726 /******************************************************************************* 727 * 728 * FUNCTION: OpnDoPackage 729 * 730 * PARAMETERS: Op - The parent parse node 731 * 732 * RETURN: None 733 * 734 * DESCRIPTION: Construct the AML operands for the PACKAGE ASL keyword. NOTE: 735 * can only be called after constants have been folded, to ensure 736 * that the PackageLength operand has been fully reduced. 737 * 738 ******************************************************************************/ 739 740 void 741 OpnDoPackage ( 742 ACPI_PARSE_OBJECT *Op) 743 { 744 ACPI_PARSE_OBJECT *InitializerOp; 745 ACPI_PARSE_OBJECT *PackageLengthOp; 746 UINT64 DeclaredLength; 747 UINT32 PackageLength = 0; 748 UINT32 MaxEncodedLength = 0x0FFFFFFF; /* Max AML package length encoding (28 bits) */ 749 750 751 /* Opcode and package length first, followed by the initializer list */ 752 753 PackageLengthOp = Op->Asl.Child; 754 InitializerOp = PackageLengthOp->Asl.Next; 755 756 /* Count the number of items in the initializer list */ 757 758 if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) 759 { 760 /* The peer list contains the byte list (if any...) */ 761 762 while (InitializerOp) 763 { 764 PackageLength++; 765 InitializerOp = InitializerOp->Asl.Next; 766 } 767 } 768 769 /* If package length is a constant, compare to the initializer list */ 770 771 if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER) || 772 (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST) || 773 (PackageLengthOp->Asl.ParseOpcode == PARSEOP_PACKAGE_LENGTH)) 774 { 775 DeclaredLength = PackageLengthOp->Asl.Value.Integer; 776 777 /* Guard against values that cannot be encoded in AML package length format */ 778 779 if (DeclaredLength > MaxEncodedLength) 780 { 781 AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, PackageLengthOp, NULL); 782 DeclaredLength = MaxEncodedLength; 783 PackageLengthOp->Asl.Value.Integer = DeclaredLength; 784 } 785 786 if (DeclaredLength > PackageLength) 787 { 788 /* 789 * Allow package length to be longer than the initializer 790 * list -- but if the length of initializer list is nonzero, 791 * issue a message since this is probably a coding error, 792 * even though technically legal. 793 */ 794 if (PackageLength > 0) 795 { 796 AslError (ASL_REMARK, ASL_MSG_LIST_LENGTH_SHORT, 797 PackageLengthOp, NULL); 798 } 799 800 PackageLength = (UINT32) DeclaredLength; 801 } 802 else if (DeclaredLength < PackageLength) 803 { 804 /* 805 * The package length is smaller than the length of the 806 * initializer list. This is an error as per the ACPI spec. 807 */ 808 AslError (ASL_ERROR, ASL_MSG_LIST_LENGTH_LONG, 809 PackageLengthOp, NULL); 810 } 811 } 812 813 if (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 814 { 815 /* 816 * This is the case if the PackageLength was left empty - Package() 817 * The package length becomes the length of the initializer list 818 */ 819 Op->Asl.Child->Asl.ParseOpcode = PARSEOP_INTEGER; 820 Op->Asl.Child->Asl.Value.Integer = PackageLength; 821 UtSetParseOpName (Op); 822 823 /* Set the AML opcode */ 824 825 (void) OpcSetOptimalIntegerSize (Op->Asl.Child); 826 } 827 828 /* If not a variable-length package, check for a zero package length */ 829 830 if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER) || 831 (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST) || 832 (PackageLengthOp->Asl.ParseOpcode == PARSEOP_ZERO) || 833 (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)) 834 { 835 if (!PackageLength) 836 { 837 /* No length AND no initializer list -- issue a remark */ 838 839 AslError (ASL_REMARK, ASL_MSG_PACKAGE_LENGTH, 840 PackageLengthOp, NULL); 841 842 /* But go ahead and put the buffer length of zero into the AML */ 843 } 844 } 845 846 /* 847 * If the PackageLength is a constant <= 255, we can change the 848 * AML opcode from VarPackage to a simple (ACPI 1.0) Package opcode. 849 */ 850 if (((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && 851 (Op->Asl.Child->Asl.Value.Integer <= 255)) || 852 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONE) || 853 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONES)|| 854 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ZERO)) 855 { 856 Op->Asl.AmlOpcode = AML_PACKAGE_OP; 857 Op->Asl.ParseOpcode = PARSEOP_PACKAGE; 858 859 /* 860 * Just set the package size node to be the package length, regardless 861 * of whether it was previously an integer or a default_arg placeholder 862 */ 863 PackageLengthOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 864 PackageLengthOp->Asl.AmlLength = 1; 865 PackageLengthOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; 866 PackageLengthOp->Asl.Value.Integer = PackageLength; 867 } 868 869 /* Remaining nodes are handled via the tree walk */ 870 } 871 872 873 /******************************************************************************* 874 * 875 * FUNCTION: OpnDoLoadTable 876 * 877 * PARAMETERS: Op - The parent parse node 878 * 879 * RETURN: None 880 * 881 * DESCRIPTION: Construct the AML operands for the LOADTABLE ASL keyword. 882 * 883 ******************************************************************************/ 884 885 static void 886 OpnDoLoadTable ( 887 ACPI_PARSE_OBJECT *Op) 888 { 889 ACPI_PARSE_OBJECT *Next; 890 891 892 /* Opcode is parent node */ 893 /* First child is the table signature */ 894 895 Next = Op->Asl.Child; 896 897 /* Second child is the OEM ID*/ 898 899 Next = Next->Asl.Next; 900 901 /* Third child is the OEM table ID */ 902 903 Next = Next->Asl.Next; 904 905 /* Fourth child is the RootPath string */ 906 907 Next = Next->Asl.Next; 908 if ((Next->Asl.ParseOpcode == PARSEOP_ZERO) || 909 ((Next->Asl.Value.Integer == 0) && 910 ((Next->Asl.ParseOpcode == PARSEOP_INTEGER) || 911 (Next->Asl.ParseOpcode == PARSEOP_BYTECONST) || 912 (Next->Asl.ParseOpcode == PARSEOP_WORDCONST) || 913 (Next->Asl.ParseOpcode == PARSEOP_DWORDCONST)|| 914 (Next->Asl.ParseOpcode == PARSEOP_QWORDCONST)))) 915 { 916 Next->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; 917 Next->Asl.Value.String = "\\"; 918 Next->Asl.AmlLength = 2; 919 OpcGenerateAmlOpcode (Next); 920 } 921 922 #ifdef ASL_FUTURE_IMPLEMENTATION 923 924 /* TBD: NOT IMPLEMENTED */ 925 /* Fifth child is the [optional] ParameterPathString */ 926 /* Sixth child is the [optional] ParameterData */ 927 928 Next = Next->Asl.Next; 929 if (Next->Asl.ParseOpcode == DEFAULT_ARG) 930 { 931 Next->Asl.AmlLength = 1; 932 Next->Asl.ParseOpcode = ZERO; 933 OpcGenerateAmlOpcode (Next); 934 } 935 936 937 Next = Next->Asl.Next; 938 if (Next->Asl.ParseOpcode == DEFAULT_ARG) 939 { 940 Next->Asl.AmlLength = 1; 941 Next->Asl.ParseOpcode = ZERO; 942 OpcGenerateAmlOpcode (Next); 943 } 944 #endif 945 } 946 947 948 /******************************************************************************* 949 * 950 * FUNCTION: OpnDoDefinitionBlock 951 * 952 * PARAMETERS: Op - The parent parse node 953 * 954 * RETURN: None 955 * 956 * DESCRIPTION: Construct the AML operands for the DEFINITIONBLOCK ASL keyword 957 * 958 ******************************************************************************/ 959 960 static void 961 OpnDoDefinitionBlock ( 962 ACPI_PARSE_OBJECT *Op) 963 { 964 ACPI_PARSE_OBJECT *Child; 965 ACPI_SIZE Length; 966 UINT32 i; 967 char *Filename; 968 ACPI_STATUS Status; 969 970 971 /* 972 * These nodes get stuffed into the table header. They are special 973 * cased when the table is written to the output file. 974 * 975 * Mark all of these nodes as non-usable so they won't get output 976 * as AML opcodes! 977 */ 978 979 /* Get AML filename. Use it if non-null */ 980 981 Child = Op->Asl.Child; 982 if (Child->Asl.Value.Buffer && 983 *Child->Asl.Value.Buffer && 984 (AslGbl_UseDefaultAmlFilename)) 985 { 986 /* 987 * The walk may traverse multiple definition blocks. Switch files 988 * to ensure that the correct files are manipulated. 989 */ 990 FlSwitchFileSet (Op->Asl.Filename); 991 992 /* 993 * We will use the AML filename that is embedded in the source file 994 * for the output filename. 995 */ 996 Filename = UtLocalCacheCalloc (strlen (AslGbl_DirectoryPath) + 997 strlen ((char *) Child->Asl.Value.Buffer) + 1); 998 999 /* Prepend the current directory path */ 1000 1001 strcpy (Filename, AslGbl_DirectoryPath); 1002 strcat (Filename, (char *) Child->Asl.Value.Buffer); 1003 1004 AslGbl_OutputFilenamePrefix = Filename; 1005 UtConvertBackslashes (AslGbl_OutputFilenamePrefix); 1006 1007 /* 1008 * Use the definition block file parameter instead of the input 1009 * filename. Since all files were opened previously, remove the 1010 * existing file and open a new file with the name of this 1011 * definition block parameter. Since AML code generation has yet 1012 * to happen, the previous file can be removed without any impacts. 1013 */ 1014 FlCloseFile (ASL_FILE_AML_OUTPUT); 1015 FlDeleteFile (ASL_FILE_AML_OUTPUT); 1016 Status = FlOpenAmlOutputFile (AslGbl_OutputFilenamePrefix); 1017 if (ACPI_FAILURE (Status)) 1018 { 1019 AslError (ASL_ERROR, ASL_MSG_OUTPUT_FILE_OPEN, NULL, NULL); 1020 return; 1021 } 1022 } 1023 1024 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1025 1026 /* Signature */ 1027 1028 Child = Child->Asl.Next; 1029 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1030 if (Child->Asl.Value.String) 1031 { 1032 AslGbl_FilesList->TableSignature = Child->Asl.Value.String; 1033 AslGbl_TableSignature = Child->Asl.Value.String; 1034 if (strlen (AslGbl_TableSignature) != ACPI_NAMESEG_SIZE) 1035 { 1036 AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child, 1037 "Length must be exactly 4 characters"); 1038 } 1039 1040 for (i = 0; i < ACPI_NAMESEG_SIZE; i++) 1041 { 1042 if (!isalnum ((int) AslGbl_TableSignature[i])) 1043 { 1044 AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child, 1045 "Contains non-alphanumeric characters"); 1046 } 1047 } 1048 } 1049 1050 /* Revision */ 1051 1052 Child = Child->Asl.Next; 1053 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1054 1055 /* 1056 * We used the revision to set the integer width earlier 1057 */ 1058 1059 /* OEMID */ 1060 1061 Child = Child->Asl.Next; 1062 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1063 if (Child->Asl.Value.String && 1064 strlen (Child->Asl.Value.String) > ACPI_OEM_ID_SIZE) 1065 { 1066 AslError (ASL_ERROR, ASL_MSG_OEM_ID, Child, 1067 "Length cannot exceed 6 characters"); 1068 } 1069 1070 /* OEM TableID */ 1071 1072 Child = Child->Asl.Next; 1073 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1074 if (Child->Asl.Value.String) 1075 { 1076 Length = strlen (Child->Asl.Value.String); 1077 if (Length > ACPI_OEM_TABLE_ID_SIZE) 1078 { 1079 AslError (ASL_ERROR, ASL_MSG_OEM_TABLE_ID, Child, 1080 "Length cannot exceed 8 characters"); 1081 } 1082 1083 AslGbl_TableId = UtLocalCacheCalloc (Length + 1); 1084 strcpy (AslGbl_TableId, Child->Asl.Value.String); 1085 AslGbl_FilesList->TableId = AslGbl_TableId; 1086 1087 /* 1088 * Convert anything non-alphanumeric to an underscore. This 1089 * allows us to use the TableID to generate unique C symbols. 1090 */ 1091 for (i = 0; i < Length; i++) 1092 { 1093 if (!isalnum ((int) AslGbl_TableId[i])) 1094 { 1095 AslGbl_TableId[i] = '_'; 1096 } 1097 } 1098 } 1099 1100 /* OEM Revision */ 1101 1102 Child = Child->Asl.Next; 1103 Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1104 } 1105 1106 1107 /******************************************************************************* 1108 * 1109 * FUNCTION: UtGetArg 1110 * 1111 * PARAMETERS: Op - Get an argument for this op 1112 * Argn - Nth argument to get 1113 * 1114 * RETURN: The argument (as an Op object). NULL if argument does not exist 1115 * 1116 * DESCRIPTION: Get the specified op's argument (peer) 1117 * 1118 ******************************************************************************/ 1119 1120 ACPI_PARSE_OBJECT * 1121 UtGetArg ( 1122 ACPI_PARSE_OBJECT *Op, 1123 UINT32 Argn) 1124 { 1125 ACPI_PARSE_OBJECT *Arg = NULL; 1126 1127 1128 /* Get the requested argument object */ 1129 1130 Arg = Op->Asl.Child; 1131 while (Arg && Argn) 1132 { 1133 Argn--; 1134 Arg = Arg->Asl.Next; 1135 } 1136 1137 return (Arg); 1138 } 1139 1140 1141 /******************************************************************************* 1142 * 1143 * FUNCTION: OpnAttachNameToNode 1144 * 1145 * PARAMETERS: Op - The parent parse node 1146 * 1147 * RETURN: None 1148 * 1149 * DESCRIPTION: For the named ASL/AML operators, get the actual name from the 1150 * argument list and attach it to the parent node so that we 1151 * can get to it quickly later. 1152 * 1153 ******************************************************************************/ 1154 1155 static void 1156 OpnAttachNameToNode ( 1157 ACPI_PARSE_OBJECT *Op) 1158 { 1159 ACPI_PARSE_OBJECT *Child = NULL; 1160 1161 1162 switch (Op->Asl.AmlOpcode) 1163 { 1164 case AML_DATA_REGION_OP: 1165 case AML_DEVICE_OP: 1166 case AML_EVENT_OP: 1167 case AML_EXTERNAL_OP: 1168 case AML_METHOD_OP: 1169 case AML_MUTEX_OP: 1170 case AML_REGION_OP: 1171 case AML_POWER_RESOURCE_OP: 1172 case AML_PROCESSOR_OP: 1173 case AML_THERMAL_ZONE_OP: 1174 case AML_NAME_OP: 1175 case AML_SCOPE_OP: 1176 1177 Child = UtGetArg (Op, 0); 1178 break; 1179 1180 case AML_ALIAS_OP: 1181 1182 Child = UtGetArg (Op, 1); 1183 break; 1184 1185 case AML_CREATE_BIT_FIELD_OP: 1186 case AML_CREATE_BYTE_FIELD_OP: 1187 case AML_CREATE_WORD_FIELD_OP: 1188 case AML_CREATE_DWORD_FIELD_OP: 1189 case AML_CREATE_QWORD_FIELD_OP: 1190 1191 Child = UtGetArg (Op, 2); 1192 break; 1193 1194 case AML_CREATE_FIELD_OP: 1195 1196 Child = UtGetArg (Op, 3); 1197 break; 1198 1199 case AML_BANK_FIELD_OP: 1200 case AML_INDEX_FIELD_OP: 1201 case AML_FIELD_OP: 1202 1203 return; 1204 1205 default: 1206 1207 return; 1208 } 1209 1210 if (Child) 1211 { 1212 UtAttachNamepathToOwner (Op, Child); 1213 } 1214 } 1215 1216 1217 /******************************************************************************* 1218 * 1219 * FUNCTION: OpnGenerateAmlOperands 1220 * 1221 * PARAMETERS: Op - The parent parse node 1222 * 1223 * RETURN: None 1224 * 1225 * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 1226 * complex AML opcodes require processing of the child nodes 1227 * (arguments/operands). 1228 * 1229 ******************************************************************************/ 1230 1231 void 1232 OpnGenerateAmlOperands ( 1233 ACPI_PARSE_OBJECT *Op) 1234 { 1235 1236 1237 if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 1238 { 1239 return; 1240 } 1241 1242 switch (Op->Asl.ParseOpcode) 1243 { 1244 case PARSEOP_DEFINITION_BLOCK: 1245 1246 OpnDoDefinitionBlock (Op); 1247 break; 1248 1249 case PARSEOP_METHOD: 1250 1251 OpnDoMethod (Op); 1252 break; 1253 1254 case PARSEOP_MUTEX: 1255 1256 OpnDoMutex (Op); 1257 break; 1258 1259 case PARSEOP_FIELD: 1260 1261 OpnDoField (Op); 1262 break; 1263 1264 case PARSEOP_INDEXFIELD: 1265 1266 OpnDoIndexField (Op); 1267 break; 1268 1269 case PARSEOP_BANKFIELD: 1270 1271 OpnDoBankField (Op); 1272 break; 1273 1274 case PARSEOP_BUFFER: 1275 1276 OpnDoBuffer (Op); 1277 break; 1278 1279 case PARSEOP_LOADTABLE: 1280 1281 OpnDoLoadTable (Op); 1282 break; 1283 1284 case PARSEOP_OPERATIONREGION: 1285 1286 OpnDoRegion (Op); 1287 break; 1288 1289 case PARSEOP_RESOURCETEMPLATE: 1290 1291 RsDoResourceTemplate (Op); 1292 break; 1293 1294 case PARSEOP_NAMESEG: 1295 case PARSEOP_NAMESTRING: 1296 case PARSEOP_METHODCALL: 1297 case PARSEOP_STRING_LITERAL: 1298 default: 1299 1300 break; 1301 } 1302 1303 /* TBD: move */ 1304 1305 OpnAttachNameToNode (Op); 1306 } 1307