1 /******************************************************************************
2 *
3 * Module Name: acfileio - Get ACPI tables from file
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, 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
AcDeleteTableList(ACPI_NEW_TABLE_DESC * ListHead)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
AcGetAllTablesFromFile(char * Filename,UINT8 GetOnlyAmlTables,ACPI_NEW_TABLE_DESC ** ReturnListHead)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
AcGetOneTableFromFile(char * Filename,FILE * File,UINT8 GetOnlyAmlTables,ACPI_TABLE_HEADER ** ReturnTable)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 /* Allocate a buffer for the entire table */
348
349 Table = AcpiOsAllocate ((ACPI_SIZE) TableLength);
350 if (!Table)
351 {
352 return (AE_NO_MEMORY);
353 }
354
355 /* Read the entire ACPI table, including header */
356
357 fseek (File, TableOffset, SEEK_SET);
358 Count = fread (Table, 1, TableLength, File);
359
360 /*
361 * Checks for data table headers happen later in the execution. Only verify
362 * for Aml tables at this point in the code.
363 */
364 if (GetOnlyAmlTables && Count != (INT32) TableLength)
365 {
366 Status = AE_ERROR;
367 goto ErrorExit;
368 }
369
370 /*
371 * Validate the checksum (just issue a warning if incorrect).
372 * Note: CDAT is special cased here because the table does
373 * not have the checksum field in the standard position.
374 */
375 if (AcpiGbl_CDAT)
376 {
377 Status = AcpiUtVerifyCdatChecksum ((ACPI_TABLE_CDAT *) Table, TableLength);
378 } else
379 {
380 Status = AcpiUtVerifyChecksum (Table, TableLength);
381 }
382
383 if (ACPI_FAILURE (Status))
384 {
385 Status = AcCheckTextModeCorruption (Table);
386 if (ACPI_FAILURE (Status))
387 {
388 goto ErrorExit;
389 }
390 }
391
392 *ReturnTable = Table;
393 return (AE_OK);
394
395
396 ErrorExit:
397 AcpiOsFree (Table);
398 return (Status);
399 }
400
401
402 /*******************************************************************************
403 *
404 * FUNCTION: AcIsFileBinary
405 *
406 * PARAMETERS: File - Open input file
407 *
408 * RETURN: TRUE if file appears to be binary
409 *
410 * DESCRIPTION: Scan a file for any non-ASCII bytes.
411 *
412 * Note: Maintains current file position.
413 *
414 ******************************************************************************/
415
416 BOOLEAN
AcIsFileBinary(FILE * File)417 AcIsFileBinary (
418 FILE *File)
419 {
420 UINT8 Byte;
421 BOOLEAN IsBinary = FALSE;
422 long FileOffset;
423
424
425 /* Scan entire file for any non-ASCII bytes */
426
427 FileOffset = ftell (File);
428 while (fread (&Byte, 1, 1, File) == 1)
429 {
430 if (!isprint (Byte) && !isspace (Byte))
431 {
432 IsBinary = TRUE;
433 goto Exit;
434 }
435 }
436
437 Exit:
438 fseek (File, FileOffset, SEEK_SET);
439 return (IsBinary);
440 }
441
442
443 /*******************************************************************************
444 *
445 * FUNCTION: AcValidateTableHeader
446 *
447 * PARAMETERS: File - Open input file
448 *
449 * RETURN: Status
450 *
451 * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI
452 * tables, via the
453 * following checks on what would be the table header:
454 * 1) File must be at least as long as an ACPI_TABLE_HEADER
455 * 2) There must be enough room in the file to hold entire table
456 * 3) Signature, OemId, OemTableId, AslCompilerId must be ASCII
457 *
458 * Note: There can be multiple definition blocks per file, so we cannot
459 * expect/compare the file size to be equal to the table length. 12/2015.
460 *
461 * Note: Maintains current file position.
462 *
463 ******************************************************************************/
464
465 ACPI_STATUS
AcValidateTableHeader(FILE * File,long TableOffset)466 AcValidateTableHeader (
467 FILE *File,
468 long TableOffset)
469 {
470 ACPI_TABLE_HEADER TableHeader;
471 ACPI_TABLE_CDAT *CdatTableHeader = ACPI_CAST_PTR (ACPI_TABLE_CDAT, &TableHeader);
472 UINT32 HeaderLength;
473 ACPI_SIZE Actual;
474 long OriginalOffset;
475 UINT32 FileSize;
476 UINT32 i;
477
478
479 ACPI_FUNCTION_TRACE (AcValidateTableHeader);
480
481 /* Determine the type of table header */
482
483 if (AcpiGbl_CDAT)
484 {
485 HeaderLength = sizeof (ACPI_TABLE_CDAT);
486 }
487 else
488 {
489 HeaderLength = sizeof (ACPI_TABLE_HEADER);
490 }
491
492 /* Read a potential table header */
493
494 OriginalOffset = ftell (File);
495 if (fseek (File, TableOffset, SEEK_SET))
496 {
497 fprintf (stderr, "SEEK error\n");
498 }
499 Actual = fread (&TableHeader, 1, HeaderLength, File);
500 if (fseek (File, OriginalOffset, SEEK_SET))
501 {
502 fprintf (stderr, "SEEK error\n");
503 }
504
505 if (Actual < HeaderLength)
506 {
507 fprintf (stderr,
508 "Could not read entire table header: Actual %u, Requested %u\n",
509 (UINT32) Actual, HeaderLength);
510 return (AE_ERROR);
511 }
512
513 /* Validate the signature (limited ASCII chars) */
514
515 if (!AcpiGbl_CDAT && !AcpiUtValidNameseg (TableHeader.Signature))
516 {
517 /*
518 * The "-ds cdat" option was not used, and the signature is not valid.
519 *
520 * For CDAT we are assuming that there should be at least one non-ASCII
521 * byte in the (normally) 4-character Signature field (at least the
522 * high-order byte should be zero). Otherwise, this is OK.
523 */
524 fprintf (stderr,
525 "\nTable appears to be a CDAT table, which has no signature.\n"
526 "If this is in fact a CDAT table, use the -ds option on the\n"
527 "command line to specify the table type (signature):\n"
528 "\"iasl -d -ds CDAT <file>\" or \"iasl -ds CDAT -T CDAT\"\n\n");
529
530 return (AE_BAD_SIGNATURE);
531 }
532
533 /* Validate table length against bytes remaining in the file */
534
535 FileSize = CmGetFileSize (File);
536 if (!AcpiGbl_CDAT)
537 {
538 /* Standard ACPI table header */
539
540 if (TableHeader.Length > (UINT32) (FileSize - TableOffset))
541 {
542 fprintf (stderr, "Table [%4.4s] is too long for file - "
543 "needs: 0x%.2X, remaining in file: 0x%.2X\n",
544 TableHeader.Signature, TableHeader.Length,
545 (UINT32) (FileSize - TableOffset));
546 return (AE_BAD_HEADER);
547 }
548 }
549 else if (CdatTableHeader->Length > (UINT32) (FileSize - TableOffset))
550 {
551 /* Special header for CDAT table */
552
553 fprintf (stderr, "Table [CDAT] is too long for file - "
554 "needs: 0x%.2X, remaining in file: 0x%.2X\n",
555 CdatTableHeader->Length,
556 (UINT32) (FileSize - TableOffset));
557 return (AE_BAD_HEADER);
558 }
559
560 /* For CDAT table, there are no ASCII fields in the header, we are done */
561
562 if (AcpiGbl_CDAT)
563 {
564 return (AE_OK);
565 }
566
567 /*
568 * These standard fields must be ASCII: OemId, OemTableId, AslCompilerId.
569 * We allow a NULL terminator in OemId and OemTableId.
570 */
571 for (i = 0; i < ACPI_NAMESEG_SIZE; i++)
572 {
573 if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i]))
574 {
575 goto BadCharacters;
576 }
577 }
578
579 for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++)
580 {
581 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i]))
582 {
583 goto BadCharacters;
584 }
585 }
586
587 for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++)
588 {
589 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i]))
590 {
591 goto BadCharacters;
592 }
593 }
594
595 return (AE_OK);
596
597
598 BadCharacters:
599
600 ACPI_WARNING ((AE_INFO,
601 "Table header for [%4.4s] has invalid ASCII character(s)",
602 TableHeader.Signature));
603 return (AE_OK);
604 }
605
606
607 /*******************************************************************************
608 *
609 * FUNCTION: AcCheckTextModeCorruption
610 *
611 * PARAMETERS: Table - Table buffer starting with table header
612 *
613 * RETURN: Status
614 *
615 * DESCRIPTION: Check table for text mode file corruption where all linefeed
616 * characters (LF) have been replaced by carriage return linefeed
617 * pairs (CR/LF).
618 *
619 ******************************************************************************/
620
621 static ACPI_STATUS
AcCheckTextModeCorruption(ACPI_TABLE_HEADER * Table)622 AcCheckTextModeCorruption (
623 ACPI_TABLE_HEADER *Table)
624 {
625 UINT32 i;
626 UINT32 Pairs = 0;
627 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table);
628
629
630 /* Scan entire table to determine if each LF has been prefixed with a CR */
631
632 for (i = 1; i < Table->Length; i++)
633 {
634 if (Buffer[i] == 0x0A)
635 {
636 if (Buffer[i - 1] != 0x0D)
637 {
638 /* The LF does not have a preceding CR, table not corrupted */
639
640 return (AE_OK);
641 }
642 else
643 {
644 /* Found a CR/LF pair */
645
646 Pairs++;
647 }
648
649 i++;
650 }
651 }
652
653 if (!Pairs)
654 {
655 return (AE_OK);
656 }
657
658 /*
659 * Entire table scanned, each CR is part of a CR/LF pair --
660 * meaning that the table was treated as a text file somewhere.
661 *
662 * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the
663 * original table are left untouched by the text conversion process --
664 * meaning that we cannot simply replace CR/LF pairs with LFs.
665 */
666 AcpiOsPrintf ("Table has been corrupted by text mode conversion\n");
667 AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs);
668 AcpiOsPrintf ("Table cannot be repaired!\n");
669
670 return (AE_BAD_VALUE);
671 }
672