xref: /freebsd/sys/contrib/dev/acpica/compiler/dtutils.c (revision 5a0bba9007c527b18db7f9b64f06b486cda4fe9d)
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_BUF16:
403     case ACPI_DMT_PCI_PATH:
404         Type = DT_FIELD_TYPE_BUFFER;
405         break;
406 
407     case ACPI_DMT_GAS:
408     case ACPI_DMT_HESTNTFY:
409         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
410         break;
411 
412     case ACPI_DMT_UNICODE:
413         Type = DT_FIELD_TYPE_UNICODE;
414         break;
415 
416     case ACPI_DMT_UUID:
417         Type = DT_FIELD_TYPE_UUID;
418         break;
419 
420     case ACPI_DMT_DEVICE_PATH:
421         Type = DT_FIELD_TYPE_DEVICE_PATH;
422         break;
423 
424     default:
425         Type = DT_FIELD_TYPE_INTEGER;
426         break;
427     }
428 
429     return (Type);
430 }
431 
432 
433 /******************************************************************************
434  *
435  * FUNCTION:    DtGetBufferLength
436  *
437  * PARAMETERS:  Buffer              - List of integers,
438  *                                    for example "10 3A 4F 2E"
439  *
440  * RETURN:      Count of integer
441  *
442  * DESCRIPTION: Get length of bytes needed to store the integers
443  *
444  *****************************************************************************/
445 
446 UINT32
447 DtGetBufferLength (
448     char                    *Buffer)
449 {
450     UINT32                  ByteLength = 0;
451 
452 
453     while (*Buffer)
454     {
455         if (*Buffer == ' ')
456         {
457             ByteLength++;
458 
459             while (*Buffer == ' ')
460             {
461                 Buffer++;
462             }
463         }
464 
465         Buffer++;
466     }
467 
468     return (++ByteLength);
469 }
470 
471 
472 /******************************************************************************
473  *
474  * FUNCTION:    DtGetFieldLength
475  *
476  * PARAMETERS:  Field               - Current field list pointer
477  *              Info                - Data table info
478  *
479  * RETURN:      Field length
480  *
481  * DESCRIPTION: Get length of bytes needed to compile the field
482  *
483  * Note: This function must remain in sync with AcpiDmDumpTable.
484  *
485  *****************************************************************************/
486 
487 UINT32
488 DtGetFieldLength (
489     DT_FIELD                *Field,
490     ACPI_DMTABLE_INFO       *Info)
491 {
492     UINT32                  ByteLength = 0;
493     char                    *Value;
494 
495 
496     /* Length is based upon the opcode for this field in the info table */
497 
498     switch (Info->Opcode)
499     {
500     case ACPI_DMT_FLAG0:
501     case ACPI_DMT_FLAG1:
502     case ACPI_DMT_FLAG2:
503     case ACPI_DMT_FLAG3:
504     case ACPI_DMT_FLAG4:
505     case ACPI_DMT_FLAG5:
506     case ACPI_DMT_FLAG6:
507     case ACPI_DMT_FLAG7:
508     case ACPI_DMT_FLAGS0:
509     case ACPI_DMT_FLAGS2:
510         ByteLength = 0;
511         break;
512 
513     case ACPI_DMT_UINT8:
514     case ACPI_DMT_CHKSUM:
515     case ACPI_DMT_SPACEID:
516     case ACPI_DMT_ACCWIDTH:
517     case ACPI_DMT_IVRS:
518     case ACPI_DMT_MADT:
519     case ACPI_DMT_SRAT:
520     case ACPI_DMT_ASF:
521     case ACPI_DMT_HESTNTYP:
522     case ACPI_DMT_FADTPM:
523     case ACPI_DMT_EINJACT:
524     case ACPI_DMT_EINJINST:
525     case ACPI_DMT_ERSTACT:
526     case ACPI_DMT_ERSTINST:
527         ByteLength = 1;
528         break;
529 
530     case ACPI_DMT_UINT16:
531     case ACPI_DMT_DMAR:
532     case ACPI_DMT_HEST:
533     case ACPI_DMT_PCI_PATH:
534         ByteLength = 2;
535         break;
536 
537     case ACPI_DMT_UINT24:
538         ByteLength = 3;
539         break;
540 
541     case ACPI_DMT_UINT32:
542     case ACPI_DMT_NAME4:
543     case ACPI_DMT_SIG:
544         ByteLength = 4;
545         break;
546 
547     case ACPI_DMT_NAME6:
548         ByteLength = 6;
549         break;
550 
551     case ACPI_DMT_UINT56:
552         ByteLength = 7;
553         break;
554 
555     case ACPI_DMT_UINT64:
556     case ACPI_DMT_NAME8:
557         ByteLength = 8;
558         break;
559 
560     case ACPI_DMT_STRING:
561         Value = DtGetFieldValue (Field, Info->Name);
562         if (Value)
563         {
564             ByteLength = ACPI_STRLEN (Value) + 1;
565         }
566         else
567         {   /* At this point, this is a fatal error */
568 
569             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
570             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
571         }
572         break;
573 
574     case ACPI_DMT_GAS:
575         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
576         break;
577 
578     case ACPI_DMT_HESTNTFY:
579         ByteLength = sizeof (ACPI_HEST_NOTIFY);
580         break;
581 
582     case ACPI_DMT_BUFFER:
583         Value = DtGetFieldValue (Field, Info->Name);
584         if (Value)
585         {
586             ByteLength = DtGetBufferLength (Value);
587         }
588         else
589         {   /* At this point, this is a fatal error */
590 
591             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
592             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
593         }
594         break;
595 
596     case ACPI_DMT_BUF16:
597     case ACPI_DMT_UUID:
598         ByteLength = 16;
599         break;
600 
601     case ACPI_DMT_UNICODE:
602         Value = DtGetFieldValue (Field, Info->Name);
603 
604         /* TBD: error if Value is NULL? (as below?) */
605 
606         ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
607         break;
608 
609     default:
610         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
611         break;
612     }
613 
614     return (ByteLength);
615 }
616 
617 
618 /******************************************************************************
619  *
620  * FUNCTION:    DtSum
621  *
622  * PARAMETERS:  DT_WALK_CALLBACK:
623  *              Subtable            - Subtable
624  *              Context             - Unused
625  *              ReturnValue         - Store the checksum of subtable
626  *
627  * RETURN:      Status
628  *
629  * DESCRIPTION: Get the checksum of subtable
630  *
631  *****************************************************************************/
632 
633 static void
634 DtSum (
635     DT_SUBTABLE             *Subtable,
636     void                    *Context,
637     void                    *ReturnValue)
638 {
639     UINT8                   Checksum;
640     UINT8                   *Sum = ReturnValue;
641 
642 
643     Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
644     *Sum = (UINT8) (*Sum + Checksum);
645 }
646 
647 
648 /******************************************************************************
649  *
650  * FUNCTION:    DtSetTableChecksum
651  *
652  * PARAMETERS:  ChecksumPointer     - Where to return the checksum
653  *
654  * RETURN:      None
655  *
656  * DESCRIPTION: Set checksum of the whole data table into the checksum field
657  *
658  *****************************************************************************/
659 
660 void
661 DtSetTableChecksum (
662     UINT8                   *ChecksumPointer)
663 {
664     UINT8                   Checksum = 0;
665     UINT8                   OldSum;
666 
667 
668     DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
669 
670     OldSum = *ChecksumPointer;
671     Checksum = (UINT8) (Checksum - OldSum);
672 
673     /* Compute the final checksum */
674 
675     Checksum = (UINT8) (0 - Checksum);
676     *ChecksumPointer = Checksum;
677 }
678 
679 
680 /******************************************************************************
681  *
682  * FUNCTION:    DtSetTableLength
683  *
684  * PARAMETERS:  None
685  *
686  * RETURN:      None
687  *
688  * DESCRIPTION: Walk the subtables and set all the length fields
689  *
690  *****************************************************************************/
691 
692 void
693 DtSetTableLength (
694     void)
695 {
696     DT_SUBTABLE             *ParentTable;
697     DT_SUBTABLE             *ChildTable;
698 
699 
700     ParentTable = Gbl_RootTable;
701     ChildTable = NULL;
702 
703     if (!ParentTable)
704     {
705         return;
706     }
707 
708     DtSetSubtableLength (ParentTable);
709 
710     while (1)
711     {
712         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
713         if (ChildTable)
714         {
715             if (ChildTable->LengthField)
716             {
717                 DtSetSubtableLength (ChildTable);
718             }
719 
720             if (ChildTable->Child)
721             {
722                 ParentTable = ChildTable;
723                 ChildTable = NULL;
724             }
725             else
726             {
727                 ParentTable->TotalLength += ChildTable->TotalLength;
728                 if (ParentTable->LengthField)
729                 {
730                     DtSetSubtableLength (ParentTable);
731                 }
732             }
733         }
734         else
735         {
736             ChildTable = ParentTable;
737 
738             if (ChildTable == Gbl_RootTable)
739             {
740                 break;
741             }
742 
743             ParentTable = DtGetParentSubtable (ParentTable);
744 
745             ParentTable->TotalLength += ChildTable->TotalLength;
746             if (ParentTable->LengthField)
747             {
748                 DtSetSubtableLength (ParentTable);
749             }
750         }
751     }
752 }
753 
754 
755 /******************************************************************************
756  *
757  * FUNCTION:    DtWalkTableTree
758  *
759  * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
760  *              UserFunction        - Called during the walk
761  *              Context             - Passed to user function
762  *              ReturnValue         - The return value of UserFunction
763  *
764  * RETURN:      None
765  *
766  * DESCRIPTION: Performs a depth-first walk of the subtable tree
767  *
768  *****************************************************************************/
769 
770 void
771 DtWalkTableTree (
772     DT_SUBTABLE             *StartTable,
773     DT_WALK_CALLBACK        UserFunction,
774     void                    *Context,
775     void                    *ReturnValue)
776 {
777     DT_SUBTABLE             *ParentTable;
778     DT_SUBTABLE             *ChildTable;
779 
780 
781     ParentTable = StartTable;
782     ChildTable = NULL;
783 
784     if (!ParentTable)
785     {
786         return;
787     }
788 
789     UserFunction (ParentTable, Context, ReturnValue);
790 
791     while (1)
792     {
793         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
794         if (ChildTable)
795         {
796             UserFunction (ChildTable, Context, ReturnValue);
797 
798             if (ChildTable->Child)
799             {
800                 ParentTable = ChildTable;
801                 ChildTable = NULL;
802             }
803         }
804         else
805         {
806             ChildTable = ParentTable;
807             if (ChildTable == Gbl_RootTable)
808             {
809                 break;
810             }
811 
812             ParentTable = DtGetParentSubtable (ParentTable);
813 
814             if (ChildTable->Peer == StartTable)
815             {
816                 break;
817             }
818         }
819     }
820 }
821 
822 
823 /******************************************************************************
824  *
825  * FUNCTION:    DtFreeFieldList
826  *
827  * PARAMETERS:  None
828  *
829  * RETURN:      None
830  *
831  * DESCRIPTION: Free the field list
832  *
833  *****************************************************************************/
834 
835 void
836 DtFreeFieldList (
837     void)
838 {
839     DT_FIELD                *Field = Gbl_FieldList;
840     DT_FIELD                *NextField;
841 
842 
843     /* Walk and free entire field list */
844 
845     while (Field)
846     {
847         NextField = Field->Next; /* Save link */
848 
849         if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
850         {
851             ACPI_FREE (Field->Name);
852             ACPI_FREE (Field->Value);
853         }
854 
855         ACPI_FREE (Field);
856         Field = NextField;
857     }
858 }
859