]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/compiler/dtutils.c
Merge ACPICA 20110316.
[FreeBSD/FreeBSD.git] / sys / contrib / dev / acpica / compiler / dtutils.c
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
55 static void
56 DtSum (
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
77 void
78 DtError (
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
131 void
132 DtNameError (
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
183 void
184 DtFatal (
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
214 ACPI_STATUS
215 DtStrtoul64 (
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
297 UINT32
298 DtGetFileSize (
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
327 char *
328 DtGetFieldValue (
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
361 UINT8
362 DtGetFieldType (
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_BUF128:
405     case ACPI_DMT_PCI_PATH:
406         Type = DT_FIELD_TYPE_BUFFER;
407         break;
408
409     case ACPI_DMT_GAS:
410     case ACPI_DMT_HESTNTFY:
411         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
412         break;
413
414     case ACPI_DMT_UNICODE:
415         Type = DT_FIELD_TYPE_UNICODE;
416         break;
417
418     case ACPI_DMT_UUID:
419         Type = DT_FIELD_TYPE_UUID;
420         break;
421
422     case ACPI_DMT_DEVICE_PATH:
423         Type = DT_FIELD_TYPE_DEVICE_PATH;
424         break;
425
426     case ACPI_DMT_LABEL:
427         Type = DT_FIELD_TYPE_LABEL;
428         break;
429
430     default:
431         Type = DT_FIELD_TYPE_INTEGER;
432         break;
433     }
434
435     return (Type);
436 }
437
438
439 /******************************************************************************
440  *
441  * FUNCTION:    DtGetBufferLength
442  *
443  * PARAMETERS:  Buffer              - List of integers,
444  *                                    for example "10 3A 4F 2E"
445  *
446  * RETURN:      Count of integer
447  *
448  * DESCRIPTION: Get length of bytes needed to store the integers
449  *
450  *****************************************************************************/
451
452 UINT32
453 DtGetBufferLength (
454     char                    *Buffer)
455 {
456     UINT32                  ByteLength = 0;
457
458
459     while (*Buffer)
460     {
461         if (*Buffer == ' ')
462         {
463             ByteLength++;
464
465             while (*Buffer == ' ')
466             {
467                 Buffer++;
468             }
469         }
470
471         Buffer++;
472     }
473
474     return (++ByteLength);
475 }
476
477
478 /******************************************************************************
479  *
480  * FUNCTION:    DtGetFieldLength
481  *
482  * PARAMETERS:  Field               - Current field list pointer
483  *              Info                - Data table info
484  *
485  * RETURN:      Field length
486  *
487  * DESCRIPTION: Get length of bytes needed to compile the field
488  *
489  * Note: This function must remain in sync with AcpiDmDumpTable.
490  *
491  *****************************************************************************/
492
493 UINT32
494 DtGetFieldLength (
495     DT_FIELD                *Field,
496     ACPI_DMTABLE_INFO       *Info)
497 {
498     UINT32                  ByteLength = 0;
499     char                    *Value;
500
501
502     /* Length is based upon the opcode for this field in the info table */
503
504     switch (Info->Opcode)
505     {
506     case ACPI_DMT_FLAG0:
507     case ACPI_DMT_FLAG1:
508     case ACPI_DMT_FLAG2:
509     case ACPI_DMT_FLAG3:
510     case ACPI_DMT_FLAG4:
511     case ACPI_DMT_FLAG5:
512     case ACPI_DMT_FLAG6:
513     case ACPI_DMT_FLAG7:
514     case ACPI_DMT_FLAGS0:
515     case ACPI_DMT_FLAGS2:
516     case ACPI_DMT_LABEL:
517         ByteLength = 0;
518         break;
519
520     case ACPI_DMT_UINT8:
521     case ACPI_DMT_CHKSUM:
522     case ACPI_DMT_SPACEID:
523     case ACPI_DMT_ACCWIDTH:
524     case ACPI_DMT_IVRS:
525     case ACPI_DMT_MADT:
526     case ACPI_DMT_SRAT:
527     case ACPI_DMT_ASF:
528     case ACPI_DMT_HESTNTYP:
529     case ACPI_DMT_FADTPM:
530     case ACPI_DMT_EINJACT:
531     case ACPI_DMT_EINJINST:
532     case ACPI_DMT_ERSTACT:
533     case ACPI_DMT_ERSTINST:
534         ByteLength = 1;
535         break;
536
537     case ACPI_DMT_UINT16:
538     case ACPI_DMT_DMAR:
539     case ACPI_DMT_HEST:
540     case ACPI_DMT_PCI_PATH:
541         ByteLength = 2;
542         break;
543
544     case ACPI_DMT_UINT24:
545         ByteLength = 3;
546         break;
547
548     case ACPI_DMT_UINT32:
549     case ACPI_DMT_NAME4:
550     case ACPI_DMT_SLIC:
551     case ACPI_DMT_SIG:
552         ByteLength = 4;
553         break;
554
555     case ACPI_DMT_NAME6:
556         ByteLength = 6;
557         break;
558
559     case ACPI_DMT_UINT56:
560     case ACPI_DMT_BUF7:
561         ByteLength = 7;
562         break;
563
564     case ACPI_DMT_UINT64:
565     case ACPI_DMT_NAME8:
566         ByteLength = 8;
567         break;
568
569     case ACPI_DMT_STRING:
570         Value = DtGetFieldValue (Field, Info->Name);
571         if (Value)
572         {
573             ByteLength = ACPI_STRLEN (Value) + 1;
574         }
575         else
576         {   /* At this point, this is a fatal error */
577
578             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
579             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
580         }
581         break;
582
583     case ACPI_DMT_GAS:
584         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
585         break;
586
587     case ACPI_DMT_HESTNTFY:
588         ByteLength = sizeof (ACPI_HEST_NOTIFY);
589         break;
590
591     case ACPI_DMT_BUFFER:
592         Value = DtGetFieldValue (Field, Info->Name);
593         if (Value)
594         {
595             ByteLength = DtGetBufferLength (Value);
596         }
597         else
598         {   /* At this point, this is a fatal error */
599
600             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
601             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
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, Info->Name);
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         break;
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
646 static void
647 DtSum (
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
673 void
674 DtSetTableChecksum (
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
705 void
706 DtSetTableLength (
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
783 void
784 DtWalkTableTree (
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
848 void
849 DtFreeFieldList (
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 }