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