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