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