1 /****************************************************************************** 2 * 3 * Module Name: acpixtract - convert ascii ACPI tables to binary 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 #include "acpi.h" 45 #include "accommon.h" 46 #include "acapps.h" 47 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <ctype.h> 52 53 /* Local prototypes */ 54 55 static void 56 AxCheckAscii ( 57 char *Name, 58 int Count); 59 60 static void 61 AxNormalizeSignature ( 62 char *Signature); 63 64 static unsigned int 65 AxGetNextInstance ( 66 char *InputPathname, 67 char *Signature); 68 69 static size_t 70 AxGetTableHeader ( 71 FILE *InputFile, 72 unsigned char *OutputData); 73 74 static unsigned int 75 AxCountTableInstances ( 76 char *InputPathname, 77 char *Signature); 78 79 int 80 AxExtractTables ( 81 char *InputPathname, 82 char *Signature, 83 unsigned int MinimumInstances); 84 85 int 86 AxListTables ( 87 char *InputPathname); 88 89 static size_t 90 AxConvertLine ( 91 char *InputLine, 92 unsigned char *OutputData); 93 94 static int 95 AxIsEmptyLine ( 96 char *Buffer); 97 98 typedef struct AxTableInfo 99 { 100 UINT32 Signature; 101 unsigned int Instances; 102 unsigned int NextInstance; 103 struct AxTableInfo *Next; 104 105 } AX_TABLE_INFO; 106 107 /* Extraction states */ 108 109 #define AX_STATE_FIND_HEADER 0 110 #define AX_STATE_EXTRACT_DATA 1 111 112 /* Miscellaneous constants */ 113 114 #define AX_LINE_BUFFER_SIZE 256 115 #define AX_MIN_TABLE_NAME_LENGTH 6 /* strlen ("DSDT @") */ 116 117 118 static AX_TABLE_INFO *AxTableListHead = NULL; 119 static char Filename[16]; 120 static unsigned char Data[16]; 121 static char LineBuffer[AX_LINE_BUFFER_SIZE]; 122 static char HeaderBuffer[AX_LINE_BUFFER_SIZE]; 123 static char InstanceBuffer[AX_LINE_BUFFER_SIZE]; 124 125 126 /******************************************************************************* 127 * 128 * FUNCTION: AxCheckAscii 129 * 130 * PARAMETERS: Name - Ascii string, at least as long as Count 131 * Count - Number of characters to check 132 * 133 * RETURN: None 134 * 135 * DESCRIPTION: Ensure that the requested number of characters are printable 136 * Ascii characters. Sets non-printable and null chars to <space>. 137 * 138 ******************************************************************************/ 139 140 static void 141 AxCheckAscii ( 142 char *Name, 143 int Count) 144 { 145 int i; 146 147 148 for (i = 0; i < Count; i++) 149 { 150 if (!Name[i] || !isprint ((int) Name[i])) 151 { 152 Name[i] = ' '; 153 } 154 } 155 } 156 157 158 /****************************************************************************** 159 * 160 * FUNCTION: AxIsEmptyLine 161 * 162 * PARAMETERS: Buffer - Line from input file 163 * 164 * RETURN: TRUE if line is empty (zero or more blanks only) 165 * 166 * DESCRIPTION: Determine if an input line is empty. 167 * 168 ******************************************************************************/ 169 170 static int 171 AxIsEmptyLine ( 172 char *Buffer) 173 { 174 175 /* Skip all spaces */ 176 177 while (*Buffer == ' ') 178 { 179 Buffer++; 180 } 181 182 /* If end-of-line, this line is empty */ 183 184 if (*Buffer == '\n') 185 { 186 return (1); 187 } 188 189 return (0); 190 } 191 192 193 /******************************************************************************* 194 * 195 * FUNCTION: AxNormalizeSignature 196 * 197 * PARAMETERS: Name - Ascii string containing an ACPI signature 198 * 199 * RETURN: None 200 * 201 * DESCRIPTION: Change "RSD PTR" to "RSDP" 202 * 203 ******************************************************************************/ 204 205 static void 206 AxNormalizeSignature ( 207 char *Signature) 208 { 209 210 if (!strncmp (Signature, "RSD ", 4)) 211 { 212 Signature[3] = 'P'; 213 } 214 } 215 216 217 /****************************************************************************** 218 * 219 * FUNCTION: AxConvertLine 220 * 221 * PARAMETERS: InputLine - One line from the input acpidump file 222 * OutputData - Where the converted data is returned 223 * 224 * RETURN: The number of bytes actually converted 225 * 226 * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes) 227 * 228 ******************************************************************************/ 229 230 static size_t 231 AxConvertLine ( 232 char *InputLine, 233 unsigned char *OutputData) 234 { 235 char *End; 236 int BytesConverted; 237 int Converted[16]; 238 int i; 239 240 241 /* Terminate the input line at the end of the actual data (for sscanf) */ 242 243 End = strstr (InputLine + 2, " "); 244 if (!End) 245 { 246 return (0); /* Don't understand the format */ 247 } 248 *End = 0; 249 250 /* 251 * Convert one line of table data, of the form: 252 * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline> 253 * 254 * Example: 255 * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08 _SB_LNKD........ 256 */ 257 BytesConverted = sscanf (InputLine, 258 "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", 259 &Converted[0], &Converted[1], &Converted[2], &Converted[3], 260 &Converted[4], &Converted[5], &Converted[6], &Converted[7], 261 &Converted[8], &Converted[9], &Converted[10], &Converted[11], 262 &Converted[12], &Converted[13], &Converted[14], &Converted[15]); 263 264 /* Pack converted data into a byte array */ 265 266 for (i = 0; i < BytesConverted; i++) 267 { 268 OutputData[i] = (unsigned char) Converted[i]; 269 } 270 271 return ((size_t) BytesConverted); 272 } 273 274 275 /****************************************************************************** 276 * 277 * FUNCTION: AxGetTableHeader 278 * 279 * PARAMETERS: InputFile - Handle for the input acpidump file 280 * OutputData - Where the table header is returned 281 * 282 * RETURN: The actual number of bytes converted 283 * 284 * DESCRIPTION: Extract and convert an ACPI table header 285 * 286 ******************************************************************************/ 287 288 static size_t 289 AxGetTableHeader ( 290 FILE *InputFile, 291 unsigned char *OutputData) 292 { 293 size_t BytesConverted; 294 size_t TotalConverted = 0; 295 int i; 296 297 298 /* Get the full 36 byte ACPI table header, requires 3 input text lines */ 299 300 for (i = 0; i < 3; i++) 301 { 302 if (!fgets (HeaderBuffer, AX_LINE_BUFFER_SIZE, InputFile)) 303 { 304 return (TotalConverted); 305 } 306 307 BytesConverted = AxConvertLine (HeaderBuffer, OutputData); 308 TotalConverted += BytesConverted; 309 OutputData += 16; 310 311 if (BytesConverted != 16) 312 { 313 return (TotalConverted); 314 } 315 } 316 317 return (TotalConverted); 318 } 319 320 321 /****************************************************************************** 322 * 323 * FUNCTION: AxCountTableInstances 324 * 325 * PARAMETERS: InputPathname - Filename for acpidump file 326 * Signature - Requested signature to count 327 * 328 * RETURN: The number of instances of the signature 329 * 330 * DESCRIPTION: Count the instances of tables with the given signature within 331 * the input acpidump file. 332 * 333 ******************************************************************************/ 334 335 static unsigned int 336 AxCountTableInstances ( 337 char *InputPathname, 338 char *Signature) 339 { 340 FILE *InputFile; 341 unsigned int Instances = 0; 342 343 344 InputFile = fopen (InputPathname, "rt"); 345 if (!InputFile) 346 { 347 printf ("Could not open file %s\n", InputPathname); 348 return (0); 349 } 350 351 /* Count the number of instances of this signature */ 352 353 while (fgets (InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile)) 354 { 355 /* Ignore empty lines and lines that start with a space */ 356 357 if (AxIsEmptyLine (InstanceBuffer) || 358 (InstanceBuffer[0] == ' ')) 359 { 360 continue; 361 } 362 363 AxNormalizeSignature (InstanceBuffer); 364 if (ACPI_COMPARE_NAME (InstanceBuffer, Signature)) 365 { 366 Instances++; 367 } 368 } 369 370 fclose (InputFile); 371 return (Instances); 372 } 373 374 375 /****************************************************************************** 376 * 377 * FUNCTION: AxGetNextInstance 378 * 379 * PARAMETERS: InputPathname - Filename for acpidump file 380 * Signature - Requested ACPI signature 381 * 382 * RETURN: The next instance number for this signature. Zero if this 383 * is the first instance of this signature. 384 * 385 * DESCRIPTION: Get the next instance number of the specified table. If this 386 * is the first instance of the table, create a new instance 387 * block. Note: only SSDT and PSDT tables can have multiple 388 * instances. 389 * 390 ******************************************************************************/ 391 392 static unsigned int 393 AxGetNextInstance ( 394 char *InputPathname, 395 char *Signature) 396 { 397 AX_TABLE_INFO *Info; 398 399 400 Info = AxTableListHead; 401 while (Info) 402 { 403 if (*(UINT32 *) Signature == Info->Signature) 404 { 405 break; 406 } 407 408 Info = Info->Next; 409 } 410 411 if (!Info) 412 { 413 /* Signature not found, create new table info block */ 414 415 Info = malloc (sizeof (AX_TABLE_INFO)); 416 if (!Info) 417 { 418 printf ("Could not allocate memory\n"); 419 exit (0); 420 } 421 422 Info->Signature = *(UINT32 *) Signature; 423 Info->Instances = AxCountTableInstances (InputPathname, Signature); 424 Info->NextInstance = 1; 425 Info->Next = AxTableListHead; 426 AxTableListHead = Info; 427 } 428 429 if (Info->Instances > 1) 430 { 431 return (Info->NextInstance++); 432 } 433 434 return (0); 435 } 436 437 438 /****************************************************************************** 439 * 440 * FUNCTION: AxExtractTables 441 * 442 * PARAMETERS: InputPathname - Filename for acpidump file 443 * Signature - Requested ACPI signature to extract. 444 * NULL means extract ALL tables. 445 * MinimumInstances - Min instances that are acceptable 446 * 447 * RETURN: Status 448 * 449 * DESCRIPTION: Convert text ACPI tables to binary 450 * 451 ******************************************************************************/ 452 453 int 454 AxExtractTables ( 455 char *InputPathname, 456 char *Signature, 457 unsigned int MinimumInstances) 458 { 459 FILE *InputFile; 460 FILE *OutputFile = NULL; 461 size_t BytesWritten; 462 size_t TotalBytesWritten = 0; 463 size_t BytesConverted; 464 unsigned int State = AX_STATE_FIND_HEADER; 465 unsigned int FoundTable = 0; 466 unsigned int Instances = 0; 467 unsigned int ThisInstance; 468 char ThisSignature[4]; 469 int Status = 0; 470 471 472 /* Open input in text mode, output is in binary mode */ 473 474 InputFile = fopen (InputPathname, "rt"); 475 if (!InputFile) 476 { 477 printf ("Could not open file %s\n", InputPathname); 478 return (-1); 479 } 480 481 if (Signature) 482 { 483 /* Are there enough instances of the table to continue? */ 484 485 AxNormalizeSignature (Signature); 486 487 Instances = AxCountTableInstances (InputPathname, Signature); 488 if (Instances < MinimumInstances) 489 { 490 printf ("Table %s was not found in %s\n", Signature, InputPathname); 491 Status = -1; 492 goto CleanupAndExit; 493 } 494 495 if (Instances == 0) 496 { 497 goto CleanupAndExit; 498 } 499 } 500 501 /* Convert all instances of the table to binary */ 502 503 while (fgets (LineBuffer, AX_LINE_BUFFER_SIZE, InputFile)) 504 { 505 switch (State) 506 { 507 case AX_STATE_FIND_HEADER: 508 509 /* Ignore lines that are too short to be header lines */ 510 511 if (strlen (LineBuffer) < AX_MIN_TABLE_NAME_LENGTH) 512 { 513 continue; 514 } 515 516 /* Ignore empty lines and lines that start with a space */ 517 518 if (AxIsEmptyLine (LineBuffer) || 519 (LineBuffer[0] == ' ')) 520 { 521 continue; 522 } 523 524 /* 525 * Ignore lines that are not of the form <sig> @ <addr>. 526 * Examples of lines that must be supported: 527 * 528 * DSDT @ 0x737e4000 529 * XSDT @ 0x737f2fff 530 * RSD PTR @ 0xf6cd0 531 * SSDT @ (nil) 532 */ 533 if (!strstr (LineBuffer, " @ ")) 534 { 535 continue; 536 } 537 538 AxNormalizeSignature (LineBuffer); 539 ACPI_MOVE_NAME (ThisSignature, LineBuffer); 540 541 if (Signature) 542 { 543 /* Ignore signatures that don't match */ 544 545 if (!ACPI_COMPARE_NAME (ThisSignature, Signature)) 546 { 547 continue; 548 } 549 } 550 551 /* 552 * Get the instance number for this signature. Only the 553 * SSDT and PSDT tables can have multiple instances. 554 */ 555 ThisInstance = AxGetNextInstance (InputPathname, ThisSignature); 556 557 /* Build an output filename and create/open the output file */ 558 559 if (ThisInstance > 0) 560 { 561 sprintf (Filename, "%4.4s%u.dat", ThisSignature, ThisInstance); 562 } 563 else 564 { 565 sprintf (Filename, "%4.4s.dat", ThisSignature); 566 } 567 568 AcpiUtStrlwr (Filename); 569 OutputFile = fopen (Filename, "w+b"); 570 if (!OutputFile) 571 { 572 printf ("Could not open file %s\n", Filename); 573 Status = -1; 574 goto CleanupAndExit; 575 } 576 577 State = AX_STATE_EXTRACT_DATA; 578 TotalBytesWritten = 0; 579 FoundTable = 1; 580 continue; 581 582 case AX_STATE_EXTRACT_DATA: 583 584 /* Empty line or non-data line terminates the data */ 585 586 if (AxIsEmptyLine (LineBuffer) || 587 (LineBuffer[0] != ' ')) 588 { 589 fclose (OutputFile); 590 OutputFile = NULL; 591 State = AX_STATE_FIND_HEADER; 592 593 printf ("Acpi table [%4.4s] - %u bytes written to %s\n", 594 ThisSignature, (unsigned int) TotalBytesWritten, Filename); 595 continue; 596 } 597 598 /* Convert the ascii data (one line of text) to binary */ 599 600 BytesConverted = AxConvertLine (LineBuffer, Data); 601 602 /* Write the binary data */ 603 604 BytesWritten = fwrite (Data, 1, BytesConverted, OutputFile); 605 if (BytesWritten != BytesConverted) 606 { 607 printf ("Error when writing file %s\n", Filename); 608 fclose (OutputFile); 609 OutputFile = NULL; 610 Status = -1; 611 goto CleanupAndExit; 612 } 613 614 TotalBytesWritten += BytesConverted; 615 continue; 616 617 default: 618 619 Status = -1; 620 goto CleanupAndExit; 621 } 622 } 623 624 if (!FoundTable) 625 { 626 printf ("Table %s was not found in %s\n", Signature, InputPathname); 627 } 628 629 630 CleanupAndExit: 631 632 if (OutputFile) 633 { 634 fclose (OutputFile); 635 if (State == AX_STATE_EXTRACT_DATA) 636 { 637 /* Received an EOF while extracting data */ 638 639 printf ("Acpi table [%4.4s] - %u bytes written to %s\n", 640 ThisSignature, (unsigned int) TotalBytesWritten, Filename); 641 } 642 } 643 644 fclose (InputFile); 645 return (Status); 646 } 647 648 649 /****************************************************************************** 650 * 651 * FUNCTION: AxListTables 652 * 653 * PARAMETERS: InputPathname - Filename for acpidump file 654 * 655 * RETURN: Status 656 * 657 * DESCRIPTION: Display info for all ACPI tables found in input. Does not 658 * perform an actual extraction of the tables. 659 * 660 ******************************************************************************/ 661 662 int 663 AxListTables ( 664 char *InputPathname) 665 { 666 FILE *InputFile; 667 size_t HeaderSize; 668 unsigned char Header[48]; 669 unsigned int TableCount = 0; 670 ACPI_TABLE_HEADER *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header; 671 672 673 /* Open input in text mode, output is in binary mode */ 674 675 InputFile = fopen (InputPathname, "rt"); 676 if (!InputFile) 677 { 678 printf ("Could not open file %s\n", InputPathname); 679 return (-1); 680 } 681 682 /* Dump the headers for all tables found in the input file */ 683 684 printf ("\nSignature Length Revision OemId OemTableId" 685 " OemRevision CompilerId CompilerRevision\n\n"); 686 687 while (fgets (LineBuffer, AX_LINE_BUFFER_SIZE, InputFile)) 688 { 689 /* Ignore empty lines and lines that start with a space */ 690 691 if (AxIsEmptyLine (LineBuffer) || 692 (LineBuffer[0] == ' ')) 693 { 694 continue; 695 } 696 697 /* Get the 36 byte header and display the fields */ 698 699 HeaderSize = AxGetTableHeader (InputFile, Header); 700 if (HeaderSize < 16) 701 { 702 continue; 703 } 704 705 /* RSDP has an oddball signature and header */ 706 707 if (!strncmp (TableHeader->Signature, "RSD PTR ", 8)) 708 { 709 AxCheckAscii ((char *) &Header[9], 6); 710 printf ("%7.4s \"%6.6s\"\n", "RSDP", &Header[9]); 711 TableCount++; 712 continue; 713 } 714 715 /* Minimum size for table with standard header */ 716 717 if (HeaderSize < sizeof (ACPI_TABLE_HEADER)) 718 { 719 continue; 720 } 721 722 /* Signature and Table length */ 723 724 TableCount++; 725 printf ("%7.4s 0x%8.8X", TableHeader->Signature, TableHeader->Length); 726 727 /* FACS has only signature and length */ 728 729 if (ACPI_COMPARE_NAME (TableHeader->Signature, "FACS")) 730 { 731 printf ("\n"); 732 continue; 733 } 734 735 /* OEM IDs and Compiler IDs */ 736 737 AxCheckAscii (TableHeader->OemId, 6); 738 AxCheckAscii (TableHeader->OemTableId, 8); 739 AxCheckAscii (TableHeader->AslCompilerId, 4); 740 741 printf (" 0x%2.2X \"%6.6s\" \"%8.8s\" 0x%8.8X \"%4.4s\" 0x%8.8X\n", 742 TableHeader->Revision, TableHeader->OemId, 743 TableHeader->OemTableId, TableHeader->OemRevision, 744 TableHeader->AslCompilerId, TableHeader->AslCompilerRevision); 745 } 746 747 printf ("\nFound %u ACPI tables\n", TableCount); 748 fclose (InputFile); 749 return (0); 750 } 751