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