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