xref: /freebsd/sys/contrib/dev/acpica/compiler/dtutils.c (revision 10b9d77bf1ccf2f3affafa6261692cb92cf7e992)
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_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 
451 UINT32
452 DtGetBufferLength (
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 
492 UINT32
493 DtGetFieldLength (
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 
640 static void
641 DtSum (
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 
667 void
668 DtSetTableChecksum (
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 
699 void
700 DtSetTableLength (
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 
777 void
778 DtWalkTableTree (
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 
842 void
843 DtFreeFieldList (
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