xref: /netbsd-src/sys/external/bsd/acpica/dist/tools/acpixtract/axutils.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
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