1 2 /****************************************************************************** 3 * 4 * Module Name: aslopcode - AML opcode generation 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2011, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 46 #include <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include "aslcompiler.y.h" 48 #include <contrib/dev/acpica/include/amlcode.h> 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("aslopcodes") 52 53 54 /* Local prototypes */ 55 56 static void 57 OpcDoAccessAs ( 58 ACPI_PARSE_OBJECT *Op); 59 60 static void 61 OpcDoUnicode ( 62 ACPI_PARSE_OBJECT *Op); 63 64 static void 65 OpcDoEisaId ( 66 ACPI_PARSE_OBJECT *Op); 67 68 static void 69 OpcDoUuId ( 70 ACPI_PARSE_OBJECT *Op); 71 72 73 /******************************************************************************* 74 * 75 * FUNCTION: OpcAmlOpcodeUpdateWalk 76 * 77 * PARAMETERS: ASL_WALK_CALLBACK 78 * 79 * RETURN: Status 80 * 81 * DESCRIPTION: Opcode update walk, ascending callback 82 * 83 ******************************************************************************/ 84 85 ACPI_STATUS 86 OpcAmlOpcodeUpdateWalk ( 87 ACPI_PARSE_OBJECT *Op, 88 UINT32 Level, 89 void *Context) 90 { 91 92 /* 93 * Handle the Package() case where the actual opcode cannot be determined 94 * until the PackageLength operand has been folded and minimized. 95 * (PackageOp versus VarPackageOp) 96 * 97 * This is (as of ACPI 3.0) the only case where the AML opcode can change 98 * based upon the value of a parameter. 99 * 100 * The parser always inserts a VarPackage opcode, which can possibly be 101 * optimized to a Package opcode. 102 */ 103 if (Op->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE) 104 { 105 OpnDoPackage (Op); 106 } 107 108 return (AE_OK); 109 } 110 111 112 /******************************************************************************* 113 * 114 * FUNCTION: OpcAmlOpcodeWalk 115 * 116 * PARAMETERS: ASL_WALK_CALLBACK 117 * 118 * RETURN: Status 119 * 120 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 121 * operands. 122 * 123 ******************************************************************************/ 124 125 ACPI_STATUS 126 OpcAmlOpcodeWalk ( 127 ACPI_PARSE_OBJECT *Op, 128 UINT32 Level, 129 void *Context) 130 { 131 132 TotalParseNodes++; 133 134 OpcGenerateAmlOpcode (Op); 135 OpnGenerateAmlOperands (Op); 136 return (AE_OK); 137 } 138 139 140 /******************************************************************************* 141 * 142 * FUNCTION: OpcGetIntegerWidth 143 * 144 * PARAMETERS: Op - DEFINITION BLOCK op 145 * 146 * RETURN: none 147 * 148 * DESCRIPTION: Extract integer width from the table revision 149 * 150 ******************************************************************************/ 151 152 void 153 OpcGetIntegerWidth ( 154 ACPI_PARSE_OBJECT *Op) 155 { 156 ACPI_PARSE_OBJECT *Child; 157 158 159 if (!Op) 160 { 161 return; 162 } 163 164 if (Gbl_RevisionOverride) 165 { 166 AcpiUtSetIntegerWidth (Gbl_RevisionOverride); 167 } 168 else 169 { 170 Child = Op->Asl.Child; 171 Child = Child->Asl.Next; 172 Child = Child->Asl.Next; 173 174 /* Use the revision to set the integer width */ 175 176 AcpiUtSetIntegerWidth ((UINT8) Child->Asl.Value.Integer); 177 } 178 } 179 180 181 /******************************************************************************* 182 * 183 * FUNCTION: OpcSetOptimalIntegerSize 184 * 185 * PARAMETERS: Op - A parse tree node 186 * 187 * RETURN: Integer width, in bytes. Also sets the node AML opcode to the 188 * optimal integer AML prefix opcode. 189 * 190 * DESCRIPTION: Determine the optimal AML encoding of an integer. All leading 191 * zeros can be truncated to squeeze the integer into the 192 * minimal number of AML bytes. 193 * 194 ******************************************************************************/ 195 196 UINT32 197 OpcSetOptimalIntegerSize ( 198 ACPI_PARSE_OBJECT *Op) 199 { 200 201 #if 0 202 /* 203 * TBD: - we don't want to optimize integers in the block header, but the 204 * code below does not work correctly. 205 */ 206 if (Op->Asl.Parent && 207 Op->Asl.Parent->Asl.Parent && 208 (Op->Asl.Parent->Asl.Parent->Asl.ParseOpcode == PARSEOP_DEFINITIONBLOCK)) 209 { 210 return 0; 211 } 212 #endif 213 214 /* 215 * Check for the special AML integers first - Zero, One, Ones. 216 * These are single-byte opcodes that are the smallest possible 217 * representation of an integer. 218 * 219 * This optimization is optional. 220 */ 221 if (Gbl_IntegerOptimizationFlag) 222 { 223 switch (Op->Asl.Value.Integer) 224 { 225 case 0: 226 227 Op->Asl.AmlOpcode = AML_ZERO_OP; 228 AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, 229 Op, "Zero"); 230 return 1; 231 232 case 1: 233 234 Op->Asl.AmlOpcode = AML_ONE_OP; 235 AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, 236 Op, "One"); 237 return 1; 238 239 case ACPI_UINT32_MAX: 240 241 /* Check for table integer width (32 or 64) */ 242 243 if (AcpiGbl_IntegerByteWidth == 4) 244 { 245 Op->Asl.AmlOpcode = AML_ONES_OP; 246 AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, 247 Op, "Ones"); 248 return 1; 249 } 250 break; 251 252 case ACPI_UINT64_MAX: 253 254 /* Check for table integer width (32 or 64) */ 255 256 if (AcpiGbl_IntegerByteWidth == 8) 257 { 258 Op->Asl.AmlOpcode = AML_ONES_OP; 259 AslError (ASL_OPTIMIZATION, ASL_MSG_INTEGER_OPTIMIZATION, 260 Op, "Ones"); 261 return 1; 262 } 263 break; 264 265 default: 266 break; 267 } 268 } 269 270 /* Find the best fit using the various AML integer prefixes */ 271 272 if (Op->Asl.Value.Integer <= ACPI_UINT8_MAX) 273 { 274 Op->Asl.AmlOpcode = AML_BYTE_OP; 275 return 1; 276 } 277 if (Op->Asl.Value.Integer <= ACPI_UINT16_MAX) 278 { 279 Op->Asl.AmlOpcode = AML_WORD_OP; 280 return 2; 281 } 282 if (Op->Asl.Value.Integer <= ACPI_UINT32_MAX) 283 { 284 Op->Asl.AmlOpcode = AML_DWORD_OP; 285 return 4; 286 } 287 else 288 { 289 if (AcpiGbl_IntegerByteWidth == 4) 290 { 291 AslError (ASL_WARNING, ASL_MSG_INTEGER_LENGTH, 292 Op, NULL); 293 294 if (!Gbl_IgnoreErrors) 295 { 296 /* Truncate the integer to 32-bit */ 297 Op->Asl.AmlOpcode = AML_DWORD_OP; 298 return 4; 299 } 300 } 301 302 Op->Asl.AmlOpcode = AML_QWORD_OP; 303 return 8; 304 } 305 } 306 307 308 /******************************************************************************* 309 * 310 * FUNCTION: OpcDoAccessAs 311 * 312 * PARAMETERS: Op - Parse node 313 * 314 * RETURN: None 315 * 316 * DESCRIPTION: Implement the ACCESS_AS ASL keyword. 317 * 318 ******************************************************************************/ 319 320 static void 321 OpcDoAccessAs ( 322 ACPI_PARSE_OBJECT *Op) 323 { 324 ACPI_PARSE_OBJECT *Next; 325 326 327 Op->Asl.AmlOpcodeLength = 1; 328 Next = Op->Asl.Child; 329 330 /* First child is the access type */ 331 332 Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 333 Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; 334 335 /* Second child is the optional access attribute */ 336 337 Next = Next->Asl.Next; 338 if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 339 { 340 Next->Asl.Value.Integer = 0; 341 } 342 Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 343 Next->Asl.ParseOpcode = PARSEOP_RAW_DATA; 344 } 345 346 347 /******************************************************************************* 348 * 349 * FUNCTION: OpcDoUnicode 350 * 351 * PARAMETERS: Op - Parse node 352 * 353 * RETURN: None 354 * 355 * DESCRIPTION: Implement the UNICODE ASL "macro". Convert the input string 356 * to a unicode buffer. There is no Unicode AML opcode. 357 * 358 * Note: The Unicode string is 16 bits per character, no leading signature, 359 * with a 16-bit terminating NULL. 360 * 361 ******************************************************************************/ 362 363 static void 364 OpcDoUnicode ( 365 ACPI_PARSE_OBJECT *Op) 366 { 367 ACPI_PARSE_OBJECT *InitializerOp; 368 UINT32 Length; 369 UINT32 Count; 370 UINT32 i; 371 UINT8 *AsciiString; 372 UINT16 *UnicodeString; 373 ACPI_PARSE_OBJECT *BufferLengthOp; 374 375 376 /* Change op into a buffer object */ 377 378 Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; 379 Op->Asl.ParseOpcode = PARSEOP_BUFFER; 380 UtSetParseOpName (Op); 381 382 /* Buffer Length is first, followed by the string */ 383 384 BufferLengthOp = Op->Asl.Child; 385 InitializerOp = BufferLengthOp->Asl.Next; 386 387 AsciiString = (UINT8 *) InitializerOp->Asl.Value.String; 388 389 /* Create a new buffer for the Unicode string */ 390 391 Count = strlen (InitializerOp->Asl.Value.String) + 1; 392 Length = Count * sizeof (UINT16); 393 UnicodeString = UtLocalCalloc (Length); 394 395 /* Convert to Unicode string (including null terminator) */ 396 397 for (i = 0; i < Count; i++) 398 { 399 UnicodeString[i] = (UINT16) AsciiString[i]; 400 } 401 402 /* 403 * Just set the buffer size node to be the buffer length, regardless 404 * of whether it was previously an integer or a default_arg placeholder 405 */ 406 BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER; 407 BufferLengthOp->Asl.AmlOpcode = AML_DWORD_OP; 408 BufferLengthOp->Asl.Value.Integer = Length; 409 UtSetParseOpName (BufferLengthOp); 410 411 (void) OpcSetOptimalIntegerSize (BufferLengthOp); 412 413 /* The Unicode string is a raw data buffer */ 414 415 InitializerOp->Asl.Value.Buffer = (UINT8 *) UnicodeString; 416 InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; 417 InitializerOp->Asl.AmlLength = Length; 418 InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA; 419 InitializerOp->Asl.Child = NULL; 420 UtSetParseOpName (InitializerOp); 421 } 422 423 424 /******************************************************************************* 425 * 426 * FUNCTION: OpcDoEisaId 427 * 428 * PARAMETERS: Op - Parse node 429 * 430 * RETURN: None 431 * 432 * DESCRIPTION: Convert a string EISA ID to numeric representation. See the 433 * Pnp BIOS Specification for details. Here is an excerpt: 434 * 435 * A seven character ASCII representation of the product 436 * identifier compressed into a 32-bit identifier. The seven 437 * character ID consists of a three character manufacturer code, 438 * a three character hexadecimal product identifier, and a one 439 * character hexadecimal revision number. The manufacturer code 440 * is a 3 uppercase character code that is compressed into 3 5-bit 441 * values as follows: 442 * 1) Find hex ASCII value for each letter 443 * 2) Subtract 40h from each ASCII value 444 * 3) Retain 5 least signficant bits for each letter by 445 * discarding upper 3 bits because they are always 0. 446 * 4) Compressed code = concatenate 0 and the 3 5-bit values 447 * 448 * The format of the compressed product identifier is as follows: 449 * Byte 0: Bit 7 - Reserved (0) 450 * Bits 6-2: - 1st character of compressed mfg code 451 * Bits 1-0 - Upper 2 bits of 2nd character of mfg code 452 * Byte 1: Bits 7-5 - Lower 3 bits of 2nd character of mfg code 453 * Bits 4-0 - 3rd character of mfg code 454 * Byte 2: Bits 7-4 - 1st hex digit of product number 455 * Bits 3-0 - 2nd hex digit of product number 456 * Byte 3: Bits 7-4 - 3st hex digit of product number 457 * Bits 3-0 - Hex digit of the revision number 458 * 459 ******************************************************************************/ 460 461 static void 462 OpcDoEisaId ( 463 ACPI_PARSE_OBJECT *Op) 464 { 465 UINT32 EisaId = 0; 466 UINT32 BigEndianId; 467 char *InString; 468 ACPI_STATUS Status = AE_OK; 469 UINT32 i; 470 471 472 InString = (char *) Op->Asl.Value.String; 473 474 /* 475 * The EISAID string must be exactly 7 characters and of the form 476 * "UUUXXXX" -- 3 uppercase letters and 4 hex digits (e.g., "PNP0001") 477 */ 478 if (ACPI_STRLEN (InString) != 7) 479 { 480 Status = AE_BAD_PARAMETER; 481 } 482 else 483 { 484 /* Check all 7 characters for correct format */ 485 486 for (i = 0; i < 7; i++) 487 { 488 /* First 3 characters must be uppercase letters */ 489 490 if (i < 3) 491 { 492 if (!isupper ((int) InString[i])) 493 { 494 Status = AE_BAD_PARAMETER; 495 } 496 } 497 498 /* Last 4 characters must be hex digits */ 499 500 else if (!isxdigit ((int) InString[i])) 501 { 502 Status = AE_BAD_PARAMETER; 503 } 504 } 505 } 506 507 if (ACPI_FAILURE (Status)) 508 { 509 AslError (ASL_ERROR, ASL_MSG_INVALID_EISAID, Op, Op->Asl.Value.String); 510 } 511 else 512 { 513 /* Create ID big-endian first (bits are contiguous) */ 514 515 BigEndianId = 516 (UINT32) ((UINT8) (InString[0] - 0x40)) << 26 | 517 (UINT32) ((UINT8) (InString[1] - 0x40)) << 21 | 518 (UINT32) ((UINT8) (InString[2] - 0x40)) << 16 | 519 520 (UtHexCharToValue (InString[3])) << 12 | 521 (UtHexCharToValue (InString[4])) << 8 | 522 (UtHexCharToValue (InString[5])) << 4 | 523 UtHexCharToValue (InString[6]); 524 525 /* Swap to little-endian to get final ID (see function header) */ 526 527 EisaId = AcpiUtDwordByteSwap (BigEndianId); 528 } 529 530 /* 531 * Morph the Op into an integer, regardless of whether there 532 * was an error in the EISAID string 533 */ 534 Op->Asl.Value.Integer = EisaId; 535 536 Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; 537 Op->Asl.ParseOpcode = PARSEOP_INTEGER; 538 (void) OpcSetOptimalIntegerSize (Op); 539 540 /* Op is now an integer */ 541 542 UtSetParseOpName (Op); 543 } 544 545 546 /******************************************************************************* 547 * 548 * FUNCTION: OpcDoUiId 549 * 550 * PARAMETERS: Op - Parse node 551 * 552 * RETURN: None 553 * 554 * DESCRIPTION: Convert UUID string to 16-byte buffer 555 * 556 ******************************************************************************/ 557 558 static void 559 OpcDoUuId ( 560 ACPI_PARSE_OBJECT *Op) 561 { 562 char *InString; 563 char *Buffer; 564 ACPI_STATUS Status = AE_OK; 565 ACPI_PARSE_OBJECT *NewOp; 566 567 568 InString = (char *) Op->Asl.Value.String; 569 Buffer = UtLocalCalloc (16); 570 571 Status = AuValidateUuid (InString); 572 if (ACPI_FAILURE (Status)) 573 { 574 AslError (ASL_ERROR, ASL_MSG_INVALID_UUID, Op, Op->Asl.Value.String); 575 } 576 else 577 { 578 (void) AuConvertStringToUuid (InString, Buffer); 579 } 580 581 /* Change Op to a Buffer */ 582 583 Op->Asl.ParseOpcode = PARSEOP_BUFFER; 584 Op->Common.AmlOpcode = AML_BUFFER_OP; 585 586 /* Disable further optimization */ 587 588 Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST; 589 UtSetParseOpName (Op); 590 591 /* Child node is the buffer length */ 592 593 NewOp = TrAllocateNode (PARSEOP_INTEGER); 594 595 NewOp->Asl.AmlOpcode = AML_BYTE_OP; 596 NewOp->Asl.Value.Integer = 16; 597 NewOp->Asl.Parent = Op; 598 599 Op->Asl.Child = NewOp; 600 Op = NewOp; 601 602 /* Peer to the child is the raw buffer data */ 603 604 NewOp = TrAllocateNode (PARSEOP_RAW_DATA); 605 NewOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; 606 NewOp->Asl.AmlLength = 16; 607 NewOp->Asl.Value.String = (char *) Buffer; 608 NewOp->Asl.Parent = Op->Asl.Parent; 609 610 Op->Asl.Next = NewOp; 611 } 612 613 614 /******************************************************************************* 615 * 616 * FUNCTION: OpcGenerateAmlOpcode 617 * 618 * PARAMETERS: Op - Parse node 619 * 620 * RETURN: None 621 * 622 * DESCRIPTION: Generate the AML opcode associated with the node and its 623 * parse (lex/flex) keyword opcode. Essentially implements 624 * a mapping between the parse opcodes and the actual AML opcodes. 625 * 626 ******************************************************************************/ 627 628 void 629 OpcGenerateAmlOpcode ( 630 ACPI_PARSE_OBJECT *Op) 631 { 632 633 UINT16 Index; 634 635 636 Index = (UINT16) (Op->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 637 638 Op->Asl.AmlOpcode = AslKeywordMapping[Index].AmlOpcode; 639 Op->Asl.AcpiBtype = AslKeywordMapping[Index].AcpiBtype; 640 Op->Asl.CompileFlags |= AslKeywordMapping[Index].Flags; 641 642 if (!Op->Asl.Value.Integer) 643 { 644 Op->Asl.Value.Integer = AslKeywordMapping[Index].Value; 645 } 646 647 /* Special handling for some opcodes */ 648 649 switch (Op->Asl.ParseOpcode) 650 { 651 case PARSEOP_INTEGER: 652 /* 653 * Set the opcode based on the size of the integer 654 */ 655 (void) OpcSetOptimalIntegerSize (Op); 656 break; 657 658 case PARSEOP_OFFSET: 659 660 Op->Asl.AmlOpcodeLength = 1; 661 break; 662 663 case PARSEOP_ACCESSAS: 664 665 OpcDoAccessAs (Op); 666 break; 667 668 case PARSEOP_EISAID: 669 670 OpcDoEisaId (Op); 671 break; 672 673 case PARSEOP_TOUUID: 674 675 OpcDoUuId (Op); 676 break; 677 678 case PARSEOP_UNICODE: 679 680 OpcDoUnicode (Op); 681 break; 682 683 case PARSEOP_INCLUDE: 684 685 Op->Asl.Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 686 Gbl_HasIncludeFiles = TRUE; 687 break; 688 689 case PARSEOP_EXTERNAL: 690 691 Op->Asl.Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 692 Op->Asl.Child->Asl.Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 693 break; 694 695 default: 696 /* Nothing to do for other opcodes */ 697 break; 698 } 699 700 return; 701 } 702 703 704