dtutils.c revision 220663
1/******************************************************************************
2 *
3 * Module Name: dtutils.c - Utility routines for the 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 __DTUTILS_C__
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include <contrib/dev/acpica/compiler/dtcompiler.h>
48#include <contrib/dev/acpica/include/actables.h>
49
50#define _COMPONENT          DT_COMPILER
51        ACPI_MODULE_NAME    ("dtutils")
52
53/* Local prototypes */
54
55static void
56DtSum (
57    DT_SUBTABLE             *Subtable,
58    void                    *Context,
59    void                    *ReturnValue);
60
61
62/******************************************************************************
63 *
64 * FUNCTION:    DtError
65 *
66 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
67 *              MessageId           - Index into global message buffer
68 *              Op                  - Parse node where error happened
69 *              ExtraMessage        - additional error message
70 *
71 * RETURN:      None
72 *
73 * DESCRIPTION: Common error interface for data table compiler
74 *
75 *****************************************************************************/
76
77void
78DtError (
79    UINT8                   Level,
80    UINT8                   MessageId,
81    DT_FIELD                *FieldObject,
82    char                    *ExtraMessage)
83{
84
85    switch (Level)
86    {
87    case ASL_WARNING2:
88    case ASL_WARNING3:
89        if (Gbl_WarningLevel < Level)
90        {
91            return;
92        }
93        break;
94
95    default:
96        break;
97    }
98
99    if (FieldObject)
100    {
101        AslCommonError (Level, MessageId,
102            FieldObject->Line,
103            FieldObject->Line,
104            FieldObject->ByteOffset,
105            FieldObject->Column,
106            Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
107    }
108    else
109    {
110        AslCommonError (Level, MessageId, 0,
111            0, 0, 0, 0, ExtraMessage);
112    }
113}
114
115
116/******************************************************************************
117 *
118 * FUNCTION:    DtNameError
119 *
120 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
121 *              MessageId           - Index into global message buffer
122 *              Op                  - Parse node where error happened
123 *              ExtraMessage        - additional error message
124 *
125 * RETURN:      None
126 *
127 * DESCRIPTION: Error interface for named objects
128 *
129 *****************************************************************************/
130
131void
132DtNameError (
133    UINT8                   Level,
134    UINT8                   MessageId,
135    DT_FIELD                *FieldObject,
136    char                    *ExtraMessage)
137{
138
139    switch (Level)
140    {
141    case ASL_WARNING2:
142    case ASL_WARNING3:
143        if (Gbl_WarningLevel < Level)
144        {
145            return;
146        }
147        break;
148
149    default:
150        break;
151    }
152
153    if (FieldObject)
154    {
155        AslCommonError (Level, MessageId,
156            FieldObject->Line,
157            FieldObject->Line,
158            FieldObject->ByteOffset,
159            FieldObject->NameColumn,
160            Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
161    }
162    else
163    {
164        AslCommonError (Level, MessageId, 0,
165            0, 0, 0, 0, ExtraMessage);
166    }
167}
168
169
170/*******************************************************************************
171 *
172 * FUNCTION:    DtFatal
173 *
174 * PARAMETERS:  None
175 *
176 * RETURN:      None
177 *
178 * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
179 *              compile or I/O errors
180 *
181 ******************************************************************************/
182
183void
184DtFatal (
185    UINT8                   MessageId,
186    DT_FIELD                *FieldObject,
187    char                    *ExtraMessage)
188{
189
190    DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
191
192/*
193 * TBD: remove this entire function, DtFatal
194 *
195 * We cannot abort the compiler on error, because we may be compiling a
196 * list of files. We must move on to the next file.
197 */
198#ifdef __OBSOLETE
199    CmCleanupAndExit ();
200    exit (1);
201#endif
202}
203
204
205/******************************************************************************
206 *
207 * FUNCTION:    DtStrtoul64
208 *
209 * PARAMETERS:  String              - Null terminated string
210 *              ReturnInteger       - Where the converted integer is returned
211 *
212 * RETURN:      Status
213 *
214 * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
215 *              value. Assumes no leading "0x" for the constant.
216 *
217 * Portability note: The reason this function exists is because a 64-bit
218 * sscanf is not available in all environments.
219 *
220 *****************************************************************************/
221
222ACPI_STATUS
223DtStrtoul64 (
224    char                    *String,
225    UINT64                  *ReturnInteger)
226{
227    char                    *ThisChar = String;
228    UINT32                  ThisDigit;
229    UINT64                  ReturnValue = 0;
230    int                     DigitCount = 0;
231
232
233    /* Skip over any white space in the buffer */
234
235    while ((*ThisChar == ' ') || (*ThisChar == '\t'))
236    {
237        ThisChar++;
238    }
239
240    /* Skip leading zeros */
241
242    while ((*ThisChar) == '0')
243    {
244        ThisChar++;
245    }
246
247    /* Convert character-by-character */
248
249    while (*ThisChar)
250    {
251        if (ACPI_IS_DIGIT (*ThisChar))
252        {
253            /* Convert ASCII 0-9 to Decimal value */
254
255            ThisDigit = ((UINT8) *ThisChar) - '0';
256        }
257        else /* Letter */
258        {
259            ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar);
260            if (!ACPI_IS_XDIGIT ((char) ThisDigit))
261            {
262                /* Not A-F */
263
264                return (AE_BAD_CHARACTER);
265            }
266
267            /* Convert ASCII Hex char (A-F) to value */
268
269            ThisDigit = (ThisDigit - 'A') + 10;
270        }
271
272        /* Insert the 4-bit hex digit */
273
274        ReturnValue <<= 4;
275        ReturnValue += ThisDigit;
276
277        ThisChar++;
278        DigitCount++;
279        if (DigitCount > 16)
280        {
281            /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
282
283            return (AE_LIMIT);
284        }
285    }
286
287    *ReturnInteger = ReturnValue;
288    return (AE_OK);
289}
290
291
292/******************************************************************************
293 *
294 * FUNCTION:    DtGetFileSize
295 *
296 * PARAMETERS:  Handle              - Open file handler
297 *
298 * RETURN:      Current file size
299 *
300 * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the
301 *              offset. Seek back to the original location.
302 *
303 *****************************************************************************/
304
305UINT32
306DtGetFileSize (
307    FILE                    *Handle)
308{
309    int                     CurrentOffset;
310    int                     LastOffset;
311
312
313    CurrentOffset = ftell (Handle);
314    fseek (Handle, 0, SEEK_END);
315    LastOffset = ftell (Handle);
316    fseek (Handle, CurrentOffset, SEEK_SET);
317
318    return ((UINT32) LastOffset);
319}
320
321
322/******************************************************************************
323 *
324 * FUNCTION:    DtGetFieldValue
325 *
326 * PARAMETERS:  Field               - Current field list pointer
327 *
328 * RETURN:      Field value
329 *
330 * DESCRIPTION: Get field value
331 *
332 *****************************************************************************/
333
334char *
335DtGetFieldValue (
336    DT_FIELD                *Field)
337{
338    if (!Field)
339    {
340        return (NULL);
341    }
342
343    return (Field->Value);
344}
345
346
347/******************************************************************************
348 *
349 * FUNCTION:    DtGetFieldType
350 *
351 * PARAMETERS:  Info                - Data table info
352 *
353 * RETURN:      Field type
354 *
355 * DESCRIPTION: Get field type
356 *
357 *****************************************************************************/
358
359UINT8
360DtGetFieldType (
361    ACPI_DMTABLE_INFO       *Info)
362{
363    UINT8                   Type;
364
365
366    /* DT_FLAG means that this is the start of a block of flag bits */
367    /* TBD - we can make these a separate opcode later */
368
369    if (Info->Flags & DT_FLAG)
370    {
371        return (DT_FIELD_TYPE_FLAGS_INTEGER);
372    }
373
374    /* Type is based upon the opcode for this field in the info table */
375
376    switch (Info->Opcode)
377    {
378    case ACPI_DMT_FLAG0:
379    case ACPI_DMT_FLAG1:
380    case ACPI_DMT_FLAG2:
381    case ACPI_DMT_FLAG3:
382    case ACPI_DMT_FLAG4:
383    case ACPI_DMT_FLAG5:
384    case ACPI_DMT_FLAG6:
385    case ACPI_DMT_FLAG7:
386    case ACPI_DMT_FLAGS0:
387    case ACPI_DMT_FLAGS2:
388        Type = DT_FIELD_TYPE_FLAG;
389        break;
390
391    case ACPI_DMT_NAME4:
392    case ACPI_DMT_SIG:
393    case ACPI_DMT_NAME6:
394    case ACPI_DMT_NAME8:
395    case ACPI_DMT_STRING:
396        Type = DT_FIELD_TYPE_STRING;
397        break;
398
399    case ACPI_DMT_BUFFER:
400    case ACPI_DMT_BUF7:
401    case ACPI_DMT_BUF16:
402    case ACPI_DMT_BUF128:
403    case ACPI_DMT_PCI_PATH:
404        Type = DT_FIELD_TYPE_BUFFER;
405        break;
406
407    case ACPI_DMT_GAS:
408    case ACPI_DMT_HESTNTFY:
409        Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
410        break;
411
412    case ACPI_DMT_UNICODE:
413        Type = DT_FIELD_TYPE_UNICODE;
414        break;
415
416    case ACPI_DMT_UUID:
417        Type = DT_FIELD_TYPE_UUID;
418        break;
419
420    case ACPI_DMT_DEVICE_PATH:
421        Type = DT_FIELD_TYPE_DEVICE_PATH;
422        break;
423
424    case ACPI_DMT_LABEL:
425        Type = DT_FIELD_TYPE_LABEL;
426        break;
427
428    default:
429        Type = DT_FIELD_TYPE_INTEGER;
430        break;
431    }
432
433    return (Type);
434}
435
436
437/******************************************************************************
438 *
439 * FUNCTION:    DtGetBufferLength
440 *
441 * PARAMETERS:  Buffer              - List of integers,
442 *                                    for example "10 3A 4F 2E"
443 *
444 * RETURN:      Count of integer
445 *
446 * DESCRIPTION: Get length of bytes needed to store the integers
447 *
448 *****************************************************************************/
449
450UINT32
451DtGetBufferLength (
452    char                    *Buffer)
453{
454    UINT32                  ByteLength = 0;
455
456
457    while (*Buffer)
458    {
459        if (*Buffer == ' ')
460        {
461            ByteLength++;
462
463            while (*Buffer == ' ')
464            {
465                Buffer++;
466            }
467        }
468
469        Buffer++;
470    }
471
472    return (++ByteLength);
473}
474
475
476/******************************************************************************
477 *
478 * FUNCTION:    DtGetFieldLength
479 *
480 * PARAMETERS:  Field               - Current field
481 *              Info                - Data table info
482 *
483 * RETURN:      Field length
484 *
485 * DESCRIPTION: Get length of bytes needed to compile the field
486 *
487 * Note: This function must remain in sync with AcpiDmDumpTable.
488 *
489 *****************************************************************************/
490
491UINT32
492DtGetFieldLength (
493    DT_FIELD                *Field,
494    ACPI_DMTABLE_INFO       *Info)
495{
496    UINT32                  ByteLength = 0;
497    char                    *Value;
498
499
500    /* Length is based upon the opcode for this field in the info table */
501
502    switch (Info->Opcode)
503    {
504    case ACPI_DMT_FLAG0:
505    case ACPI_DMT_FLAG1:
506    case ACPI_DMT_FLAG2:
507    case ACPI_DMT_FLAG3:
508    case ACPI_DMT_FLAG4:
509    case ACPI_DMT_FLAG5:
510    case ACPI_DMT_FLAG6:
511    case ACPI_DMT_FLAG7:
512    case ACPI_DMT_FLAGS0:
513    case ACPI_DMT_FLAGS2:
514    case ACPI_DMT_LABEL:
515        ByteLength = 0;
516        break;
517
518    case ACPI_DMT_UINT8:
519    case ACPI_DMT_CHKSUM:
520    case ACPI_DMT_SPACEID:
521    case ACPI_DMT_ACCWIDTH:
522    case ACPI_DMT_IVRS:
523    case ACPI_DMT_MADT:
524    case ACPI_DMT_SRAT:
525    case ACPI_DMT_ASF:
526    case ACPI_DMT_HESTNTYP:
527    case ACPI_DMT_FADTPM:
528    case ACPI_DMT_EINJACT:
529    case ACPI_DMT_EINJINST:
530    case ACPI_DMT_ERSTACT:
531    case ACPI_DMT_ERSTINST:
532        ByteLength = 1;
533        break;
534
535    case ACPI_DMT_UINT16:
536    case ACPI_DMT_DMAR:
537    case ACPI_DMT_HEST:
538    case ACPI_DMT_PCI_PATH:
539        ByteLength = 2;
540        break;
541
542    case ACPI_DMT_UINT24:
543        ByteLength = 3;
544        break;
545
546    case ACPI_DMT_UINT32:
547    case ACPI_DMT_NAME4:
548    case ACPI_DMT_SLIC:
549    case ACPI_DMT_SIG:
550        ByteLength = 4;
551        break;
552
553    case ACPI_DMT_NAME6:
554        ByteLength = 6;
555        break;
556
557    case ACPI_DMT_UINT56:
558    case ACPI_DMT_BUF7:
559        ByteLength = 7;
560        break;
561
562    case ACPI_DMT_UINT64:
563    case ACPI_DMT_NAME8:
564        ByteLength = 8;
565        break;
566
567    case ACPI_DMT_STRING:
568        Value = DtGetFieldValue (Field);
569        if (Value)
570        {
571            ByteLength = ACPI_STRLEN (Value) + 1;
572        }
573        else
574        {   /* At this point, this is a fatal error */
575
576            sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
577            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
578            return (0);
579        }
580        break;
581
582    case ACPI_DMT_GAS:
583        ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
584        break;
585
586    case ACPI_DMT_HESTNTFY:
587        ByteLength = sizeof (ACPI_HEST_NOTIFY);
588        break;
589
590    case ACPI_DMT_BUFFER:
591        Value = DtGetFieldValue (Field);
592        if (Value)
593        {
594            ByteLength = DtGetBufferLength (Value);
595        }
596        else
597        {   /* At this point, this is a fatal error */
598
599            sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
600            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
601            return (0);
602        }
603        break;
604
605    case ACPI_DMT_BUF16:
606    case ACPI_DMT_UUID:
607        ByteLength = 16;
608        break;
609
610    case ACPI_DMT_BUF128:
611        ByteLength = 128;
612        break;
613
614    case ACPI_DMT_UNICODE:
615        Value = DtGetFieldValue (Field);
616
617        /* TBD: error if Value is NULL? (as below?) */
618
619        ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
620        break;
621
622    default:
623        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
624        return (0);
625    }
626
627    return (ByteLength);
628}
629
630
631/******************************************************************************
632 *
633 * FUNCTION:    DtSum
634 *
635 * PARAMETERS:  DT_WALK_CALLBACK:
636 *              Subtable            - Subtable
637 *              Context             - Unused
638 *              ReturnValue         - Store the checksum of subtable
639 *
640 * RETURN:      Status
641 *
642 * DESCRIPTION: Get the checksum of subtable
643 *
644 *****************************************************************************/
645
646static void
647DtSum (
648    DT_SUBTABLE             *Subtable,
649    void                    *Context,
650    void                    *ReturnValue)
651{
652    UINT8                   Checksum;
653    UINT8                   *Sum = ReturnValue;
654
655
656    Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
657    *Sum = (UINT8) (*Sum + Checksum);
658}
659
660
661/******************************************************************************
662 *
663 * FUNCTION:    DtSetTableChecksum
664 *
665 * PARAMETERS:  ChecksumPointer     - Where to return the checksum
666 *
667 * RETURN:      None
668 *
669 * DESCRIPTION: Set checksum of the whole data table into the checksum field
670 *
671 *****************************************************************************/
672
673void
674DtSetTableChecksum (
675    UINT8                   *ChecksumPointer)
676{
677    UINT8                   Checksum = 0;
678    UINT8                   OldSum;
679
680
681    DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
682
683    OldSum = *ChecksumPointer;
684    Checksum = (UINT8) (Checksum - OldSum);
685
686    /* Compute the final checksum */
687
688    Checksum = (UINT8) (0 - Checksum);
689    *ChecksumPointer = Checksum;
690}
691
692
693/******************************************************************************
694 *
695 * FUNCTION:    DtSetTableLength
696 *
697 * PARAMETERS:  None
698 *
699 * RETURN:      None
700 *
701 * DESCRIPTION: Walk the subtables and set all the length fields
702 *
703 *****************************************************************************/
704
705void
706DtSetTableLength (
707    void)
708{
709    DT_SUBTABLE             *ParentTable;
710    DT_SUBTABLE             *ChildTable;
711
712
713    ParentTable = Gbl_RootTable;
714    ChildTable = NULL;
715
716    if (!ParentTable)
717    {
718        return;
719    }
720
721    DtSetSubtableLength (ParentTable);
722
723    while (1)
724    {
725        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
726        if (ChildTable)
727        {
728            if (ChildTable->LengthField)
729            {
730                DtSetSubtableLength (ChildTable);
731            }
732
733            if (ChildTable->Child)
734            {
735                ParentTable = ChildTable;
736                ChildTable = NULL;
737            }
738            else
739            {
740                ParentTable->TotalLength += ChildTable->TotalLength;
741                if (ParentTable->LengthField)
742                {
743                    DtSetSubtableLength (ParentTable);
744                }
745            }
746        }
747        else
748        {
749            ChildTable = ParentTable;
750
751            if (ChildTable == Gbl_RootTable)
752            {
753                break;
754            }
755
756            ParentTable = DtGetParentSubtable (ParentTable);
757
758            ParentTable->TotalLength += ChildTable->TotalLength;
759            if (ParentTable->LengthField)
760            {
761                DtSetSubtableLength (ParentTable);
762            }
763        }
764    }
765}
766
767
768/******************************************************************************
769 *
770 * FUNCTION:    DtWalkTableTree
771 *
772 * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
773 *              UserFunction        - Called during the walk
774 *              Context             - Passed to user function
775 *              ReturnValue         - The return value of UserFunction
776 *
777 * RETURN:      None
778 *
779 * DESCRIPTION: Performs a depth-first walk of the subtable tree
780 *
781 *****************************************************************************/
782
783void
784DtWalkTableTree (
785    DT_SUBTABLE             *StartTable,
786    DT_WALK_CALLBACK        UserFunction,
787    void                    *Context,
788    void                    *ReturnValue)
789{
790    DT_SUBTABLE             *ParentTable;
791    DT_SUBTABLE             *ChildTable;
792
793
794    ParentTable = StartTable;
795    ChildTable = NULL;
796
797    if (!ParentTable)
798    {
799        return;
800    }
801
802    UserFunction (ParentTable, Context, ReturnValue);
803
804    while (1)
805    {
806        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
807        if (ChildTable)
808        {
809            UserFunction (ChildTable, Context, ReturnValue);
810
811            if (ChildTable->Child)
812            {
813                ParentTable = ChildTable;
814                ChildTable = NULL;
815            }
816        }
817        else
818        {
819            ChildTable = ParentTable;
820            if (ChildTable == Gbl_RootTable)
821            {
822                break;
823            }
824
825            ParentTable = DtGetParentSubtable (ParentTable);
826
827            if (ChildTable->Peer == StartTable)
828            {
829                break;
830            }
831        }
832    }
833}
834
835
836/******************************************************************************
837 *
838 * FUNCTION:    DtFreeFieldList
839 *
840 * PARAMETERS:  None
841 *
842 * RETURN:      None
843 *
844 * DESCRIPTION: Free the field list
845 *
846 *****************************************************************************/
847
848void
849DtFreeFieldList (
850    void)
851{
852    DT_FIELD                *Field = Gbl_FieldList;
853    DT_FIELD                *NextField;
854
855
856    /* Walk and free entire field list */
857
858    while (Field)
859    {
860        NextField = Field->Next; /* Save link */
861
862        if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
863        {
864            ACPI_FREE (Field->Name);
865            ACPI_FREE (Field->Value);
866        }
867
868        ACPI_FREE (Field);
869        Field = NextField;
870    }
871}
872