Home | History | Annotate | Line # | Download | only in acpixtract
acpixtract.c revision 1.5
      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                 snprintf (Filename, sizeof(Filename), "%4.4s%u.dat", ThisSignature, ThisInstance);
    562             }
    563             else
    564             {
    565                 snprintf (Filename, sizeof(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