acfileio.c revision 306536
157429Smarkm/****************************************************************************** 257429Smarkm * 357429Smarkm * Module Name: acfileio - Get ACPI tables from file 457429Smarkm * 557429Smarkm *****************************************************************************/ 665674Skris 765674Skris/* 865674Skris * Copyright (C) 2000 - 2016, Intel Corp. 965674Skris * All rights reserved. 1065674Skris * 1157429Smarkm * Redistribution and use in source and binary forms, with or without 1276262Sgreen * modification, are permitted provided that the following conditions 1376262Sgreen * are met: 1476262Sgreen * 1. Redistributions of source code must retain the above copyright 1565674Skris * notice, this list of conditions, and the following disclaimer, 1665674Skris * without modification. 1765674Skris * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1865674Skris * substantially similar to the "NO WARRANTY" disclaimer below 1965674Skris * ("Disclaimer") and any redistribution must be conditioned upon 2065674Skris * including a substantially similar Disclaimer requirement for further 2165674Skris * binary redistribution. 2265674Skris * 3. Neither the names of the above-listed copyright holders nor the names 2365674Skris * of any contributors may be used to endorse or promote products derived 2465674Skris * from this software without specific prior written permission. 2565674Skris * 2665674Skris * Alternatively, this software may be distributed under the terms of the 2765674Skris * GNU General Public License ("GPL") version 2 as published by the Free 2865674Skris * Software Foundation. 2965674Skris * 3065674Skris * NO WARRANTY 3165674Skris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3265674Skris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3365674Skris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3465674Skris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3565674Skris * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36263970Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3799050Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38263970Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3957429Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4057429Smarkm * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4157429Smarkm * POSSIBILITY OF SUCH DAMAGES. 4257429Smarkm */ 4376262Sgreen 4457429Smarkm#include <contrib/dev/acpica/include/acpi.h> 4557429Smarkm#include <contrib/dev/acpica/include/accommon.h> 46113911Sdes#include <contrib/dev/acpica/include/acapps.h> 47181111Sdes#include <contrib/dev/acpica/include/actables.h> 4857429Smarkm#include <contrib/dev/acpica/include/acutils.h> 49181111Sdes#include <errno.h> 50204917Sdes 51263970Sdes#define _COMPONENT ACPI_UTILITIES 5257429Smarkm ACPI_MODULE_NAME ("acfileio") 5357429Smarkm 5457429Smarkm 5557429Smarkm/* Local prototypes */ 5692559Sdes 5757429Smarkmstatic ACPI_STATUS 5865674SkrisAcGetOneTableFromFile ( 59113911Sdes char *Filename, 6060576Skris FILE *File, 6157429Smarkm UINT8 GetOnlyAmlTables, 62157019Sdes ACPI_TABLE_HEADER **Table); 6357429Smarkm 64181111Sdesstatic ACPI_STATUS 65181111SdesAcCheckTextModeCorruption ( 66181111Sdes ACPI_TABLE_HEADER *Table); 67181111Sdes 68181111Sdes 6958585Skris/******************************************************************************* 7057429Smarkm * 7157429Smarkm * FUNCTION: AcGetAllTablesFromFile 72157019Sdes * 7392559Sdes * PARAMETERS: Filename - Table filename 7499050Sdes * GetOnlyAmlTables - TRUE if the tables must be AML tables 7557429Smarkm * ReturnListHead - Where table list is returned 7658585Skris * 7758585Skris * RETURN: Status 7857429Smarkm * 7957429Smarkm * DESCRIPTION: Get all ACPI tables from within a single file. 8057429Smarkm * 8157429Smarkm ******************************************************************************/ 82126277Sdes 83126277SdesACPI_STATUS 84157019SdesAcGetAllTablesFromFile ( 85157019Sdes char *Filename, 8657429Smarkm UINT8 GetOnlyAmlTables, 8757429Smarkm ACPI_NEW_TABLE_DESC **ReturnListHead) 8857429Smarkm{ 8976262Sgreen ACPI_NEW_TABLE_DESC *ListHead = NULL; 90162856Sdes ACPI_NEW_TABLE_DESC *ListTail = NULL; 9176262Sgreen ACPI_NEW_TABLE_DESC *TableDesc; 9257429Smarkm FILE *File; 9357429Smarkm ACPI_TABLE_HEADER *Table = NULL; 9457429Smarkm UINT32 FileSize; 95126277Sdes ACPI_STATUS Status = AE_OK; 96126277Sdes 97126277Sdes 98126277Sdes File = fopen (Filename, "rb"); 99126277Sdes if (!File) 100126277Sdes { 101126277Sdes perror ("Could not open input file"); 102126277Sdes if (errno == ENOENT) 10357429Smarkm { 10476262Sgreen return (AE_NOT_EXIST); 105181111Sdes } 106181111Sdes 107181111Sdes return (AE_ERROR); 108181111Sdes } 109181111Sdes 110181111Sdes /* Get the file size */ 111181111Sdes 112181111Sdes FileSize = CmGetFileSize (File); 113181111Sdes if (FileSize == ACPI_UINT32_MAX) 114181111Sdes { 115181111Sdes Status = AE_ERROR; 116181111Sdes goto ErrorExit; 117181111Sdes } 118181111Sdes 119247485Sdes fprintf (stderr, 120247485Sdes "Input file %s, Length 0x%X (%u) bytes\n", 121181111Sdes Filename, FileSize, FileSize); 122181111Sdes 123181111Sdes /* We must have at least one ACPI table header */ 124181111Sdes 125181111Sdes if (FileSize < sizeof (ACPI_TABLE_HEADER)) 126204917Sdes { 127204917Sdes Status = AE_BAD_HEADER; 128204917Sdes goto ErrorExit; 129204917Sdes } 130204917Sdes 131204917Sdes /* Check for an non-binary file */ 132204917Sdes 133204917Sdes if (!AcIsFileBinary (File)) 134204917Sdes { 135126277Sdes fprintf (stderr, 136126277Sdes " %s: File does not appear to contain a valid AML table\n", 137126277Sdes Filename); 138126277Sdes return (AE_TYPE); 139126277Sdes } 140126277Sdes 14157429Smarkm /* Read all tables within the file */ 14258585Skris 143204917Sdes while (ACPI_SUCCESS (Status)) 144204917Sdes { 14558585Skris /* Get one entire ACPI table */ 14658585Skris 147113911Sdes Status = AcGetOneTableFromFile ( 148113911Sdes Filename, File, GetOnlyAmlTables, &Table); 149113911Sdes 15069591Sgreen if (Status == AE_CTRL_TERMINATE) 151263970Sdes { 152263970Sdes Status = AE_OK; 153263970Sdes break; 154263970Sdes } 15576262Sgreen else if (Status == AE_TYPE) 156263970Sdes { 157181111Sdes return (AE_OK); 15858585Skris } 15958585Skris else if (ACPI_FAILURE (Status)) 16057811Skris { 16157429Smarkm goto ErrorExit; 16257429Smarkm } 16357429Smarkm 16457429Smarkm /* Print table header for iASL/disassembler only */ 165106130Sdes 16658585Skris#ifdef ACPI_ASL_COMPILER 16758585Skris 16858585Skris AcpiTbPrintTableHeader (0, Table); 16957429Smarkm#endif 17092559Sdes 17157429Smarkm /* Allocate and link a table descriptor */ 17257429Smarkm 17357429Smarkm TableDesc = AcpiOsAllocate (sizeof (ACPI_NEW_TABLE_DESC)); 17492559Sdes TableDesc->Table = Table; 17592559Sdes TableDesc->Next = NULL; 17692559Sdes 17792559Sdes /* Link at the end of the local table list */ 178221420Sdes 179263970Sdes if (!ListHead) 180263970Sdes { 181221420Sdes ListHead = TableDesc; 182181111Sdes ListTail = TableDesc; 18392559Sdes } 18476262Sgreen else 18576262Sgreen { 18657429Smarkm ListTail->Next = TableDesc; 18757429Smarkm ListTail = TableDesc; 18857429Smarkm } 189113911Sdes } 190113911Sdes 19157429Smarkm /* Add the local table list to the end of the global list */ 19257429Smarkm 19357429Smarkm if (*ReturnListHead) 19458585Skris { 19558585Skris ListTail = *ReturnListHead; 196162856Sdes while (ListTail->Next) 19757429Smarkm { 19857429Smarkm ListTail = ListTail->Next; 19957429Smarkm } 20057429Smarkm 20176262Sgreen ListTail->Next = ListHead; 20276262Sgreen } 20358585Skris else 204126277Sdes { 20557429Smarkm *ReturnListHead = ListHead; 20657429Smarkm } 20758585Skris 20858585SkrisErrorExit: 20992559Sdes fclose(File); 21092559Sdes return (Status); 21192559Sdes} 21292559Sdes 213126277Sdes 214126277Sdes/******************************************************************************* 21557429Smarkm * 21657429Smarkm * FUNCTION: AcGetOneTableFromFile 21757429Smarkm * 21892559Sdes * PARAMETERS: Filename - File where table is located 219157019Sdes * File - Open FILE pointer to Filename 220157019Sdes * GetOnlyAmlTables - TRUE if the tables must be AML tables. 221157019Sdes * ReturnTable - Where a pointer to the table is returned 222157019Sdes * 223157019Sdes * RETURN: Status 224157019Sdes * 22557429Smarkm * DESCRIPTION: Read the next ACPI table from a file. Implements support 22658585Skris * for multiple tables within a single file. File must already 22758585Skris * be open. 22858585Skris * 22957429Smarkm * Note: Loading an RSDP is not supported. 230181111Sdes * 231181111Sdes ******************************************************************************/ 232181111Sdes 233181111Sdesstatic ACPI_STATUS 234181111SdesAcGetOneTableFromFile ( 235181111Sdes char *Filename, 236181111Sdes FILE *File, 237181111Sdes UINT8 GetOnlyAmlTables, 238181111Sdes ACPI_TABLE_HEADER **ReturnTable) 23992559Sdes{ 24092559Sdes ACPI_STATUS Status = AE_OK; 24192559Sdes ACPI_TABLE_HEADER TableHeader; 24292559Sdes ACPI_TABLE_HEADER *Table; 24392559Sdes INT32 Count; 24492559Sdes long TableOffset; 24565674Skris 24665674Skris 24765674Skris *ReturnTable = NULL; 24865674Skris 24965674Skris /* Get the table header to examine signature and length */ 25065674Skris 25165674Skris TableOffset = ftell (File); 25265674Skris Count = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File); 25365674Skris if (Count != sizeof (ACPI_TABLE_HEADER)) 25465674Skris { 25565674Skris return (AE_CTRL_TERMINATE); 25665674Skris } 25765674Skris 25865674Skris /* Validate the table signature/header (limited ASCII chars) */ 25965674Skris 26065674Skris Status = AcValidateTableHeader (File, TableOffset); 26192559Sdes if (ACPI_FAILURE (Status)) 262113911Sdes { 26392559Sdes return (Status); 26492559Sdes } 26592559Sdes 26692559Sdes if (GetOnlyAmlTables) 26792559Sdes { 268157019Sdes /* Table must be an AML table (DSDT/SSDT) or FADT */ 26992559Sdes 27092559Sdes if (!ACPI_COMPARE_NAME (TableHeader.Signature, ACPI_SIG_FADT) && 27192559Sdes !AcpiUtIsAmlTable (&TableHeader)) 27292559Sdes { 27392559Sdes fprintf (stderr, 27492559Sdes " %s: Table [%4.4s] is not an AML table - ignoring\n", 27592559Sdes Filename, TableHeader.Signature); 27692559Sdes 27757429Smarkm return (AE_TYPE); 278157019Sdes } 279157019Sdes } 280204917Sdes 281157019Sdes /* Allocate a buffer for the entire table */ 282157019Sdes 283157019Sdes Table = AcpiOsAllocate ((size_t) TableHeader.Length); 28498706Sdes if (!Table) 285263970Sdes { 286157019Sdes return (AE_NO_MEMORY); 287157019Sdes } 288157019Sdes 289157019Sdes /* Read the entire ACPI table, including header */ 290157019Sdes 291157019Sdes fseek (File, TableOffset, SEEK_SET); 292157019Sdes 293157019Sdes Count = fread (Table, 1, TableHeader.Length, File); 294157019Sdes if (Count != (INT32) TableHeader.Length) 295157019Sdes { 296157019Sdes Status = AE_ERROR; 297157019Sdes goto ErrorExit; 298157019Sdes } 299157019Sdes 300157019Sdes /* Validate the checksum (just issue a warning) */ 301157019Sdes 302157019Sdes Status = AcpiTbVerifyChecksum (Table, TableHeader.Length); 303157019Sdes if (ACPI_FAILURE (Status)) 304157019Sdes { 305157019Sdes Status = AcCheckTextModeCorruption (Table); 306157019Sdes if (ACPI_FAILURE (Status)) 307157019Sdes { 308157019Sdes goto ErrorExit; 309157019Sdes } 310157019Sdes } 311157019Sdes 312157019Sdes *ReturnTable = Table; 313157019Sdes return (AE_OK); 314157019Sdes 315157019Sdes 316157019SdesErrorExit: 317157019Sdes AcpiOsFree (Table); 318157019Sdes return (Status); 319157019Sdes} 320157019Sdes 321157019Sdes 322157019Sdes/******************************************************************************* 323157019Sdes * 324251135Sdes * FUNCTION: AcIsFileBinary 325247485Sdes * 326157019Sdes * PARAMETERS: File - Open input file 327157019Sdes * 328157019Sdes * RETURN: TRUE if file appears to be binary 329157019Sdes * 330157019Sdes * DESCRIPTION: Scan a file for any non-ASCII bytes. 331157019Sdes * 332157019Sdes * Note: Maintains current file position. 333157019Sdes * 334157019Sdes ******************************************************************************/ 335157019Sdes 336157019SdesBOOLEAN 337157019SdesAcIsFileBinary ( 338157019Sdes FILE *File) 339157019Sdes{ 340157019Sdes UINT8 Byte; 341157019Sdes BOOLEAN IsBinary = FALSE; 342157019Sdes long FileOffset; 343157019Sdes 344157019Sdes 345157019Sdes /* Scan entire file for any non-ASCII bytes */ 346157019Sdes 347157019Sdes FileOffset = ftell (File); 348157019Sdes while (fread (&Byte, 1, 1, File) == 1) 349157019Sdes { 350157019Sdes if (!isprint (Byte) && !isspace (Byte)) 351181111Sdes { 352181111Sdes IsBinary = TRUE; 353181111Sdes goto Exit; 354157019Sdes } 355157019Sdes } 356157019Sdes 357157019SdesExit: 358157019Sdes fseek (File, FileOffset, SEEK_SET); 359157019Sdes return (IsBinary); 360157019Sdes} 361157019Sdes 362157019Sdes 363157019Sdes/******************************************************************************* 364157019Sdes * 365157019Sdes * FUNCTION: AcValidateTableHeader 366157019Sdes * 367157019Sdes * PARAMETERS: File - Open input file 368162856Sdes * 369157019Sdes * RETURN: Status 370157019Sdes * 371157019Sdes * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI 372157019Sdes * tables, via the 373157019Sdes * following checks on what would be the table header: 374157019Sdes * 1) File must be at least as long as an ACPI_TABLE_HEADER 375157019Sdes * 2) There must be enough room in the file to hold entire table 376157019Sdes * 3) Signature, OemId, OemTableId, AslCompilerId must be ASCII 37757429Smarkm * 37857429Smarkm * Note: There can be multiple definition blocks per file, so we cannot 37957429Smarkm * expect/compare the file size to be equal to the table length. 12/2015. 38057429Smarkm * 38157429Smarkm * Note: Maintains current file position. 38257429Smarkm * 38357429Smarkm ******************************************************************************/ 38460576Skris 38557429SmarkmACPI_STATUS 38657429SmarkmAcValidateTableHeader ( 387149753Sdes FILE *File, 38857429Smarkm long TableOffset) 38960576Skris{ 39057429Smarkm ACPI_TABLE_HEADER TableHeader; 39157429Smarkm size_t Actual; 39257429Smarkm long OriginalOffset; 39357429Smarkm UINT32 FileSize; 39457429Smarkm UINT32 i; 39599050Sdes 39699050Sdes 39799050Sdes ACPI_FUNCTION_TRACE ("AcValidateTableHeader"); 39857429Smarkm 39957429Smarkm 40057429Smarkm /* Read a potential table header */ 40157429Smarkm 40257429Smarkm OriginalOffset = ftell (File); 40357429Smarkm fseek (File, TableOffset, SEEK_SET); 404126277Sdes 405149753Sdes Actual = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File); 406126277Sdes fseek (File, OriginalOffset, SEEK_SET); 407106130Sdes 408106130Sdes if (Actual < sizeof (ACPI_TABLE_HEADER)) 409106130Sdes { 410106130Sdes return (AE_ERROR); 41157429Smarkm } 41257429Smarkm 41357429Smarkm /* Validate the signature (limited ASCII chars) */ 41457429Smarkm 415149753Sdes if (!AcpiUtValidNameseg (TableHeader.Signature)) 41657429Smarkm { 41757811Skris fprintf (stderr, "Invalid table signature: 0x%8.8X\n", 41857429Smarkm *ACPI_CAST_PTR (UINT32, TableHeader.Signature)); 41999050Sdes return (AE_BAD_SIGNATURE); 42099050Sdes } 42157952Skris 42257429Smarkm /* Validate table length against bytes remaining in the file */ 42357429Smarkm 424162856Sdes FileSize = CmGetFileSize (File); 425162856Sdes if (TableHeader.Length > (UINT32) (FileSize - TableOffset)) 426162856Sdes { 427162856Sdes fprintf (stderr, "Table [%4.4s] is too long for file - " 42857429Smarkm "needs: 0x%.2X, remaining in file: 0x%.2X\n", 42957429Smarkm TableHeader.Signature, TableHeader.Length, 43057429Smarkm (UINT32) (FileSize - TableOffset)); 431162856Sdes return (AE_BAD_HEADER); 432162856Sdes } 433162856Sdes 434162856Sdes /* 435162856Sdes * These fields must be ASCII: OemId, OemTableId, AslCompilerId. 436162856Sdes * We allow a NULL terminator in OemId and OemTableId. 437162856Sdes */ 438162856Sdes for (i = 0; i < ACPI_NAME_SIZE; i++) 439162856Sdes { 440162856Sdes if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i])) 441162856Sdes { 442162856Sdes goto BadCharacters; 443162856Sdes } 444162856Sdes } 445162856Sdes 446162856Sdes for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++) 447162856Sdes { 448162856Sdes if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i])) 449162856Sdes { 450162856Sdes goto BadCharacters; 451162856Sdes } 452162856Sdes } 453162856Sdes 454162856Sdes for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++) 455162856Sdes { 456162856Sdes if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i])) 457162856Sdes { 458162856Sdes goto BadCharacters; 459162856Sdes } 460162856Sdes } 461162856Sdes 462162856Sdes return (AE_OK); 463162856Sdes 464162856Sdes 465162856SdesBadCharacters: 466162856Sdes 467162856Sdes ACPI_WARNING ((AE_INFO, 468162856Sdes "Table header for [%4.4s] has invalid ASCII character(s)", 469162856Sdes TableHeader.Signature)); 470162856Sdes return (AE_OK); 471162856Sdes} 472162856Sdes 47357429Smarkm 47492559Sdes/******************************************************************************* 475247485Sdes * 476162856Sdes * FUNCTION: AcCheckTextModeCorruption 477162856Sdes * 478247485Sdes * PARAMETERS: Table - Table buffer starting with table header 479247485Sdes * 480247485Sdes * RETURN: Status 48158585Skris * 48257429Smarkm * DESCRIPTION: Check table for text mode file corruption where all linefeed 48357429Smarkm * characters (LF) have been replaced by carriage return linefeed 48457429Smarkm * pairs (CR/LF). 48558585Skris * 486162856Sdes ******************************************************************************/ 487162856Sdes 488162856Sdesstatic ACPI_STATUS 489162856SdesAcCheckTextModeCorruption ( 490162856Sdes ACPI_TABLE_HEADER *Table) 491162856Sdes{ 492106130Sdes UINT32 i; 493162856Sdes UINT32 Pairs = 0; 49476262Sgreen UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table); 49557429Smarkm 49657429Smarkm 49776262Sgreen /* Scan entire table to determine if each LF has been prefixed with a CR */ 498221420Sdes 499221420Sdes for (i = 1; i < Table->Length; i++) 500221420Sdes { 501263970Sdes if (Buffer[i] == 0x0A) 50276262Sgreen { 50376262Sgreen if (Buffer[i - 1] != 0x0D) 50476262Sgreen { 50557429Smarkm /* The LF does not have a preceding CR, table not corrupted */ 50657429Smarkm 507147005Sdes return (AE_OK); 508147005Sdes } 509147005Sdes else 51058585Skris { 51176262Sgreen /* Found a CR/LF pair */ 512162856Sdes 513221420Sdes Pairs++; 514263970Sdes } 51576262Sgreen 51676262Sgreen i++; 51757429Smarkm } 51857429Smarkm } 51998706Sdes 52098706Sdes if (!Pairs) 52198706Sdes { 52298706Sdes return (AE_OK); 52365674Skris } 52458585Skris 52558585Skris /* 52692559Sdes * Entire table scanned, each CR is part of a CR/LF pair -- 52792559Sdes * meaning that the table was treated as a text file somewhere. 52857429Smarkm * 529204917Sdes * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the 530204917Sdes * original table are left untouched by the text conversion process -- 531204917Sdes * meaning that we cannot simply replace CR/LF pairs with LFs. 532204917Sdes */ 533204917Sdes AcpiOsPrintf ("Table has been corrupted by text mode conversion\n"); 534204917Sdes AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs); 535204917Sdes AcpiOsPrintf ("Table cannot be repaired!\n"); 53657429Smarkm 53757429Smarkm return (AE_BAD_VALUE); 53858585Skris} 53958585Skris