xref: /illumos-gate/usr/src/cmd/acpi/acpixtract/axutils.c (revision 7855d95b30fd903e3918bad5a29b777e765db821)
1 /******************************************************************************
2  *
3  * Module Name: axutils - Utility functions for acpixtract tool.
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 "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
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:    AxIsEmptyLine
82  *
83  * PARAMETERS:  Buffer              - Line from input file
84  *
85  * RETURN:      TRUE if line is empty (zero or more blanks only)
86  *
87  * DESCRIPTION: Determine if an input line is empty.
88  *
89  ******************************************************************************/
90 
91 int
92 AxIsEmptyLine (
93     char                    *Buffer)
94 {
95 
96     /* Skip all spaces */
97 
98     while (*Buffer == ' ')
99     {
100         Buffer++;
101     }
102 
103     /* If end-of-line, this line is empty */
104 
105     if (*Buffer == '\n')
106     {
107         return (1);
108     }
109 
110     return (0);
111 }
112 
113 
114 /*******************************************************************************
115  *
116  * FUNCTION:    AxNormalizeSignature
117  *
118  * PARAMETERS:  Name                - Ascii string containing an ACPI signature
119  *
120  * RETURN:      None
121  *
122  * DESCRIPTION: Change "RSD PTR" to "RSDP"
123  *
124  ******************************************************************************/
125 
126 void
127 AxNormalizeSignature (
128     char                    *Signature)
129 {
130 
131     if (!strncmp (Signature, "RSD ", 4))
132     {
133         Signature[3] = 'P';
134     }
135 }
136 
137 
138 /******************************************************************************
139  *
140  * FUNCTION:    AxConvertLine
141  *
142  * PARAMETERS:  InputLine           - One line from the input acpidump file
143  *              OutputData          - Where the converted data is returned
144  *
145  * RETURN:      The number of bytes actually converted
146  *
147  * DESCRIPTION: Convert one line of ascii text binary (up to 16 bytes)
148  *
149  ******************************************************************************/
150 
151 size_t
152 AxConvertLine (
153     char                    *InputLine,
154     unsigned char           *OutputData)
155 {
156     char                    *End;
157     int                     BytesConverted;
158     int                     Converted[16];
159     int                     i;
160 
161 
162     /* Terminate the input line at the end of the actual data (for sscanf) */
163 
164     End = strstr (InputLine + 2, "  ");
165     if (!End)
166     {
167         return (0); /* Don't understand the format */
168     }
169     *End = 0;
170 
171     /*
172      * Convert one line of table data, of the form:
173      * <offset>: <up to 16 bytes of hex data> <ASCII representation> <newline>
174      *
175      * Example:
176      * 02C0: 5F 53 42 5F 4C 4E 4B 44 00 12 13 04 0C FF FF 08  _SB_LNKD........
177      */
178     BytesConverted = sscanf (InputLine,
179         "%*s %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
180         &Converted[0],  &Converted[1],  &Converted[2],  &Converted[3],
181         &Converted[4],  &Converted[5],  &Converted[6],  &Converted[7],
182         &Converted[8],  &Converted[9],  &Converted[10], &Converted[11],
183         &Converted[12], &Converted[13], &Converted[14], &Converted[15]);
184 
185     /* Pack converted data into a byte array */
186 
187     for (i = 0; i < BytesConverted; i++)
188     {
189         OutputData[i] = (unsigned char) Converted[i];
190     }
191 
192     return ((size_t) BytesConverted);
193 }
194 
195 
196 /******************************************************************************
197  *
198  * FUNCTION:    AxGetTableHeader
199  *
200  * PARAMETERS:  InputFile           - Handle for the input acpidump file
201  *              OutputData          - Where the table header is returned
202  *
203  * RETURN:      The actual number of bytes converted
204  *
205  * DESCRIPTION: Extract and convert an ACPI table header
206  *
207  ******************************************************************************/
208 
209 size_t
210 AxGetTableHeader (
211     FILE                    *InputFile,
212     unsigned char           *OutputData)
213 {
214     size_t                  BytesConverted;
215     size_t                  TotalConverted = 0;
216     int                     i;
217 
218 
219     /* Get the full 36 byte ACPI table header, requires 3 input text lines */
220 
221     for (i = 0; i < 3; i++)
222     {
223         if (!fgets (Gbl_HeaderBuffer, AX_LINE_BUFFER_SIZE, InputFile))
224         {
225             return (TotalConverted);
226         }
227 
228         BytesConverted = AxConvertLine (Gbl_HeaderBuffer, OutputData);
229         TotalConverted += BytesConverted;
230         OutputData += 16;
231 
232         if (BytesConverted != 16)
233         {
234             return (TotalConverted);
235         }
236     }
237 
238     return (TotalConverted);
239 }
240 
241 
242 /******************************************************************************
243  *
244  * FUNCTION:    AxCountTableInstances
245  *
246  * PARAMETERS:  InputPathname       - Filename for acpidump file
247  *              Signature           - Requested signature to count
248  *
249  * RETURN:      The number of instances of the signature
250  *
251  * DESCRIPTION: Count the instances of tables with the given signature within
252  *              the input acpidump file.
253  *
254  ******************************************************************************/
255 
256 unsigned int
257 AxCountTableInstances (
258     char                    *InputPathname,
259     char                    *Signature)
260 {
261     FILE                    *InputFile;
262     unsigned int            Instances = 0;
263 
264 
265     InputFile = fopen (InputPathname, "rt");
266     if (!InputFile)
267     {
268         printf ("Could not open input file %s\n", InputPathname);
269         return (0);
270     }
271 
272     /* Count the number of instances of this signature */
273 
274     while (fgets (Gbl_InstanceBuffer, AX_LINE_BUFFER_SIZE, InputFile))
275     {
276         /* Ignore empty lines and lines that start with a space */
277 
278         if (AxIsEmptyLine (Gbl_InstanceBuffer) ||
279             (Gbl_InstanceBuffer[0] == ' '))
280         {
281             continue;
282         }
283 
284         AxNormalizeSignature (Gbl_InstanceBuffer);
285         if (ACPI_COMPARE_NAME (Gbl_InstanceBuffer, Signature))
286         {
287             Instances++;
288         }
289     }
290 
291     fclose (InputFile);
292     return (Instances);
293 }
294 
295 
296 /******************************************************************************
297  *
298  * FUNCTION:    AxGetNextInstance
299  *
300  * PARAMETERS:  InputPathname       - Filename for acpidump file
301  *              Signature           - Requested ACPI signature
302  *
303  * RETURN:      The next instance number for this signature. Zero if this
304  *              is the first instance of this signature.
305  *
306  * DESCRIPTION: Get the next instance number of the specified table. If this
307  *              is the first instance of the table, create a new instance
308  *              block. Note: only SSDT and PSDT tables can have multiple
309  *              instances.
310  *
311  ******************************************************************************/
312 
313 unsigned int
314 AxGetNextInstance (
315     char                    *InputPathname,
316     char                    *Signature)
317 {
318     AX_TABLE_INFO           *Info;
319 
320 
321     Info = Gbl_TableListHead;
322     while (Info)
323     {
324         if (*(UINT32 *) Signature == Info->Signature)
325         {
326             break;
327         }
328 
329         Info = Info->Next;
330     }
331 
332     if (!Info)
333     {
334         /* Signature not found, create new table info block */
335 
336         Info = malloc (sizeof (AX_TABLE_INFO));
337         if (!Info)
338         {
339             printf ("Could not allocate memory (0x%X bytes)\n",
340                 (unsigned int) sizeof (AX_TABLE_INFO));
341             exit (0);
342         }
343 
344         Info->Signature = *(UINT32 *) Signature;
345         Info->Instances = AxCountTableInstances (InputPathname, Signature);
346         Info->NextInstance = 1;
347         Info->Next = Gbl_TableListHead;
348         Gbl_TableListHead = Info;
349     }
350 
351     if (Info->Instances > 1)
352     {
353         return (Info->NextInstance++);
354     }
355 
356     return (0);
357 }
358 
359 
360 /******************************************************************************
361  *
362  * FUNCTION:    AxIsDataBlockHeader
363  *
364  * PARAMETERS:  None
365  *
366  * RETURN:      Status. 1 if the table header is valid, 0 otherwise.
367  *
368  * DESCRIPTION: Check if the ACPI table identifier in the input acpidump text
369  *              file is valid (of the form: <sig> @ <addr>).
370  *
371  ******************************************************************************/
372 
373 int
374 AxIsDataBlockHeader (
375     void)
376 {
377 
378     /* Ignore lines that are too short to be header lines */
379 
380     if (strlen (Gbl_LineBuffer) < AX_MIN_BLOCK_HEADER_LENGTH)
381     {
382         return (0);
383     }
384 
385     /* Ignore empty lines and lines that start with a space */
386 
387     if (AxIsEmptyLine (Gbl_LineBuffer) ||
388         (Gbl_LineBuffer[0] == ' '))
389     {
390         return (0);
391     }
392 
393     /*
394      * Ignore lines that are not headers of the form <sig> @ <addr>.
395      * Basically, just look for the '@' symbol, surrounded by spaces.
396      *
397      * Examples of headers that must be supported:
398      *
399      * DSDT @ 0x737e4000
400      * XSDT @ 0x737f2fff
401      * RSD PTR @ 0xf6cd0
402      * SSDT @ (nil)
403      */
404     if (!strstr (Gbl_LineBuffer, " @ "))
405     {
406         return (0);
407     }
408 
409     AxNormalizeSignature (Gbl_LineBuffer);
410     return (1);
411 }
412 
413 
414 /******************************************************************************
415  *
416  * FUNCTION:    AxProcessOneTextLine
417  *
418  * PARAMETERS:  OutputFile              - Where to write the binary data
419  *              ThisSignature           - Signature of current ACPI table
420  *              ThisTableBytesWritten   - Total count of data written
421  *
422  * RETURN:      Length of the converted line
423  *
424  * DESCRIPTION: Convert one line of input hex ascii text to binary, and write
425  *              the binary data to the table output file.
426  *
427  ******************************************************************************/
428 
429 long
430 AxProcessOneTextLine (
431     FILE                    *OutputFile,
432     char                    *ThisSignature,
433     unsigned int            ThisTableBytesWritten)
434 {
435     size_t                  BytesWritten;
436     size_t                  BytesConverted;
437 
438 
439     /* Check for the end of this table data block */
440 
441     if (AxIsEmptyLine (Gbl_LineBuffer) ||
442         (Gbl_LineBuffer[0] != ' '))
443     {
444         printf (AX_TABLE_INFO_FORMAT,
445             ThisSignature, ThisTableBytesWritten, Gbl_OutputFilename);
446         return (0);
447     }
448 
449     /* Convert one line of ascii hex data to binary */
450 
451     BytesConverted = AxConvertLine (Gbl_LineBuffer, Gbl_BinaryData);
452 
453     /* Write the binary data */
454 
455     BytesWritten = fwrite (Gbl_BinaryData, 1, BytesConverted, OutputFile);
456     if (BytesWritten != BytesConverted)
457     {
458         printf ("Error while writing file %s\n", Gbl_OutputFilename);
459         return (-1);
460     }
461 
462     return (BytesWritten);
463 }
464