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