1 2 /****************************************************************************** 3 * 4 * Module Name: acpixtract - convert ascii ACPI tables to binary 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2011, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <ctype.h> 49 50 51 /* Note: This is a 32-bit program only */ 52 53 #define VERSION 0x20110330 54 #define FIND_HEADER 0 55 #define EXTRACT_DATA 1 56 #define BUFFER_SIZE 256 57 #define MIN_HEADER_LENGTH 6 /* strlen ("DSDT @") */ 58 59 /* Local prototypes */ 60 61 static void 62 CheckAscii ( 63 char *Name, 64 int Count); 65 66 static void 67 NormalizeSignature ( 68 char *Signature); 69 70 static unsigned int 71 GetNextInstance ( 72 char *InputPathname, 73 char *Signature); 74 75 static int 76 ExtractTables ( 77 char *InputPathname, 78 char *Signature, 79 unsigned int MinimumInstances); 80 81 static size_t 82 GetTableHeader ( 83 FILE *InputFile, 84 unsigned char *OutputData); 85 86 static unsigned int 87 CountTableInstances ( 88 char *InputPathname, 89 char *Signature); 90 91 static int 92 ListTables ( 93 char *InputPathname); 94 95 static size_t 96 ConvertLine ( 97 char *InputLine, 98 unsigned char *OutputData); 99 100 static void 101 DisplayUsage ( 102 void); 103 104 105 typedef struct acpi_table_header 106 { 107 char Signature[4]; 108 int Length; 109 unsigned char Revision; 110 unsigned char Checksum; 111 char OemId[6]; 112 char OemTableId[8]; 113 int OemRevision; 114 char AslCompilerId[4]; 115 int AslCompilerRevision; 116 117 } ACPI_TABLE_HEADER; 118 119 struct TableInfo 120 { 121 unsigned int Signature; 122 unsigned int Instances; 123 unsigned int NextInstance; 124 struct TableInfo *Next; 125 }; 126 127 static struct TableInfo *ListHead = NULL; 128 static char Filename[16]; 129 static unsigned char Data[16]; 130 131 132 /****************************************************************************** 133 * 134 * FUNCTION: DisplayUsage 135 * 136 * DESCRIPTION: Usage message 137 * 138 ******************************************************************************/ 139 140 static void 141 DisplayUsage ( 142 void) 143 { 144 145 printf ("Usage: acpixtract [option] <InputFile>\n"); 146 printf ("\nExtract binary ACPI tables from text acpidump output\n"); 147 printf ("Default invocation extracts all DSDTs and SSDTs\n"); 148 printf ("Version %8.8X\n\n", VERSION); 149 printf ("Options:\n"); 150 printf (" -a Extract all tables, not just DSDT/SSDT\n"); 151 printf (" -l List table summaries, do not extract\n"); 152 printf (" -s<Signature> Extract all tables named <Signature>\n"); 153 printf ("\n"); 154 } 155 156 157 /******************************************************************************* 158 * 159 * FUNCTION: CheckAscii 160 * 161 * PARAMETERS: Name - Ascii string, at least as long as Count 162 * Count - Number of characters to check 163 * 164 * RETURN: None 165 * 166 * DESCRIPTION: Ensure that the requested number of characters are printable 167 * Ascii characters. Sets non-printable and null chars to <space>. 168 * 169 ******************************************************************************/ 170 171 static void 172 CheckAscii ( 173 char *Name, 174 int Count) 175 { 176 int i; 177 178 179 for (i = 0; i < Count; i++) 180 { 181 if (!Name[i] || !isprint ((int) Name[i])) 182 { 183 Name[i] = ' '; 184 } 185 } 186 } 187 188 189 /******************************************************************************* 190 * 191 * FUNCTION: NormalizeSignature 192 * 193 * PARAMETERS: Name - Ascii string containing an ACPI signature 194 * 195 * RETURN: None 196 * 197 * DESCRIPTION: Change "RSD PTR" to "RSDP" 198 * 199 ******************************************************************************/ 200 201 static void 202 NormalizeSignature ( 203 char *Signature) 204 { 205 206 if (!strncmp (Signature, "RSD ", 4)) 207 { 208 Signature[3] = 'P'; 209 } 210 } 211 212 213 /****************************************************************************** 214 * 215 * FUNCTION: ConvertLine 216 * 217 * PARAMETERS: InputLine - One line from the input acpidump file 218 * OutputData - Where the converted data is returned 219 * 220 * RETURN: The number of bytes actually converted 221 * 222 * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes) 223 * 224 ******************************************************************************/ 225 226 static size_t 227 ConvertLine ( 228 char *InputLine, 229 unsigned char *OutputData) 230 { 231 char *End; 232 int BytesConverted; 233 int Converted[16]; 234 int i; 235 236 237 /* Terminate the input line at the end of the actual data (for sscanf) */ 238 239 End = strstr (InputLine + 2, " "); 240 if (!End) 241 { 242 return (0); /* Don't understand the format */ 243 } 244 *End = 0; 245 246 /* 247 * Convert one line of table data, of the form: 248 * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline> 249 * 250 * Example: 251 * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08 _SB_LNKD........ 252 */ 253 BytesConverted = sscanf (InputLine, 254 "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", 255 &Converted[0], &Converted[1], &Converted[2], &Converted[3], 256 &Converted[4], &Converted[5], &Converted[6], &Converted[7], 257 &Converted[8], &Converted[9], &Converted[10], &Converted[11], 258 &Converted[12], &Converted[13], &Converted[14], &Converted[15]); 259 260 /* Pack converted data into a byte array */ 261 262 for (i = 0; i < BytesConverted; i++) 263 { 264 OutputData[i] = (unsigned char) Converted[i]; 265 } 266 267 return ((size_t) BytesConverted); 268 } 269 270 271 /****************************************************************************** 272 * 273 * FUNCTION: GetTableHeader 274 * 275 * PARAMETERS: InputFile - Handle for the input acpidump file 276 * OutputData - Where the table header is returned 277 * 278 * RETURN: The actual number of bytes converted 279 * 280 * DESCRIPTION: Extract and convert an ACPI table header 281 * 282 ******************************************************************************/ 283 284 static size_t 285 GetTableHeader ( 286 FILE *InputFile, 287 unsigned char *OutputData) 288 { 289 size_t BytesConverted; 290 size_t TotalConverted = 0; 291 char Buffer[BUFFER_SIZE]; 292 int i; 293 294 295 /* Get the full 36 byte header, requires 3 lines */ 296 297 for (i = 0; i < 3; i++) 298 { 299 if (!fgets (Buffer, BUFFER_SIZE, InputFile)) 300 { 301 return (TotalConverted); 302 } 303 304 BytesConverted = ConvertLine (Buffer, OutputData); 305 TotalConverted += BytesConverted; 306 OutputData += 16; 307 308 if (BytesConverted != 16) 309 { 310 return (TotalConverted); 311 } 312 } 313 314 return (TotalConverted); 315 } 316 317 318 /****************************************************************************** 319 * 320 * FUNCTION: CountTableInstances 321 * 322 * PARAMETERS: InputPathname - Filename for acpidump file 323 * Signature - Requested signature to count 324 * 325 * RETURN: The number of instances of the signature 326 * 327 * DESCRIPTION: Count the instances of tables with the given signature within 328 * the input acpidump file. 329 * 330 ******************************************************************************/ 331 332 static unsigned int 333 CountTableInstances ( 334 char *InputPathname, 335 char *Signature) 336 { 337 char Buffer[BUFFER_SIZE]; 338 FILE *InputFile; 339 unsigned int Instances = 0; 340 341 342 InputFile = fopen (InputPathname, "rt"); 343 if (!InputFile) 344 { 345 printf ("Could not open %s\n", InputPathname); 346 return (0); 347 } 348 349 /* Count the number of instances of this signature */ 350 351 while (fgets (Buffer, BUFFER_SIZE, InputFile)) 352 { 353 /* Ignore empty lines and lines that start with a space */ 354 355 if ((Buffer[0] == ' ') || 356 (Buffer[0] == '\n')) 357 { 358 continue; 359 } 360 361 NormalizeSignature (Buffer); 362 if (!strncmp (Buffer, Signature, 4)) 363 { 364 Instances++; 365 } 366 } 367 368 fclose (InputFile); 369 return (Instances); 370 } 371 372 373 /****************************************************************************** 374 * 375 * FUNCTION: GetNextInstance 376 * 377 * PARAMETERS: InputPathname - Filename for acpidump file 378 * Signature - Requested ACPI signature 379 * 380 * RETURN: The next instance number for this signature. Zero if this 381 * is the first instance of this signature. 382 * 383 * DESCRIPTION: Get the next instance number of the specified table. If this 384 * is the first instance of the table, create a new instance 385 * block. Note: only SSDT and PSDT tables can have multiple 386 * instances. 387 * 388 ******************************************************************************/ 389 390 static unsigned int 391 GetNextInstance ( 392 char *InputPathname, 393 char *Signature) 394 { 395 struct TableInfo *Info; 396 397 398 Info = ListHead; 399 while (Info) 400 { 401 if (*(unsigned int *) Signature == Info->Signature) 402 { 403 break; 404 } 405 406 Info = Info->Next; 407 } 408 409 if (!Info) 410 { 411 /* Signature not found, create new table info block */ 412 413 Info = malloc (sizeof (struct TableInfo)); 414 if (!Info) 415 { 416 printf ("Could not allocate memory\n"); 417 exit (0); 418 } 419 420 Info->Signature = *(unsigned int *) Signature; 421 Info->Instances = CountTableInstances (InputPathname, Signature); 422 Info->NextInstance = 1; 423 Info->Next = ListHead; 424 ListHead = Info; 425 } 426 427 if (Info->Instances > 1) 428 { 429 return (Info->NextInstance++); 430 } 431 432 return (0); 433 } 434 435 436 /****************************************************************************** 437 * 438 * FUNCTION: ExtractTables 439 * 440 * PARAMETERS: InputPathname - Filename for acpidump file 441 * Signature - Requested ACPI signature to extract. 442 * NULL means extract ALL tables. 443 * MinimumInstances - Min instances that are acceptable 444 * 445 * RETURN: Status 446 * 447 * DESCRIPTION: Convert text ACPI tables to binary 448 * 449 ******************************************************************************/ 450 451 static int 452 ExtractTables ( 453 char *InputPathname, 454 char *Signature, 455 unsigned int MinimumInstances) 456 { 457 char Buffer[BUFFER_SIZE]; 458 FILE *InputFile; 459 FILE *OutputFile = NULL; 460 size_t BytesWritten; 461 size_t TotalBytesWritten = 0; 462 size_t BytesConverted; 463 unsigned int State = FIND_HEADER; 464 unsigned int FoundTable = 0; 465 unsigned int Instances = 0; 466 unsigned int ThisInstance; 467 char ThisSignature[4]; 468 int Status = 0; 469 470 471 /* Open input in text mode, output is in binary mode */ 472 473 InputFile = fopen (InputPathname, "rt"); 474 if (!InputFile) 475 { 476 printf ("Could not open %s\n", InputPathname); 477 return (-1); 478 } 479 480 if (Signature) 481 { 482 /* Are there enough instances of the table to continue? */ 483 484 NormalizeSignature (Signature); 485 486 Instances = CountTableInstances (InputPathname, Signature); 487 if (Instances < MinimumInstances) 488 { 489 printf ("Table %s was not found in %s\n", Signature, InputPathname); 490 Status = -1; 491 goto CleanupAndExit; 492 } 493 494 if (Instances == 0) 495 { 496 goto CleanupAndExit; 497 } 498 } 499 500 /* Convert all instances of the table to binary */ 501 502 while (fgets (Buffer, BUFFER_SIZE, InputFile)) 503 { 504 switch (State) 505 { 506 case FIND_HEADER: 507 508 /* Ignore lines that are too short to be header lines */ 509 510 if (strlen (Buffer) < MIN_HEADER_LENGTH) 511 { 512 continue; 513 } 514 515 /* Ignore empty lines and lines that start with a space */ 516 517 if ((Buffer[0] == ' ') || 518 (Buffer[0] == '\n')) 519 { 520 continue; 521 } 522 523 /* 524 * Ignore lines that are not of the form <sig> @ <addr>. Examples: 525 * 526 * DSDT @ 0x737e4000 527 * XSDT @ 0x737f2fff 528 * RSD PTR @ 0xf6cd0 529 * SSDT @ (nil) 530 */ 531 if (!strstr (Buffer, " @ ")) 532 { 533 continue; 534 } 535 536 NormalizeSignature (Buffer); 537 strncpy (ThisSignature, Buffer, 4); 538 539 if (Signature) 540 { 541 /* Ignore signatures that don't match */ 542 543 if (strncmp (ThisSignature, Signature, 4)) 544 { 545 continue; 546 } 547 } 548 549 /* 550 * Get the instance number for this signature. Only the 551 * SSDT and PSDT tables can have multiple instances. 552 */ 553 ThisInstance = GetNextInstance (InputPathname, ThisSignature); 554 555 /* Build an output filename and create/open the output file */ 556 557 if (ThisInstance > 0) 558 { 559 sprintf (Filename, "%4.4s%u.dat", ThisSignature, ThisInstance); 560 } 561 else 562 { 563 sprintf (Filename, "%4.4s.dat", ThisSignature); 564 } 565 566 OutputFile = fopen (Filename, "w+b"); 567 if (!OutputFile) 568 { 569 printf ("Could not open %s\n", Filename); 570 Status = -1; 571 goto CleanupAndExit; 572 } 573 574 State = EXTRACT_DATA; 575 TotalBytesWritten = 0; 576 FoundTable = 1; 577 continue; 578 579 case EXTRACT_DATA: 580 581 /* Empty line or non-data line terminates the data */ 582 583 if ((Buffer[0] == '\n') || 584 (Buffer[0] != ' ')) 585 { 586 fclose (OutputFile); 587 OutputFile = NULL; 588 State = FIND_HEADER; 589 590 printf ("Acpi table [%4.4s] - %u bytes written to %s\n", 591 ThisSignature, (unsigned int) TotalBytesWritten, Filename); 592 continue; 593 } 594 595 /* Convert the ascii data (one line of text) to binary */ 596 597 BytesConverted = ConvertLine (Buffer, Data); 598 599 /* Write the binary data */ 600 601 BytesWritten = fwrite (Data, 1, BytesConverted, OutputFile); 602 if (BytesWritten != BytesConverted) 603 { 604 printf ("Write error on %s\n", Filename); 605 fclose (OutputFile); 606 OutputFile = NULL; 607 Status = -1; 608 goto CleanupAndExit; 609 } 610 611 TotalBytesWritten += BytesConverted; 612 continue; 613 614 default: 615 Status = -1; 616 goto CleanupAndExit; 617 } 618 } 619 620 if (!FoundTable) 621 { 622 printf ("Table %s was not found in %s\n", Signature, InputPathname); 623 } 624 625 626 CleanupAndExit: 627 628 if (OutputFile) 629 { 630 fclose (OutputFile); 631 if (State == EXTRACT_DATA) 632 { 633 /* Received an EOF while extracting data */ 634 635 printf ("Acpi table [%4.4s] - %u bytes written to %s\n", 636 ThisSignature, (unsigned int) TotalBytesWritten, Filename); 637 } 638 } 639 640 fclose (InputFile); 641 return (Status); 642 } 643 644 645 /****************************************************************************** 646 * 647 * FUNCTION: ListTables 648 * 649 * PARAMETERS: InputPathname - Filename for acpidump file 650 * 651 * RETURN: Status 652 * 653 * DESCRIPTION: Display info for all ACPI tables found in input. Does not 654 * perform an actual extraction of the tables. 655 * 656 ******************************************************************************/ 657 658 static int 659 ListTables ( 660 char *InputPathname) 661 { 662 FILE *InputFile; 663 char Buffer[BUFFER_SIZE]; 664 size_t HeaderSize; 665 unsigned char Header[48]; 666 int TableCount = 0; 667 ACPI_TABLE_HEADER *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header; 668 669 670 /* Open input in text mode, output is in binary mode */ 671 672 InputFile = fopen (InputPathname, "rt"); 673 if (!InputFile) 674 { 675 printf ("Could not open %s\n", InputPathname); 676 return (-1); 677 } 678 679 /* Dump the headers for all tables found in the input file */ 680 681 printf ("\nSignature Length Revision OemId OemTableId" 682 " OemRevision CompilerId CompilerRevision\n\n"); 683 684 while (fgets (Buffer, BUFFER_SIZE, InputFile)) 685 { 686 /* Ignore empty lines and lines that start with a space */ 687 688 if ((Buffer[0] == ' ') || 689 (Buffer[0] == '\n')) 690 { 691 continue; 692 } 693 694 /* Get the 36 byte header and display the fields */ 695 696 HeaderSize = GetTableHeader (InputFile, Header); 697 if (HeaderSize < 16) 698 { 699 continue; 700 } 701 702 /* RSDP has an oddball signature and header */ 703 704 if (!strncmp (TableHeader->Signature, "RSD PTR ", 8)) 705 { 706 CheckAscii ((char *) &Header[9], 6); 707 printf ("%8.4s \"%6.6s\"\n", "RSDP", &Header[9]); 708 TableCount++; 709 continue; 710 } 711 712 /* Minimum size for table with standard header */ 713 714 if (HeaderSize < 36) 715 { 716 continue; 717 } 718 719 /* Signature and Table length */ 720 721 TableCount++; 722 printf ("%8.4s % 7d", TableHeader->Signature, TableHeader->Length); 723 724 /* FACS has only signature and length */ 725 726 if (!strncmp (TableHeader->Signature, "FACS", 4)) 727 { 728 printf ("\n"); 729 continue; 730 } 731 732 /* OEM IDs and Compiler IDs */ 733 734 CheckAscii (TableHeader->OemId, 6); 735 CheckAscii (TableHeader->OemTableId, 8); 736 CheckAscii (TableHeader->AslCompilerId, 4); 737 738 printf (" %2.2X \"%6.6s\" \"%8.8s\" %8.8X \"%4.4s\" %8.8X\n", 739 TableHeader->Revision, TableHeader->OemId, 740 TableHeader->OemTableId, TableHeader->OemRevision, 741 TableHeader->AslCompilerId, TableHeader->AslCompilerRevision); 742 } 743 744 printf ("\nFound %u ACPI tables [%8.8X]\n", TableCount, VERSION); 745 fclose (InputFile); 746 return (0); 747 } 748 749 750 /****************************************************************************** 751 * 752 * FUNCTION: main 753 * 754 * DESCRIPTION: C main function 755 * 756 ******************************************************************************/ 757 758 int 759 main ( 760 int argc, 761 char *argv[]) 762 { 763 int Status; 764 765 766 if (argc < 2) 767 { 768 DisplayUsage (); 769 return (0); 770 } 771 772 if (argv[1][0] == '-') 773 { 774 if (argc < 3) 775 { 776 DisplayUsage (); 777 return (0); 778 } 779 780 switch (argv[1][1]) 781 { 782 case 'a': 783 784 /* Extract all tables found */ 785 786 return (ExtractTables (argv[2], NULL, 0)); 787 788 case 'l': 789 790 /* List tables only, do not extract */ 791 792 return (ListTables (argv[2])); 793 794 case 's': 795 796 /* Extract only tables with this signature */ 797 798 return (ExtractTables (argv[2], &argv[1][2], 1)); 799 800 default: 801 DisplayUsage (); 802 return (0); 803 } 804 } 805 806 /* 807 * Default output is the DSDT and all SSDTs. One DSDT is required, 808 * any SSDTs are optional. 809 */ 810 Status = ExtractTables (argv[1], "DSDT", 1); 811 if (Status) 812 { 813 return (Status); 814 } 815 816 Status = ExtractTables (argv[1], "SSDT", 0); 817 return (Status); 818 } 819 820 821