xref: /netbsd-src/sys/external/bsd/acpica/dist/tools/acpixtract/acpixtract.c (revision e39ef1d61eee3ccba837ee281f1e098c864487aa)
1 
2 /******************************************************************************
3  *
4  * Module Name: acpixtract - convert ascii ACPI tables to binary
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 
50 
51 /* Note: This is a 32-bit program only */
52 
53 #define VERSION             0x20110330
54 #define FIND_HEADER         0
55 #define EXTRACT_DATA        1
56 #define BUFFER_SIZE         256
57 #define MIN_HEADER_LENGTH   6   /* strlen ("DSDT @") */
58 
59 /* Local prototypes */
60 
61 static void
62 CheckAscii (
63     char                    *Name,
64     int                     Count);
65 
66 static void
67 NormalizeSignature (
68     char                    *Signature);
69 
70 static unsigned int
71 GetNextInstance (
72     char                    *InputPathname,
73     char                    *Signature);
74 
75 static int
76 ExtractTables (
77     char                    *InputPathname,
78     char                    *Signature,
79     unsigned int            MinimumInstances);
80 
81 static size_t
82 GetTableHeader (
83     FILE                    *InputFile,
84     unsigned char           *OutputData);
85 
86 static unsigned int
87 CountTableInstances (
88     char                    *InputPathname,
89     char                    *Signature);
90 
91 static int
92 ListTables (
93     char                    *InputPathname);
94 
95 static size_t
96 ConvertLine (
97     char                    *InputLine,
98     unsigned char           *OutputData);
99 
100 static void
101 DisplayUsage (
102     void);
103 
104 
105 typedef struct acpi_table_header
106 {
107     char                    Signature[4];
108     int                     Length;
109     unsigned char           Revision;
110     unsigned char           Checksum;
111     char                    OemId[6];
112     char                    OemTableId[8];
113     int                     OemRevision;
114     char                    AslCompilerId[4];
115     int                     AslCompilerRevision;
116 
117 } ACPI_TABLE_HEADER;
118 
119 struct TableInfo
120 {
121     unsigned int            Signature;
122     unsigned int            Instances;
123     unsigned int            NextInstance;
124     struct TableInfo        *Next;
125 };
126 
127 static struct TableInfo     *ListHead = NULL;
128 static char                 Filename[16];
129 static unsigned char        Data[16];
130 
131 
132 /******************************************************************************
133  *
134  * FUNCTION:    DisplayUsage
135  *
136  * DESCRIPTION: Usage message
137  *
138  ******************************************************************************/
139 
140 static void
141 DisplayUsage (
142     void)
143 {
144 
145     printf ("Usage: acpixtract [option] <InputFile>\n");
146     printf ("\nExtract binary ACPI tables from text acpidump output\n");
147     printf ("Default invocation extracts all DSDTs and SSDTs\n");
148     printf ("Version %8.8X\n\n", VERSION);
149     printf ("Options:\n");
150     printf (" -a                    Extract all tables, not just DSDT/SSDT\n");
151     printf (" -l                    List table summaries, do not extract\n");
152     printf (" -s<Signature>         Extract all tables named <Signature>\n");
153     printf ("\n");
154 }
155 
156 
157 /*******************************************************************************
158  *
159  * FUNCTION:    CheckAscii
160  *
161  * PARAMETERS:  Name                - Ascii string, at least as long as Count
162  *              Count               - Number of characters to check
163  *
164  * RETURN:      None
165  *
166  * DESCRIPTION: Ensure that the requested number of characters are printable
167  *              Ascii characters. Sets non-printable and null chars to <space>.
168  *
169  ******************************************************************************/
170 
171 static void
172 CheckAscii (
173     char                    *Name,
174     int                     Count)
175 {
176     int                     i;
177 
178 
179     for (i = 0; i < Count; i++)
180     {
181         if (!Name[i] || !isprint ((int) Name[i]))
182         {
183             Name[i] = ' ';
184         }
185     }
186 }
187 
188 
189 /*******************************************************************************
190  *
191  * FUNCTION:    NormalizeSignature
192  *
193  * PARAMETERS:  Name                - Ascii string containing an ACPI signature
194  *
195  * RETURN:      None
196  *
197  * DESCRIPTION: Change "RSD PTR" to "RSDP"
198  *
199  ******************************************************************************/
200 
201 static void
202 NormalizeSignature (
203     char                    *Signature)
204 {
205 
206     if (!strncmp (Signature, "RSD ", 4))
207     {
208         Signature[3] = 'P';
209     }
210 }
211 
212 
213 /******************************************************************************
214  *
215  * FUNCTION:    ConvertLine
216  *
217  * PARAMETERS:  InputLine           - One line from the input acpidump file
218  *              OutputData          - Where the converted data is returned
219  *
220  * RETURN:      The number of bytes actually converted
221  *
222  * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes)
223  *
224  ******************************************************************************/
225 
226 static size_t
227 ConvertLine (
228     char                    *InputLine,
229     unsigned char           *OutputData)
230 {
231     char                    *End;
232     int                     BytesConverted;
233     int                     Converted[16];
234     int                     i;
235 
236 
237     /* Terminate the input line at the end of the actual data (for sscanf) */
238 
239     End = strstr (InputLine + 2, "  ");
240     if (!End)
241     {
242         return (0); /* Don't understand the format */
243     }
244     *End = 0;
245 
246     /*
247      * Convert one line of table data, of the form:
248      * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline>
249      *
250      * Example:
251      * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08  _SB_LNKD........
252      */
253     BytesConverted = sscanf (InputLine,
254         "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
255         &Converted[0],  &Converted[1],  &Converted[2],  &Converted[3],
256         &Converted[4],  &Converted[5],  &Converted[6],  &Converted[7],
257         &Converted[8],  &Converted[9],  &Converted[10], &Converted[11],
258         &Converted[12], &Converted[13], &Converted[14], &Converted[15]);
259 
260     /* Pack converted data into a byte array */
261 
262     for (i = 0; i < BytesConverted; i++)
263     {
264         OutputData[i] = (unsigned char) Converted[i];
265     }
266 
267     return ((size_t) BytesConverted);
268 }
269 
270 
271 /******************************************************************************
272  *
273  * FUNCTION:    GetTableHeader
274  *
275  * PARAMETERS:  InputFile           - Handle for the input acpidump file
276  *              OutputData          - Where the table header is returned
277  *
278  * RETURN:      The actual number of bytes converted
279  *
280  * DESCRIPTION: Extract and convert an ACPI table header
281  *
282  ******************************************************************************/
283 
284 static size_t
285 GetTableHeader (
286     FILE                    *InputFile,
287     unsigned char           *OutputData)
288 {
289     size_t                  BytesConverted;
290     size_t                  TotalConverted = 0;
291     char                    Buffer[BUFFER_SIZE];
292     int                     i;
293 
294 
295     /* Get the full 36 byte header, requires 3 lines */
296 
297     for (i = 0; i < 3; i++)
298     {
299         if (!fgets (Buffer, BUFFER_SIZE, InputFile))
300         {
301             return (TotalConverted);
302         }
303 
304         BytesConverted = ConvertLine (Buffer, OutputData);
305         TotalConverted += BytesConverted;
306         OutputData += 16;
307 
308         if (BytesConverted != 16)
309         {
310             return (TotalConverted);
311         }
312     }
313 
314     return (TotalConverted);
315 }
316 
317 
318 /******************************************************************************
319  *
320  * FUNCTION:    CountTableInstances
321  *
322  * PARAMETERS:  InputPathname       - Filename for acpidump file
323  *              Signature           - Requested signature to count
324  *
325  * RETURN:      The number of instances of the signature
326  *
327  * DESCRIPTION: Count the instances of tables with the given signature within
328  *              the input acpidump file.
329  *
330  ******************************************************************************/
331 
332 static unsigned int
333 CountTableInstances (
334     char                    *InputPathname,
335     char                    *Signature)
336 {
337     char                    Buffer[BUFFER_SIZE];
338     FILE                    *InputFile;
339     unsigned int            Instances = 0;
340 
341 
342     InputFile = fopen (InputPathname, "rt");
343     if (!InputFile)
344     {
345         printf ("Could not open %s\n", InputPathname);
346         return (0);
347     }
348 
349     /* Count the number of instances of this signature */
350 
351     while (fgets (Buffer, BUFFER_SIZE, InputFile))
352     {
353         /* Ignore empty lines and lines that start with a space */
354 
355         if ((Buffer[0] == ' ') ||
356             (Buffer[0] == '\n'))
357         {
358             continue;
359         }
360 
361         NormalizeSignature (Buffer);
362         if (!strncmp (Buffer, Signature, 4))
363         {
364             Instances++;
365         }
366     }
367 
368     fclose (InputFile);
369     return (Instances);
370 }
371 
372 
373 /******************************************************************************
374  *
375  * FUNCTION:    GetNextInstance
376  *
377  * PARAMETERS:  InputPathname       - Filename for acpidump file
378  *              Signature           - Requested ACPI signature
379  *
380  * RETURN:      The next instance number for this signature. Zero if this
381  *              is the first instance of this signature.
382  *
383  * DESCRIPTION: Get the next instance number of the specified table. If this
384  *              is the first instance of the table, create a new instance
385  *              block. Note: only SSDT and PSDT tables can have multiple
386  *              instances.
387  *
388  ******************************************************************************/
389 
390 static unsigned int
391 GetNextInstance (
392     char                    *InputPathname,
393     char                    *Signature)
394 {
395     struct TableInfo        *Info;
396 
397 
398     Info = ListHead;
399     while (Info)
400     {
401         if (*(unsigned int *) Signature == Info->Signature)
402         {
403             break;
404         }
405 
406         Info = Info->Next;
407     }
408 
409     if (!Info)
410     {
411         /* Signature not found, create new table info block */
412 
413         Info = malloc (sizeof (struct TableInfo));
414         if (!Info)
415         {
416             printf ("Could not allocate memory\n");
417             exit (0);
418         }
419 
420         Info->Signature = *(unsigned int *) Signature;
421         Info->Instances = CountTableInstances (InputPathname, Signature);
422         Info->NextInstance = 1;
423         Info->Next = ListHead;
424         ListHead = Info;
425     }
426 
427     if (Info->Instances > 1)
428     {
429         return (Info->NextInstance++);
430     }
431 
432     return (0);
433 }
434 
435 
436 /******************************************************************************
437  *
438  * FUNCTION:    ExtractTables
439  *
440  * PARAMETERS:  InputPathname       - Filename for acpidump file
441  *              Signature           - Requested ACPI signature to extract.
442  *                                    NULL means extract ALL tables.
443  *              MinimumInstances    - Min instances that are acceptable
444  *
445  * RETURN:      Status
446  *
447  * DESCRIPTION: Convert text ACPI tables to binary
448  *
449  ******************************************************************************/
450 
451 static int
452 ExtractTables (
453     char                    *InputPathname,
454     char                    *Signature,
455     unsigned int            MinimumInstances)
456 {
457     char                    Buffer[BUFFER_SIZE];
458     FILE                    *InputFile;
459     FILE                    *OutputFile = NULL;
460     size_t                  BytesWritten;
461     size_t                  TotalBytesWritten = 0;
462     size_t                  BytesConverted;
463     unsigned int            State = FIND_HEADER;
464     unsigned int            FoundTable = 0;
465     unsigned int            Instances = 0;
466     unsigned int            ThisInstance;
467     char                    ThisSignature[4];
468     int                     Status = 0;
469 
470 
471     /* Open input in text mode, output is in binary mode */
472 
473     InputFile = fopen (InputPathname, "rt");
474     if (!InputFile)
475     {
476         printf ("Could not open %s\n", InputPathname);
477         return (-1);
478     }
479 
480     if (Signature)
481     {
482         /* Are there enough instances of the table to continue? */
483 
484         NormalizeSignature (Signature);
485 
486         Instances = CountTableInstances (InputPathname, Signature);
487         if (Instances < MinimumInstances)
488         {
489             printf ("Table %s was not found in %s\n", Signature, InputPathname);
490             Status = -1;
491             goto CleanupAndExit;
492         }
493 
494         if (Instances == 0)
495         {
496             goto CleanupAndExit;
497         }
498     }
499 
500     /* Convert all instances of the table to binary */
501 
502     while (fgets (Buffer, BUFFER_SIZE, InputFile))
503     {
504         switch (State)
505         {
506         case FIND_HEADER:
507 
508             /* Ignore lines that are too short to be header lines */
509 
510             if (strlen (Buffer) < MIN_HEADER_LENGTH)
511             {
512                 continue;
513             }
514 
515             /* Ignore empty lines and lines that start with a space */
516 
517             if ((Buffer[0] == ' ') ||
518                 (Buffer[0] == '\n'))
519             {
520                 continue;
521             }
522 
523             /*
524              * Ignore lines that are not of the form <sig> @ <addr>. Examples:
525              *
526              * DSDT @ 0x737e4000
527              * XSDT @ 0x737f2fff
528              * RSD PTR @ 0xf6cd0
529              * SSDT @ (nil)
530              */
531             if (!strstr (Buffer, " @ "))
532             {
533                 continue;
534             }
535 
536             NormalizeSignature (Buffer);
537             strncpy (ThisSignature, Buffer, 4);
538 
539             if (Signature)
540             {
541                 /* Ignore signatures that don't match */
542 
543                 if (strncmp (ThisSignature, Signature, 4))
544                 {
545                     continue;
546                 }
547             }
548 
549             /*
550              * Get the instance number for this signature. Only the
551              * SSDT and PSDT tables can have multiple instances.
552              */
553             ThisInstance = GetNextInstance (InputPathname, ThisSignature);
554 
555             /* Build an output filename and create/open the output file */
556 
557             if (ThisInstance > 0)
558             {
559                 sprintf (Filename, "%4.4s%u.dat", ThisSignature, ThisInstance);
560             }
561             else
562             {
563                 sprintf (Filename, "%4.4s.dat", ThisSignature);
564             }
565 
566             OutputFile = fopen (Filename, "w+b");
567             if (!OutputFile)
568             {
569                 printf ("Could not open %s\n", Filename);
570                 Status = -1;
571                 goto CleanupAndExit;
572             }
573 
574             State = EXTRACT_DATA;
575             TotalBytesWritten = 0;
576             FoundTable = 1;
577             continue;
578 
579         case EXTRACT_DATA:
580 
581             /* Empty line or non-data line terminates the data */
582 
583             if ((Buffer[0] == '\n') ||
584                 (Buffer[0] != ' '))
585             {
586                 fclose (OutputFile);
587                 OutputFile = NULL;
588                 State = FIND_HEADER;
589 
590                 printf ("Acpi table [%4.4s] - %u bytes written to %s\n",
591                     ThisSignature, (unsigned int) TotalBytesWritten, Filename);
592                 continue;
593             }
594 
595             /* Convert the ascii data (one line of text) to binary */
596 
597             BytesConverted = ConvertLine (Buffer, Data);
598 
599             /* Write the binary data */
600 
601             BytesWritten = fwrite (Data, 1, BytesConverted, OutputFile);
602             if (BytesWritten != BytesConverted)
603             {
604                 printf ("Write error on %s\n", Filename);
605                 fclose (OutputFile);
606                 OutputFile = NULL;
607                 Status = -1;
608                 goto CleanupAndExit;
609             }
610 
611             TotalBytesWritten += BytesConverted;
612             continue;
613 
614         default:
615             Status = -1;
616             goto CleanupAndExit;
617         }
618     }
619 
620     if (!FoundTable)
621     {
622         printf ("Table %s was not found in %s\n", Signature, InputPathname);
623     }
624 
625 
626 CleanupAndExit:
627 
628     if (OutputFile)
629     {
630         fclose (OutputFile);
631         if (State == EXTRACT_DATA)
632         {
633             /* Received an EOF while extracting data */
634 
635             printf ("Acpi table [%4.4s] - %u bytes written to %s\n",
636                 ThisSignature, (unsigned int) TotalBytesWritten, Filename);
637         }
638     }
639 
640     fclose (InputFile);
641     return (Status);
642 }
643 
644 
645 /******************************************************************************
646  *
647  * FUNCTION:    ListTables
648  *
649  * PARAMETERS:  InputPathname       - Filename for acpidump file
650  *
651  * RETURN:      Status
652  *
653  * DESCRIPTION: Display info for all ACPI tables found in input. Does not
654  *              perform an actual extraction of the tables.
655  *
656  ******************************************************************************/
657 
658 static int
659 ListTables (
660     char                    *InputPathname)
661 {
662     FILE                    *InputFile;
663     char                    Buffer[BUFFER_SIZE];
664     size_t                  HeaderSize;
665     unsigned char           Header[48];
666     int                     TableCount = 0;
667     ACPI_TABLE_HEADER       *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header;
668 
669 
670     /* Open input in text mode, output is in binary mode */
671 
672     InputFile = fopen (InputPathname, "rt");
673     if (!InputFile)
674     {
675         printf ("Could not open %s\n", InputPathname);
676         return (-1);
677     }
678 
679     /* Dump the headers for all tables found in the input file */
680 
681     printf ("\nSignature Length Revision  OemId     OemTableId"
682             "   OemRevision CompilerId CompilerRevision\n\n");
683 
684     while (fgets (Buffer, BUFFER_SIZE, InputFile))
685     {
686         /* Ignore empty lines and lines that start with a space */
687 
688         if ((Buffer[0] == ' ') ||
689             (Buffer[0] == '\n'))
690         {
691             continue;
692         }
693 
694         /* Get the 36 byte header and display the fields */
695 
696         HeaderSize = GetTableHeader (InputFile, Header);
697         if (HeaderSize < 16)
698         {
699             continue;
700         }
701 
702         /* RSDP has an oddball signature and header */
703 
704         if (!strncmp (TableHeader->Signature, "RSD PTR ", 8))
705         {
706             CheckAscii ((char *) &Header[9], 6);
707             printf ("%8.4s                   \"%6.6s\"\n", "RSDP", &Header[9]);
708             TableCount++;
709             continue;
710         }
711 
712         /* Minimum size for table with standard header */
713 
714         if (HeaderSize < 36)
715         {
716             continue;
717         }
718 
719         /* Signature and Table length */
720 
721         TableCount++;
722         printf ("%8.4s % 7d", TableHeader->Signature, TableHeader->Length);
723 
724         /* FACS has only signature and length */
725 
726         if (!strncmp (TableHeader->Signature, "FACS", 4))
727         {
728             printf ("\n");
729             continue;
730         }
731 
732         /* OEM IDs and Compiler IDs */
733 
734         CheckAscii (TableHeader->OemId, 6);
735         CheckAscii (TableHeader->OemTableId, 8);
736         CheckAscii (TableHeader->AslCompilerId, 4);
737 
738         printf ("     %2.2X    \"%6.6s\"  \"%8.8s\"    %8.8X    \"%4.4s\"     %8.8X\n",
739             TableHeader->Revision, TableHeader->OemId,
740             TableHeader->OemTableId, TableHeader->OemRevision,
741             TableHeader->AslCompilerId, TableHeader->AslCompilerRevision);
742     }
743 
744     printf ("\nFound %u ACPI tables [%8.8X]\n", TableCount, VERSION);
745     fclose (InputFile);
746     return (0);
747 }
748 
749 
750 /******************************************************************************
751  *
752  * FUNCTION:    main
753  *
754  * DESCRIPTION: C main function
755  *
756  ******************************************************************************/
757 
758 int
759 main (
760     int                     argc,
761     char                    *argv[])
762 {
763     int                     Status;
764 
765 
766     if (argc < 2)
767     {
768         DisplayUsage ();
769         return (0);
770     }
771 
772     if (argv[1][0] == '-')
773     {
774         if (argc < 3)
775         {
776             DisplayUsage ();
777             return (0);
778         }
779 
780         switch (argv[1][1])
781         {
782         case 'a':
783 
784             /* Extract all tables found */
785 
786             return (ExtractTables (argv[2], NULL, 0));
787 
788         case 'l':
789 
790             /* List tables only, do not extract */
791 
792             return (ListTables (argv[2]));
793 
794         case 's':
795 
796             /* Extract only tables with this signature */
797 
798             return (ExtractTables (argv[2], &argv[1][2], 1));
799 
800         default:
801             DisplayUsage ();
802             return (0);
803         }
804     }
805 
806     /*
807      * Default output is the DSDT and all SSDTs. One DSDT is required,
808      * any SSDTs are optional.
809      */
810     Status = ExtractTables (argv[1], "DSDT", 1);
811     if (Status)
812     {
813         return (Status);
814     }
815 
816     Status = ExtractTables (argv[1], "SSDT", 0);
817     return (Status);
818 }
819 
820 
821