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