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