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