Home | History | Annotate | Line # | Download | only in common
acfileio.c revision 1.1.1.1.2.5
      1 /******************************************************************************
      2  *
      3  * Module Name: acfileio - Get ACPI tables from file
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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 "actables.h"
     47 #include "acutils.h"
     48 #include "acapps.h"
     49 
     50 #define _COMPONENT          ACPI_UTILITIES
     51         ACPI_MODULE_NAME    ("acfileio")
     52 
     53 
     54 /* Local prototypes */
     55 
     56 static ACPI_STATUS
     57 AcGetOneTableFromFile (
     58     char                    *Filename,
     59     FILE                    *File,
     60     UINT8                   GetOnlyAmlTables,
     61     ACPI_TABLE_HEADER       **Table);
     62 
     63 static ACPI_STATUS
     64 AcCheckTextModeCorruption (
     65     ACPI_TABLE_HEADER       *Table);
     66 
     67 
     68 /*******************************************************************************
     69  *
     70  * FUNCTION:    AcGetAllTablesFromFile
     71  *
     72  * PARAMETERS:  Filename            - Table filename
     73  *              GetOnlyAmlTables    - TRUE if the tables must be AML tables
     74  *              ReturnListHead      - Where table list is returned
     75  *
     76  * RETURN:      Status
     77  *
     78  * DESCRIPTION: Get all ACPI tables from within a single file.
     79  *
     80  ******************************************************************************/
     81 
     82 ACPI_STATUS
     83 AcGetAllTablesFromFile (
     84     char                    *Filename,
     85     UINT8                   GetOnlyAmlTables,
     86     ACPI_NEW_TABLE_DESC     **ReturnListHead)
     87 {
     88     ACPI_NEW_TABLE_DESC     *ListHead = NULL;
     89     ACPI_NEW_TABLE_DESC     *ListTail = NULL;
     90     ACPI_NEW_TABLE_DESC     *TableDesc;
     91     FILE                    *File;
     92     ACPI_TABLE_HEADER       *Table = NULL;
     93     UINT32                  FileSize;
     94     ACPI_STATUS             Status = AE_OK;
     95 
     96 
     97     File = fopen (Filename, "rb");
     98     if (!File)
     99     {
    100         fprintf (stderr, "Could not open input file: %s\n", Filename);
    101         if (errno == ENOENT)
    102         {
    103             return (AE_NOT_EXIST);
    104         }
    105 
    106         return (AE_ERROR);
    107     }
    108 
    109     /* Get the file size */
    110 
    111     FileSize = CmGetFileSize (File);
    112     if (FileSize == ACPI_UINT32_MAX)
    113     {
    114         Status = AE_ERROR;
    115         goto Exit;
    116     }
    117 
    118     fprintf (stderr,
    119         "Input file %s, Length 0x%X (%u) bytes\n",
    120         Filename, FileSize, FileSize);
    121 
    122     /* We must have at least one ACPI table header */
    123 
    124     if (FileSize < sizeof (ACPI_TABLE_HEADER))
    125     {
    126         Status = AE_BAD_HEADER;
    127         goto Exit;
    128     }
    129 
    130     /* Check for an non-binary file */
    131 
    132     if (!AcIsFileBinary (File))
    133     {
    134         fprintf (stderr,
    135             "    %s: File does not appear to contain a valid AML table\n",
    136             Filename);
    137         Status = AE_TYPE;
    138         goto Exit;
    139     }
    140 
    141     /* Read all tables within the file */
    142 
    143     while (ACPI_SUCCESS (Status))
    144     {
    145         /* Get one entire ACPI table */
    146 
    147         Status = AcGetOneTableFromFile (
    148             Filename, File, GetOnlyAmlTables, &Table);
    149 
    150         if (Status == AE_CTRL_TERMINATE)
    151         {
    152             Status = AE_OK;
    153             break;
    154         }
    155         else if (Status == AE_TYPE)
    156         {
    157             Status = AE_OK;
    158             goto Exit;
    159         }
    160         else if (ACPI_FAILURE (Status))
    161         {
    162             goto Exit;
    163         }
    164 
    165         /* Print table header for iASL/disassembler only */
    166 
    167 #ifdef ACPI_ASL_COMPILER
    168 
    169         AcpiTbPrintTableHeader (0, Table);
    170 #endif
    171 
    172         /* Allocate and link a table descriptor */
    173 
    174         TableDesc = AcpiOsAllocate (sizeof (ACPI_NEW_TABLE_DESC));
    175         if (!TableDesc)
    176         {
    177             AcpiOsFree (Table);
    178             Status = AE_NO_MEMORY;
    179             goto Exit;
    180         }
    181 
    182         TableDesc->Table = Table;
    183         TableDesc->Next = NULL;
    184 
    185         /* Link at the end of the local table list */
    186 
    187         if (!ListHead)
    188         {
    189             ListHead = TableDesc;
    190             ListTail = TableDesc;
    191         }
    192         else
    193         {
    194             ListTail->Next = TableDesc;
    195             ListTail = TableDesc;
    196         }
    197     }
    198 
    199     /* Add the local table list to the end of the global list */
    200 
    201     if (*ReturnListHead)
    202     {
    203         ListTail = *ReturnListHead;
    204         while (ListTail->Next)
    205         {
    206             ListTail = ListTail->Next;
    207         }
    208 
    209         ListTail->Next = ListHead;
    210     }
    211     else
    212     {
    213         *ReturnListHead = ListHead;
    214     }
    215 
    216 Exit:
    217     fclose(File);
    218     return (Status);
    219 }
    220 
    221 
    222 /*******************************************************************************
    223  *
    224  * FUNCTION:    AcGetOneTableFromFile
    225  *
    226  * PARAMETERS:  Filename            - File where table is located
    227  *              File                - Open FILE pointer to Filename
    228  *              GetOnlyAmlTables    - TRUE if the tables must be AML tables.
    229  *              ReturnTable         - Where a pointer to the table is returned
    230  *
    231  * RETURN:      Status
    232  *
    233  * DESCRIPTION: Read the next ACPI table from a file. Implements support
    234  *              for multiple tables within a single file. File must already
    235  *              be open.
    236  *
    237  * Note: Loading an RSDP is not supported.
    238  *
    239  ******************************************************************************/
    240 
    241 static ACPI_STATUS
    242 AcGetOneTableFromFile (
    243     char                    *Filename,
    244     FILE                    *File,
    245     UINT8                   GetOnlyAmlTables,
    246     ACPI_TABLE_HEADER       **ReturnTable)
    247 {
    248     ACPI_STATUS             Status = AE_OK;
    249     ACPI_TABLE_HEADER       TableHeader;
    250     ACPI_TABLE_HEADER       *Table;
    251     INT32                   Count;
    252     long                    TableOffset;
    253 
    254 
    255     *ReturnTable = NULL;
    256 
    257     /* Get the table header to examine signature and length */
    258 
    259     TableOffset = ftell (File);
    260     Count = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File);
    261     if (Count != sizeof (ACPI_TABLE_HEADER))
    262     {
    263         return (AE_CTRL_TERMINATE);
    264     }
    265 
    266     /* Validate the table signature/header (limited ASCII chars) */
    267 
    268     Status = AcValidateTableHeader (File, TableOffset);
    269     if (ACPI_FAILURE (Status))
    270     {
    271         return (Status);
    272     }
    273 
    274     if (GetOnlyAmlTables)
    275     {
    276         /*
    277          * Table must be an AML table (DSDT/SSDT).
    278          * Used for iASL -e option only.
    279          */
    280         if (!AcpiUtIsAmlTable (&TableHeader))
    281         {
    282             fprintf (stderr,
    283                 "    %s: Table [%4.4s] is not an AML table - ignoring\n",
    284                 Filename, TableHeader.Signature);
    285 
    286             return (AE_TYPE);
    287         }
    288     }
    289 
    290     /* Allocate a buffer for the entire table */
    291 
    292     Table = AcpiOsAllocate ((ACPI_SIZE) TableHeader.Length);
    293     if (!Table)
    294     {
    295         return (AE_NO_MEMORY);
    296     }
    297 
    298     /* Read the entire ACPI table, including header */
    299 
    300     fseek (File, TableOffset, SEEK_SET);
    301 
    302     Count = fread (Table, 1, TableHeader.Length, File);
    303     if (Count != (INT32) TableHeader.Length)
    304     {
    305         Status = AE_ERROR;
    306         goto ErrorExit;
    307     }
    308 
    309     /* Validate the checksum (just issue a warning) */
    310 
    311     Status = AcpiTbVerifyChecksum (Table, TableHeader.Length);
    312     if (ACPI_FAILURE (Status))
    313     {
    314         Status = AcCheckTextModeCorruption (Table);
    315         if (ACPI_FAILURE (Status))
    316         {
    317             goto ErrorExit;
    318         }
    319     }
    320 
    321     *ReturnTable = Table;
    322     return (AE_OK);
    323 
    324 
    325 ErrorExit:
    326     AcpiOsFree (Table);
    327     return (Status);
    328 }
    329 
    330 
    331 /*******************************************************************************
    332  *
    333  * FUNCTION:    AcIsFileBinary
    334  *
    335  * PARAMETERS:  File                - Open input file
    336  *
    337  * RETURN:      TRUE if file appears to be binary
    338  *
    339  * DESCRIPTION: Scan a file for any non-ASCII bytes.
    340  *
    341  * Note: Maintains current file position.
    342  *
    343  ******************************************************************************/
    344 
    345 BOOLEAN
    346 AcIsFileBinary (
    347     FILE                    *File)
    348 {
    349     UINT8                   Byte;
    350     BOOLEAN                 IsBinary = FALSE;
    351     long                    FileOffset;
    352 
    353 
    354     /* Scan entire file for any non-ASCII bytes */
    355 
    356     FileOffset = ftell (File);
    357     while (fread (&Byte, 1, 1, File) == 1)
    358     {
    359         if (!isprint (Byte) && !isspace (Byte))
    360         {
    361             IsBinary = TRUE;
    362             goto Exit;
    363         }
    364     }
    365 
    366 Exit:
    367     fseek (File, FileOffset, SEEK_SET);
    368     return (IsBinary);
    369 }
    370 
    371 
    372 /*******************************************************************************
    373  *
    374  * FUNCTION:    AcValidateTableHeader
    375  *
    376  * PARAMETERS:  File                - Open input file
    377  *
    378  * RETURN:      Status
    379  *
    380  * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI
    381  *              tables, via the
    382  *              following checks on what would be the table header:
    383  *              1) File must be at least as long as an ACPI_TABLE_HEADER
    384  *              2) There must be enough room in the file to hold entire table
    385  *              3) Signature, OemId, OemTableId, AslCompilerId must be ASCII
    386  *
    387  * Note: There can be multiple definition blocks per file, so we cannot
    388  * expect/compare the file size to be equal to the table length. 12/2015.
    389  *
    390  * Note: Maintains current file position.
    391  *
    392  ******************************************************************************/
    393 
    394 ACPI_STATUS
    395 AcValidateTableHeader (
    396     FILE                    *File,
    397     long                    TableOffset)
    398 {
    399     ACPI_TABLE_HEADER       TableHeader;
    400     ACPI_SIZE               Actual;
    401     long                    OriginalOffset;
    402     UINT32                  FileSize;
    403     UINT32                  i;
    404 
    405 
    406     ACPI_FUNCTION_TRACE (AcValidateTableHeader);
    407 
    408 
    409     /* Read a potential table header */
    410 
    411     OriginalOffset = ftell (File);
    412     fseek (File, TableOffset, SEEK_SET);
    413 
    414     Actual = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File);
    415     fseek (File, OriginalOffset, SEEK_SET);
    416 
    417     if (Actual < sizeof (ACPI_TABLE_HEADER))
    418     {
    419         return (AE_ERROR);
    420     }
    421 
    422     /* Validate the signature (limited ASCII chars) */
    423 
    424     if (!AcpiUtValidNameseg (TableHeader.Signature))
    425     {
    426         fprintf (stderr, "Invalid table signature: 0x%8.8X\n",
    427             *ACPI_CAST_PTR (UINT32, TableHeader.Signature));
    428         return (AE_BAD_SIGNATURE);
    429     }
    430 
    431     /* Validate table length against bytes remaining in the file */
    432 
    433     FileSize = CmGetFileSize (File);
    434     if (TableHeader.Length > (UINT32) (FileSize - TableOffset))
    435     {
    436         fprintf (stderr, "Table [%4.4s] is too long for file - "
    437             "needs: 0x%.2X, remaining in file: 0x%.2X\n",
    438             TableHeader.Signature, TableHeader.Length,
    439             (UINT32) (FileSize - TableOffset));
    440         return (AE_BAD_HEADER);
    441     }
    442 
    443     /*
    444      * These fields must be ASCII: OemId, OemTableId, AslCompilerId.
    445      * We allow a NULL terminator in OemId and OemTableId.
    446      */
    447     for (i = 0; i < ACPI_NAME_SIZE; i++)
    448     {
    449         if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i]))
    450         {
    451             goto BadCharacters;
    452         }
    453     }
    454 
    455     for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++)
    456     {
    457         if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i]))
    458         {
    459             goto BadCharacters;
    460         }
    461     }
    462 
    463     for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++)
    464     {
    465         if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i]))
    466         {
    467             goto BadCharacters;
    468         }
    469     }
    470 
    471     return (AE_OK);
    472 
    473 
    474 BadCharacters:
    475 
    476     ACPI_WARNING ((AE_INFO,
    477         "Table header for [%4.4s] has invalid ASCII character(s)",
    478         TableHeader.Signature));
    479     return (AE_OK);
    480 }
    481 
    482 
    483 /*******************************************************************************
    484  *
    485  * FUNCTION:    AcCheckTextModeCorruption
    486  *
    487  * PARAMETERS:  Table           - Table buffer starting with table header
    488  *
    489  * RETURN:      Status
    490  *
    491  * DESCRIPTION: Check table for text mode file corruption where all linefeed
    492  *              characters (LF) have been replaced by carriage return linefeed
    493  *              pairs (CR/LF).
    494  *
    495  ******************************************************************************/
    496 
    497 static ACPI_STATUS
    498 AcCheckTextModeCorruption (
    499     ACPI_TABLE_HEADER       *Table)
    500 {
    501     UINT32                  i;
    502     UINT32                  Pairs = 0;
    503     UINT8                   *Buffer = ACPI_CAST_PTR (UINT8, Table);
    504 
    505 
    506     /* Scan entire table to determine if each LF has been prefixed with a CR */
    507 
    508     for (i = 1; i < Table->Length; i++)
    509     {
    510         if (Buffer[i] == 0x0A)
    511         {
    512             if (Buffer[i - 1] != 0x0D)
    513             {
    514                 /* The LF does not have a preceding CR, table not corrupted */
    515 
    516                 return (AE_OK);
    517             }
    518             else
    519             {
    520                 /* Found a CR/LF pair */
    521 
    522                 Pairs++;
    523             }
    524 
    525             i++;
    526         }
    527     }
    528 
    529     if (!Pairs)
    530     {
    531         return (AE_OK);
    532     }
    533 
    534     /*
    535      * Entire table scanned, each CR is part of a CR/LF pair --
    536      * meaning that the table was treated as a text file somewhere.
    537      *
    538      * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the
    539      * original table are left untouched by the text conversion process --
    540      * meaning that we cannot simply replace CR/LF pairs with LFs.
    541      */
    542     AcpiOsPrintf ("Table has been corrupted by text mode conversion\n");
    543     AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs);
    544     AcpiOsPrintf ("Table cannot be repaired!\n");
    545 
    546     return (AE_BAD_VALUE);
    547 }
    548