1/******************************************************************************
2 *
3 * Module Name: acfileio - Get ACPI tables from file
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2019, 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
56static ACPI_STATUS
57AcGetOneTableFromFile (
58 char *Filename,
59 FILE *File,
60 UINT8 GetOnlyAmlTables,
61 ACPI_TABLE_HEADER **Table);
62
63static ACPI_STATUS
64AcCheckTextModeCorruption (
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
81void
82AcDeleteTableList (
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
112ACPI_STATUS
113AcGetAllTablesFromFile (
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
246Exit:
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
271static ACPI_STATUS
272AcGetOneTableFromFile (
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
360ErrorExit:
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
380BOOLEAN
381AcIsFileBinary (
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
401Exit:
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
429ACPI_STATUS
430AcValidateTableHeader (
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 return (AE_ERROR);
455 }
456
457 /* Validate the signature (limited ASCII chars) */
458
459 if (!AcpiUtValidNameseg (TableHeader.Signature))
460 {
461 return (AE_BAD_SIGNATURE);
462 }
463
464 /* Validate table length against bytes remaining in the file */
465
466 FileSize = CmGetFileSize (File);
467 if (TableHeader.Length > (UINT32) (FileSize - TableOffset))
468 {
469 fprintf (stderr, "Table [%4.4s] is too long for file - "
470 "needs: 0x%.2X, remaining in file: 0x%.2X\n",
471 TableHeader.Signature, TableHeader.Length,
472 (UINT32) (FileSize - TableOffset));
473 return (AE_BAD_HEADER);
474 }
475
476 /*
477 * These fields must be ASCII: OemId, OemTableId, AslCompilerId.
478 * We allow a NULL terminator in OemId and OemTableId.
479 */
480 for (i = 0; i < ACPI_NAMESEG_SIZE; i++)
481 {
482 if (!ACPI_IS_ASCII ((UINT8) TableHeader.AslCompilerId[i]))
483 {
484 goto BadCharacters;
485 }
486 }
487
488 for (i = 0; (i < ACPI_OEM_ID_SIZE) && (TableHeader.OemId[i]); i++)
489 {
490 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemId[i]))
491 {
492 goto BadCharacters;
493 }
494 }
495
496 for (i = 0; (i < ACPI_OEM_TABLE_ID_SIZE) && (TableHeader.OemTableId[i]); i++)
497 {
498 if (!ACPI_IS_ASCII ((UINT8) TableHeader.OemTableId[i]))
499 {
500 goto BadCharacters;
501 }
502 }
503
504 return (AE_OK);
505
506
507BadCharacters:
508
509 ACPI_WARNING ((AE_INFO,
510 "Table header for [%4.4s] has invalid ASCII character(s)",
511 TableHeader.Signature));
512 return (AE_OK);
513}
514
515
516/*******************************************************************************
517 *
518 * FUNCTION: AcCheckTextModeCorruption
519 *
520 * PARAMETERS: Table - Table buffer starting with table header
521 *
522 * RETURN: Status
523 *
524 * DESCRIPTION: Check table for text mode file corruption where all linefeed
525 * characters (LF) have been replaced by carriage return linefeed
526 * pairs (CR/LF).
527 *
528 ******************************************************************************/
529
530static ACPI_STATUS
531AcCheckTextModeCorruption (
532 ACPI_TABLE_HEADER *Table)
533{
534 UINT32 i;
535 UINT32 Pairs = 0;
536 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Table);
537
538
539 /* Scan entire table to determine if each LF has been prefixed with a CR */
540
541 for (i = 1; i < Table->Length; i++)
542 {
543 if (Buffer[i] == 0x0A)
544 {
545 if (Buffer[i - 1] != 0x0D)
546 {
547 /* The LF does not have a preceding CR, table not corrupted */
548
549 return (AE_OK);
550 }
551 else
552 {
553 /* Found a CR/LF pair */
554
555 Pairs++;
556 }
557
558 i++;
559 }
560 }
561
562 if (!Pairs)
563 {
564 return (AE_OK);
565 }
566
567 /*
568 * Entire table scanned, each CR is part of a CR/LF pair --
569 * meaning that the table was treated as a text file somewhere.
570 *
571 * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the
572 * original table are left untouched by the text conversion process --
573 * meaning that we cannot simply replace CR/LF pairs with LFs.
574 */
575 AcpiOsPrintf ("Table has been corrupted by text mode conversion\n");
576 AcpiOsPrintf ("All LFs (%u) were changed to CR/LF pairs\n", Pairs);
577 AcpiOsPrintf ("Table cannot be repaired!\n");
578
579 return (AE_BAD_VALUE);
580}
581