1 /****************************************************************************** 2 * 3 * Module Name: dtutils.c - Utility routines for the data table compiler 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #define __DTUTILS_C__ 45 46 #include <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include <contrib/dev/acpica/compiler/dtcompiler.h> 48 #include <contrib/dev/acpica/include/actables.h> 49 50 #define _COMPONENT DT_COMPILER 51 ACPI_MODULE_NAME ("dtutils") 52 53 /* Local prototypes */ 54 55 static void 56 DtSum ( 57 DT_SUBTABLE *Subtable, 58 void *Context, 59 void *ReturnValue); 60 61 62 /****************************************************************************** 63 * 64 * FUNCTION: DtError 65 * 66 * PARAMETERS: Level - Seriousness (Warning/error, etc.) 67 * MessageId - Index into global message buffer 68 * Op - Parse node where error happened 69 * ExtraMessage - additional error message 70 * 71 * RETURN: None 72 * 73 * DESCRIPTION: Common error interface for data table compiler 74 * 75 *****************************************************************************/ 76 77 void 78 DtError ( 79 UINT8 Level, 80 UINT8 MessageId, 81 DT_FIELD *FieldObject, 82 char *ExtraMessage) 83 { 84 85 switch (Level) 86 { 87 case ASL_WARNING2: 88 case ASL_WARNING3: 89 if (Gbl_WarningLevel < Level) 90 { 91 return; 92 } 93 break; 94 95 default: 96 break; 97 } 98 99 if (FieldObject) 100 { 101 AslCommonError (Level, MessageId, 102 FieldObject->Line, 103 FieldObject->Line, 104 FieldObject->ByteOffset, 105 FieldObject->Column, 106 Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage); 107 } 108 else 109 { 110 AslCommonError (Level, MessageId, 0, 111 0, 0, 0, 0, ExtraMessage); 112 } 113 } 114 115 116 /****************************************************************************** 117 * 118 * FUNCTION: DtNameError 119 * 120 * PARAMETERS: Level - Seriousness (Warning/error, etc.) 121 * MessageId - Index into global message buffer 122 * Op - Parse node where error happened 123 * ExtraMessage - additional error message 124 * 125 * RETURN: None 126 * 127 * DESCRIPTION: Error interface for named objects 128 * 129 *****************************************************************************/ 130 131 void 132 DtNameError ( 133 UINT8 Level, 134 UINT8 MessageId, 135 DT_FIELD *FieldObject, 136 char *ExtraMessage) 137 { 138 139 switch (Level) 140 { 141 case ASL_WARNING2: 142 case ASL_WARNING3: 143 if (Gbl_WarningLevel < Level) 144 { 145 return; 146 } 147 break; 148 149 default: 150 break; 151 } 152 153 if (FieldObject) 154 { 155 AslCommonError (Level, MessageId, 156 FieldObject->Line, 157 FieldObject->Line, 158 FieldObject->ByteOffset, 159 FieldObject->NameColumn, 160 Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage); 161 } 162 else 163 { 164 AslCommonError (Level, MessageId, 0, 165 0, 0, 0, 0, ExtraMessage); 166 } 167 } 168 169 170 /******************************************************************************* 171 * 172 * FUNCTION: DtFatal 173 * 174 * PARAMETERS: None 175 * 176 * RETURN: None 177 * 178 * DESCRIPTION: Dump the error log and abort the compiler. Used for serious 179 * compile or I/O errors 180 * 181 ******************************************************************************/ 182 183 void 184 DtFatal ( 185 UINT8 MessageId, 186 DT_FIELD *FieldObject, 187 char *ExtraMessage) 188 { 189 190 DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage); 191 192 /* 193 * TBD: remove this entire function, DtFatal 194 * 195 * We cannot abort the compiler on error, because we may be compiling a 196 * list of files. We must move on to the next file. 197 */ 198 #ifdef __OBSOLETE 199 CmCleanupAndExit (); 200 exit (1); 201 #endif 202 } 203 204 205 /****************************************************************************** 206 * 207 * FUNCTION: DtStrtoul64 208 * 209 * PARAMETERS: String - Null terminated string 210 * ReturnInteger - Where the converted integer is returned 211 * 212 * RETURN: Status 213 * 214 * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned 215 * value. Assumes no leading "0x" for the constant. 216 * 217 * Portability note: The reason this function exists is because a 64-bit 218 * sscanf is not available in all environments. 219 * 220 *****************************************************************************/ 221 222 ACPI_STATUS 223 DtStrtoul64 ( 224 char *String, 225 UINT64 *ReturnInteger) 226 { 227 char *ThisChar = String; 228 UINT32 ThisDigit; 229 UINT64 ReturnValue = 0; 230 int DigitCount = 0; 231 232 233 /* Skip over any white space in the buffer */ 234 235 while ((*ThisChar == ' ') || (*ThisChar == '\t')) 236 { 237 ThisChar++; 238 } 239 240 /* Skip leading zeros */ 241 242 while ((*ThisChar) == '0') 243 { 244 ThisChar++; 245 } 246 247 /* Convert character-by-character */ 248 249 while (*ThisChar) 250 { 251 if (ACPI_IS_DIGIT (*ThisChar)) 252 { 253 /* Convert ASCII 0-9 to Decimal value */ 254 255 ThisDigit = ((UINT8) *ThisChar) - '0'; 256 } 257 else /* Letter */ 258 { 259 ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar); 260 if (!ACPI_IS_XDIGIT ((char) ThisDigit)) 261 { 262 /* Not A-F */ 263 264 return (AE_BAD_CHARACTER); 265 } 266 267 /* Convert ASCII Hex char (A-F) to value */ 268 269 ThisDigit = (ThisDigit - 'A') + 10; 270 } 271 272 /* Insert the 4-bit hex digit */ 273 274 ReturnValue <<= 4; 275 ReturnValue += ThisDigit; 276 277 ThisChar++; 278 DigitCount++; 279 if (DigitCount > 16) 280 { 281 /* Value is too large (> 64 bits/8 bytes/16 hex digits) */ 282 283 return (AE_LIMIT); 284 } 285 } 286 287 *ReturnInteger = ReturnValue; 288 return (AE_OK); 289 } 290 291 292 /****************************************************************************** 293 * 294 * FUNCTION: DtGetFileSize 295 * 296 * PARAMETERS: Handle - Open file handler 297 * 298 * RETURN: Current file size 299 * 300 * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the 301 * offset. Seek back to the original location. 302 * 303 *****************************************************************************/ 304 305 UINT32 306 DtGetFileSize ( 307 FILE *Handle) 308 { 309 int CurrentOffset; 310 int LastOffset; 311 312 313 CurrentOffset = ftell (Handle); 314 fseek (Handle, 0, SEEK_END); 315 LastOffset = ftell (Handle); 316 fseek (Handle, CurrentOffset, SEEK_SET); 317 318 return ((UINT32) LastOffset); 319 } 320 321 322 /****************************************************************************** 323 * 324 * FUNCTION: DtGetFieldValue 325 * 326 * PARAMETERS: Field - Current field list pointer 327 * 328 * RETURN: Field value 329 * 330 * DESCRIPTION: Get field value 331 * 332 *****************************************************************************/ 333 334 char * 335 DtGetFieldValue ( 336 DT_FIELD *Field) 337 { 338 if (!Field) 339 { 340 return (NULL); 341 } 342 343 return (Field->Value); 344 } 345 346 347 /****************************************************************************** 348 * 349 * FUNCTION: DtGetFieldType 350 * 351 * PARAMETERS: Info - Data table info 352 * 353 * RETURN: Field type 354 * 355 * DESCRIPTION: Get field type 356 * 357 *****************************************************************************/ 358 359 UINT8 360 DtGetFieldType ( 361 ACPI_DMTABLE_INFO *Info) 362 { 363 UINT8 Type; 364 365 366 /* DT_FLAG means that this is the start of a block of flag bits */ 367 /* TBD - we can make these a separate opcode later */ 368 369 if (Info->Flags & DT_FLAG) 370 { 371 return (DT_FIELD_TYPE_FLAGS_INTEGER); 372 } 373 374 /* Type is based upon the opcode for this field in the info table */ 375 376 switch (Info->Opcode) 377 { 378 case ACPI_DMT_FLAG0: 379 case ACPI_DMT_FLAG1: 380 case ACPI_DMT_FLAG2: 381 case ACPI_DMT_FLAG3: 382 case ACPI_DMT_FLAG4: 383 case ACPI_DMT_FLAG5: 384 case ACPI_DMT_FLAG6: 385 case ACPI_DMT_FLAG7: 386 case ACPI_DMT_FLAGS0: 387 case ACPI_DMT_FLAGS2: 388 Type = DT_FIELD_TYPE_FLAG; 389 break; 390 391 case ACPI_DMT_NAME4: 392 case ACPI_DMT_SIG: 393 case ACPI_DMT_NAME6: 394 case ACPI_DMT_NAME8: 395 case ACPI_DMT_STRING: 396 Type = DT_FIELD_TYPE_STRING; 397 break; 398 399 case ACPI_DMT_BUFFER: 400 case ACPI_DMT_BUF7: 401 case ACPI_DMT_BUF16: 402 case ACPI_DMT_BUF128: 403 case ACPI_DMT_PCI_PATH: 404 Type = DT_FIELD_TYPE_BUFFER; 405 break; 406 407 case ACPI_DMT_GAS: 408 case ACPI_DMT_HESTNTFY: 409 Type = DT_FIELD_TYPE_INLINE_SUBTABLE; 410 break; 411 412 case ACPI_DMT_UNICODE: 413 Type = DT_FIELD_TYPE_UNICODE; 414 break; 415 416 case ACPI_DMT_UUID: 417 Type = DT_FIELD_TYPE_UUID; 418 break; 419 420 case ACPI_DMT_DEVICE_PATH: 421 Type = DT_FIELD_TYPE_DEVICE_PATH; 422 break; 423 424 case ACPI_DMT_LABEL: 425 Type = DT_FIELD_TYPE_LABEL; 426 break; 427 428 default: 429 Type = DT_FIELD_TYPE_INTEGER; 430 break; 431 } 432 433 return (Type); 434 } 435 436 437 /****************************************************************************** 438 * 439 * FUNCTION: DtGetBufferLength 440 * 441 * PARAMETERS: Buffer - List of integers, 442 * for example "10 3A 4F 2E" 443 * 444 * RETURN: Count of integer 445 * 446 * DESCRIPTION: Get length of bytes needed to store the integers 447 * 448 *****************************************************************************/ 449 450 UINT32 451 DtGetBufferLength ( 452 char *Buffer) 453 { 454 UINT32 ByteLength = 0; 455 456 457 while (*Buffer) 458 { 459 if (*Buffer == ' ') 460 { 461 ByteLength++; 462 463 while (*Buffer == ' ') 464 { 465 Buffer++; 466 } 467 } 468 469 Buffer++; 470 } 471 472 return (++ByteLength); 473 } 474 475 476 /****************************************************************************** 477 * 478 * FUNCTION: DtGetFieldLength 479 * 480 * PARAMETERS: Field - Current field 481 * Info - Data table info 482 * 483 * RETURN: Field length 484 * 485 * DESCRIPTION: Get length of bytes needed to compile the field 486 * 487 * Note: This function must remain in sync with AcpiDmDumpTable. 488 * 489 *****************************************************************************/ 490 491 UINT32 492 DtGetFieldLength ( 493 DT_FIELD *Field, 494 ACPI_DMTABLE_INFO *Info) 495 { 496 UINT32 ByteLength = 0; 497 char *Value; 498 499 500 /* Length is based upon the opcode for this field in the info table */ 501 502 switch (Info->Opcode) 503 { 504 case ACPI_DMT_FLAG0: 505 case ACPI_DMT_FLAG1: 506 case ACPI_DMT_FLAG2: 507 case ACPI_DMT_FLAG3: 508 case ACPI_DMT_FLAG4: 509 case ACPI_DMT_FLAG5: 510 case ACPI_DMT_FLAG6: 511 case ACPI_DMT_FLAG7: 512 case ACPI_DMT_FLAGS0: 513 case ACPI_DMT_FLAGS2: 514 case ACPI_DMT_LABEL: 515 ByteLength = 0; 516 break; 517 518 case ACPI_DMT_UINT8: 519 case ACPI_DMT_CHKSUM: 520 case ACPI_DMT_SPACEID: 521 case ACPI_DMT_ACCWIDTH: 522 case ACPI_DMT_IVRS: 523 case ACPI_DMT_MADT: 524 case ACPI_DMT_SRAT: 525 case ACPI_DMT_ASF: 526 case ACPI_DMT_HESTNTYP: 527 case ACPI_DMT_FADTPM: 528 case ACPI_DMT_EINJACT: 529 case ACPI_DMT_EINJINST: 530 case ACPI_DMT_ERSTACT: 531 case ACPI_DMT_ERSTINST: 532 ByteLength = 1; 533 break; 534 535 case ACPI_DMT_UINT16: 536 case ACPI_DMT_DMAR: 537 case ACPI_DMT_HEST: 538 case ACPI_DMT_PCI_PATH: 539 ByteLength = 2; 540 break; 541 542 case ACPI_DMT_UINT24: 543 ByteLength = 3; 544 break; 545 546 case ACPI_DMT_UINT32: 547 case ACPI_DMT_NAME4: 548 case ACPI_DMT_SLIC: 549 case ACPI_DMT_SIG: 550 ByteLength = 4; 551 break; 552 553 case ACPI_DMT_NAME6: 554 ByteLength = 6; 555 break; 556 557 case ACPI_DMT_UINT56: 558 case ACPI_DMT_BUF7: 559 ByteLength = 7; 560 break; 561 562 case ACPI_DMT_UINT64: 563 case ACPI_DMT_NAME8: 564 ByteLength = 8; 565 break; 566 567 case ACPI_DMT_STRING: 568 Value = DtGetFieldValue (Field); 569 if (Value) 570 { 571 ByteLength = ACPI_STRLEN (Value) + 1; 572 } 573 else 574 { /* At this point, this is a fatal error */ 575 576 sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); 577 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); 578 return (0); 579 } 580 break; 581 582 case ACPI_DMT_GAS: 583 ByteLength = sizeof (ACPI_GENERIC_ADDRESS); 584 break; 585 586 case ACPI_DMT_HESTNTFY: 587 ByteLength = sizeof (ACPI_HEST_NOTIFY); 588 break; 589 590 case ACPI_DMT_BUFFER: 591 Value = DtGetFieldValue (Field); 592 if (Value) 593 { 594 ByteLength = DtGetBufferLength (Value); 595 } 596 else 597 { /* At this point, this is a fatal error */ 598 599 sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); 600 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); 601 return (0); 602 } 603 break; 604 605 case ACPI_DMT_BUF16: 606 case ACPI_DMT_UUID: 607 ByteLength = 16; 608 break; 609 610 case ACPI_DMT_BUF128: 611 ByteLength = 128; 612 break; 613 614 case ACPI_DMT_UNICODE: 615 Value = DtGetFieldValue (Field); 616 617 /* TBD: error if Value is NULL? (as below?) */ 618 619 ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16); 620 break; 621 622 default: 623 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode"); 624 return (0); 625 } 626 627 return (ByteLength); 628 } 629 630 631 /****************************************************************************** 632 * 633 * FUNCTION: DtSum 634 * 635 * PARAMETERS: DT_WALK_CALLBACK: 636 * Subtable - Subtable 637 * Context - Unused 638 * ReturnValue - Store the checksum of subtable 639 * 640 * RETURN: Status 641 * 642 * DESCRIPTION: Get the checksum of subtable 643 * 644 *****************************************************************************/ 645 646 static void 647 DtSum ( 648 DT_SUBTABLE *Subtable, 649 void *Context, 650 void *ReturnValue) 651 { 652 UINT8 Checksum; 653 UINT8 *Sum = ReturnValue; 654 655 656 Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length); 657 *Sum = (UINT8) (*Sum + Checksum); 658 } 659 660 661 /****************************************************************************** 662 * 663 * FUNCTION: DtSetTableChecksum 664 * 665 * PARAMETERS: ChecksumPointer - Where to return the checksum 666 * 667 * RETURN: None 668 * 669 * DESCRIPTION: Set checksum of the whole data table into the checksum field 670 * 671 *****************************************************************************/ 672 673 void 674 DtSetTableChecksum ( 675 UINT8 *ChecksumPointer) 676 { 677 UINT8 Checksum = 0; 678 UINT8 OldSum; 679 680 681 DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum); 682 683 OldSum = *ChecksumPointer; 684 Checksum = (UINT8) (Checksum - OldSum); 685 686 /* Compute the final checksum */ 687 688 Checksum = (UINT8) (0 - Checksum); 689 *ChecksumPointer = Checksum; 690 } 691 692 693 /****************************************************************************** 694 * 695 * FUNCTION: DtSetTableLength 696 * 697 * PARAMETERS: None 698 * 699 * RETURN: None 700 * 701 * DESCRIPTION: Walk the subtables and set all the length fields 702 * 703 *****************************************************************************/ 704 705 void 706 DtSetTableLength ( 707 void) 708 { 709 DT_SUBTABLE *ParentTable; 710 DT_SUBTABLE *ChildTable; 711 712 713 ParentTable = Gbl_RootTable; 714 ChildTable = NULL; 715 716 if (!ParentTable) 717 { 718 return; 719 } 720 721 DtSetSubtableLength (ParentTable); 722 723 while (1) 724 { 725 ChildTable = DtGetNextSubtable (ParentTable, ChildTable); 726 if (ChildTable) 727 { 728 if (ChildTable->LengthField) 729 { 730 DtSetSubtableLength (ChildTable); 731 } 732 733 if (ChildTable->Child) 734 { 735 ParentTable = ChildTable; 736 ChildTable = NULL; 737 } 738 else 739 { 740 ParentTable->TotalLength += ChildTable->TotalLength; 741 if (ParentTable->LengthField) 742 { 743 DtSetSubtableLength (ParentTable); 744 } 745 } 746 } 747 else 748 { 749 ChildTable = ParentTable; 750 751 if (ChildTable == Gbl_RootTable) 752 { 753 break; 754 } 755 756 ParentTable = DtGetParentSubtable (ParentTable); 757 758 ParentTable->TotalLength += ChildTable->TotalLength; 759 if (ParentTable->LengthField) 760 { 761 DtSetSubtableLength (ParentTable); 762 } 763 } 764 } 765 } 766 767 768 /****************************************************************************** 769 * 770 * FUNCTION: DtWalkTableTree 771 * 772 * PARAMETERS: StartTable - Subtable in the tree where walking begins 773 * UserFunction - Called during the walk 774 * Context - Passed to user function 775 * ReturnValue - The return value of UserFunction 776 * 777 * RETURN: None 778 * 779 * DESCRIPTION: Performs a depth-first walk of the subtable tree 780 * 781 *****************************************************************************/ 782 783 void 784 DtWalkTableTree ( 785 DT_SUBTABLE *StartTable, 786 DT_WALK_CALLBACK UserFunction, 787 void *Context, 788 void *ReturnValue) 789 { 790 DT_SUBTABLE *ParentTable; 791 DT_SUBTABLE *ChildTable; 792 793 794 ParentTable = StartTable; 795 ChildTable = NULL; 796 797 if (!ParentTable) 798 { 799 return; 800 } 801 802 UserFunction (ParentTable, Context, ReturnValue); 803 804 while (1) 805 { 806 ChildTable = DtGetNextSubtable (ParentTable, ChildTable); 807 if (ChildTable) 808 { 809 UserFunction (ChildTable, Context, ReturnValue); 810 811 if (ChildTable->Child) 812 { 813 ParentTable = ChildTable; 814 ChildTable = NULL; 815 } 816 } 817 else 818 { 819 ChildTable = ParentTable; 820 if (ChildTable == Gbl_RootTable) 821 { 822 break; 823 } 824 825 ParentTable = DtGetParentSubtable (ParentTable); 826 827 if (ChildTable->Peer == StartTable) 828 { 829 break; 830 } 831 } 832 } 833 } 834 835 836 /****************************************************************************** 837 * 838 * FUNCTION: DtFreeFieldList 839 * 840 * PARAMETERS: None 841 * 842 * RETURN: None 843 * 844 * DESCRIPTION: Free the field list 845 * 846 *****************************************************************************/ 847 848 void 849 DtFreeFieldList ( 850 void) 851 { 852 DT_FIELD *Field = Gbl_FieldList; 853 DT_FIELD *NextField; 854 855 856 /* Walk and free entire field list */ 857 858 while (Field) 859 { 860 NextField = Field->Next; /* Save link */ 861 862 if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED)) 863 { 864 ACPI_FREE (Field->Name); 865 ACPI_FREE (Field->Value); 866 } 867 868 ACPI_FREE (Field); 869 Field = NextField; 870 } 871 } 872