1 /******************************************************************************
2 *
3 * Module Name: axutils - Utility functions for acpixtract tool.
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 "acpixtract.h"
45
46
47 /*******************************************************************************
48 *
49 * FUNCTION: AxCheckAscii
50 *
51 * PARAMETERS: Name - Ascii string, at least as long as Count
52 * Count - Number of characters to check
53 *
54 * RETURN: None
55 *
56 * DESCRIPTION: Ensure that the requested number of characters are printable
57 * Ascii characters. Sets non-printable and null chars to <space>.
58 *
59 ******************************************************************************/
60
61 void
AxCheckAscii(char * Name,int Count)62 AxCheckAscii (
63 char *Name,
64 int Count)
65 {
66 int i;
67
68
69 for (i = 0; i < Count; i++)
70 {
71 if (!Name[i] || !isprint ((int) Name[i]))
72 {
73 Name[i] = ' ';
74 }
75 }
76 }
77
78
79 /*******************************************************************************
80 *
81 * FUNCTION: AxIsFileAscii
82 *
83 * PARAMETERS: Handle - To open input file
84 *
85 * RETURN: TRUE if file is entirely ASCII and printable
86 *
87 * DESCRIPTION: Verify that the input file is entirely ASCII.
88 *
89 ******************************************************************************/
90
91 BOOLEAN
AxIsFileAscii(FILE * Handle)92 AxIsFileAscii (
93 FILE *Handle)
94 {
95 UINT8 Byte;
96 UINT32 Offset = 0;
97
98
99 /* Read the entire file */
100
101 fseek (Handle, 0, SEEK_SET);
102 while (fread (&Byte, 1, 1, Handle) == 1)
103 {
104 /*
105 * Ignore null characters. Some acpidump-type utilities insert
106 * a few of these, probably a bug in the utility. As long as these
107 * characters are in lines that are tossed (non-data), they
108 * won't cause a problem.
109 */
110 if (!Byte)
111 {
112 continue;
113 }
114
115 /* Check for an ASCII character */
116
117 if (!ACPI_IS_ASCII (Byte))
118 {
119 printf ("Found non-ascii char: %2.2X at file offset %u (0x%X)\n",
120 Byte, Offset, Offset);
121 if (!Gbl_ForceExtraction)
122 {
123 goto ErrorExit;
124 }
125 }
126
127 /* Ensure character is either printable or a "space" char */
128
129 else if (!isprint (Byte) && !isspace (Byte))
130 {
131 printf ("Found non-printable char: %2.2X at file offset %u (0x%X)\n",
132 Byte, Offset, Offset);
133 if (!Gbl_ForceExtraction)
134 {
135 goto ErrorExit;
136 }
137 }
138
139 Offset++;
140 }
141
142 /* File is OK (100% ASCII) */
143
144 fseek (Handle, 0, SEEK_SET);
145 return (TRUE);
146
147 ErrorExit:
148
149 printf ("File appears to be binary "
150 "(contains non-text or non-ascii characters)\n");
151 fseek (Handle, 0, SEEK_SET);
152 return (FALSE);
153 }
154
155
156 /******************************************************************************
157 *
158 * FUNCTION: AxIsEmptyLine
159 *
160 * PARAMETERS: Buffer - Line from input file
161 *
162 * RETURN: TRUE if line is empty (zero or more blanks only)
163 *
164 * DESCRIPTION: Determine if an input line is empty.
165 *
166 ******************************************************************************/
167
168 BOOLEAN
AxIsEmptyLine(char * Buffer)169 AxIsEmptyLine (
170 char *Buffer)
171 {
172
173 /* Skip all spaces */
174
175 while (*Buffer == ' ')
176 {
177 Buffer++;
178 }
179
180 /* Line is empty when a Unix or DOS-style line terminator is found. */
181
182 if ((*Buffer == '\r') || (*Buffer == '\n'))
183 {
184 return (1);
185 }
186
187 return (0);
188 }
189
190
191 /******************************************************************************
192 *
193 * FUNCTION: AxIsHexDataLine
194 *
195 * PARAMETERS: None
196 *
197 * RETURN: Status. 1 if the table header is valid, 0 otherwise.
198 *
199 * DESCRIPTION: Check for a valid line of hex data of the form:
200 *
201 * 00a0: 0c 00 00 00 03 00 00 00 43 48 41 35 0c 00 00 00 ........CHA5....
202 *
203 ******************************************************************************/
204
205 BOOLEAN
AxIsHexDataLine(void)206 AxIsHexDataLine (
207 void)
208 {
209
210 if (AxIsEmptyLine (Gbl_LineBuffer) ||
211 (Gbl_LineBuffer[0] != ' '))
212 {
213 return (FALSE);
214 }
215
216 if (!strstr (Gbl_LineBuffer, ": "))
217 {
218 /* Not valid data line */
219
220 return (FALSE);
221 }
222
223 return (TRUE);
224 }
225
226
227 /******************************************************************************
228 *
229 * FUNCTION: AxIsDataBlockHeader
230 *
231 * PARAMETERS: None
232 *
233 * RETURN: Status. 1 if the table header is valid, 0 otherwise.
234 *
235 * DESCRIPTION: Check if the ACPI table identifier in the input acpidump text
236 * file is valid (of the form: <sig> @ <addr>).
237 *
238 ******************************************************************************/
239
240 BOOLEAN
AxIsDataBlockHeader(void)241 AxIsDataBlockHeader (
242 void)
243 {
244
245 /* Ignore lines that are too short to be header lines */
246
247 if (strlen (Gbl_LineBuffer) < AX_MIN_BLOCK_HEADER_LENGTH)
248 {
249 return (FALSE);
250 }
251
252 /* Ignore empty lines and lines that start with a space */
253
254 if (AxIsEmptyLine (Gbl_LineBuffer) ||
255 (Gbl_LineBuffer[0] == ' '))
256 {
257 return (FALSE);
258 }
259
260 /*
261 * Ignore lines that are not headers of the form <sig> @ <addr>.
262 * Basically, just look for the '@' symbol, surrounded by spaces.
263 *
264 * Examples of headers that must be supported:
265 *
266 * DSDT @ 0x737e4000
267 * XSDT @ 0x737f2fff
268 * RSD PTR @ 0xf6cd0
269 * SSDT @ (nil)
270 */
271 if (!AX_IS_TABLE_BLOCK_HEADER)
272 {
273 return (FALSE);
274 }
275
276 AxNormalizeSignature (Gbl_LineBuffer);
277 return (TRUE);
278 }
279
280
281 /*******************************************************************************
282 *
283 * FUNCTION: AxNormalizeSignature
284 *
285 * PARAMETERS: Name - Ascii string containing an ACPI signature
286 *
287 * RETURN: None
288 *
289 * DESCRIPTION: Change "RSD PTR" to "RSDP"
290 *
291 ******************************************************************************/
292
293 void
AxNormalizeSignature(char * Signature)294 AxNormalizeSignature (
295 char *Signature)
296 {
297
298 if (!strncmp (Signature, "RSD ", 4))
299 {
300 Signature[3] = 'P';
301 }
302 }
303
304
305 /******************************************************************************
306 *
307 * FUNCTION: AxConvertToBinary
308 *
309 * PARAMETERS: InputLine - One line from the input acpidump file
310 * OutputData - Where the converted data is returned
311 *
312 * RETURN: The number of bytes actually converted
313 *
314 * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes)
315 *
316 * NOTE: Assumes the input data line has been validated to be of the form:
317 *
318 * 0010: 48 53 57 55 4c 54 2d 52 01 00 00 00 49 4e 54 4c HSWULT-R....INTL
319 *
320 ******************************************************************************/
321
322 int
AxConvertToBinary(char * InputLine,unsigned char * OutputData)323 AxConvertToBinary (
324 char *InputLine,
325 unsigned char *OutputData)
326 {
327 char *ColonDelimiter;
328 int BytesConverted;
329 int Converted[16];
330 int i;
331
332
333 /*
334 * Terminate input line immediately after the data. Otherwise, the
335 * second line below will not scan correctly.
336 *
337 * This handles varying lengths for the offset: line prefix. This support
338 * for tables larger than 1mb was added 05/2018.
339 *
340 * 00b0: 03 00 00 00 43 48 41 36 0c 00 00 00 03 00 00 00 ....CHA6........
341 * 00c0: 43 48 41 37 CHA7
342 *
343 * 012340b0: 03 00 00 00 43 48 41 36 0c 00 00 00 03 00 00 00 ....CHA6........
344 * 012340c0: 43 48 41 37 CHA7
345 */
346 ColonDelimiter = strchr (InputLine, ':');
347 ColonDelimiter [AX_HEX_DATA_LENGTH] = 0;
348
349 /*
350 * Convert one line of table data, of the form:
351 * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline>
352 *
353 * Example:
354 * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08 _SB_LNKD........
355 */
356 BytesConverted = sscanf (InputLine,
357 "%*s %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X",
358 &Converted[0], &Converted[1], &Converted[2], &Converted[3],
359 &Converted[4], &Converted[5], &Converted[6], &Converted[7],
360 &Converted[8], &Converted[9], &Converted[10], &Converted[11],
361 &Converted[12], &Converted[13], &Converted[14], &Converted[15]);
362
363 if (BytesConverted == EOF)
364 {
365 printf ("EOF while converting ASCII line to binary\n");
366 return (-1);
367 }
368
369 /*
370 * Pack converted data into a byte array.
371 * Note: BytesConverted == 0 is acceptable.
372 */
373 for (i = 0; i < BytesConverted; i++)
374 {
375 OutputData[i] = (unsigned char) Converted[i];
376 }
377
378 return (BytesConverted);
379 }
380
381
382 /******************************************************************************
383 *
384 * FUNCTION: AxCountTableInstances
385 *
386 * PARAMETERS: InputPathname - Filename for acpidump file
387 * Signature - Requested signature to count
388 *
389 * RETURN: The number of instances of the signature
390 *
391 * DESCRIPTION: Count the instances of tables with the given signature within
392 * the input acpidump file.
393 *
394 ******************************************************************************/
395
396 unsigned int
AxCountTableInstances(char * InputPathname,char * Signature)397 AxCountTableInstances (
398 char *InputPathname,
399 char *Signature)
400 {
401 FILE *InputFile;
402 unsigned int Instances = 0;
403
404
405 InputFile = fopen (InputPathname, "r");
406 if (!InputFile)
407 {
408 printf ("Could not open input file %s\n", InputPathname);
409 return (0);
410 }
411
412 /* Count the number of instances of this signature */
413
414 while (fgets (Gbl_InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile))
415 {
416 /* Ignore empty lines and lines that start with a space */
417
418 if (AxIsEmptyLine (Gbl_InstanceBuffer) ||
419 (Gbl_InstanceBuffer[0] == ' '))
420 {
421 continue;
422 }
423
424 AxNormalizeSignature (Gbl_InstanceBuffer);
425 if (ACPI_COMPARE_NAMESEG (Gbl_InstanceBuffer, Signature))
426 {
427 Instances++;
428 }
429 }
430
431 fclose (InputFile);
432 return (Instances);
433 }
434
435
436 /******************************************************************************
437 *
438 * FUNCTION: AxGetNextInstance
439 *
440 * PARAMETERS: InputPathname - Filename for acpidump file
441 * Signature - Requested ACPI signature
442 *
443 * RETURN: The next instance number for this signature. Zero if this
444 * is the first instance of this signature.
445 *
446 * DESCRIPTION: Get the next instance number of the specified table. If this
447 * is the first instance of the table, create a new instance
448 * block. Note: only SSDT and PSDT tables can have multiple
449 * instances.
450 *
451 ******************************************************************************/
452
453 unsigned int
AxGetNextInstance(char * InputPathname,char * Signature)454 AxGetNextInstance (
455 char *InputPathname,
456 char *Signature)
457 {
458 AX_TABLE_INFO *Info;
459
460
461 Info = Gbl_TableListHead;
462 while (Info)
463 {
464 if (*(UINT32 *) Signature == Info->Signature)
465 {
466 break;
467 }
468
469 Info = Info->Next;
470 }
471
472 if (!Info)
473 {
474 /* Signature not found, create new table info block */
475
476 Info = malloc (sizeof (AX_TABLE_INFO));
477 if (!Info)
478 {
479 printf ("Could not allocate memory (0x%X bytes)\n",
480 (unsigned int) sizeof (AX_TABLE_INFO));
481 exit (0);
482 }
483
484 Info->Signature = *(UINT32 *) Signature;
485 Info->Instances = AxCountTableInstances (InputPathname, Signature);
486 Info->NextInstance = 1;
487 Info->Next = Gbl_TableListHead;
488 Gbl_TableListHead = Info;
489 }
490
491 if (Info->Instances > 1)
492 {
493 return (Info->NextInstance++);
494 }
495
496 return (0);
497 }
498
499
500 /******************************************************************************
501 *
502 * FUNCTION: AxConvertAndWrite
503 *
504 * PARAMETERS: OutputFile - Where to write the binary data
505 * ThisSignature - Signature of current ACPI table
506 *
507 * RETURN: Length of the converted line
508 *
509 * DESCRIPTION: Convert one line of input hex ascii text to binary, and write
510 * the binary data to the table output file.
511 *
512 * NOTE: Assumes the input data line has been validated to be of the form:
513 *
514 * 0010: 48 53 57 55 4c 54 2d 52 01 00 00 00 49 4e 54 4c HSWULT-R....INTL
515 *
516 ******************************************************************************/
517
518 int
AxConvertAndWrite(FILE * OutputFile,char * ThisSignature)519 AxConvertAndWrite (
520 FILE *OutputFile,
521 char *ThisSignature)
522 {
523 int BytesWritten;
524 int BytesConverted;
525
526
527 /* Convert one line of ascii hex data to binary */
528
529 BytesConverted = AxConvertToBinary (Gbl_LineBuffer, Gbl_BinaryData);
530 if (BytesConverted == EOF)
531 {
532 return (EOF);
533 }
534 if (!BytesConverted)
535 {
536 return (0);
537 }
538
539 /* Write the binary data */
540
541 BytesWritten = fwrite (Gbl_BinaryData, 1, BytesConverted, OutputFile);
542 if (BytesWritten != BytesConverted)
543 {
544 printf ("Error while writing file %s\n", Gbl_OutputFilename);
545 return (-1);
546 }
547
548 return (BytesWritten);
549 }
550
551
552 /******************************************************************************
553 *
554 * FUNCTION: AxDumpTableHeader
555 *
556 * PARAMETERS: Header - A binary ACPI table header
557 *
558 * RETURN: None
559 *
560 * DESCRIPTION: Display the contents of a standard ACPI table header
561 *
562 ******************************************************************************/
563
564 void
AxDumpTableHeader(unsigned char * Header)565 AxDumpTableHeader (
566 unsigned char *Header)
567 {
568 ACPI_TABLE_HEADER *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header;
569 ACPI_TABLE_RSDP *Rsdp = (ACPI_TABLE_RSDP *) (void *) Header;
570 ACPI_TABLE_FACS *Facs = (ACPI_TABLE_FACS *) (void *) Header;
571
572
573 /* RSDP has an oddball signature and header */
574
575 if (!strncmp (TableHeader->Signature, "RSD PTR ", 8))
576 {
577 AxCheckAscii ((char *) &Header[9], 6);
578
579 Gbl_TableCount++;
580 printf (" %.2u) %5.4s 0x%8.8X 0x%2.2X \"%6.6s\"\n",
581 Gbl_TableCount, "RSDP", Rsdp->Length, Rsdp->Revision, Rsdp->OemId);
582 return;
583 }
584
585 if (!AcpiUtValidNameseg (TableHeader->Signature))
586 {
587 return;
588 }
589
590 /* Signature and Table length */
591
592 Gbl_TableCount++;
593 printf (" %.2u) %5.4s 0x%8.8X", Gbl_TableCount, TableHeader->Signature,
594 TableHeader->Length);
595
596 /* FACS has only signature and length */
597
598 if (ACPI_COMPARE_NAMESEG (TableHeader->Signature, "FACS"))
599 {
600 printf (" 0x%2.2X\n", Facs->Version);
601 return;
602 }
603
604 /* OEM IDs and Compiler IDs */
605
606 AxCheckAscii (TableHeader->OemId, 6);
607 AxCheckAscii (TableHeader->OemTableId, 8);
608 AxCheckAscii (TableHeader->AslCompilerId, 4);
609
610 printf (
611 " 0x%2.2X \"%6.6s\" \"%8.8s\" 0x%8.8X"
612 " \"%4.4s\" 0x%8.8X\n",
613 TableHeader->Revision, TableHeader->OemId,
614 TableHeader->OemTableId, TableHeader->OemRevision,
615 TableHeader->AslCompilerId, TableHeader->AslCompilerRevision);
616 }
617
618
619 #ifdef _AX_FUTURE_ENHANCEMENTS
620
621 /* Possible enhancement to validate table lengths */
622
623 void
AxCheckTableLengths(UINT32 ByteCount,UINT32 AmlByteCount)624 AxCheckTableLengths (
625 UINT32 ByteCount,
626 UINT32 AmlByteCount)
627 {
628
629 if (AmlByteCount == 0)
630 {
631 return;
632 }
633
634 if (ByteCount == 0)
635 {
636 return;
637 }
638
639 if ((ByteCount < sizeof (ACPI_TABLE_HEADER)) &&
640 (ByteCount >= ACPI_NAMESEG_SIZE))
641 {
642 printf (" : (Table too short for an ACPI table)");
643 }
644
645 else if (ByteCount != AmlByteCount)
646 {
647 printf (" : (Hex data length mismatch with AML length 0x%X)",
648 AmlByteCount);
649 }
650
651 printf ("\n");
652 }
653 #endif
654