xref: /freebsd/sys/contrib/dev/acpica/compiler/dtio.c (revision 8f861da99cb9865b2f1ef6098ad074150f368c23)
1 /******************************************************************************
2  *
3  * Module Name: dtio.c - File I/O support for data table compiler
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2011, 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 #define __DTIO_C__
45 
46 #include <contrib/dev/acpica/compiler/aslcompiler.h>
47 #include <contrib/dev/acpica/compiler/dtcompiler.h>
48 
49 #define _COMPONENT          DT_COMPILER
50         ACPI_MODULE_NAME    ("dtio")
51 
52 
53 /* Local prototypes */
54 
55 static char *
56 DtTrim (
57     char                    *String);
58 
59 static void
60 DtLinkField (
61     DT_FIELD                *Field);
62 
63 static ACPI_STATUS
64 DtParseLine (
65     char                    *LineBuffer,
66     UINT32                  Line,
67     UINT32                  Offset);
68 
69 static UINT32
70 DtGetNextLine (
71     FILE                    *Handle);
72 
73 static void
74 DtWriteBinary (
75     DT_SUBTABLE             *Subtable,
76     void                    *Context,
77     void                    *ReturnValue);
78 
79 static void
80 DtDumpBuffer (
81     UINT32                  FileId,
82     UINT8                   *Buffer,
83     UINT32                  Length);
84 
85 /* States for DtGetNextLine */
86 
87 #define DT_NORMAL_TEXT              0
88 #define DT_START_QUOTED_STRING      1
89 #define DT_START_COMMENT            2
90 #define DT_SLASH_ASTERISK_COMMENT   3
91 #define DT_SLASH_SLASH_COMMENT      4
92 #define DT_END_COMMENT              5
93 
94 static UINT32  Gbl_NextLineOffset;
95 
96 
97 /******************************************************************************
98  *
99  * FUNCTION:    DtTrim
100  *
101  * PARAMETERS:  String              - Current source code line to trim
102  *
103  * RETURN:      Trimmed line. Must be freed by caller.
104  *
105  * DESCRIPTION: Trim left and right spaces
106  *
107  *****************************************************************************/
108 
109 static char *
110 DtTrim (
111     char                    *String)
112 {
113     char                    *Start;
114     char                    *End;
115     char                    *ReturnString;
116     ACPI_SIZE               Length;
117 
118 
119     /* Skip lines that start with a space */
120 
121     if (!ACPI_STRCMP (String, " "))
122     {
123         ReturnString = UtLocalCalloc (1);
124         return (ReturnString);
125     }
126 
127     /* Setup pointers to start and end of input string */
128 
129     Start = String;
130     End = String + ACPI_STRLEN (String) - 1;
131 
132     /* Find first non-whitespace character */
133 
134     while ((Start <= End) && ((*Start == ' ') || (*Start == '\t')))
135     {
136         Start++;
137     }
138 
139     /* Find last non-space character */
140 
141     while (End >= Start)
142     {
143         if (*End == '\r' || *End == '\n')
144         {
145             End--;
146             continue;
147         }
148 
149         if (*End != ' ')
150         {
151             break;
152         }
153 
154         End--;
155     }
156 
157     /* Remove any quotes around the string */
158 
159     if (*Start == '\"')
160     {
161         Start++;
162     }
163     if (*End == '\"')
164     {
165         End--;
166     }
167 
168     /* Create the trimmed return string */
169 
170     Length = ACPI_PTR_DIFF (End, Start) + 1;
171     ReturnString = UtLocalCalloc (Length + 1);
172     if (ACPI_STRLEN (Start))
173     {
174         ACPI_STRNCPY (ReturnString, Start, Length);
175     }
176 
177     ReturnString[Length] = 0;
178     return (ReturnString);
179 }
180 
181 
182 /******************************************************************************
183  *
184  * FUNCTION:    DtLinkField
185  *
186  * PARAMETERS:  Field               - New field object to link
187  *
188  * RETURN:      None
189  *
190  * DESCRIPTION: Link one field name and value to the list
191  *
192  *****************************************************************************/
193 
194 static void
195 DtLinkField (
196     DT_FIELD                *Field)
197 {
198     DT_FIELD                *Prev;
199     DT_FIELD                *Next;
200 
201 
202     Prev = Next = Gbl_FieldList;
203 
204     while (Next)
205     {
206         Prev = Next;
207         Next = Next->Next;
208     }
209 
210     if (Prev)
211     {
212         Prev->Next = Field;
213     }
214     else
215     {
216         Gbl_FieldList = Field;
217     }
218 }
219 
220 
221 /******************************************************************************
222  *
223  * FUNCTION:    DtParseLine
224  *
225  * PARAMETERS:  LineBuffer          - Current source code line
226  *              Line                - Current line number in the source
227  *              Offset              - Current byte offset of the line
228  *
229  * RETURN:      Status
230  *
231  * DESCRIPTION: Parse one source line
232  *
233  *****************************************************************************/
234 
235 static ACPI_STATUS
236 DtParseLine (
237     char                    *LineBuffer,
238     UINT32                  Line,
239     UINT32                  Offset)
240 {
241     char                    *Start;
242     char                    *End;
243     char                    *TmpName;
244     char                    *TmpValue;
245     char                    *Name;
246     char                    *Value;
247     char                    *Colon;
248     UINT32                  Length;
249     DT_FIELD                *Field;
250     UINT32                  Column;
251     UINT32                  NameColumn;
252 
253 
254     if (!LineBuffer)
255     {
256         return (AE_OK);
257     }
258 
259     /* All lines after "Raw Table Data" are ingored */
260 
261     if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER))
262     {
263         return (AE_NOT_FOUND);
264     }
265 
266     Colon = strchr (LineBuffer, ':');
267     if (!Colon)
268     {
269         return (AE_OK);
270     }
271 
272     Start = LineBuffer;
273     End = Colon;
274 
275     while (Start < Colon)
276     {
277         if (*Start == ' ')
278         {
279             Start++;
280             continue;
281         }
282 
283         /* Found left bracket, go to the right bracket */
284 
285         if (*Start == '[')
286         {
287             while (Start < Colon && *Start != ']')
288             {
289                 Start++;
290             }
291 
292             if (Start == Colon)
293             {
294                 break;
295             }
296 
297             Start++;
298             continue;
299         }
300 
301         break;
302     }
303 
304     /*
305      * There are two column values. One for the field name,
306      * and one for the field value.
307      */
308     Column = ACPI_PTR_DIFF (Colon, LineBuffer) + 3;
309     NameColumn = ACPI_PTR_DIFF (Start, LineBuffer) + 1;
310 
311     Length = ACPI_PTR_DIFF (End, Start);
312 
313     TmpName = UtLocalCalloc (Length + 1);
314     ACPI_STRNCPY (TmpName, Start, Length);
315     Name = DtTrim (TmpName);
316     ACPI_FREE (TmpName);
317 
318     Start = End = (Colon + 1);
319 
320     while (*End)
321     {
322         /* Found left quotation, go to the right quotation and break */
323 
324         if (*End == '"')
325         {
326             End++;
327             while (*End && *End != '"')
328             {
329                 End++;
330             }
331 
332             End++;
333             break;
334         }
335 
336         if (*End == '(' ||
337             *End == '<' ||
338             *End == '/')
339         {
340             break;
341         }
342 
343         End++;
344     }
345 
346     Length = ACPI_PTR_DIFF (End, Start);
347     TmpValue = UtLocalCalloc (Length + 1);
348     ACPI_STRNCPY (TmpValue, Start, Length);
349     Value = DtTrim (TmpValue);
350     ACPI_FREE (TmpValue);
351 
352     if (Name && Value)
353     {
354         Field = UtLocalCalloc (sizeof (DT_FIELD));
355         Field->Name = Name;
356         Field->Value = Value;
357         Field->Line = Line;
358         Field->ByteOffset = Offset;
359         Field->NameColumn = NameColumn;
360         Field->Column = Column;
361 
362         DtLinkField (Field);
363     }
364 
365     return (AE_OK);
366 }
367 
368 
369 /******************************************************************************
370  *
371  * FUNCTION:    DtGetNextLine
372  *
373  * PARAMETERS:  Handle              - Open file handle for the source file
374  *
375  * RETURN:      Filled line buffer and offset of start-of-line (zero on EOF)
376  *
377  * DESCRIPTION: Get the next valid source line. Removes all comments.
378  *              Ignores empty lines.
379  *
380  * Handles both slash-asterisk and slash-slash comments.
381  * Also, quoted strings, but no escapes within.
382  *
383  * Line is returned in Gbl_CurrentLineBuffer.
384  * Line number in original file is returned in Gbl_CurrentLineNumber.
385  *
386  *****************************************************************************/
387 
388 static UINT32
389 DtGetNextLine (
390     FILE                    *Handle)
391 {
392     UINT32                  State = DT_NORMAL_TEXT;
393     UINT32                  CurrentLineOffset;
394     UINT32                  i;
395     char                    c;
396 
397 
398     for (i = 0; i < ASL_LINE_BUFFER_SIZE;)
399     {
400         c = (char) getc (Handle);
401         if (c == EOF)
402         {
403             return (0);
404         }
405 
406         switch (State)
407         {
408         case DT_NORMAL_TEXT:
409 
410             /* Normal text, insert char into line buffer */
411 
412             Gbl_CurrentLineBuffer[i] = c;
413             switch (c)
414             {
415             case '/':
416                 State = DT_START_COMMENT;
417                 break;
418 
419             case '"':
420                 State = DT_START_QUOTED_STRING;
421                 i++;
422                 break;
423 
424             case '\n':
425                 CurrentLineOffset = Gbl_NextLineOffset;
426                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
427                 Gbl_CurrentLineNumber++;
428 
429                 /* Exit if line is complete. Ignore blank lines */
430 
431                 if (i != 0)
432                 {
433                     Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate line */
434                     return (CurrentLineOffset);
435                 }
436                 break;
437 
438             default:
439                 i++;
440                 break;
441             }
442             break;
443 
444         case DT_START_QUOTED_STRING:
445 
446             /* Insert raw chars until end of quoted string */
447 
448             Gbl_CurrentLineBuffer[i] = c;
449             i++;
450 
451             if (c == '"')
452             {
453                 State = DT_NORMAL_TEXT;
454             }
455             break;
456 
457         case DT_START_COMMENT:
458 
459             /* Open comment if this character is an asterisk or slash */
460 
461             switch (c)
462             {
463             case '*':
464                 State = DT_SLASH_ASTERISK_COMMENT;
465                 break;
466 
467             case '/':
468                 State = DT_SLASH_SLASH_COMMENT;
469                 break;
470 
471             default:    /* Not a comment */
472                 i++;    /* Save the preceeding slash */
473                 Gbl_CurrentLineBuffer[i] = c;
474                 i++;
475                 State = DT_NORMAL_TEXT;
476                 break;
477             }
478             break;
479 
480         case DT_SLASH_ASTERISK_COMMENT:
481 
482             /* Ignore chars until an asterisk-slash is found */
483 
484             switch (c)
485             {
486             case '\n':
487                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
488                 Gbl_CurrentLineNumber++;
489                 break;
490 
491             case '*':
492                 State = DT_END_COMMENT;
493                 break;
494 
495             default:
496                 break;
497             }
498             break;
499 
500         case DT_SLASH_SLASH_COMMENT:
501 
502             /* Ignore chars until end-of-line */
503 
504             if (c == '\n')
505             {
506                 /* We will exit via the NORMAL_TEXT path */
507 
508                 ungetc (c, Handle);
509                 State = DT_NORMAL_TEXT;
510             }
511             break;
512 
513         case DT_END_COMMENT:
514 
515             /* End comment if this char is a slash */
516 
517             switch (c)
518             {
519             case '/':
520                 State = DT_NORMAL_TEXT;
521                 break;
522 
523             default:
524                 State = DT_SLASH_ASTERISK_COMMENT;
525                 break;
526             }
527             break;
528 
529         default:
530             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state");
531             return (0);
532         }
533     }
534 
535     printf ("ERROR - Input line is too long (max %u)\n", ASL_LINE_BUFFER_SIZE);
536     return (0);
537 }
538 
539 
540 /******************************************************************************
541  *
542  * FUNCTION:    DtScanFile
543  *
544  * PARAMETERS:  Handle              - Open file handle for the source file
545  *
546  * RETURN:      Pointer to start of the constructed parse tree.
547  *
548  * DESCRIPTION: Scan source file, link all field names and values
549  *              to the global parse tree: Gbl_FieldList
550  *
551  *****************************************************************************/
552 
553 DT_FIELD *
554 DtScanFile (
555     FILE                    *Handle)
556 {
557     ACPI_STATUS             Status;
558     UINT32                  Offset;
559 
560 
561     ACPI_FUNCTION_NAME (DtScanFile);
562 
563 
564     /* Get the file size */
565 
566     Gbl_InputByteCount = DtGetFileSize (Handle);
567 
568     Gbl_CurrentLineNumber = 0;
569     Gbl_CurrentLineOffset = 0;
570     Gbl_NextLineOffset = 0;
571 
572     /* Scan line-by-line */
573 
574     while ((Offset = DtGetNextLine (Handle)))
575     {
576         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s",
577             Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer));
578 
579         Status = DtParseLine (Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber, Offset);
580         if (Status == AE_NOT_FOUND)
581         {
582             break;
583         }
584     }
585 
586     return (Gbl_FieldList);
587 }
588 
589 
590 /*
591  * Output functions
592  */
593 
594 /******************************************************************************
595  *
596  * FUNCTION:    DtWriteBinary
597  *
598  * PARAMETERS:  DT_WALK_CALLBACK
599  *
600  * RETURN:      Status
601  *
602  * DESCRIPTION: Write one subtable of a binary ACPI table
603  *
604  *****************************************************************************/
605 
606 static void
607 DtWriteBinary (
608     DT_SUBTABLE             *Subtable,
609     void                    *Context,
610     void                    *ReturnValue)
611 {
612 
613     FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length);
614 }
615 
616 
617 /******************************************************************************
618  *
619  * FUNCTION:    DtOutputBinary
620  *
621  * PARAMETERS:
622  *
623  * RETURN:      Status
624  *
625  * DESCRIPTION: Write entire binary ACPI table (result of compilation)
626  *
627  *****************************************************************************/
628 
629 void
630 DtOutputBinary (
631     DT_SUBTABLE             *RootTable)
632 {
633 
634     if (!RootTable)
635     {
636         return;
637     }
638 
639     /* Walk the entire parse tree, emitting the binary data */
640 
641     DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL);
642     Gbl_TableLength = DtGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
643 }
644 
645 
646 /*
647  * Listing support
648  */
649 
650 /******************************************************************************
651  *
652  * FUNCTION:    DtDumpBuffer
653  *
654  * PARAMETERS:  FileID              - Where to write buffer data
655  *              Buffer              - Buffer to dump
656  *              Length              - Buffer Length
657  *
658  * RETURN:      None
659  *
660  * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately).
661  *
662  * TBD: merge dump buffer routines
663  *
664  *****************************************************************************/
665 
666 static void
667 DtDumpBuffer (
668     UINT32                  FileId,
669     UINT8                   *Buffer,
670     UINT32                  Length)
671 {
672     UINT32                  i;
673     UINT32                  j;
674     UINT8                   BufChar;
675 
676 
677     i = 0;
678     while (i < Length)
679     {
680         /* Print 16 hex chars */
681 
682         FlPrintFile (FileId, "Output: [%.3d] ", Length);
683 
684         for (j = 0; j < 16;)
685         {
686             if (i + j >= Length)
687             {
688                 /* Dump fill spaces */
689 
690                 FlPrintFile (FileId, "   ");
691                 j++;
692                 continue;
693             }
694 
695             FlPrintFile (FileId, "%02X ", Buffer[i+j]);
696             j++;
697         }
698 
699         FlPrintFile (FileId, " ");
700         for (j = 0; j < 16; j++)
701         {
702             if (i + j >= Length)
703             {
704                 FlPrintFile (FileId, "\n\n");
705                 return;
706             }
707 
708             BufChar = Buffer[(ACPI_SIZE) i + j];
709             if (ACPI_IS_PRINT (BufChar))
710             {
711                 FlPrintFile (FileId, "%c", BufChar);
712             }
713             else
714             {
715                 FlPrintFile (FileId, ".");
716             }
717         }
718 
719         /* Done with that line. */
720 
721         FlPrintFile (FileId, "\n");
722         i += 16;
723     }
724 
725     FlPrintFile (FileId, "\n\n");
726 }
727 
728 
729 /******************************************************************************
730  *
731  * FUNCTION:    DtWriteFieldToListing
732  *
733  * PARAMETERS:  Buffer              - Contains the compiled data
734  *              Field               - Field node for the input line
735  *              Length              - Length of the output data
736  *
737  * RETURN:      None
738  *
739  * DESCRIPTION: Write one field to the listing file (if listing is enabled).
740  *
741  *****************************************************************************/
742 
743 void
744 DtWriteFieldToListing (
745     UINT8                   *Buffer,
746     DT_FIELD                *Field,
747     UINT32                  Length)
748 {
749     UINT8                   FileByte;
750 
751 
752     if (!Gbl_ListingFlag || !Field)
753     {
754         return;
755     }
756 
757     /* Dump the original source line */
758 
759     FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input:  ");
760     FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset);
761 
762     while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK)
763     {
764         FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1);
765         if (FileByte == '\n')
766         {
767             break;
768         }
769     }
770 
771     /* Dump the line as parsed and represented internally */
772 
773     FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %s\n",
774         Field->Column-4, Field->Name, Field->Value);
775 
776 #if 0
777     /* TBD Dump the length and AML offset */
778 
779     FlPrintFile (ASL_FILE_LISTING_OUTPUT,
780         "Output: Length %d(0x%X) Offset %d(0x%X)\n",
781         Field->Column-4, Field->Name, Field->Value);
782 #endif
783 
784     /* Dump the hex data that will be output for this field */
785 
786     DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Length);
787 }
788 
789 
790 /******************************************************************************
791  *
792  * FUNCTION:    DtWriteTableToListing
793  *
794  * PARAMETERS:  None
795  *
796  * RETURN:      None
797  *
798  * DESCRIPTION: Write the entire compiled table to the listing file
799  *              in hex format
800  *
801  *****************************************************************************/
802 
803 void
804 DtWriteTableToListing (
805     void)
806 {
807     UINT8                   *Buffer;
808 
809 
810     if (!Gbl_ListingFlag)
811     {
812         return;
813     }
814 
815     /* Read the entire table from the output file */
816 
817     Buffer = UtLocalCalloc (Gbl_TableLength);
818     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
819     FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength);
820 
821     /* Dump the raw table data */
822 
823     AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle);
824 
825     AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n",
826         ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength);
827     AcpiUtDumpBuffer2 (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY);
828 
829     AcpiOsRedirectOutput (stdout);
830 }
831