1 /****************************************************************************** 2 * 3 * Module Name: acfileio - Get ACPI tables from file 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2026, 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 MERCHANTABILITY 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: AcDeleteTableList 71 * 72 * PARAMETERS: ListHead - List to delete 73 * 74 * RETURN: Status 75 * 76 * DESCRIPTION: Delete a list of tables. This is useful for removing memory 77 * allocated by AcGetAllTablesFromFile 78 * 79 ******************************************************************************/ 80 81 void 82 AcDeleteTableList ( 83 ACPI_NEW_TABLE_DESC *ListHead) 84 { 85 ACPI_NEW_TABLE_DESC *Current = ListHead; 86 ACPI_NEW_TABLE_DESC *Previous = Current; 87 88 89 while (Current) 90 { 91 Current = Current->Next; 92 AcpiOsFree (Previous); 93 Previous = Current; 94 } 95 } 96 97 98 /******************************************************************************* 99 * 100 * FUNCTION: AcGetAllTablesFromFile 101 * 102 * PARAMETERS: Filename - Table filename 103 * GetOnlyAmlTables - TRUE if the tables must be AML tables 104 * ReturnListHead - Where table list is returned 105 * 106 * RETURN: Status 107 * 108 * DESCRIPTION: Get all ACPI tables from within a single file. 109 * 110 ******************************************************************************/ 111 112 ACPI_STATUS 113 AcGetAllTablesFromFile ( 114 char *Filename, 115 UINT8 GetOnlyAmlTables, 116 ACPI_NEW_TABLE_DESC **ReturnListHead) 117 { 118 ACPI_NEW_TABLE_DESC *ListHead = NULL; 119 ACPI_NEW_TABLE_DESC *ListTail = NULL; 120 ACPI_NEW_TABLE_DESC *TableDesc; 121 FILE *File; 122 ACPI_TABLE_HEADER *Table = NULL; 123 UINT32 FileSize; 124 ACPI_STATUS Status = AE_OK; 125 126 127 File = fopen (Filename, "rb"); 128 if (!File) 129 { 130 fprintf (stderr, "Could not open input file: %s\n", Filename); 131 if (errno == ENOENT) 132 { 133 return (AE_NOT_EXIST); 134 } 135 136 return (AE_ERROR); 137 } 138 139 /* Get the file size */ 140 141 FileSize = CmGetFileSize (File); 142 if (FileSize == ACPI_UINT32_MAX) 143 { 144 Status = AE_ERROR; 145 goto Exit; 146 } 147 148 fprintf (stderr, 149 "Input file %s, Length 0x%X (%u) bytes\n", 150 Filename, FileSize, FileSize); 151 152 /* We must have at least one ACPI table header */ 153 154 if (FileSize < sizeof (ACPI_TABLE_HEADER)) 155 { 156 Status = AE_BAD_HEADER; 157 goto Exit; 158 } 159 160 /* Check for an non-binary file */ 161 162 if (!AcIsFileBinary (File)) 163 { 164 fprintf (stderr, 165 " %s: File does not appear to contain a valid AML table\n", 166 Filename); 167 Status = AE_TYPE; 168 goto Exit; 169 } 170 171 /* Read all tables within the file */ 172 173 while (ACPI_SUCCESS (Status)) 174 { 175 /* Get one entire ACPI table */ 176 177 Status = AcGetOneTableFromFile ( 178 Filename, File, GetOnlyAmlTables, &Table); 179 180 if (Status == AE_CTRL_TERMINATE) 181 { 182 Status = AE_OK; 183 break; 184 } 185 else if (Status == AE_TYPE) 186 { 187 Status = AE_OK; 188 goto Exit; 189 } 190 else if (ACPI_FAILURE (Status)) 191 { 192 goto Exit; 193 } 194 195 /* Print table header for iASL/disassembler only */ 196 197 #ifdef ACPI_ASL_COMPILER 198 199 AcpiTbPrintTableHeader (0, Table); 200 #endif 201 202 /* Allocate and link a table descriptor */ 203 204 TableDesc = AcpiOsAllocate (sizeof (ACPI_NEW_TABLE_DESC)); 205 if (!TableDesc) 206 { 207 AcpiOsFree (Table); 208 Status = AE_NO_MEMORY; 209 goto Exit; 210 } 211 212 TableDesc->Table = Table; 213 TableDesc->Next = NULL; 214 215 /* Link at the end of the local table list */ 216 217 if (!ListHead) 218 { 219 ListHead = TableDesc; 220 ListTail = TableDesc; 221 } 222 else 223 { 224 ListTail->Next = TableDesc; 225 ListTail = TableDesc; 226 } 227 } 228 229 /* Add the local table list to the end of the global list */ 230 231 if (*ReturnListHead) 232 { 233 ListTail = *ReturnListHead; 234 while (ListTail->Next) 235 { 236 ListTail = ListTail->Next; 237 } 238 239 ListTail->Next = ListHead; 240 } 241 else 242 { 243 *ReturnListHead = ListHead; 244 } 245 246 Exit: 247 fclose(File); 248 return (Status); 249 } 250 251 252 /******************************************************************************* 253 * 254 * FUNCTION: AcGetOneTableFromFile 255 * 256 * PARAMETERS: Filename - File where table is located 257 * File - Open FILE pointer to Filename 258 * GetOnlyAmlTables - TRUE if the tables must be AML tables. 259 * ReturnTable - Where a pointer to the table is returned 260 * 261 * RETURN: Status 262 * 263 * DESCRIPTION: Read the next ACPI table from a file. Implements support 264 * for multiple tables within a single file. File must already 265 * be open. 266 * 267 * Note: Loading an RSDP is not supported. 268 * 269 ******************************************************************************/ 270 271 static ACPI_STATUS 272 AcGetOneTableFromFile ( 273 char *Filename, 274 FILE *File, 275 UINT8 GetOnlyAmlTables, 276 ACPI_TABLE_HEADER **ReturnTable) 277 { 278 ACPI_STATUS Status = AE_OK; 279 ACPI_TABLE_HEADER TableHeader; 280 ACPI_TABLE_HEADER *Table; 281 INT32 Count; 282 UINT32 TableLength; 283 UINT32 HeaderLength; 284 long TableOffset = 0; 285 286 *ReturnTable = NULL; 287 288 /* Get the table header to examine signature and length */ 289 /* 290 * Special handling for the CDAT table (both the Length field 291 * and the Checksum field are not in the standard positions). 292 * (The table header is non-standard). 293 */ 294 if (AcpiGbl_CDAT) 295 { 296 HeaderLength = sizeof (ACPI_TABLE_CDAT); 297 } 298 else 299 { 300 HeaderLength = sizeof (ACPI_TABLE_HEADER); 301 } 302 303 Status = AcValidateTableHeader (File, TableOffset); 304 if (ACPI_FAILURE (Status)) 305 { 306 return (Status); 307 } 308 309 TableOffset = ftell (File); 310 Count = fread (&TableHeader, 1, HeaderLength, File); 311 if (Count != (INT32) HeaderLength) 312 { 313 return (AE_CTRL_TERMINATE); 314 } 315 316 if (GetOnlyAmlTables) 317 { 318 /* Validate the table signature/header (limited ASCII chars) */ 319 320 /* 321 * Table must be an AML table (DSDT/SSDT). 322 * Used for iASL -e option only. 323 */ 324 if (!AcpiUtIsAmlTable (&TableHeader)) 325 { 326 fprintf (stderr, 327 " %s: Table [%4.4s] is not an AML table - ignoring\n", 328 Filename, TableHeader.Signature); 329 330 return (AE_TYPE); 331 } 332 } 333 334 /* 335 * Special handling for the CDAT table (both the Length field 336 * and the Checksum field are not in the standard positions). 337 */ 338 if (AcpiGbl_CDAT) 339 { 340 TableLength = ACPI_CAST_PTR (ACPI_TABLE_CDAT, &TableHeader)->Length; 341 } 342 else 343 { 344 TableLength = TableHeader.Length; 345 } 346 347 /* Table length must be at least large enough to hold the header */ 348 349 if (TableLength < HeaderLength) 350 { 351 fprintf (stderr, "Table length too small for header: 0x%.2X\n", 352 TableLength); 353 return (AE_BAD_HEADER); 354 } 355 356 /* Allocate a buffer for the entire table */ 357 358 Table = AcpiOsAllocate ((ACPI_SIZE) TableLength); 359 if (!Table) 360 { 361 return (AE_NO_MEMORY); 362 } 363 364 /* Read the entire ACPI table, including header */ 365 366 fseek (File, TableOffset, SEEK_SET); 367 Count = fread (Table, 1, TableLength, File); 368 369 /* 370 * Checks for data table headers happen later in the execution. Only verify 371 * for Aml tables at this point in the code. 372 */ 373 if (GetOnlyAmlTables && Count != (INT32) TableLength) 374 { 375 Status = AE_ERROR; 376 goto ErrorExit; 377 } 378 379 /* 380 * Validate the checksum (just issue a warning if incorrect). 381 * Note: CDAT is special cased here because the table does 382 * not have the checksum field in the standard position. 383 */ 384 if (AcpiGbl_CDAT) 385 { 386 Status = AcpiUtVerifyCdatChecksum ((ACPI_TABLE_CDAT *) Table, TableLength); 387 } else 388 { 389 Status = AcpiUtVerifyChecksum (Table, TableLength); 390 } 391 392 if (ACPI_FAILURE (Status)) 393 { 394 Status = AcCheckTextModeCorruption (Table); 395 if (ACPI_FAILURE (Status)) 396 { 397 goto ErrorExit; 398 } 399 } 400 401 *ReturnTable = Table; 402 return (AE_OK); 403 404 405 ErrorExit: 406 AcpiOsFree (Table); 407 return (Status); 408 } 409 410 411 /******************************************************************************* 412 * 413 * FUNCTION: AcIsFileBinary 414 * 415 * PARAMETERS: File - Open input file 416 * 417 * RETURN: TRUE if file appears to be binary 418 * 419 * DESCRIPTION: Scan a file for any non-ASCII bytes. 420 * 421 * Note: Maintains current file position. 422 * 423 ******************************************************************************/ 424 425 BOOLEAN 426 AcIsFileBinary ( 427 FILE *File) 428 { 429 UINT8 Byte; 430 BOOLEAN IsBinary = FALSE; 431 long FileOffset; 432 433 434 /* Scan entire file for any non-ASCII bytes */ 435 436 FileOffset = ftell (File); 437 while (fread (&Byte, 1, 1, File) == 1) 438 { 439 if (!isprint (Byte) && !isspace (Byte)) 440 { 441 IsBinary = TRUE; 442 goto Exit; 443 } 444 } 445 446 Exit: 447 fseek (File, FileOffset, SEEK_SET); 448 return (IsBinary); 449 } 450 451 452 /******************************************************************************* 453 * 454 * FUNCTION: AcValidateTableHeader 455 * 456 * PARAMETERS: File - Open input file 457 * 458 * RETURN: Status 459 * 460 * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI 461 * tables, via the 462 * following checks on what would be the table header: 463 * 1) File must be at least as long as an ACPI_TABLE_HEADER 464 * 2) There must be enough room in the file to hold entire table 465 * 3) Signature, OemId, OemTableId, AslCompilerId must be ASCII 466 * 467 * Note: There can be multiple definition blocks per file, so we cannot 468 * expect/compare the file size to be equal to the table length. 12/2015. 469 * 470 * Note: Maintains current file position. 471 * 472 ******************************************************************************/ 473 474 ACPI_STATUS 475 AcValidateTableHeader ( 476 FILE *File, 477 long TableOffset) 478 { 479 ACPI_TABLE_HEADER TableHeader; 480 ACPI_TABLE_CDAT *CdatTableHeader = ACPI_CAST_PTR (ACPI_TABLE_CDAT, &TableHeader); 481 UINT32 HeaderLength; 482 ACPI_SIZE Actual; 483 long OriginalOffset; 484 UINT32 FileSize; 485 UINT32 i; 486 487 488 ACPI_FUNCTION_TRACE (AcValidateTableHeader); 489 490 /* Determine the type of table header */ 491 492 if (AcpiGbl_CDAT) 493 { 494 HeaderLength = sizeof (ACPI_TABLE_CDAT); 495 } 496 else 497 { 498 HeaderLength = sizeof (ACPI_TABLE_HEADER); 499 } 500 501 /* Read a potential table header */ 502 503 OriginalOffset = ftell (File); 504 if (fseek (File, TableOffset, SEEK_SET)) 505 { 506 fprintf (stderr, "SEEK error\n"); 507 } 508 Actual = fread (&TableHeader, 1, HeaderLength, File); 509 if (fseek (File, OriginalOffset, SEEK_SET)) 510 { 511 fprintf (stderr, "SEEK error\n"); 512 } 513 514 if (Actual < HeaderLength) 515 { 516 fprintf (stderr, 517 "Could not read entire table header: Actual %u, Requested %u\n", 518 (UINT32) Actual, HeaderLength); 519 return (AE_ERROR); 520 } 521 522 /* Validate the signature (limited ASCII chars) */ 523 524 if (!AcpiGbl_CDAT && !AcpiUtValidNameseg (TableHeader.Signature)) 525 { 526 /* 527 * The "-ds cdat" option was not used, and the signature is not valid. 528 * 529 * For CDAT we are assuming that there should be at least one non-ASCII 530 * byte in the (normally) 4-character Signature field (at least the 531 * high-order byte should be zero). Otherwise, this is OK. 532 */ 533 fprintf (stderr, 534 "\nTable appears to be a CDAT table, which has no signature.\n" 535 "If this is in fact a CDAT table, use the -ds option on the\n" 536 "command line to specify the table type (signature):\n" 537 "\"iasl -d -ds CDAT <file>\" or \"iasl -ds CDAT -T CDAT\"\n\n"); 538 539 return (AE_BAD_SIGNATURE); 540 } 541 542 /* Validate table length against bytes remaining in the file */ 543 544 FileSize = CmGetFileSize (File); 545 if (!AcpiGbl_CDAT) 546 { 547 /* Standard ACPI table header */ 548 549 if (TableHeader.Length > (UINT32) (FileSize - TableOffset)) 550 { 551 fprintf (stderr, "Table [%4.4s] is too long for file - " 552 "needs: 0x%.2X, remaining in file: 0x%.2X\n", 553 TableHeader.Signature, TableHeader.Length, 554 (UINT32) (FileSize - TableOffset)); 555 return (AE_BAD_HEADER); 556 } 557 } 558 else if (CdatTableHeader->Length > (UINT32) (FileSize - TableOffset)) 559 { 560 /* Special header for CDAT table */ 561 562 fprintf (stderr, "Table [CDAT] is too long for file - " 563 "needs: 0x%.2X, remaining in file: 0x%.2X\n", 564 CdatTableHeader->Length, 565 (UINT32) (FileSize - TableOffset)); 566 return (AE_BAD_HEADER); 567 } 568 569 /* For CDAT table, there are no ASCII fields in the header, we are done */ 570 571 if (AcpiGbl_CDAT) 572 { 573 return (AE_OK); 574 } 575 576 /* 577 * These standard fields must be ASCII: OemId, OemTableId, AslCompilerId. 578 * We allow a NULL terminator in OemId and OemTableId. 579 */ 580 for (i = 0; i < ACPI_NAMESEG_SIZE; i++) 581 { 582 if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i])) 583 { 584 goto BadCharacters; 585 } 586 } 587 588 for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++) 589 { 590 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i])) 591 { 592 goto BadCharacters; 593 } 594 } 595 596 for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++) 597 { 598 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i])) 599 { 600 goto BadCharacters; 601 } 602 } 603 604 return (AE_OK); 605 606 607 BadCharacters: 608 609 ACPI_WARNING ((AE_INFO, 610 "Table header for [%4.4s] has invalid ASCII character(s)", 611 TableHeader.Signature)); 612 return (AE_OK); 613 } 614 615 616 /******************************************************************************* 617 * 618 * FUNCTION: AcCheckTextModeCorruption 619 * 620 * PARAMETERS: Table - Table buffer starting with table header 621 * 622 * RETURN: Status 623 * 624 * DESCRIPTION: Check table for text mode file corruption where all linefeed 625 * characters (LF) have been replaced by carriage return linefeed 626 * pairs (CR/LF). 627 * 628 ******************************************************************************/ 629 630 static ACPI_STATUS 631 AcCheckTextModeCorruption ( 632 ACPI_TABLE_HEADER *Table) 633 { 634 UINT32 i; 635 UINT32 Pairs = 0; 636 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table); 637 638 639 /* Scan entire table to determine if each LF has been prefixed with a CR */ 640 641 for (i = 1; i < Table->Length; i++) 642 { 643 if (Buffer[i] == 0x0A) 644 { 645 if (Buffer[i - 1] != 0x0D) 646 { 647 /* The LF does not have a preceding CR, table not corrupted */ 648 649 return (AE_OK); 650 } 651 else 652 { 653 /* Found a CR/LF pair */ 654 655 Pairs++; 656 } 657 658 i++; 659 } 660 } 661 662 if (!Pairs) 663 { 664 return (AE_OK); 665 } 666 667 /* 668 * Entire table scanned, each CR is part of a CR/LF pair -- 669 * meaning that the table was treated as a text file somewhere. 670 * 671 * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the 672 * original table are left untouched by the text conversion process -- 673 * meaning that we cannot simply replace CR/LF pairs with LFs. 674 */ 675 AcpiOsPrintf ("Table has been corrupted by text mode conversion\n"); 676 AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs); 677 AcpiOsPrintf ("Table cannot be repaired!\n"); 678 679 return (AE_BAD_VALUE); 680 } 681