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