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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/actables.h> 47 #include <contrib/dev/acpica/include/acutils.h> 48 #include <contrib/dev/acpica/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