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