xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/dtutils.c (revision 404ee5b9334f618040b6cdef96a0ff35a6fc4636)
1 /******************************************************************************
2  *
3  * Module Name: dtutils.c - Utility routines for the data table compiler
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2019, 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 #include "aslcompiler.h"
45 #include "actables.h"
46 
47 #define _COMPONENT          DT_COMPILER
48         ACPI_MODULE_NAME    ("dtutils")
49 
50 /* Local prototypes */
51 
52 static void
53 DtSum (
54     DT_SUBTABLE             *Subtable,
55     void                    *Context,
56     void                    *ReturnValue);
57 
58 
59 /******************************************************************************
60  *
61  * FUNCTION:    DtError
62  *
63  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
64  *              MessageId           - Index into global message buffer
65  *              Op                  - Parse node where error happened
66  *              ExtraMessage        - additional error message
67  *
68  * RETURN:      None
69  *
70  * DESCRIPTION: Common error interface for data table compiler
71  *
72  *****************************************************************************/
73 
74 void
75 DtError (
76     UINT8                   Level,
77     UINT16                  MessageId,
78     DT_FIELD                *FieldObject,
79     char                    *ExtraMessage)
80 {
81 
82     /* Check if user wants to ignore this exception */
83 
84     if (AslIsExceptionIgnored (Level, MessageId))
85     {
86         return;
87     }
88 
89     if (FieldObject)
90     {
91         AslCommonError (Level, MessageId,
92             FieldObject->Line,
93             FieldObject->Line,
94             FieldObject->ByteOffset,
95             FieldObject->Column,
96             AslGbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
97     }
98     else
99     {
100         AslCommonError (Level, MessageId, 0,
101             0, 0, 0, 0, ExtraMessage);
102     }
103 }
104 
105 
106 /******************************************************************************
107  *
108  * FUNCTION:    DtNameError
109  *
110  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
111  *              MessageId           - Index into global message buffer
112  *              Op                  - Parse node where error happened
113  *              ExtraMessage        - additional error message
114  *
115  * RETURN:      None
116  *
117  * DESCRIPTION: Error interface for named objects
118  *
119  *****************************************************************************/
120 
121 void
122 DtNameError (
123     UINT8                   Level,
124     UINT16                  MessageId,
125     DT_FIELD                *FieldObject,
126     char                    *ExtraMessage)
127 {
128 
129     switch (Level)
130     {
131     case ASL_WARNING2:
132     case ASL_WARNING3:
133 
134         if (AslGbl_WarningLevel < Level)
135         {
136             return;
137         }
138         break;
139 
140     default:
141 
142         break;
143     }
144 
145     if (FieldObject)
146     {
147         AslCommonError (Level, MessageId,
148             FieldObject->Line,
149             FieldObject->Line,
150             FieldObject->ByteOffset,
151             FieldObject->NameColumn,
152             AslGbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
153     }
154     else
155     {
156         AslCommonError (Level, MessageId, 0,
157             0, 0, 0, 0, ExtraMessage);
158     }
159 }
160 
161 
162 /*******************************************************************************
163  *
164  * FUNCTION:    DtFatal
165  *
166  * PARAMETERS:  None
167  *
168  * RETURN:      None
169  *
170  * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
171  *              compile or I/O errors
172  *
173  ******************************************************************************/
174 
175 void
176 DtFatal (
177     UINT16                  MessageId,
178     DT_FIELD                *FieldObject,
179     char                    *ExtraMessage)
180 {
181 
182     DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
183 
184 /*
185  * TBD: remove this entire function, DtFatal
186  *
187  * We cannot abort the compiler on error, because we may be compiling a
188  * list of files. We must move on to the next file.
189  */
190 #ifdef __OBSOLETE
191     CmCleanupAndExit ();
192     exit (1);
193 #endif
194 }
195 
196 
197 /*******************************************************************************
198  *
199  * FUNCTION:    DtDoConstant
200  *
201  * PARAMETERS:  String              - Only hex constants are supported,
202  *                                    regardless of whether the 0x prefix
203  *                                    is used
204  *
205  * RETURN:      Converted Integer
206  *
207  * DESCRIPTION: Convert a string to an integer, with overflow/error checking.
208  *
209  ******************************************************************************/
210 
211 UINT64
212 DtDoConstant (
213     char                    *String)
214 {
215     UINT64                  ConvertedInteger;
216 
217 
218     /*
219      * TBD: The ImplicitStrtoul64 function does not report overflow
220      * conditions. The input string is simply truncated. If it is
221      * desired to report overflow to the table compiler, this should
222      * somehow be added here. Note: integers that are prefixed with 0x
223      * or not are both hex integers.
224      */
225     ConvertedInteger = AcpiUtImplicitStrtoul64 (String);
226     return (ConvertedInteger);
227 }
228 
229 /******************************************************************************
230  *
231  * FUNCTION:    DtGetFieldValue
232  *
233  * PARAMETERS:  Field               - Current field list pointer
234  *
235  * RETURN:      Field value
236  *
237  * DESCRIPTION: Get field value
238  *
239  *****************************************************************************/
240 
241 char *
242 DtGetFieldValue (
243     DT_FIELD                *Field)
244 {
245     if (!Field)
246     {
247         return (NULL);
248     }
249 
250     return (Field->Value);
251 }
252 
253 
254 /******************************************************************************
255  *
256  * FUNCTION:    DtGetFieldType
257  *
258  * PARAMETERS:  Info                - Data table info
259  *
260  * RETURN:      Field type
261  *
262  * DESCRIPTION: Get field type
263  *
264  *****************************************************************************/
265 
266 UINT8
267 DtGetFieldType (
268     ACPI_DMTABLE_INFO       *Info)
269 {
270     UINT8                   Type;
271 
272 
273     /* DT_FLAG means that this is the start of a block of flag bits */
274     /* TBD - we can make these a separate opcode later */
275 
276     if (Info->Flags & DT_FLAG)
277     {
278         return (DT_FIELD_TYPE_FLAGS_INTEGER);
279     }
280 
281     /* Type is based upon the opcode for this field in the info table */
282 
283     switch (Info->Opcode)
284     {
285     case ACPI_DMT_FLAG0:
286     case ACPI_DMT_FLAG1:
287     case ACPI_DMT_FLAG2:
288     case ACPI_DMT_FLAG3:
289     case ACPI_DMT_FLAG4:
290     case ACPI_DMT_FLAG5:
291     case ACPI_DMT_FLAG6:
292     case ACPI_DMT_FLAG7:
293     case ACPI_DMT_FLAGS0:
294     case ACPI_DMT_FLAGS1:
295     case ACPI_DMT_FLAGS2:
296     case ACPI_DMT_FLAGS4:
297     case ACPI_DMT_FLAGS4_0:
298     case ACPI_DMT_FLAGS4_4:
299     case ACPI_DMT_FLAGS4_8:
300     case ACPI_DMT_FLAGS4_12:
301     case ACPI_DMT_FLAGS16_16:
302 
303         Type = DT_FIELD_TYPE_FLAG;
304         break;
305 
306     case ACPI_DMT_NAME4:
307     case ACPI_DMT_SIG:
308     case ACPI_DMT_NAME6:
309     case ACPI_DMT_NAME8:
310     case ACPI_DMT_STRING:
311 
312         Type = DT_FIELD_TYPE_STRING;
313         break;
314 
315     case ACPI_DMT_BUFFER:
316     case ACPI_DMT_RAW_BUFFER:
317     case ACPI_DMT_BUF7:
318     case ACPI_DMT_BUF10:
319     case ACPI_DMT_BUF12:
320     case ACPI_DMT_BUF16:
321     case ACPI_DMT_BUF128:
322     case ACPI_DMT_PCI_PATH:
323 
324         Type = DT_FIELD_TYPE_BUFFER;
325         break;
326 
327     case ACPI_DMT_GAS:
328     case ACPI_DMT_HESTNTFY:
329     case ACPI_DMT_IORTMEM:
330 
331         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
332         break;
333 
334     case ACPI_DMT_UNICODE:
335 
336         Type = DT_FIELD_TYPE_UNICODE;
337         break;
338 
339     case ACPI_DMT_UUID:
340 
341         Type = DT_FIELD_TYPE_UUID;
342         break;
343 
344     case ACPI_DMT_DEVICE_PATH:
345 
346         Type = DT_FIELD_TYPE_DEVICE_PATH;
347         break;
348 
349     case ACPI_DMT_LABEL:
350 
351         Type = DT_FIELD_TYPE_LABEL;
352         break;
353 
354     default:
355 
356         Type = DT_FIELD_TYPE_INTEGER;
357         break;
358     }
359 
360     return (Type);
361 }
362 
363 
364 /******************************************************************************
365  *
366  * FUNCTION:    DtGetBufferLength
367  *
368  * PARAMETERS:  Buffer              - List of integers,
369  *                                    for example "10 3A 4F 2E"
370  *
371  * RETURN:      Count of integer
372  *
373  * DESCRIPTION: Get length of bytes needed to store the integers
374  *
375  *****************************************************************************/
376 
377 UINT32
378 DtGetBufferLength (
379     char                    *Buffer)
380 {
381     UINT32                  ByteLength = 0;
382 
383 
384     while (*Buffer)
385     {
386         if (*Buffer == ' ')
387         {
388             ByteLength++;
389 
390             while (*Buffer == ' ')
391             {
392                 Buffer++;
393             }
394         }
395 
396         Buffer++;
397     }
398 
399     return (++ByteLength);
400 }
401 
402 
403 /******************************************************************************
404  *
405  * FUNCTION:    DtGetFieldLength
406  *
407  * PARAMETERS:  Field               - Current field
408  *              Info                - Data table info
409  *
410  * RETURN:      Field length
411  *
412  * DESCRIPTION: Get length of bytes needed to compile the field
413  *
414  * Note: This function must remain in sync with AcpiDmDumpTable.
415  *
416  *****************************************************************************/
417 
418 UINT32
419 DtGetFieldLength (
420     DT_FIELD                *Field,
421     ACPI_DMTABLE_INFO       *Info)
422 {
423     UINT32                  ByteLength = 0;
424     char                    *Value;
425 
426 
427     /* Length is based upon the opcode for this field in the info table */
428 
429     switch (Info->Opcode)
430     {
431     case ACPI_DMT_FLAG0:
432     case ACPI_DMT_FLAG1:
433     case ACPI_DMT_FLAG2:
434     case ACPI_DMT_FLAG3:
435     case ACPI_DMT_FLAG4:
436     case ACPI_DMT_FLAG5:
437     case ACPI_DMT_FLAG6:
438     case ACPI_DMT_FLAG7:
439     case ACPI_DMT_FLAGS0:
440     case ACPI_DMT_FLAGS1:
441     case ACPI_DMT_FLAGS2:
442     case ACPI_DMT_FLAGS4:
443     case ACPI_DMT_FLAGS4_0:
444     case ACPI_DMT_FLAGS4_4:
445     case ACPI_DMT_FLAGS4_8:
446     case ACPI_DMT_FLAGS4_12:
447     case ACPI_DMT_FLAGS16_16:
448     case ACPI_DMT_LABEL:
449     case ACPI_DMT_EXTRA_TEXT:
450 
451         ByteLength = 0;
452         break;
453 
454     case ACPI_DMT_UINT8:
455     case ACPI_DMT_CHKSUM:
456     case ACPI_DMT_SPACEID:
457     case ACPI_DMT_ACCWIDTH:
458     case ACPI_DMT_IVRS:
459     case ACPI_DMT_GTDT:
460     case ACPI_DMT_MADT:
461     case ACPI_DMT_PCCT:
462     case ACPI_DMT_PMTT:
463     case ACPI_DMT_PPTT:
464     case ACPI_DMT_SDEV:
465     case ACPI_DMT_SRAT:
466     case ACPI_DMT_ASF:
467     case ACPI_DMT_HESTNTYP:
468     case ACPI_DMT_FADTPM:
469     case ACPI_DMT_EINJACT:
470     case ACPI_DMT_EINJINST:
471     case ACPI_DMT_ERSTACT:
472     case ACPI_DMT_ERSTINST:
473     case ACPI_DMT_DMAR_SCOPE:
474 
475         ByteLength = 1;
476         break;
477 
478     case ACPI_DMT_UINT16:
479     case ACPI_DMT_DMAR:
480     case ACPI_DMT_HEST:
481     case ACPI_DMT_HMAT:
482     case ACPI_DMT_NFIT:
483     case ACPI_DMT_PCI_PATH:
484 
485         ByteLength = 2;
486         break;
487 
488     case ACPI_DMT_UINT24:
489 
490         ByteLength = 3;
491         break;
492 
493     case ACPI_DMT_UINT32:
494     case ACPI_DMT_NAME4:
495     case ACPI_DMT_SIG:
496     case ACPI_DMT_LPIT:
497     case ACPI_DMT_TPM2:
498 
499         ByteLength = 4;
500         break;
501 
502     case ACPI_DMT_UINT40:
503 
504         ByteLength = 5;
505         break;
506 
507     case ACPI_DMT_UINT48:
508     case ACPI_DMT_NAME6:
509 
510         ByteLength = 6;
511         break;
512 
513     case ACPI_DMT_UINT56:
514     case ACPI_DMT_BUF7:
515 
516         ByteLength = 7;
517         break;
518 
519     case ACPI_DMT_UINT64:
520     case ACPI_DMT_NAME8:
521 
522         ByteLength = 8;
523         break;
524 
525     case ACPI_DMT_STRING:
526 
527         Value = DtGetFieldValue (Field);
528         if (Value)
529         {
530             ByteLength = strlen (Value) + 1;
531         }
532         else
533         {   /* At this point, this is a fatal error */
534 
535             snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Expected \"%s\"", Info->Name);
536             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, AslGbl_MsgBuffer);
537             return (0);
538         }
539         break;
540 
541     case ACPI_DMT_GAS:
542 
543         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
544         break;
545 
546     case ACPI_DMT_HESTNTFY:
547 
548         ByteLength = sizeof (ACPI_HEST_NOTIFY);
549         break;
550 
551     case ACPI_DMT_IORTMEM:
552 
553         ByteLength = sizeof (ACPI_IORT_MEMORY_ACCESS);
554         break;
555 
556     case ACPI_DMT_BUFFER:
557     case ACPI_DMT_RAW_BUFFER:
558 
559         Value = DtGetFieldValue (Field);
560         if (Value)
561         {
562             ByteLength = DtGetBufferLength (Value);
563         }
564         else
565         {   /* At this point, this is a fatal error */
566 
567             snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Expected \"%s\"", Info->Name);
568             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, AslGbl_MsgBuffer);
569             return (0);
570         }
571         break;
572 
573     case ACPI_DMT_BUF10:
574 
575         ByteLength = 10;
576         break;
577 
578     case ACPI_DMT_BUF12:
579 
580         ByteLength = 12;
581         break;
582 
583     case ACPI_DMT_BUF16:
584     case ACPI_DMT_UUID:
585 
586         ByteLength = 16;
587         break;
588 
589     case ACPI_DMT_BUF128:
590 
591         ByteLength = 128;
592         break;
593 
594     case ACPI_DMT_UNICODE:
595 
596         Value = DtGetFieldValue (Field);
597 
598         /* TBD: error if Value is NULL? (as below?) */
599 
600         ByteLength = (strlen (Value) + 1) * sizeof(UINT16);
601         break;
602 
603     default:
604 
605         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
606         return (0);
607     }
608 
609     return (ByteLength);
610 }
611 
612 
613 /******************************************************************************
614  *
615  * FUNCTION:    DtSum
616  *
617  * PARAMETERS:  DT_WALK_CALLBACK:
618  *              Subtable            - Subtable
619  *              Context             - Unused
620  *              ReturnValue         - Store the checksum of subtable
621  *
622  * RETURN:      Status
623  *
624  * DESCRIPTION: Get the checksum of subtable
625  *
626  *****************************************************************************/
627 
628 static void
629 DtSum (
630     DT_SUBTABLE             *Subtable,
631     void                    *Context,
632     void                    *ReturnValue)
633 {
634     UINT8                   Checksum;
635     UINT8                   *Sum = ReturnValue;
636 
637 
638     Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
639     *Sum = (UINT8) (*Sum + Checksum);
640 }
641 
642 
643 /******************************************************************************
644  *
645  * FUNCTION:    DtSetTableChecksum
646  *
647  * PARAMETERS:  ChecksumPointer     - Where to return the checksum
648  *
649  * RETURN:      None
650  *
651  * DESCRIPTION: Set checksum of the whole data table into the checksum field
652  *
653  *****************************************************************************/
654 
655 void
656 DtSetTableChecksum (
657     UINT8                   *ChecksumPointer)
658 {
659     UINT8                   Checksum = 0;
660     UINT8                   OldSum;
661 
662 
663     DtWalkTableTree (AslGbl_RootTable, DtSum, NULL, &Checksum);
664 
665     OldSum = *ChecksumPointer;
666     Checksum = (UINT8) (Checksum - OldSum);
667 
668     /* Compute the final checksum */
669 
670     Checksum = (UINT8) (0 - Checksum);
671     *ChecksumPointer = Checksum;
672 }
673 
674 
675 /******************************************************************************
676  *
677  * FUNCTION:    DtSetTableLength
678  *
679  * PARAMETERS:  None
680  *
681  * RETURN:      None
682  *
683  * DESCRIPTION: Walk the subtables and set all the length fields
684  *
685  *****************************************************************************/
686 
687 void
688 DtSetTableLength (
689     void)
690 {
691     DT_SUBTABLE             *ParentTable;
692     DT_SUBTABLE             *ChildTable;
693 
694 
695     ParentTable = AslGbl_RootTable;
696     ChildTable = NULL;
697 
698     if (!ParentTable)
699     {
700         return;
701     }
702 
703     DtSetSubtableLength (ParentTable);
704 
705     while (1)
706     {
707         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
708         if (ChildTable)
709         {
710             if (ChildTable->LengthField)
711             {
712                 DtSetSubtableLength (ChildTable);
713             }
714 
715             if (ChildTable->Child)
716             {
717                 ParentTable = ChildTable;
718                 ChildTable = NULL;
719             }
720             else
721             {
722                 ParentTable->TotalLength += ChildTable->TotalLength;
723                 if (ParentTable->LengthField)
724                 {
725                     DtSetSubtableLength (ParentTable);
726                 }
727             }
728         }
729         else
730         {
731             ChildTable = ParentTable;
732 
733             if (ChildTable == AslGbl_RootTable)
734             {
735                 break;
736             }
737 
738             ParentTable = DtGetParentSubtable (ParentTable);
739 
740             ParentTable->TotalLength += ChildTable->TotalLength;
741             if (ParentTable->LengthField)
742             {
743                 DtSetSubtableLength (ParentTable);
744             }
745         }
746     }
747 }
748 
749 
750 /******************************************************************************
751  *
752  * FUNCTION:    DtWalkTableTree
753  *
754  * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
755  *              UserFunction        - Called during the walk
756  *              Context             - Passed to user function
757  *              ReturnValue         - The return value of UserFunction
758  *
759  * RETURN:      None
760  *
761  * DESCRIPTION: Performs a depth-first walk of the subtable tree
762  *
763  *****************************************************************************/
764 
765 void
766 DtWalkTableTree (
767     DT_SUBTABLE             *StartTable,
768     DT_WALK_CALLBACK        UserFunction,
769     void                    *Context,
770     void                    *ReturnValue)
771 {
772     DT_SUBTABLE             *ParentTable;
773     DT_SUBTABLE             *ChildTable;
774 
775 
776     ParentTable = StartTable;
777     ChildTable = NULL;
778 
779     if (!ParentTable)
780     {
781         return;
782     }
783 
784     UserFunction (ParentTable, Context, ReturnValue);
785 
786     while (1)
787     {
788         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
789         if (ChildTable)
790         {
791             UserFunction (ChildTable, Context, ReturnValue);
792 
793             if (ChildTable->Child)
794             {
795                 ParentTable = ChildTable;
796                 ChildTable = NULL;
797             }
798         }
799         else
800         {
801             ChildTable = ParentTable;
802             if (ChildTable == AslGbl_RootTable)
803             {
804                 break;
805             }
806 
807             ParentTable = DtGetParentSubtable (ParentTable);
808 
809             if (ChildTable->Peer == StartTable)
810             {
811                 break;
812             }
813         }
814     }
815 }
816