1 /******************************************************************************
2  *
3  * Module Name: acpixtract - convert ascii ACPI tables to binary
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, 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 "acapps.h"
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <ctype.h>
52 
53 /* Local prototypes */
54 
55 static void
56 AxStrlwr (
57     char                    *String);
58 
59 static void
60 AxCheckAscii (
61     char                    *Name,
62     int                     Count);
63 
64 static void
65 AxNormalizeSignature (
66     char                    *Signature);
67 
68 static unsigned int
69 AxGetNextInstance (
70     char                    *InputPathname,
71     char                    *Signature);
72 
73 static size_t
74 AxGetTableHeader (
75     FILE                    *InputFile,
76     unsigned char           *OutputData);
77 
78 static unsigned int
79 AxCountTableInstances (
80     char                    *InputPathname,
81     char                    *Signature);
82 
83 int
84 AxExtractTables (
85     char                    *InputPathname,
86     char                    *Signature,
87     unsigned int            MinimumInstances);
88 
89 int
90 AxListTables (
91     char                    *InputPathname);
92 
93 static size_t
94 AxConvertLine (
95     char                    *InputLine,
96     unsigned char           *OutputData);
97 
98 static int
99 AxIsEmptyLine (
100     char                    *Buffer);
101 
102 typedef struct AxTableInfo
103 {
104     UINT32                  Signature;
105     unsigned int            Instances;
106     unsigned int            NextInstance;
107     struct AxTableInfo      *Next;
108 
109 } AX_TABLE_INFO;
110 
111 /* Extraction states */
112 
113 #define AX_STATE_FIND_HEADER        0
114 #define AX_STATE_EXTRACT_DATA       1
115 
116 /* Miscellaneous constants */
117 
118 #define AX_LINE_BUFFER_SIZE         256
119 #define AX_MIN_TABLE_NAME_LENGTH    6   /* strlen ("DSDT @") */
120 
121 
122 static AX_TABLE_INFO        *AxTableListHead = NULL;
123 static char                 Filename[16];
124 static unsigned char        Data[16];
125 static char                 LineBuffer[AX_LINE_BUFFER_SIZE];
126 static char                 HeaderBuffer[AX_LINE_BUFFER_SIZE];
127 static char                 InstanceBuffer[AX_LINE_BUFFER_SIZE];
128 
129 
130 /*******************************************************************************
131  *
132  * FUNCTION:    AxStrlwr
133  *
134  * PARAMETERS:  String              - Ascii string
135  *
136  * RETURN:      None
137  *
138  * DESCRIPTION: String lowercase function.
139  *
140  ******************************************************************************/
141 
142 static void
143 AxStrlwr (
144     char                    *String)
145 {
146 
147     while (*String)
148     {
149         *String = (char) tolower ((int) *String);
150         String++;
151     }
152 }
153 
154 
155 /*******************************************************************************
156  *
157  * FUNCTION:    AxCheckAscii
158  *
159  * PARAMETERS:  Name                - Ascii string, at least as long as Count
160  *              Count               - Number of characters to check
161  *
162  * RETURN:      None
163  *
164  * DESCRIPTION: Ensure that the requested number of characters are printable
165  *              Ascii characters. Sets non-printable and null chars to <space>.
166  *
167  ******************************************************************************/
168 
169 static void
170 AxCheckAscii (
171     char                    *Name,
172     int                     Count)
173 {
174     int                     i;
175 
176 
177     for (i = 0; i < Count; i++)
178     {
179         if (!Name[i] || !isprint ((int) Name[i]))
180         {
181             Name[i] = ' ';
182         }
183     }
184 }
185 
186 
187 /******************************************************************************
188  *
189  * FUNCTION:    AxIsEmptyLine
190  *
191  * PARAMETERS:  Buffer              - Line from input file
192  *
193  * RETURN:      TRUE if line is empty (zero or more blanks only)
194  *
195  * DESCRIPTION: Determine if an input line is empty.
196  *
197  ******************************************************************************/
198 
199 static int
200 AxIsEmptyLine (
201     char                    *Buffer)
202 {
203 
204     /* Skip all spaces */
205 
206     while (*Buffer == ' ')
207     {
208         Buffer++;
209     }
210 
211     /* If end-of-line, this line is empty */
212 
213     if (*Buffer == '\n')
214     {
215         return (1);
216     }
217 
218     return (0);
219 }
220 
221 
222 /*******************************************************************************
223  *
224  * FUNCTION:    AxNormalizeSignature
225  *
226  * PARAMETERS:  Name                - Ascii string containing an ACPI signature
227  *
228  * RETURN:      None
229  *
230  * DESCRIPTION: Change "RSD PTR" to "RSDP"
231  *
232  ******************************************************************************/
233 
234 static void
235 AxNormalizeSignature (
236     char                    *Signature)
237 {
238 
239     if (!strncmp (Signature, "RSD ", 4))
240     {
241         Signature[3] = 'P';
242     }
243 }
244 
245 
246 /******************************************************************************
247  *
248  * FUNCTION:    AxConvertLine
249  *
250  * PARAMETERS:  InputLine           - One line from the input acpidump file
251  *              OutputData          - Where the converted data is returned
252  *
253  * RETURN:      The number of bytes actually converted
254  *
255  * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes)
256  *
257  ******************************************************************************/
258 
259 static size_t
260 AxConvertLine (
261     char                    *InputLine,
262     unsigned char           *OutputData)
263 {
264     char                    *End;
265     int                     BytesConverted;
266     int                     Converted[16];
267     int                     i;
268 
269 
270     /* Terminate the input line at the end of the actual data (for sscanf) */
271 
272     End = strstr (InputLine + 2, "  ");
273     if (!End)
274     {
275         return (0); /* Don't understand the format */
276     }
277     *End = 0;
278 
279     /*
280      * Convert one line of table data, of the form:
281      * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline>
282      *
283      * Example:
284      * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08  _SB_LNKD........
285      */
286     BytesConverted = sscanf (InputLine,
287         "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
288         &Converted[0],  &Converted[1],  &Converted[2],  &Converted[3],
289         &Converted[4],  &Converted[5],  &Converted[6],  &Converted[7],
290         &Converted[8],  &Converted[9],  &Converted[10], &Converted[11],
291         &Converted[12], &Converted[13], &Converted[14], &Converted[15]);
292 
293     /* Pack converted data into a byte array */
294 
295     for (i = 0; i < BytesConverted; i++)
296     {
297         OutputData[i] = (unsigned char) Converted[i];
298     }
299 
300     return ((size_t) BytesConverted);
301 }
302 
303 
304 /******************************************************************************
305  *
306  * FUNCTION:    AxGetTableHeader
307  *
308  * PARAMETERS:  InputFile           - Handle for the input acpidump file
309  *              OutputData          - Where the table header is returned
310  *
311  * RETURN:      The actual number of bytes converted
312  *
313  * DESCRIPTION: Extract and convert an ACPI table header
314  *
315  ******************************************************************************/
316 
317 static size_t
318 AxGetTableHeader (
319     FILE                    *InputFile,
320     unsigned char           *OutputData)
321 {
322     size_t                  BytesConverted;
323     size_t                  TotalConverted = 0;
324     int                     i;
325 
326 
327     /* Get the full 36 byte ACPI table header, requires 3 input text lines */
328 
329     for (i = 0; i < 3; i++)
330     {
331         if (!fgets (HeaderBuffer, AX_LINE_BUFFER_SIZE, InputFile))
332         {
333             return (TotalConverted);
334         }
335 
336         BytesConverted = AxConvertLine (HeaderBuffer, OutputData);
337         TotalConverted += BytesConverted;
338         OutputData += 16;
339 
340         if (BytesConverted != 16)
341         {
342             return (TotalConverted);
343         }
344     }
345 
346     return (TotalConverted);
347 }
348 
349 
350 /******************************************************************************
351  *
352  * FUNCTION:    AxCountTableInstances
353  *
354  * PARAMETERS:  InputPathname       - Filename for acpidump file
355  *              Signature           - Requested signature to count
356  *
357  * RETURN:      The number of instances of the signature
358  *
359  * DESCRIPTION: Count the instances of tables with the given signature within
360  *              the input acpidump file.
361  *
362  ******************************************************************************/
363 
364 static unsigned int
365 AxCountTableInstances (
366     char                    *InputPathname,
367     char                    *Signature)
368 {
369     FILE                    *InputFile;
370     unsigned int            Instances = 0;
371 
372 
373     InputFile = fopen (InputPathname, "rt");
374     if (!InputFile)
375     {
376         printf ("Could not open file %s\n", InputPathname);
377         return (0);
378     }
379 
380     /* Count the number of instances of this signature */
381 
382     while (fgets (InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile))
383     {
384         /* Ignore empty lines and lines that start with a space */
385 
386         if (AxIsEmptyLine (InstanceBuffer) ||
387             (InstanceBuffer[0] == ' '))
388         {
389             continue;
390         }
391 
392         AxNormalizeSignature (InstanceBuffer);
393         if (ACPI_COMPARE_NAME (InstanceBuffer, Signature))
394         {
395             Instances++;
396         }
397     }
398 
399     fclose (InputFile);
400     return (Instances);
401 }
402 
403 
404 /******************************************************************************
405  *
406  * FUNCTION:    AxGetNextInstance
407  *
408  * PARAMETERS:  InputPathname       - Filename for acpidump file
409  *              Signature           - Requested ACPI signature
410  *
411  * RETURN:      The next instance number for this signature. Zero if this
412  *              is the first instance of this signature.
413  *
414  * DESCRIPTION: Get the next instance number of the specified table. If this
415  *              is the first instance of the table, create a new instance
416  *              block. Note: only SSDT and PSDT tables can have multiple
417  *              instances.
418  *
419  ******************************************************************************/
420 
421 static unsigned int
422 AxGetNextInstance (
423     char                    *InputPathname,
424     char                    *Signature)
425 {
426     AX_TABLE_INFO           *Info;
427 
428 
429     Info = AxTableListHead;
430     while (Info)
431     {
432         if (*(UINT32 *) Signature == Info->Signature)
433         {
434             break;
435         }
436 
437         Info = Info->Next;
438     }
439 
440     if (!Info)
441     {
442         /* Signature not found, create new table info block */
443 
444         Info = malloc (sizeof (AX_TABLE_INFO));
445         if (!Info)
446         {
447             printf ("Could not allocate memory\n");
448             exit (0);
449         }
450 
451         Info->Signature = *(UINT32 *) Signature;
452         Info->Instances = AxCountTableInstances (InputPathname, Signature);
453         Info->NextInstance = 1;
454         Info->Next = AxTableListHead;
455         AxTableListHead = Info;
456     }
457 
458     if (Info->Instances > 1)
459     {
460         return (Info->NextInstance++);
461     }
462 
463     return (0);
464 }
465 
466 
467 /******************************************************************************
468  *
469  * FUNCTION:    AxExtractTables
470  *
471  * PARAMETERS:  InputPathname       - Filename for acpidump file
472  *              Signature           - Requested ACPI signature to extract.
473  *                                    NULL means extract ALL tables.
474  *              MinimumInstances    - Min instances that are acceptable
475  *
476  * RETURN:      Status
477  *
478  * DESCRIPTION: Convert text ACPI tables to binary
479  *
480  ******************************************************************************/
481 
482 int
483 AxExtractTables (
484     char                    *InputPathname,
485     char                    *Signature,
486     unsigned int            MinimumInstances)
487 {
488     FILE                    *InputFile;
489     FILE                    *OutputFile = NULL;
490     size_t                  BytesWritten;
491     size_t                  TotalBytesWritten = 0;
492     size_t                  BytesConverted;
493     unsigned int            State = AX_STATE_FIND_HEADER;
494     unsigned int            FoundTable = 0;
495     unsigned int            Instances = 0;
496     unsigned int            ThisInstance;
497     char                    ThisSignature[4];
498     int                     Status = 0;
499 
500 
501     /* Open input in text mode, output is in binary mode */
502 
503     InputFile = fopen (InputPathname, "rt");
504     if (!InputFile)
505     {
506         printf ("Could not open file %s\n", InputPathname);
507         return (-1);
508     }
509 
510     if (Signature)
511     {
512         /* Are there enough instances of the table to continue? */
513 
514         AxNormalizeSignature (Signature);
515 
516         Instances = AxCountTableInstances (InputPathname, Signature);
517         if (Instances < MinimumInstances)
518         {
519             printf ("Table %s was not found in %s\n", Signature, InputPathname);
520             Status = -1;
521             goto CleanupAndExit;
522         }
523 
524         if (Instances == 0)
525         {
526             goto CleanupAndExit;
527         }
528     }
529 
530     /* Convert all instances of the table to binary */
531 
532     while (fgets (LineBuffer, AX_LINE_BUFFER_SIZE, InputFile))
533     {
534         switch (State)
535         {
536         case AX_STATE_FIND_HEADER:
537 
538             /* Ignore lines that are too short to be header lines */
539 
540             if (strlen (LineBuffer) < AX_MIN_TABLE_NAME_LENGTH)
541             {
542                 continue;
543             }
544 
545             /* Ignore empty lines and lines that start with a space */
546 
547             if (AxIsEmptyLine (LineBuffer) ||
548                 (LineBuffer[0] == ' '))
549             {
550                 continue;
551             }
552 
553             /*
554              * Ignore lines that are not of the form <sig> @ <addr>.
555              * Examples of lines that must be supported:
556              *
557              * DSDT @ 0x737e4000
558              * XSDT @ 0x737f2fff
559              * RSD PTR @ 0xf6cd0
560              * SSDT @ (nil)
561              */
562             if (!strstr (LineBuffer, " @ "))
563             {
564                 continue;
565             }
566 
567             AxNormalizeSignature (LineBuffer);
568             ACPI_MOVE_NAME (ThisSignature, LineBuffer);
569 
570             if (Signature)
571             {
572                 /* Ignore signatures that don't match */
573 
574                 if (!ACPI_COMPARE_NAME (ThisSignature, Signature))
575                 {
576                     continue;
577                 }
578             }
579 
580             /*
581              * Get the instance number for this signature. Only the
582              * SSDT and PSDT tables can have multiple instances.
583              */
584             ThisInstance = AxGetNextInstance (InputPathname, ThisSignature);
585 
586             /* Build an output filename and create/open the output file */
587 
588             if (ThisInstance > 0)
589             {
590                 sprintf (Filename, "%4.4s%u.dat", ThisSignature, ThisInstance);
591             }
592             else
593             {
594                 sprintf (Filename, "%4.4s.dat", ThisSignature);
595             }
596 
597             AxStrlwr (Filename);
598             OutputFile = fopen (Filename, "w+b");
599             if (!OutputFile)
600             {
601                 printf ("Could not open file %s\n", Filename);
602                 Status = -1;
603                 goto CleanupAndExit;
604             }
605 
606             State = AX_STATE_EXTRACT_DATA;
607             TotalBytesWritten = 0;
608             FoundTable = 1;
609             continue;
610 
611         case AX_STATE_EXTRACT_DATA:
612 
613             /* Empty line or non-data line terminates the data */
614 
615             if (AxIsEmptyLine (LineBuffer) ||
616                 (LineBuffer[0] != ' '))
617             {
618                 fclose (OutputFile);
619                 OutputFile = NULL;
620                 State = AX_STATE_FIND_HEADER;
621 
622                 printf ("Acpi table [%4.4s] - %u bytes written to %s\n",
623                     ThisSignature, (unsigned int) TotalBytesWritten, Filename);
624                 continue;
625             }
626 
627             /* Convert the ascii data (one line of text) to binary */
628 
629             BytesConverted = AxConvertLine (LineBuffer, Data);
630 
631             /* Write the binary data */
632 
633             BytesWritten = fwrite (Data, 1, BytesConverted, OutputFile);
634             if (BytesWritten != BytesConverted)
635             {
636                 printf ("Error when writing file %s\n", Filename);
637                 fclose (OutputFile);
638                 OutputFile = NULL;
639                 Status = -1;
640                 goto CleanupAndExit;
641             }
642 
643             TotalBytesWritten += BytesConverted;
644             continue;
645 
646         default:
647 
648             Status = -1;
649             goto CleanupAndExit;
650         }
651     }
652 
653     if (!FoundTable)
654     {
655         printf ("Table %s was not found in %s\n", Signature, InputPathname);
656     }
657 
658 
659 CleanupAndExit:
660 
661     if (OutputFile)
662     {
663         fclose (OutputFile);
664         if (State == AX_STATE_EXTRACT_DATA)
665         {
666             /* Received an EOF while extracting data */
667 
668             printf ("Acpi table [%4.4s] - %u bytes written to %s\n",
669                 ThisSignature, (unsigned int) TotalBytesWritten, Filename);
670         }
671     }
672 
673     fclose (InputFile);
674     return (Status);
675 }
676 
677 
678 /******************************************************************************
679  *
680  * FUNCTION:    AxListTables
681  *
682  * PARAMETERS:  InputPathname       - Filename for acpidump file
683  *
684  * RETURN:      Status
685  *
686  * DESCRIPTION: Display info for all ACPI tables found in input. Does not
687  *              perform an actual extraction of the tables.
688  *
689  ******************************************************************************/
690 
691 int
692 AxListTables (
693     char                    *InputPathname)
694 {
695     FILE                    *InputFile;
696     size_t                  HeaderSize;
697     unsigned char           Header[48];
698     int                     TableCount = 0;
699     ACPI_TABLE_HEADER       *TableHeader = (ACPI_TABLE_HEADER *) (void *) Header;
700 
701 
702     /* Open input in text mode, output is in binary mode */
703 
704     InputFile = fopen (InputPathname, "rt");
705     if (!InputFile)
706     {
707         printf ("Could not open file %s\n", InputPathname);
708         return (-1);
709     }
710 
711     /* Dump the headers for all tables found in the input file */
712 
713     printf ("\nSignature  Length      Revision   OemId    OemTableId"
714             "   OemRevision CompilerId CompilerRevision\n\n");
715 
716     while (fgets (LineBuffer, AX_LINE_BUFFER_SIZE, InputFile))
717     {
718         /* Ignore empty lines and lines that start with a space */
719 
720         if (AxIsEmptyLine (LineBuffer) ||
721             (LineBuffer[0] == ' '))
722         {
723             continue;
724         }
725 
726         /* Get the 36 byte header and display the fields */
727 
728         HeaderSize = AxGetTableHeader (InputFile, Header);
729         if (HeaderSize < 16)
730         {
731             continue;
732         }
733 
734         /* RSDP has an oddball signature and header */
735 
736         if (!strncmp (TableHeader->Signature, "RSD PTR ", 8))
737         {
738             AxCheckAscii ((char *) &Header[9], 6);
739             printf ("%7.4s                          \"%6.6s\"\n", "RSDP", &Header[9]);
740             TableCount++;
741             continue;
742         }
743 
744         /* Minimum size for table with standard header */
745 
746         if (HeaderSize < sizeof (ACPI_TABLE_HEADER))
747         {
748             continue;
749         }
750 
751         /* Signature and Table length */
752 
753         TableCount++;
754         printf ("%7.4s   0x%8.8X", TableHeader->Signature, TableHeader->Length);
755 
756         /* FACS has only signature and length */
757 
758         if (ACPI_COMPARE_NAME (TableHeader->Signature, "FACS"))
759         {
760             printf ("\n");
761             continue;
762         }
763 
764         /* OEM IDs and Compiler IDs */
765 
766         AxCheckAscii (TableHeader->OemId, 6);
767         AxCheckAscii (TableHeader->OemTableId, 8);
768         AxCheckAscii (TableHeader->AslCompilerId, 4);
769 
770         printf ("     0x%2.2X    \"%6.6s\"  \"%8.8s\"   0x%8.8X    \"%4.4s\"     0x%8.8X\n",
771             TableHeader->Revision, TableHeader->OemId,
772             TableHeader->OemTableId, TableHeader->OemRevision,
773             TableHeader->AslCompilerId, TableHeader->AslCompilerRevision);
774     }
775 
776     printf ("\nFound %u ACPI tables\n", TableCount);
777     fclose (InputFile);
778     return (0);
779 }
780