dtutils.c revision 218590
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    CmCleanupAndExit ();
193    exit (1);
194}
195
196
197/******************************************************************************
198 *
199 * FUNCTION:    DtStrtoul64
200 *
201 * PARAMETERS:  String              - Null terminated string
202 *              ReturnInteger       - Where the converted integer is returned
203 *
204 * RETURN:      Status
205 *
206 * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
207 *              value. Assumes no leading "0x" for the constant.
208 *
209 * Portability note: The reason this function exists is because a 64-bit
210 * sscanf is not available in all environments.
211 *
212 *****************************************************************************/
213
214ACPI_STATUS
215DtStrtoul64 (
216    char                    *String,
217    UINT64                  *ReturnInteger)
218{
219    char                    *ThisChar = String;
220    UINT32                  ThisDigit;
221    UINT64                  ReturnValue = 0;
222    int                     DigitCount = 0;
223
224
225    /* Skip over any white space in the buffer */
226
227    while ((*ThisChar == ' ') || (*ThisChar == '\t'))
228    {
229        ThisChar++;
230    }
231
232    /* Skip leading zeros */
233
234    while ((*ThisChar) == '0')
235    {
236        ThisChar++;
237    }
238
239    /* Convert character-by-character */
240
241    while (*ThisChar)
242    {
243        if (ACPI_IS_DIGIT (*ThisChar))
244        {
245            /* Convert ASCII 0-9 to Decimal value */
246
247            ThisDigit = ((UINT8) *ThisChar) - '0';
248        }
249        else /* Letter */
250        {
251            ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar);
252            if (!ACPI_IS_XDIGIT ((char) ThisDigit))
253            {
254                /* Not A-F */
255
256                return (AE_BAD_CHARACTER);
257            }
258
259            /* Convert ASCII Hex char (A-F) to value */
260
261            ThisDigit = (ThisDigit - 'A') + 10;
262        }
263
264        /* Insert the 4-bit hex digit */
265
266        ReturnValue <<= 4;
267        ReturnValue += ThisDigit;
268
269        ThisChar++;
270        DigitCount++;
271        if (DigitCount > 16)
272        {
273            /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
274
275            return (AE_LIMIT);
276        }
277    }
278
279    *ReturnInteger = ReturnValue;
280    return (AE_OK);
281}
282
283
284/******************************************************************************
285 *
286 * FUNCTION:    DtGetFileSize
287 *
288 * PARAMETERS:  Handle              - Open file handler
289 *
290 * RETURN:      Current file size
291 *
292 * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the
293 *              offset. Seek back to the original location.
294 *
295 *****************************************************************************/
296
297UINT32
298DtGetFileSize (
299    FILE                    *Handle)
300{
301    int                     CurrentOffset;
302    int                     LastOffset;
303
304
305    CurrentOffset = ftell (Handle);
306    fseek (Handle, 0, SEEK_END);
307    LastOffset = ftell (Handle);
308    fseek (Handle, CurrentOffset, SEEK_SET);
309
310    return ((UINT32) LastOffset);
311}
312
313
314/******************************************************************************
315 *
316 * FUNCTION:    DtGetFieldValue
317 *
318 * PARAMETERS:  Field               - Current field list pointer
319 *              Name                - Field name
320 *
321 * RETURN:      Field value
322 *
323 * DESCRIPTION: Get field value
324 *
325 *****************************************************************************/
326
327char *
328DtGetFieldValue (
329    DT_FIELD                *Field,
330    char                    *Name)
331{
332
333    /* Search the field list for the name */
334
335    while (Field)
336    {
337        if (!ACPI_STRCMP (Name, Field->Name))
338        {
339            return (Field->Value);
340        }
341
342        Field = Field->Next;
343    }
344
345    return (NULL);
346}
347
348
349/******************************************************************************
350 *
351 * FUNCTION:    DtGetFieldType
352 *
353 * PARAMETERS:  Info                - Data table info
354 *
355 * RETURN:      Field type
356 *
357 * DESCRIPTION: Get field type
358 *
359 *****************************************************************************/
360
361UINT8
362DtGetFieldType (
363    ACPI_DMTABLE_INFO       *Info)
364{
365    UINT8                   Type;
366
367
368    /* DT_FLAG means that this is the start of a block of flag bits */
369    /* TBD - we can make these a separate opcode later */
370
371    if (Info->Flags & DT_FLAG)
372    {
373        return (DT_FIELD_TYPE_FLAGS_INTEGER);
374    }
375
376    /* Type is based upon the opcode for this field in the info table */
377
378    switch (Info->Opcode)
379    {
380    case ACPI_DMT_FLAG0:
381    case ACPI_DMT_FLAG1:
382    case ACPI_DMT_FLAG2:
383    case ACPI_DMT_FLAG3:
384    case ACPI_DMT_FLAG4:
385    case ACPI_DMT_FLAG5:
386    case ACPI_DMT_FLAG6:
387    case ACPI_DMT_FLAG7:
388    case ACPI_DMT_FLAGS0:
389    case ACPI_DMT_FLAGS2:
390        Type = DT_FIELD_TYPE_FLAG;
391        break;
392
393    case ACPI_DMT_NAME4:
394    case ACPI_DMT_SIG:
395    case ACPI_DMT_NAME6:
396    case ACPI_DMT_NAME8:
397    case ACPI_DMT_STRING:
398        Type = DT_FIELD_TYPE_STRING;
399        break;
400
401    case ACPI_DMT_BUFFER:
402    case ACPI_DMT_BUF7:
403    case ACPI_DMT_BUF16:
404    case ACPI_DMT_PCI_PATH:
405        Type = DT_FIELD_TYPE_BUFFER;
406        break;
407
408    case ACPI_DMT_GAS:
409    case ACPI_DMT_HESTNTFY:
410        Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
411        break;
412
413    case ACPI_DMT_UNICODE:
414        Type = DT_FIELD_TYPE_UNICODE;
415        break;
416
417    case ACPI_DMT_UUID:
418        Type = DT_FIELD_TYPE_UUID;
419        break;
420
421    case ACPI_DMT_DEVICE_PATH:
422        Type = DT_FIELD_TYPE_DEVICE_PATH;
423        break;
424
425    case ACPI_DMT_LABEL:
426        Type = DT_FIELD_TYPE_LABEL;
427        break;
428
429    default:
430        Type = DT_FIELD_TYPE_INTEGER;
431        break;
432    }
433
434    return (Type);
435}
436
437
438/******************************************************************************
439 *
440 * FUNCTION:    DtGetBufferLength
441 *
442 * PARAMETERS:  Buffer              - List of integers,
443 *                                    for example "10 3A 4F 2E"
444 *
445 * RETURN:      Count of integer
446 *
447 * DESCRIPTION: Get length of bytes needed to store the integers
448 *
449 *****************************************************************************/
450
451UINT32
452DtGetBufferLength (
453    char                    *Buffer)
454{
455    UINT32                  ByteLength = 0;
456
457
458    while (*Buffer)
459    {
460        if (*Buffer == ' ')
461        {
462            ByteLength++;
463
464            while (*Buffer == ' ')
465            {
466                Buffer++;
467            }
468        }
469
470        Buffer++;
471    }
472
473    return (++ByteLength);
474}
475
476
477/******************************************************************************
478 *
479 * FUNCTION:    DtGetFieldLength
480 *
481 * PARAMETERS:  Field               - Current field list pointer
482 *              Info                - Data table info
483 *
484 * RETURN:      Field length
485 *
486 * DESCRIPTION: Get length of bytes needed to compile the field
487 *
488 * Note: This function must remain in sync with AcpiDmDumpTable.
489 *
490 *****************************************************************************/
491
492UINT32
493DtGetFieldLength (
494    DT_FIELD                *Field,
495    ACPI_DMTABLE_INFO       *Info)
496{
497    UINT32                  ByteLength = 0;
498    char                    *Value;
499
500
501    /* Length is based upon the opcode for this field in the info table */
502
503    switch (Info->Opcode)
504    {
505    case ACPI_DMT_FLAG0:
506    case ACPI_DMT_FLAG1:
507    case ACPI_DMT_FLAG2:
508    case ACPI_DMT_FLAG3:
509    case ACPI_DMT_FLAG4:
510    case ACPI_DMT_FLAG5:
511    case ACPI_DMT_FLAG6:
512    case ACPI_DMT_FLAG7:
513    case ACPI_DMT_FLAGS0:
514    case ACPI_DMT_FLAGS2:
515    case ACPI_DMT_LABEL:
516        ByteLength = 0;
517        break;
518
519    case ACPI_DMT_UINT8:
520    case ACPI_DMT_CHKSUM:
521    case ACPI_DMT_SPACEID:
522    case ACPI_DMT_ACCWIDTH:
523    case ACPI_DMT_IVRS:
524    case ACPI_DMT_MADT:
525    case ACPI_DMT_SRAT:
526    case ACPI_DMT_ASF:
527    case ACPI_DMT_HESTNTYP:
528    case ACPI_DMT_FADTPM:
529    case ACPI_DMT_EINJACT:
530    case ACPI_DMT_EINJINST:
531    case ACPI_DMT_ERSTACT:
532    case ACPI_DMT_ERSTINST:
533        ByteLength = 1;
534        break;
535
536    case ACPI_DMT_UINT16:
537    case ACPI_DMT_DMAR:
538    case ACPI_DMT_HEST:
539    case ACPI_DMT_PCI_PATH:
540        ByteLength = 2;
541        break;
542
543    case ACPI_DMT_UINT24:
544        ByteLength = 3;
545        break;
546
547    case ACPI_DMT_UINT32:
548    case ACPI_DMT_NAME4:
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, Info->Name);
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        }
579        break;
580
581    case ACPI_DMT_GAS:
582        ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
583        break;
584
585    case ACPI_DMT_HESTNTFY:
586        ByteLength = sizeof (ACPI_HEST_NOTIFY);
587        break;
588
589    case ACPI_DMT_BUFFER:
590        Value = DtGetFieldValue (Field, Info->Name);
591        if (Value)
592        {
593            ByteLength = DtGetBufferLength (Value);
594        }
595        else
596        {   /* At this point, this is a fatal error */
597
598            sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
599            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
600        }
601        break;
602
603    case ACPI_DMT_BUF16:
604    case ACPI_DMT_UUID:
605        ByteLength = 16;
606        break;
607
608    case ACPI_DMT_UNICODE:
609        Value = DtGetFieldValue (Field, Info->Name);
610
611        /* TBD: error if Value is NULL? (as below?) */
612
613        ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
614        break;
615
616    default:
617        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
618        break;
619    }
620
621    return (ByteLength);
622}
623
624
625/******************************************************************************
626 *
627 * FUNCTION:    DtSum
628 *
629 * PARAMETERS:  DT_WALK_CALLBACK:
630 *              Subtable            - Subtable
631 *              Context             - Unused
632 *              ReturnValue         - Store the checksum of subtable
633 *
634 * RETURN:      Status
635 *
636 * DESCRIPTION: Get the checksum of subtable
637 *
638 *****************************************************************************/
639
640static void
641DtSum (
642    DT_SUBTABLE             *Subtable,
643    void                    *Context,
644    void                    *ReturnValue)
645{
646    UINT8                   Checksum;
647    UINT8                   *Sum = ReturnValue;
648
649
650    Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
651    *Sum = (UINT8) (*Sum + Checksum);
652}
653
654
655/******************************************************************************
656 *
657 * FUNCTION:    DtSetTableChecksum
658 *
659 * PARAMETERS:  ChecksumPointer     - Where to return the checksum
660 *
661 * RETURN:      None
662 *
663 * DESCRIPTION: Set checksum of the whole data table into the checksum field
664 *
665 *****************************************************************************/
666
667void
668DtSetTableChecksum (
669    UINT8                   *ChecksumPointer)
670{
671    UINT8                   Checksum = 0;
672    UINT8                   OldSum;
673
674
675    DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
676
677    OldSum = *ChecksumPointer;
678    Checksum = (UINT8) (Checksum - OldSum);
679
680    /* Compute the final checksum */
681
682    Checksum = (UINT8) (0 - Checksum);
683    *ChecksumPointer = Checksum;
684}
685
686
687/******************************************************************************
688 *
689 * FUNCTION:    DtSetTableLength
690 *
691 * PARAMETERS:  None
692 *
693 * RETURN:      None
694 *
695 * DESCRIPTION: Walk the subtables and set all the length fields
696 *
697 *****************************************************************************/
698
699void
700DtSetTableLength (
701    void)
702{
703    DT_SUBTABLE             *ParentTable;
704    DT_SUBTABLE             *ChildTable;
705
706
707    ParentTable = Gbl_RootTable;
708    ChildTable = NULL;
709
710    if (!ParentTable)
711    {
712        return;
713    }
714
715    DtSetSubtableLength (ParentTable);
716
717    while (1)
718    {
719        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
720        if (ChildTable)
721        {
722            if (ChildTable->LengthField)
723            {
724                DtSetSubtableLength (ChildTable);
725            }
726
727            if (ChildTable->Child)
728            {
729                ParentTable = ChildTable;
730                ChildTable = NULL;
731            }
732            else
733            {
734                ParentTable->TotalLength += ChildTable->TotalLength;
735                if (ParentTable->LengthField)
736                {
737                    DtSetSubtableLength (ParentTable);
738                }
739            }
740        }
741        else
742        {
743            ChildTable = ParentTable;
744
745            if (ChildTable == Gbl_RootTable)
746            {
747                break;
748            }
749
750            ParentTable = DtGetParentSubtable (ParentTable);
751
752            ParentTable->TotalLength += ChildTable->TotalLength;
753            if (ParentTable->LengthField)
754            {
755                DtSetSubtableLength (ParentTable);
756            }
757        }
758    }
759}
760
761
762/******************************************************************************
763 *
764 * FUNCTION:    DtWalkTableTree
765 *
766 * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
767 *              UserFunction        - Called during the walk
768 *              Context             - Passed to user function
769 *              ReturnValue         - The return value of UserFunction
770 *
771 * RETURN:      None
772 *
773 * DESCRIPTION: Performs a depth-first walk of the subtable tree
774 *
775 *****************************************************************************/
776
777void
778DtWalkTableTree (
779    DT_SUBTABLE             *StartTable,
780    DT_WALK_CALLBACK        UserFunction,
781    void                    *Context,
782    void                    *ReturnValue)
783{
784    DT_SUBTABLE             *ParentTable;
785    DT_SUBTABLE             *ChildTable;
786
787
788    ParentTable = StartTable;
789    ChildTable = NULL;
790
791    if (!ParentTable)
792    {
793        return;
794    }
795
796    UserFunction (ParentTable, Context, ReturnValue);
797
798    while (1)
799    {
800        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
801        if (ChildTable)
802        {
803            UserFunction (ChildTable, Context, ReturnValue);
804
805            if (ChildTable->Child)
806            {
807                ParentTable = ChildTable;
808                ChildTable = NULL;
809            }
810        }
811        else
812        {
813            ChildTable = ParentTable;
814            if (ChildTable == Gbl_RootTable)
815            {
816                break;
817            }
818
819            ParentTable = DtGetParentSubtable (ParentTable);
820
821            if (ChildTable->Peer == StartTable)
822            {
823                break;
824            }
825        }
826    }
827}
828
829
830/******************************************************************************
831 *
832 * FUNCTION:    DtFreeFieldList
833 *
834 * PARAMETERS:  None
835 *
836 * RETURN:      None
837 *
838 * DESCRIPTION: Free the field list
839 *
840 *****************************************************************************/
841
842void
843DtFreeFieldList (
844    void)
845{
846    DT_FIELD                *Field = Gbl_FieldList;
847    DT_FIELD                *NextField;
848
849
850    /* Walk and free entire field list */
851
852    while (Field)
853    {
854        NextField = Field->Next; /* Save link */
855
856        if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
857        {
858            ACPI_FREE (Field->Name);
859            ACPI_FREE (Field->Value);
860        }
861
862        ACPI_FREE (Field);
863        Field = NextField;
864    }
865}
866