dtutils.c revision 1.12 1 /******************************************************************************
2 *
3 * Module Name: dtutils.c - Utility routines for the data table compiler
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2018, 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