acfileio.c revision 1.1.1.10 1 /******************************************************************************
2 *
3 * Module Name: acfileio - Get ACPI tables from file
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2021, 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 long TableOffset;
283
284
285 *ReturnTable = NULL;
286
287 /* Get the table header to examine signature and length */
288
289 TableOffset = ftell (File);
290 Count = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File);
291 if (Count != sizeof (ACPI_TABLE_HEADER))
292 {
293 return (AE_CTRL_TERMINATE);
294 }
295
296 if (GetOnlyAmlTables)
297 {
298 /* Validate the table signature/header (limited ASCII chars) */
299
300 Status = AcValidateTableHeader (File, TableOffset);
301 if (ACPI_FAILURE (Status))
302 {
303 return (Status);
304 }
305
306 /*
307 * Table must be an AML table (DSDT/SSDT).
308 * Used for iASL -e option only.
309 */
310 if (!AcpiUtIsAmlTable (&TableHeader))
311 {
312 fprintf (stderr,
313 " %s: Table [%4.4s] is not an AML table - ignoring\n",
314 Filename, TableHeader.Signature);
315
316 return (AE_TYPE);
317 }
318 }
319
320 /* Allocate a buffer for the entire table */
321
322 Table = AcpiOsAllocate ((ACPI_SIZE) TableHeader.Length);
323 if (!Table)
324 {
325 return (AE_NO_MEMORY);
326 }
327
328 /* Read the entire ACPI table, including header */
329
330 fseek (File, TableOffset, SEEK_SET);
331
332 Count = fread (Table, 1, TableHeader.Length, File);
333
334 /*
335 * Checks for data table headers happen later in the execution. Only verify
336 * for Aml tables at this point in the code.
337 */
338 if (GetOnlyAmlTables && Count != (INT32) TableHeader.Length)
339 {
340 Status = AE_ERROR;
341 goto ErrorExit;
342 }
343
344 /* Validate the checksum (just issue a warning) */
345
346 Status = AcpiTbVerifyChecksum (Table, TableHeader.Length);
347 if (ACPI_FAILURE (Status))
348 {
349 Status = AcCheckTextModeCorruption (Table);
350 if (ACPI_FAILURE (Status))
351 {
352 goto ErrorExit;
353 }
354 }
355
356 *ReturnTable = Table;
357 return (AE_OK);
358
359
360 ErrorExit:
361 AcpiOsFree (Table);
362 return (Status);
363 }
364
365
366 /*******************************************************************************
367 *
368 * FUNCTION: AcIsFileBinary
369 *
370 * PARAMETERS: File - Open input file
371 *
372 * RETURN: TRUE if file appears to be binary
373 *
374 * DESCRIPTION: Scan a file for any non-ASCII bytes.
375 *
376 * Note: Maintains current file position.
377 *
378 ******************************************************************************/
379
380 BOOLEAN
381 AcIsFileBinary (
382 FILE *File)
383 {
384 UINT8 Byte;
385 BOOLEAN IsBinary = FALSE;
386 long FileOffset;
387
388
389 /* Scan entire file for any non-ASCII bytes */
390
391 FileOffset = ftell (File);
392 while (fread (&Byte, 1, 1, File) == 1)
393 {
394 if (!isprint (Byte) && !isspace (Byte))
395 {
396 IsBinary = TRUE;
397 goto Exit;
398 }
399 }
400
401 Exit:
402 fseek (File, FileOffset, SEEK_SET);
403 return (IsBinary);
404 }
405
406
407 /*******************************************************************************
408 *
409 * FUNCTION: AcValidateTableHeader
410 *
411 * PARAMETERS: File - Open input file
412 *
413 * RETURN: Status
414 *
415 * DESCRIPTION: Determine if a file seems to contain one or more binary ACPI
416 * tables, via the
417 * following checks on what would be the table header:
418 * 1) File must be at least as long as an ACPI_TABLE_HEADER
419 * 2) There must be enough room in the file to hold entire table
420 * 3) Signature, OemId, OemTableId, AslCompilerId must be ASCII
421 *
422 * Note: There can be multiple definition blocks per file, so we cannot
423 * expect/compare the file size to be equal to the table length. 12/2015.
424 *
425 * Note: Maintains current file position.
426 *
427 ******************************************************************************/
428
429 ACPI_STATUS
430 AcValidateTableHeader (
431 FILE *File,
432 long TableOffset)
433 {
434 ACPI_TABLE_HEADER TableHeader;
435 ACPI_SIZE Actual;
436 long OriginalOffset;
437 UINT32 FileSize;
438 UINT32 i;
439
440
441 ACPI_FUNCTION_TRACE (AcValidateTableHeader);
442
443
444 /* Read a potential table header */
445
446 OriginalOffset = ftell (File);
447 fseek (File, TableOffset, SEEK_SET);
448
449 Actual = fread (&TableHeader, 1, sizeof (ACPI_TABLE_HEADER), File);
450 fseek (File, OriginalOffset, SEEK_SET);
451
452 if (Actual < sizeof (ACPI_TABLE_HEADER))
453 {
454 fprintf (stderr,
455 "Could not read entire table header: Actual %u, Requested %u\n",
456 (UINT32) Actual, (UINT32) sizeof (ACPI_TABLE_HEADER));
457 return (AE_ERROR);
458 }
459
460 /* Validate the signature (limited ASCII chars) */
461
462 if (!AcpiUtValidNameseg (TableHeader.Signature))
463 {
464 return (AE_BAD_SIGNATURE);
465 }
466
467 /* Validate table length against bytes remaining in the file */
468
469 FileSize = CmGetFileSize (File);
470 if (TableHeader.Length > (UINT32) (FileSize - TableOffset))
471 {
472 fprintf (stderr, "Table [%4.4s] is too long for file - "
473 "needs: 0x%.2X, remaining in file: 0x%.2X\n",
474 TableHeader.Signature, TableHeader.Length,
475 (UINT32) (FileSize - TableOffset));
476 return (AE_BAD_HEADER);
477 }
478
479 /*
480 * These fields must be ASCII: OemId, OemTableId, AslCompilerId.
481 * We allow a NULL terminator in OemId and OemTableId.
482 */
483 for (i = 0; i < ACPI_NAMESEG_SIZE; i++)
484 {
485 if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i]))
486 {
487 goto BadCharacters;
488 }
489 }
490
491 for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++)
492 {
493 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i]))
494 {
495 goto BadCharacters;
496 }
497 }
498
499 for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++)
500 {
501 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i]))
502 {
503 goto BadCharacters;
504 }
505 }
506
507 return (AE_OK);
508
509
510 BadCharacters:
511
512 ACPI_WARNING ((AE_INFO,
513 "Table header for [%4.4s] has invalid ASCII character(s)",
514 TableHeader.Signature));
515 return (AE_OK);
516 }
517
518
519 /*******************************************************************************
520 *
521 * FUNCTION: AcCheckTextModeCorruption
522 *
523 * PARAMETERS: Table - Table buffer starting with table header
524 *
525 * RETURN: Status
526 *
527 * DESCRIPTION: Check table for text mode file corruption where all linefeed
528 * characters (LF) have been replaced by carriage return linefeed
529 * pairs (CR/LF).
530 *
531 ******************************************************************************/
532
533 static ACPI_STATUS
534 AcCheckTextModeCorruption (
535 ACPI_TABLE_HEADER *Table)
536 {
537 UINT32 i;
538 UINT32 Pairs = 0;
539 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table);
540
541
542 /* Scan entire table to determine if each LF has been prefixed with a CR */
543
544 for (i = 1; i < Table->Length; i++)
545 {
546 if (Buffer[i] == 0x0A)
547 {
548 if (Buffer[i - 1] != 0x0D)
549 {
550 /* The LF does not have a preceding CR, table not corrupted */
551
552 return (AE_OK);
553 }
554 else
555 {
556 /* Found a CR/LF pair */
557
558 Pairs++;
559 }
560
561 i++;
562 }
563 }
564
565 if (!Pairs)
566 {
567 return (AE_OK);
568 }
569
570 /*
571 * Entire table scanned, each CR is part of a CR/LF pair --
572 * meaning that the table was treated as a text file somewhere.
573 *
574 * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the
575 * original table are left untouched by the text conversion process --
576 * meaning that we cannot simply replace CR/LF pairs with LFs.
577 */
578 AcpiOsPrintf ("Table has been corrupted by text mode conversion\n");
579 AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs);
580 AcpiOsPrintf ("Table cannot be repaired!\n");
581
582 return (AE_BAD_VALUE);
583 }
584