1 /****************************************************************************** 2 * 3 * Module Name: dtutils.c - Utility routines for the data table compiler 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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_FLAGS1: 388 case ACPI_DMT_FLAGS2: 389 case ACPI_DMT_FLAGS4: 390 Type = DT_FIELD_TYPE_FLAG; 391 break; 392 393 case ACPI_DMT_NAME4: 394 case ACPI_DMT_SIG: 395 case ACPI_DMT_NAME6: 396 case ACPI_DMT_NAME8: 397 case ACPI_DMT_STRING: 398 Type = DT_FIELD_TYPE_STRING; 399 break; 400 401 case ACPI_DMT_BUFFER: 402 case ACPI_DMT_BUF7: 403 case ACPI_DMT_BUF16: 404 case ACPI_DMT_BUF128: 405 case ACPI_DMT_PCI_PATH: 406 Type = DT_FIELD_TYPE_BUFFER; 407 break; 408 409 case ACPI_DMT_GAS: 410 case ACPI_DMT_HESTNTFY: 411 Type = DT_FIELD_TYPE_INLINE_SUBTABLE; 412 break; 413 414 case ACPI_DMT_UNICODE: 415 Type = DT_FIELD_TYPE_UNICODE; 416 break; 417 418 case ACPI_DMT_UUID: 419 Type = DT_FIELD_TYPE_UUID; 420 break; 421 422 case ACPI_DMT_DEVICE_PATH: 423 Type = DT_FIELD_TYPE_DEVICE_PATH; 424 break; 425 426 case ACPI_DMT_LABEL: 427 Type = DT_FIELD_TYPE_LABEL; 428 break; 429 430 default: 431 Type = DT_FIELD_TYPE_INTEGER; 432 break; 433 } 434 435 return (Type); 436 } 437 438 439 /****************************************************************************** 440 * 441 * FUNCTION: DtGetBufferLength 442 * 443 * PARAMETERS: Buffer - List of integers, 444 * for example "10 3A 4F 2E" 445 * 446 * RETURN: Count of integer 447 * 448 * DESCRIPTION: Get length of bytes needed to store the integers 449 * 450 *****************************************************************************/ 451 452 UINT32 453 DtGetBufferLength ( 454 char *Buffer) 455 { 456 UINT32 ByteLength = 0; 457 458 459 while (*Buffer) 460 { 461 if (*Buffer == ' ') 462 { 463 ByteLength++; 464 465 while (*Buffer == ' ') 466 { 467 Buffer++; 468 } 469 } 470 471 Buffer++; 472 } 473 474 return (++ByteLength); 475 } 476 477 478 /****************************************************************************** 479 * 480 * FUNCTION: DtGetFieldLength 481 * 482 * PARAMETERS: Field - Current field 483 * Info - Data table info 484 * 485 * RETURN: Field length 486 * 487 * DESCRIPTION: Get length of bytes needed to compile the field 488 * 489 * Note: This function must remain in sync with AcpiDmDumpTable. 490 * 491 *****************************************************************************/ 492 493 UINT32 494 DtGetFieldLength ( 495 DT_FIELD *Field, 496 ACPI_DMTABLE_INFO *Info) 497 { 498 UINT32 ByteLength = 0; 499 char *Value; 500 501 502 /* Length is based upon the opcode for this field in the info table */ 503 504 switch (Info->Opcode) 505 { 506 case ACPI_DMT_FLAG0: 507 case ACPI_DMT_FLAG1: 508 case ACPI_DMT_FLAG2: 509 case ACPI_DMT_FLAG3: 510 case ACPI_DMT_FLAG4: 511 case ACPI_DMT_FLAG5: 512 case ACPI_DMT_FLAG6: 513 case ACPI_DMT_FLAG7: 514 case ACPI_DMT_FLAGS0: 515 case ACPI_DMT_FLAGS1: 516 case ACPI_DMT_FLAGS2: 517 case ACPI_DMT_FLAGS4: 518 case ACPI_DMT_LABEL: 519 case ACPI_DMT_EXTRA_TEXT: 520 ByteLength = 0; 521 break; 522 523 case ACPI_DMT_UINT8: 524 case ACPI_DMT_CHKSUM: 525 case ACPI_DMT_SPACEID: 526 case ACPI_DMT_ACCWIDTH: 527 case ACPI_DMT_IVRS: 528 case ACPI_DMT_MADT: 529 case ACPI_DMT_PMTT: 530 case ACPI_DMT_SRAT: 531 case ACPI_DMT_ASF: 532 case ACPI_DMT_HESTNTYP: 533 case ACPI_DMT_FADTPM: 534 case ACPI_DMT_EINJACT: 535 case ACPI_DMT_EINJINST: 536 case ACPI_DMT_ERSTACT: 537 case ACPI_DMT_ERSTINST: 538 ByteLength = 1; 539 break; 540 541 case ACPI_DMT_UINT16: 542 case ACPI_DMT_DMAR: 543 case ACPI_DMT_HEST: 544 case ACPI_DMT_PCI_PATH: 545 ByteLength = 2; 546 break; 547 548 case ACPI_DMT_UINT24: 549 ByteLength = 3; 550 break; 551 552 case ACPI_DMT_UINT32: 553 case ACPI_DMT_NAME4: 554 case ACPI_DMT_SLIC: 555 case ACPI_DMT_SIG: 556 ByteLength = 4; 557 break; 558 559 case ACPI_DMT_UINT40: 560 ByteLength = 5; 561 break; 562 563 case ACPI_DMT_UINT48: 564 case ACPI_DMT_NAME6: 565 ByteLength = 6; 566 break; 567 568 case ACPI_DMT_UINT56: 569 case ACPI_DMT_BUF7: 570 ByteLength = 7; 571 break; 572 573 case ACPI_DMT_UINT64: 574 case ACPI_DMT_NAME8: 575 ByteLength = 8; 576 break; 577 578 case ACPI_DMT_STRING: 579 Value = DtGetFieldValue (Field); 580 if (Value) 581 { 582 ByteLength = ACPI_STRLEN (Value) + 1; 583 } 584 else 585 { /* At this point, this is a fatal error */ 586 587 sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); 588 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); 589 return (0); 590 } 591 break; 592 593 case ACPI_DMT_GAS: 594 ByteLength = sizeof (ACPI_GENERIC_ADDRESS); 595 break; 596 597 case ACPI_DMT_HESTNTFY: 598 ByteLength = sizeof (ACPI_HEST_NOTIFY); 599 break; 600 601 case ACPI_DMT_BUFFER: 602 Value = DtGetFieldValue (Field); 603 if (Value) 604 { 605 ByteLength = DtGetBufferLength (Value); 606 } 607 else 608 { /* At this point, this is a fatal error */ 609 610 sprintf (MsgBuffer, "Expected \"%s\"", Info->Name); 611 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); 612 return (0); 613 } 614 break; 615 616 case ACPI_DMT_BUF16: 617 case ACPI_DMT_UUID: 618 ByteLength = 16; 619 break; 620 621 case ACPI_DMT_BUF128: 622 ByteLength = 128; 623 break; 624 625 case ACPI_DMT_UNICODE: 626 Value = DtGetFieldValue (Field); 627 628 /* TBD: error if Value is NULL? (as below?) */ 629 630 ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16); 631 break; 632 633 default: 634 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode"); 635 return (0); 636 } 637 638 return (ByteLength); 639 } 640 641 642 /****************************************************************************** 643 * 644 * FUNCTION: DtSum 645 * 646 * PARAMETERS: DT_WALK_CALLBACK: 647 * Subtable - Subtable 648 * Context - Unused 649 * ReturnValue - Store the checksum of subtable 650 * 651 * RETURN: Status 652 * 653 * DESCRIPTION: Get the checksum of subtable 654 * 655 *****************************************************************************/ 656 657 static void 658 DtSum ( 659 DT_SUBTABLE *Subtable, 660 void *Context, 661 void *ReturnValue) 662 { 663 UINT8 Checksum; 664 UINT8 *Sum = ReturnValue; 665 666 667 Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length); 668 *Sum = (UINT8) (*Sum + Checksum); 669 } 670 671 672 /****************************************************************************** 673 * 674 * FUNCTION: DtSetTableChecksum 675 * 676 * PARAMETERS: ChecksumPointer - Where to return the checksum 677 * 678 * RETURN: None 679 * 680 * DESCRIPTION: Set checksum of the whole data table into the checksum field 681 * 682 *****************************************************************************/ 683 684 void 685 DtSetTableChecksum ( 686 UINT8 *ChecksumPointer) 687 { 688 UINT8 Checksum = 0; 689 UINT8 OldSum; 690 691 692 DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum); 693 694 OldSum = *ChecksumPointer; 695 Checksum = (UINT8) (Checksum - OldSum); 696 697 /* Compute the final checksum */ 698 699 Checksum = (UINT8) (0 - Checksum); 700 *ChecksumPointer = Checksum; 701 } 702 703 704 /****************************************************************************** 705 * 706 * FUNCTION: DtSetTableLength 707 * 708 * PARAMETERS: None 709 * 710 * RETURN: None 711 * 712 * DESCRIPTION: Walk the subtables and set all the length fields 713 * 714 *****************************************************************************/ 715 716 void 717 DtSetTableLength ( 718 void) 719 { 720 DT_SUBTABLE *ParentTable; 721 DT_SUBTABLE *ChildTable; 722 723 724 ParentTable = Gbl_RootTable; 725 ChildTable = NULL; 726 727 if (!ParentTable) 728 { 729 return; 730 } 731 732 DtSetSubtableLength (ParentTable); 733 734 while (1) 735 { 736 ChildTable = DtGetNextSubtable (ParentTable, ChildTable); 737 if (ChildTable) 738 { 739 if (ChildTable->LengthField) 740 { 741 DtSetSubtableLength (ChildTable); 742 } 743 744 if (ChildTable->Child) 745 { 746 ParentTable = ChildTable; 747 ChildTable = NULL; 748 } 749 else 750 { 751 ParentTable->TotalLength += ChildTable->TotalLength; 752 if (ParentTable->LengthField) 753 { 754 DtSetSubtableLength (ParentTable); 755 } 756 } 757 } 758 else 759 { 760 ChildTable = ParentTable; 761 762 if (ChildTable == Gbl_RootTable) 763 { 764 break; 765 } 766 767 ParentTable = DtGetParentSubtable (ParentTable); 768 769 ParentTable->TotalLength += ChildTable->TotalLength; 770 if (ParentTable->LengthField) 771 { 772 DtSetSubtableLength (ParentTable); 773 } 774 } 775 } 776 } 777 778 779 /****************************************************************************** 780 * 781 * FUNCTION: DtWalkTableTree 782 * 783 * PARAMETERS: StartTable - Subtable in the tree where walking begins 784 * UserFunction - Called during the walk 785 * Context - Passed to user function 786 * ReturnValue - The return value of UserFunction 787 * 788 * RETURN: None 789 * 790 * DESCRIPTION: Performs a depth-first walk of the subtable tree 791 * 792 *****************************************************************************/ 793 794 void 795 DtWalkTableTree ( 796 DT_SUBTABLE *StartTable, 797 DT_WALK_CALLBACK UserFunction, 798 void *Context, 799 void *ReturnValue) 800 { 801 DT_SUBTABLE *ParentTable; 802 DT_SUBTABLE *ChildTable; 803 804 805 ParentTable = StartTable; 806 ChildTable = NULL; 807 808 if (!ParentTable) 809 { 810 return; 811 } 812 813 UserFunction (ParentTable, Context, ReturnValue); 814 815 while (1) 816 { 817 ChildTable = DtGetNextSubtable (ParentTable, ChildTable); 818 if (ChildTable) 819 { 820 UserFunction (ChildTable, Context, ReturnValue); 821 822 if (ChildTable->Child) 823 { 824 ParentTable = ChildTable; 825 ChildTable = NULL; 826 } 827 } 828 else 829 { 830 ChildTable = ParentTable; 831 if (ChildTable == Gbl_RootTable) 832 { 833 break; 834 } 835 836 ParentTable = DtGetParentSubtable (ParentTable); 837 838 if (ChildTable->Peer == StartTable) 839 { 840 break; 841 } 842 } 843 } 844 } 845 846 847 /****************************************************************************** 848 * 849 * FUNCTION: DtFreeFieldList 850 * 851 * PARAMETERS: None 852 * 853 * RETURN: None 854 * 855 * DESCRIPTION: Free the field list 856 * 857 *****************************************************************************/ 858 859 void 860 DtFreeFieldList ( 861 void) 862 { 863 DT_FIELD *Field = Gbl_FieldList; 864 DT_FIELD *NextField; 865 866 867 /* Walk and free entire field list */ 868 869 while (Field) 870 { 871 NextField = Field->Next; /* Save link */ 872 873 if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED)) 874 { 875 ACPI_FREE (Field->Name); 876 ACPI_FREE (Field->Value); 877 } 878 879 ACPI_FREE (Field); 880 Field = NextField; 881 } 882 } 883