1 /****************************************************************************** 2 * 3 * Module Name: dtio.c - File I/O support for 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 __DTIO_C__ 45 46 #include <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include <contrib/dev/acpica/compiler/dtcompiler.h> 48 49 #define _COMPONENT DT_COMPILER 50 ACPI_MODULE_NAME ("dtio") 51 52 53 /* Local prototypes */ 54 55 static char * 56 DtTrim ( 57 char *String); 58 59 static void 60 DtLinkField ( 61 DT_FIELD *Field); 62 63 static void 64 DtMergeField ( 65 char *Value); 66 67 static ACPI_STATUS 68 DtParseLine ( 69 char *LineBuffer, 70 UINT32 Line, 71 UINT32 Offset); 72 73 UINT32 74 DtGetNextLine ( 75 FILE *Handle); 76 77 static void 78 DtWriteBinary ( 79 DT_SUBTABLE *Subtable, 80 void *Context, 81 void *ReturnValue); 82 83 static void 84 DtDumpBuffer ( 85 UINT32 FileId, 86 UINT8 *Buffer, 87 UINT32 Offset, 88 UINT32 Length); 89 90 91 /* States for DtGetNextLine */ 92 93 #define DT_NORMAL_TEXT 0 94 #define DT_START_QUOTED_STRING 1 95 #define DT_START_COMMENT 2 96 #define DT_SLASH_ASTERISK_COMMENT 3 97 #define DT_SLASH_SLASH_COMMENT 4 98 #define DT_END_COMMENT 5 99 100 static UINT32 Gbl_NextLineOffset; 101 102 103 /****************************************************************************** 104 * 105 * FUNCTION: DtTrim 106 * 107 * PARAMETERS: String - Current source code line to trim 108 * 109 * RETURN: Trimmed line. Must be freed by caller. 110 * 111 * DESCRIPTION: Trim left and right spaces 112 * 113 *****************************************************************************/ 114 115 static char * 116 DtTrim ( 117 char *String) 118 { 119 char *Start; 120 char *End; 121 char *ReturnString; 122 ACPI_SIZE Length; 123 124 125 /* Skip lines that start with a space */ 126 127 if (!ACPI_STRCMP (String, " ")) 128 { 129 ReturnString = UtLocalCalloc (1); 130 return (ReturnString); 131 } 132 133 /* Setup pointers to start and end of input string */ 134 135 Start = String; 136 End = String + ACPI_STRLEN (String) - 1; 137 138 /* Find first non-whitespace character */ 139 140 while ((Start <= End) && ((*Start == ' ') || (*Start == '\t'))) 141 { 142 Start++; 143 } 144 145 /* Find last non-space character */ 146 147 while (End >= Start) 148 { 149 if (*End == '\r' || *End == '\n') 150 { 151 End--; 152 continue; 153 } 154 155 if (*End != ' ') 156 { 157 break; 158 } 159 160 End--; 161 } 162 163 /* Remove any quotes around the string */ 164 165 if (*Start == '\"') 166 { 167 Start++; 168 } 169 if (*End == '\"') 170 { 171 End--; 172 } 173 174 /* Create the trimmed return string */ 175 176 Length = ACPI_PTR_DIFF (End, Start) + 1; 177 ReturnString = UtLocalCalloc (Length + 1); 178 if (ACPI_STRLEN (Start)) 179 { 180 ACPI_STRNCPY (ReturnString, Start, Length); 181 } 182 183 ReturnString[Length] = 0; 184 return (ReturnString); 185 } 186 187 188 /****************************************************************************** 189 * 190 * FUNCTION: DtLinkField 191 * 192 * PARAMETERS: Field - New field object to link 193 * 194 * RETURN: None 195 * 196 * DESCRIPTION: Link one field name and value to the list 197 * 198 *****************************************************************************/ 199 200 static void 201 DtLinkField ( 202 DT_FIELD *Field) 203 { 204 DT_FIELD *Prev; 205 DT_FIELD *Next; 206 207 208 Prev = Next = Gbl_FieldList; 209 210 while (Next) 211 { 212 Prev = Next; 213 Next = Next->Next; 214 } 215 216 if (Prev) 217 { 218 Prev->Next = Field; 219 } 220 else 221 { 222 Gbl_FieldList = Field; 223 } 224 } 225 226 227 /****************************************************************************** 228 * 229 * FUNCTION: DtMergeField 230 * 231 * PARAMETERS: Value - Merge this line into previous one 232 * 233 * RETURN: None 234 * 235 * DESCRIPTION: Merge a field value to the previous one, 236 * probably for a multi-line buffer definition. 237 * 238 *****************************************************************************/ 239 240 static void 241 DtMergeField ( 242 char *Value) 243 { 244 DT_FIELD *Prev; 245 DT_FIELD *Next; 246 char *NewValue; 247 UINT32 PrevLength; 248 UINT32 ThisLength; 249 250 251 Prev = Next = Gbl_FieldList; 252 253 while (Next) 254 { 255 Prev = Next; 256 Next = Next->Next; 257 } 258 259 if (Prev) 260 { 261 PrevLength = ACPI_STRLEN (Prev->Value); 262 ThisLength = ACPI_STRLEN (Value); 263 264 /* Add two for: separator + NULL terminator */ 265 266 NewValue = UtLocalCalloc (PrevLength + ThisLength + 2); 267 ACPI_STRNCPY (NewValue, Prev->Value, PrevLength); 268 NewValue[PrevLength] = ' '; 269 270 ACPI_STRNCPY ((NewValue + PrevLength + 1), Value, ThisLength); 271 ACPI_FREE (Prev->Value); 272 Prev->Value = NewValue; 273 } 274 } 275 276 277 /****************************************************************************** 278 * 279 * FUNCTION: DtParseLine 280 * 281 * PARAMETERS: LineBuffer - Current source code line 282 * Line - Current line number in the source 283 * Offset - Current byte offset of the line 284 * 285 * RETURN: Status 286 * 287 * DESCRIPTION: Parse one source line 288 * 289 *****************************************************************************/ 290 291 static ACPI_STATUS 292 DtParseLine ( 293 char *LineBuffer, 294 UINT32 Line, 295 UINT32 Offset) 296 { 297 char *Start; 298 char *End; 299 char *TmpName; 300 char *TmpValue; 301 char *Name; 302 char *Value; 303 char *Colon; 304 UINT32 Length; 305 DT_FIELD *Field; 306 UINT32 Column; 307 UINT32 NameColumn; 308 309 310 if (!LineBuffer) 311 { 312 return (AE_OK); 313 } 314 315 /* All lines after "Raw Table Data" are ingored */ 316 317 if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER)) 318 { 319 return (AE_NOT_FOUND); 320 } 321 322 Colon = strchr (LineBuffer, ':'); 323 if (!Colon) 324 { 325 return (AE_OK); 326 } 327 328 Start = LineBuffer; 329 End = Colon; 330 331 while (Start < Colon) 332 { 333 if (*Start == ' ') 334 { 335 Start++; 336 continue; 337 } 338 339 /* Found left bracket, go to the right bracket */ 340 341 if (*Start == '[') 342 { 343 while (Start < Colon && *Start != ']') 344 { 345 Start++; 346 } 347 348 if (Start == Colon) 349 { 350 break; 351 } 352 353 Start++; 354 continue; 355 } 356 357 break; 358 } 359 360 /* 361 * There are two column values. One for the field name, 362 * and one for the field value. 363 */ 364 Column = ACPI_PTR_DIFF (Colon, LineBuffer) + 3; 365 NameColumn = ACPI_PTR_DIFF (Start, LineBuffer) + 1; 366 367 Length = ACPI_PTR_DIFF (End, Start); 368 369 TmpName = UtLocalCalloc (Length + 1); 370 ACPI_STRNCPY (TmpName, Start, Length); 371 Name = DtTrim (TmpName); 372 ACPI_FREE (TmpName); 373 374 Start = End = (Colon + 1); 375 376 while (*End) 377 { 378 /* Found left quotation, go to the right quotation and break */ 379 380 if (*End == '"') 381 { 382 End++; 383 while (*End && (*End != '"')) 384 { 385 End++; 386 } 387 388 End++; 389 break; 390 } 391 392 /* 393 * Special "comment" fields at line end, ignore them. 394 * Note: normal slash-slash and slash-asterisk comments are 395 * stripped already by the DtGetNextLine parser. 396 * 397 * TBD: Perhaps DtGetNextLine should parse the following type 398 * of comments also. 399 */ 400 if (*End == '(' || 401 *End == '<') 402 { 403 break; 404 } 405 406 End++; 407 } 408 409 Length = ACPI_PTR_DIFF (End, Start); 410 TmpValue = UtLocalCalloc (Length + 1); 411 412 ACPI_STRNCPY (TmpValue, Start, Length); 413 Value = DtTrim (TmpValue); 414 ACPI_FREE (TmpValue); 415 416 if (ACPI_STRLEN (Name) && Value) 417 { 418 Field = UtLocalCalloc (sizeof (DT_FIELD)); 419 Field->Name = Name; 420 Field->Value = Value; 421 Field->Line = Line; 422 Field->ByteOffset = Offset; 423 Field->NameColumn = NameColumn; 424 Field->Column = Column; 425 426 DtLinkField (Field); 427 } 428 else if (!ACPI_STRLEN (Name)) 429 { 430 /* Handle multi-line buffers (length > 16) */ 431 432 DtMergeField (Value); 433 } 434 else 435 { 436 ACPI_FREE (Name); 437 ACPI_FREE (Value); 438 } 439 440 return (AE_OK); 441 } 442 443 444 /****************************************************************************** 445 * 446 * FUNCTION: DtGetNextLine 447 * 448 * PARAMETERS: Handle - Open file handle for the source file 449 * 450 * RETURN: Filled line buffer and offset of start-of-line (zero on EOF) 451 * 452 * DESCRIPTION: Get the next valid source line. Removes all comments. 453 * Ignores empty lines. 454 * 455 * Handles both slash-asterisk and slash-slash comments. 456 * Also, quoted strings, but no escapes within. 457 * 458 * Line is returned in Gbl_CurrentLineBuffer. 459 * Line number in original file is returned in Gbl_CurrentLineNumber. 460 * 461 *****************************************************************************/ 462 463 UINT32 464 DtGetNextLine ( 465 FILE *Handle) 466 { 467 UINT32 State = DT_NORMAL_TEXT; 468 UINT32 CurrentLineOffset; 469 UINT32 i; 470 char c; 471 472 473 for (i = 0; i < ASL_LINE_BUFFER_SIZE;) 474 { 475 c = (char) getc (Handle); 476 if (c == EOF) 477 { 478 switch (State) 479 { 480 case DT_START_QUOTED_STRING: 481 case DT_SLASH_ASTERISK_COMMENT: 482 case DT_SLASH_SLASH_COMMENT: 483 484 AcpiOsPrintf ("**** EOF within comment/string %u\n", State); 485 break; 486 487 default: 488 break; 489 } 490 491 return (0); 492 } 493 494 switch (State) 495 { 496 case DT_NORMAL_TEXT: 497 498 /* Normal text, insert char into line buffer */ 499 500 Gbl_CurrentLineBuffer[i] = c; 501 switch (c) 502 { 503 case '/': 504 State = DT_START_COMMENT; 505 break; 506 507 case '"': 508 State = DT_START_QUOTED_STRING; 509 i++; 510 break; 511 512 case '\n': 513 CurrentLineOffset = Gbl_NextLineOffset; 514 Gbl_NextLineOffset = (UINT32) ftell (Handle); 515 Gbl_CurrentLineNumber++; 516 517 /* Exit if line is complete. Ignore blank lines */ 518 519 if (i != 0) 520 { 521 Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate line */ 522 return (CurrentLineOffset); 523 } 524 break; 525 526 default: 527 i++; 528 break; 529 } 530 break; 531 532 case DT_START_QUOTED_STRING: 533 534 /* Insert raw chars until end of quoted string */ 535 536 Gbl_CurrentLineBuffer[i] = c; 537 i++; 538 539 if (c == '"') 540 { 541 State = DT_NORMAL_TEXT; 542 } 543 break; 544 545 case DT_START_COMMENT: 546 547 /* Open comment if this character is an asterisk or slash */ 548 549 switch (c) 550 { 551 case '*': 552 State = DT_SLASH_ASTERISK_COMMENT; 553 break; 554 555 case '/': 556 State = DT_SLASH_SLASH_COMMENT; 557 break; 558 559 default: /* Not a comment */ 560 i++; /* Save the preceeding slash */ 561 Gbl_CurrentLineBuffer[i] = c; 562 i++; 563 State = DT_NORMAL_TEXT; 564 break; 565 } 566 break; 567 568 case DT_SLASH_ASTERISK_COMMENT: 569 570 /* Ignore chars until an asterisk-slash is found */ 571 572 switch (c) 573 { 574 case '\n': 575 Gbl_NextLineOffset = (UINT32) ftell (Handle); 576 Gbl_CurrentLineNumber++; 577 break; 578 579 case '*': 580 State = DT_END_COMMENT; 581 break; 582 583 default: 584 break; 585 } 586 break; 587 588 case DT_SLASH_SLASH_COMMENT: 589 590 /* Ignore chars until end-of-line */ 591 592 if (c == '\n') 593 { 594 /* We will exit via the NORMAL_TEXT path */ 595 596 ungetc (c, Handle); 597 State = DT_NORMAL_TEXT; 598 } 599 break; 600 601 case DT_END_COMMENT: 602 603 /* End comment if this char is a slash */ 604 605 switch (c) 606 { 607 case '/': 608 State = DT_NORMAL_TEXT; 609 break; 610 611 case '\n': 612 CurrentLineOffset = Gbl_NextLineOffset; 613 Gbl_NextLineOffset = (UINT32) ftell (Handle); 614 Gbl_CurrentLineNumber++; 615 break; 616 617 case '*': 618 /* Consume all adjacent asterisks */ 619 break; 620 621 default: 622 State = DT_SLASH_ASTERISK_COMMENT; 623 break; 624 } 625 break; 626 627 default: 628 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state"); 629 return (0); 630 } 631 } 632 633 printf ("ERROR - Input line is too long (max %u)\n", ASL_LINE_BUFFER_SIZE); 634 return (0); 635 } 636 637 638 /****************************************************************************** 639 * 640 * FUNCTION: DtScanFile 641 * 642 * PARAMETERS: Handle - Open file handle for the source file 643 * 644 * RETURN: Pointer to start of the constructed parse tree. 645 * 646 * DESCRIPTION: Scan source file, link all field names and values 647 * to the global parse tree: Gbl_FieldList 648 * 649 *****************************************************************************/ 650 651 DT_FIELD * 652 DtScanFile ( 653 FILE *Handle) 654 { 655 ACPI_STATUS Status; 656 UINT32 Offset; 657 658 659 ACPI_FUNCTION_NAME (DtScanFile); 660 661 662 /* Get the file size */ 663 664 Gbl_InputByteCount = DtGetFileSize (Handle); 665 666 Gbl_CurrentLineNumber = 0; 667 Gbl_CurrentLineOffset = 0; 668 Gbl_NextLineOffset = 0; 669 670 /* Scan line-by-line */ 671 672 while ((Offset = DtGetNextLine (Handle))) 673 { 674 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s", 675 Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer)); 676 677 Status = DtParseLine (Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber, Offset); 678 if (Status == AE_NOT_FOUND) 679 { 680 break; 681 } 682 } 683 684 return (Gbl_FieldList); 685 } 686 687 688 /* 689 * Output functions 690 */ 691 692 /****************************************************************************** 693 * 694 * FUNCTION: DtWriteBinary 695 * 696 * PARAMETERS: DT_WALK_CALLBACK 697 * 698 * RETURN: Status 699 * 700 * DESCRIPTION: Write one subtable of a binary ACPI table 701 * 702 *****************************************************************************/ 703 704 static void 705 DtWriteBinary ( 706 DT_SUBTABLE *Subtable, 707 void *Context, 708 void *ReturnValue) 709 { 710 711 FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length); 712 } 713 714 715 /****************************************************************************** 716 * 717 * FUNCTION: DtOutputBinary 718 * 719 * PARAMETERS: 720 * 721 * RETURN: Status 722 * 723 * DESCRIPTION: Write entire binary ACPI table (result of compilation) 724 * 725 *****************************************************************************/ 726 727 void 728 DtOutputBinary ( 729 DT_SUBTABLE *RootTable) 730 { 731 732 if (!RootTable) 733 { 734 return; 735 } 736 737 /* Walk the entire parse tree, emitting the binary data */ 738 739 DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL); 740 Gbl_TableLength = DtGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); 741 } 742 743 744 /* 745 * Listing support 746 */ 747 748 /****************************************************************************** 749 * 750 * FUNCTION: DtDumpBuffer 751 * 752 * PARAMETERS: FileID - Where to write buffer data 753 * Buffer - Buffer to dump 754 * Offset - Offset in current table 755 * Length - Buffer Length 756 * 757 * RETURN: None 758 * 759 * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately). 760 * 761 * TBD: merge dump buffer routines 762 * 763 *****************************************************************************/ 764 765 static void 766 DtDumpBuffer ( 767 UINT32 FileId, 768 UINT8 *Buffer, 769 UINT32 Offset, 770 UINT32 Length) 771 { 772 UINT32 i; 773 UINT32 j; 774 UINT8 BufChar; 775 776 777 FlPrintFile (FileId, "Output: [%3.3Xh %4.4d% 3d] ", 778 Offset, Offset, Length); 779 780 i = 0; 781 while (i < Length) 782 { 783 if (i >= 16) 784 { 785 FlPrintFile (FileId, "%23s", ""); 786 } 787 788 /* Print 16 hex chars */ 789 790 for (j = 0; j < 16;) 791 { 792 if (i + j >= Length) 793 { 794 /* Dump fill spaces */ 795 796 FlPrintFile (FileId, " "); 797 j++; 798 continue; 799 } 800 801 FlPrintFile (FileId, "%02X ", Buffer[i+j]); 802 j++; 803 } 804 805 FlPrintFile (FileId, " "); 806 for (j = 0; j < 16; j++) 807 { 808 if (i + j >= Length) 809 { 810 FlPrintFile (FileId, "\n\n"); 811 return; 812 } 813 814 BufChar = Buffer[(ACPI_SIZE) i + j]; 815 if (ACPI_IS_PRINT (BufChar)) 816 { 817 FlPrintFile (FileId, "%c", BufChar); 818 } 819 else 820 { 821 FlPrintFile (FileId, "."); 822 } 823 } 824 825 /* Done with that line. */ 826 827 FlPrintFile (FileId, "\n"); 828 i += 16; 829 } 830 831 FlPrintFile (FileId, "\n\n"); 832 } 833 834 835 /****************************************************************************** 836 * 837 * FUNCTION: DtWriteFieldToListing 838 * 839 * PARAMETERS: Buffer - Contains the compiled data 840 * Field - Field node for the input line 841 * Length - Length of the output data 842 * 843 * RETURN: None 844 * 845 * DESCRIPTION: Write one field to the listing file (if listing is enabled). 846 * 847 *****************************************************************************/ 848 849 void 850 DtWriteFieldToListing ( 851 UINT8 *Buffer, 852 DT_FIELD *Field, 853 UINT32 Length) 854 { 855 UINT8 FileByte; 856 857 858 if (!Gbl_ListingFlag || !Field) 859 { 860 return; 861 } 862 863 /* Dump the original source line */ 864 865 FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input: "); 866 FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset); 867 868 while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK) 869 { 870 FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1); 871 if (FileByte == '\n') 872 { 873 break; 874 } 875 } 876 877 /* Dump the line as parsed and represented internally */ 878 879 FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %s\n", 880 Field->Column-4, Field->Name, Field->Value); 881 882 /* Dump the hex data that will be output for this field */ 883 884 DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Field->TableOffset, Length); 885 } 886 887 888 /****************************************************************************** 889 * 890 * FUNCTION: DtWriteTableToListing 891 * 892 * PARAMETERS: None 893 * 894 * RETURN: None 895 * 896 * DESCRIPTION: Write the entire compiled table to the listing file 897 * in hex format 898 * 899 *****************************************************************************/ 900 901 void 902 DtWriteTableToListing ( 903 void) 904 { 905 UINT8 *Buffer; 906 907 908 if (!Gbl_ListingFlag) 909 { 910 return; 911 } 912 913 /* Read the entire table from the output file */ 914 915 Buffer = UtLocalCalloc (Gbl_TableLength); 916 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 917 FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength); 918 919 /* Dump the raw table data */ 920 921 AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle); 922 923 AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n", 924 ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength); 925 AcpiUtDumpBuffer2 (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY); 926 927 AcpiOsRedirectOutput (stdout); 928 } 929