dtfield.c revision 1.1.1.19 1 /******************************************************************************
2 *
3 * Module Name: dtfield.c - Code generation for individual source fields
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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
46 #define _COMPONENT DT_COMPILER
47 ACPI_MODULE_NAME ("dtfield")
48
49
50 /* Local prototypes */
51
52 static void
53 DtCompileString (
54 UINT8 *Buffer,
55 DT_FIELD *Field,
56 UINT32 ByteLength);
57
58 static void
59 DtCompileUnicode (
60 UINT8 *Buffer,
61 DT_FIELD *Field,
62 UINT32 ByteLength);
63
64 static ACPI_STATUS
65 DtCompileUuid (
66 UINT8 *Buffer,
67 DT_FIELD *Field,
68 UINT32 ByteLength);
69
70 static char *
71 DtNormalizeBuffer (
72 char *Buffer,
73 UINT32 *Count);
74
75
76 /******************************************************************************
77 *
78 * FUNCTION: DtCompileOneField
79 *
80 * PARAMETERS: Buffer - Output buffer
81 * Field - Field to be compiled
82 * ByteLength - Byte length of the field
83 * Type - Field type
84 *
85 * RETURN: None
86 *
87 * DESCRIPTION: Compile a field value to binary
88 *
89 *****************************************************************************/
90
91 void
92 DtCompileOneField (
93 UINT8 *Buffer,
94 DT_FIELD *Field,
95 UINT32 ByteLength,
96 UINT8 Type,
97 UINT8 Flags)
98 {
99 ACPI_STATUS Status;
100
101
102 switch (Type)
103 {
104 case DT_FIELD_TYPE_INTEGER:
105
106 DtCompileInteger (Buffer, Field, ByteLength, Flags);
107 break;
108
109 case DT_FIELD_TYPE_STRING:
110
111 DtCompileString (Buffer, Field, ByteLength);
112 break;
113
114 case DT_FIELD_TYPE_UUID:
115
116 Status = DtCompileUuid (Buffer, Field, ByteLength);
117 if (ACPI_SUCCESS (Status))
118 {
119 break;
120 }
121
122 ACPI_FALLTHROUGH;
123
124 case DT_FIELD_TYPE_BUFFER:
125
126 DtCompileBuffer (Buffer, Field->Value, Field, ByteLength);
127 break;
128
129 case DT_FIELD_TYPE_UNICODE:
130
131 DtCompileUnicode (Buffer, Field, ByteLength);
132 break;
133
134 case DT_FIELD_TYPE_DEVICE_PATH:
135
136 break;
137
138 default:
139
140 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid field type");
141 break;
142 }
143 }
144
145
146 /******************************************************************************
147 *
148 * FUNCTION: DtCompileString
149 *
150 * PARAMETERS: Buffer - Output buffer
151 * Field - String to be copied to buffer
152 * ByteLength - Maximum length of string
153 *
154 * RETURN: None
155 *
156 * DESCRIPTION: Copy string to the buffer
157 *
158 *****************************************************************************/
159
160 static void
161 DtCompileString (
162 UINT8 *Buffer,
163 DT_FIELD *Field,
164 UINT32 ByteLength)
165 {
166 UINT32 Length;
167
168
169 Length = strlen (Field->Value);
170
171 /* Check if the string is too long for the field */
172
173 if (Length > ByteLength)
174 {
175 sprintf (AslGbl_MsgBuffer,
176 "Maximum %u characters, found %u characters [%s]",
177 ByteLength, Length, Field->Value);
178 DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, AslGbl_MsgBuffer);
179 Length = ByteLength;
180 }
181
182 memcpy (Buffer, Field->Value, Length);
183 }
184
185
186 /******************************************************************************
187 *
188 * FUNCTION: DtCompileUnicode
189 *
190 * PARAMETERS: Buffer - Output buffer
191 * Field - String to be copied to buffer
192 * ByteLength - Maximum length of string
193 *
194 * RETURN: None
195 *
196 * DESCRIPTION: Convert ASCII string to Unicode string
197 *
198 * Note: The Unicode string is 16 bits per character, no leading signature,
199 * with a 16-bit terminating NULL.
200 *
201 *****************************************************************************/
202
203 static void
204 DtCompileUnicode (
205 UINT8 *Buffer,
206 DT_FIELD *Field,
207 UINT32 ByteLength)
208 {
209 UINT32 Count;
210 UINT32 i;
211 char *AsciiString;
212 UINT16 *UnicodeString;
213
214
215 AsciiString = Field->Value;
216 UnicodeString = (UINT16 *) Buffer;
217 Count = strlen (AsciiString) + 1;
218
219 /* Convert to Unicode string (including null terminator) */
220
221 for (i = 0; i < Count; i++)
222 {
223 UnicodeString[i] = (UINT16) AsciiString[i];
224 }
225 }
226
227
228 /*******************************************************************************
229 *
230 * FUNCTION: DtCompileUuid
231 *
232 * PARAMETERS: Buffer - Output buffer
233 * Field - String to be copied to buffer
234 * ByteLength - Maximum length of string
235 *
236 * RETURN: None
237 *
238 * DESCRIPTION: Convert UUID string to 16-byte buffer
239 *
240 ******************************************************************************/
241
242 static ACPI_STATUS
243 DtCompileUuid (
244 UINT8 *Buffer,
245 DT_FIELD *Field,
246 UINT32 ByteLength)
247 {
248 char *InString;
249 ACPI_STATUS Status;
250
251
252 InString = Field->Value;
253
254 Status = AuValidateUuid (InString);
255 if (ACPI_FAILURE (Status))
256 {
257 sprintf (AslGbl_MsgBuffer, "%s", Field->Value);
258 DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, AslGbl_MsgBuffer);
259 }
260 else
261 {
262 AcpiUtConvertStringToUuid (InString, Buffer);
263 }
264
265 return (Status);
266 }
267
268
269 /******************************************************************************
270 *
271 * FUNCTION: DtCompileInteger
272 *
273 * PARAMETERS: Buffer - Output buffer
274 * Field - Field obj with Integer to be compiled
275 * ByteLength - Byte length of the integer
276 * Flags - Additional compile info
277 *
278 * RETURN: None
279 *
280 * DESCRIPTION: Compile an integer. Supports integer expressions with C-style
281 * operators.
282 *
283 *****************************************************************************/
284
285 void
286 DtCompileInteger (
287 UINT8 *Buffer,
288 DT_FIELD *Field,
289 UINT32 ByteLength,
290 UINT8 Flags)
291 {
292 UINT64 Value;
293 UINT64 MaxValue;
294 ACPI_STATUS Status;
295
296
297 /* Output buffer byte length must be in range 1-8 */
298
299 if ((ByteLength > 8) || (ByteLength == 0))
300 {
301 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field,
302 "Invalid internal Byte length");
303 return;
304 }
305
306 /* Resolve integer expression to a single integer value */
307
308 Status = DtResolveIntegerExpression (Field, &Value);
309 if (ACPI_FAILURE (Status))
310 {
311 return;
312 }
313
314 /*
315 * Ensure that reserved fields are set properly. Note: uses
316 * the DT_NON_ZERO flag to indicate that the reserved value
317 * must be exactly one. Otherwise, the value must be zero.
318 * This is sufficient for now.
319 */
320
321 /* TBD: Should use a flag rather than compare "Reserved" */
322
323 if (!strcmp (Field->Name, "Reserved"))
324 {
325 if (Flags & DT_NON_ZERO)
326 {
327 if (Value != 1)
328 {
329 DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
330 "Must be one, setting to one");
331 Value = 1;
332 }
333 }
334 else if (Value != 0)
335 {
336 DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
337 "Must be zero, setting to zero");
338 Value = 0;
339 }
340 }
341
342 /* Check if the value must be non-zero */
343
344 else if ((Flags & DT_NON_ZERO) && (Value == 0))
345 {
346 DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL);
347 }
348
349 /*
350 * Generate the maximum value for the data type (ByteLength)
351 * Note: construct chosen for maximum portability
352 */
353 MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8));
354
355 /* Validate that the input value is within range of the target */
356
357 if (Value > MaxValue)
358 {
359 sprintf (AslGbl_MsgBuffer, "%8.8X%8.8X - max %u bytes",
360 ACPI_FORMAT_UINT64 (Value), ByteLength);
361 DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, AslGbl_MsgBuffer);
362 }
363
364 memcpy (Buffer, &Value, ByteLength);
365 return;
366 }
367
368
369 /******************************************************************************
370 *
371 * FUNCTION: DtNormalizeBuffer
372 *
373 * PARAMETERS: Buffer - Input buffer
374 * Count - Output the count of hex numbers in
375 * the Buffer
376 *
377 * RETURN: The normalized buffer, must be freed by caller
378 *
379 * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized
380 * to 1A 2B 3C 4D
381 *
382 *****************************************************************************/
383
384 static char *
385 DtNormalizeBuffer (
386 char *Buffer,
387 UINT32 *Count)
388 {
389 char *NewBuffer;
390 char *TmpBuffer;
391 UINT32 BufferCount = 0;
392 BOOLEAN Separator = TRUE;
393 char c;
394
395
396 NewBuffer = UtLocalCalloc (strlen (Buffer) + 1);
397 TmpBuffer = NewBuffer;
398
399 while ((c = *Buffer++))
400 {
401 switch (c)
402 {
403 /* Valid separators */
404
405 case '[':
406 case ']':
407 case ' ':
408 case ',':
409
410 Separator = TRUE;
411 break;
412
413 default:
414
415 if (Separator)
416 {
417 /* Insert blank as the standard separator */
418
419 if (NewBuffer[0])
420 {
421 *TmpBuffer++ = ' ';
422 BufferCount++;
423 }
424
425 Separator = FALSE;
426 }
427
428 *TmpBuffer++ = c;
429 break;
430 }
431 }
432
433 *Count = BufferCount + 1;
434 return (NewBuffer);
435 }
436
437
438 /******************************************************************************
439 *
440 * FUNCTION: DtCompileBuffer
441 *
442 * PARAMETERS: Buffer - Output buffer
443 * StringValue - Integer list to be compiled
444 * Field - Current field object
445 * ByteLength - Byte length of the integer list
446 *
447 * RETURN: Count of remaining data in the input list
448 *
449 * DESCRIPTION: Compile and pack an integer list, for example
450 * "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B}
451 *
452 *****************************************************************************/
453
454 UINT32
455 DtCompileBuffer (
456 UINT8 *Buffer,
457 char *StringValue,
458 DT_FIELD *Field,
459 UINT32 ByteLength)
460 {
461 char *Substring;
462 ACPI_STATUS Status;
463 UINT32 Count;
464 UINT32 i;
465
466
467 /* Allow several different types of value separators */
468
469 StringValue = DtNormalizeBuffer (StringValue, &Count);
470 Substring = StringValue;
471 if (Count != ByteLength)
472 {
473 sprintf(AslGbl_MsgBuffer,
474 "Found %u values, must match expected count: %u",
475 Count, ByteLength);
476 DtError (ASL_ERROR, ASL_MSG_BUFFER_LIST, Field, AslGbl_MsgBuffer);
477 goto Exit;
478 }
479
480 /* Each element of StringValue is now three chars (2 hex + 1 space) */
481
482 for (i = 0; i < Count; i++, Substring += 3)
483 {
484 /* Check for byte value too long */
485
486 if (*(&Substring[2]) &&
487 (*(&Substring[2]) != ' '))
488 {
489 DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring);
490 goto Exit;
491 }
492
493 /* Convert two ASCII characters to one hex byte */
494
495 Status = AcpiUtAsciiToHexByte (Substring, &Buffer[i]);
496 if (ACPI_FAILURE (Status))
497 {
498 DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring);
499 goto Exit;
500 }
501 }
502
503 Exit:
504 ACPI_FREE (StringValue);
505 return (ByteLength - Count);
506 }
507
508
509 /******************************************************************************
510 *
511 * FUNCTION: DtCompileFlag
512 *
513 * PARAMETERS: Buffer - Output buffer
514 * Field - Field to be compiled
515 * Info - Flag info
516 *
517 * RETURN: None
518 *
519 * DESCRIPTION: Compile a flag field. Handles flags up to 64 bits.
520 *
521 *****************************************************************************/
522
523 void
524 DtCompileFlag (
525 UINT8 *Buffer,
526 DT_FIELD *Field,
527 ACPI_DMTABLE_INFO *Info)
528 {
529 UINT64 Value = 0;
530 UINT32 BitLength = 1;
531 UINT8 BitPosition = 0;
532
533
534 Value = AcpiUtImplicitStrtoul64 (Field->Value);
535
536 switch (Info->Opcode)
537 {
538 case ACPI_DMT_FLAG0:
539 case ACPI_DMT_FLAG1:
540 case ACPI_DMT_FLAG2:
541 case ACPI_DMT_FLAG3:
542 case ACPI_DMT_FLAG4:
543 case ACPI_DMT_FLAG5:
544 case ACPI_DMT_FLAG6:
545 case ACPI_DMT_FLAG7:
546
547 BitPosition = Info->Opcode;
548 BitLength = 1;
549 break;
550
551 case ACPI_DMT_FLAGS0:
552
553 BitPosition = 0;
554 BitLength = 2;
555 break;
556
557
558 case ACPI_DMT_FLAGS1:
559
560 BitPosition = 1;
561 BitLength = 2;
562 break;
563
564
565 case ACPI_DMT_FLAGS2:
566
567 BitPosition = 2;
568 BitLength = 2;
569 break;
570
571 case ACPI_DMT_FLAGS4:
572
573 BitPosition = 4;
574 BitLength = 2;
575 break;
576
577 case ACPI_DMT_FLAGS4_0:
578
579 BitPosition = 0;
580 BitLength = 4;
581 break;
582
583 case ACPI_DMT_FLAGS4_4:
584
585 BitPosition = 4;
586 BitLength = 4;
587 break;
588
589 case ACPI_DMT_FLAGS4_8:
590
591 BitPosition = 8;
592 BitLength = 4;
593 break;
594
595 case ACPI_DMT_FLAGS4_12:
596
597 BitPosition = 12;
598 BitLength = 4;
599 break;
600
601 case ACPI_DMT_FLAGS16_16:
602
603 BitPosition = 16;
604 BitLength = 16;
605 break;
606
607 default:
608
609 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode");
610 break;
611 }
612
613 /* Check range of the input flag value */
614
615 if (Value >= ((UINT64) 1 << BitLength))
616 {
617 sprintf (AslGbl_MsgBuffer, "Maximum %u bit", BitLength);
618 DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, AslGbl_MsgBuffer);
619 Value = 0;
620 }
621
622 *Buffer |= (UINT8) (Value << BitPosition);
623 }
624
625
626 /******************************************************************************
627 *
628 * FUNCTION: DtCreateField
629 *
630 * PARAMETERS: Name
631 * Value
632 * Line
633 * Offset
634 * Column
635 * NameColumn
636 *
637 * RETURN: None
638 *
639 * DESCRIPTION: Create a field
640 *
641 *****************************************************************************/
642
643 void
644 DtCreateField (
645 DT_TABLE_UNIT *FieldKey,
646 DT_TABLE_UNIT *FieldValue,
647 UINT32 Offset)
648 {
649 DT_FIELD *Field = UtFieldCacheCalloc ();
650
651
652 Field->StringLength = 0;
653 if (FieldKey->Value)
654 {
655 Field->Name =
656 strcpy (UtLocalCacheCalloc (strlen (FieldKey->Value) + 1), FieldKey->Value);
657 }
658
659 if (FieldValue->Value)
660 {
661 Field->StringLength = strlen (FieldValue->Value);
662 Field->Value =
663 strcpy (UtLocalCacheCalloc (Field->StringLength + 1), FieldValue->Value);
664 }
665
666 Field->Line = FieldValue->Line;
667 Field->ByteOffset = Offset;
668 Field->NameColumn = FieldKey->Column;
669 Field->Column = FieldValue->Column;
670 DtLinkField (Field);
671
672 DtDumpFieldList (AslGbl_FieldList);
673 }
674
675
676 /******************************************************************************
677 *
678 * FUNCTION: DtCreateTableUnit
679 *
680 * PARAMETERS: Data
681 * Line
682 * Column
683 *
684 * RETURN: a table unit
685 *
686 * DESCRIPTION: Create a table unit
687 *
688 *****************************************************************************/
689
690 DT_TABLE_UNIT *
691 DtCreateTableUnit (
692 char *Data,
693 UINT32 Line,
694 UINT32 Column)
695 {
696 DT_TABLE_UNIT *Unit = (DT_TABLE_UNIT *) UtFieldCacheCalloc ();
697
698
699 Unit->Value = Data;
700 Unit->Line = Line;
701 Unit->Column = Column;
702 return (Unit);
703 }
704
705
706 /******************************************************************************
707 *
708 * FUNCTION: DtLinkField
709 *
710 * PARAMETERS: Field - New field object to link
711 *
712 * RETURN: None
713 *
714 * DESCRIPTION: Link one field name and value to the list
715 *
716 *****************************************************************************/
717
718 void
719 DtLinkField (
720 DT_FIELD *Field)
721 {
722 DT_FIELD *Prev;
723 DT_FIELD *Next;
724
725
726 Prev = Next = AslGbl_FieldList;
727
728 while (Next)
729 {
730 Prev = Next;
731 Next = Next->Next;
732 }
733
734 if (Prev)
735 {
736 Prev->Next = Field;
737 }
738 else
739 {
740 AslGbl_FieldList = Field;
741 }
742 }
743