xref: /freebsd/sys/contrib/dev/acpica/compiler/dtfield.c (revision 86c9d9918f1db7cdd968b60f8902466887bcd9e9)
1 /******************************************************************************
2  *
3  * Module Name: dtfield.c - Code generation for individual source fields
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 <contrib/dev/acpica/compiler/aslcompiler.h>
45 #include <contrib/dev/acpica/compiler/dtcompiler.h>
46 
47 #define _COMPONENT          DT_COMPILER
48         ACPI_MODULE_NAME    ("dtfield")
49 
50 
51 /* Local prototypes */
52 
53 static void
54 DtCompileString (
55     UINT8                   *Buffer,
56     DT_FIELD                *Field,
57     UINT32                  ByteLength);
58 
59 static void
60 DtCompileUnicode (
61     UINT8                   *Buffer,
62     DT_FIELD                *Field,
63     UINT32                  ByteLength);
64 
65 static ACPI_STATUS
66 DtCompileUuid (
67     UINT8                   *Buffer,
68     DT_FIELD                *Field,
69     UINT32                  ByteLength);
70 
71 static char *
72 DtNormalizeBuffer (
73     char                    *Buffer,
74     UINT32                  *Count);
75 
76 
77 /******************************************************************************
78  *
79  * FUNCTION:    DtCompileOneField
80  *
81  * PARAMETERS:  Buffer              - Output buffer
82  *              Field               - Field to be compiled
83  *              ByteLength          - Byte length of the field
84  *              Type                - Field type
85  *
86  * RETURN:      None
87  *
88  * DESCRIPTION: Compile a field value to binary
89  *
90  *****************************************************************************/
91 
92 void
93 DtCompileOneField (
94     UINT8                   *Buffer,
95     DT_FIELD                *Field,
96     UINT32                  ByteLength,
97     UINT8                   Type,
98     UINT8                   Flags)
99 {
100     ACPI_STATUS             Status;
101 
102 
103     switch (Type)
104     {
105     case DT_FIELD_TYPE_INTEGER:
106 
107         DtCompileInteger (Buffer, Field, ByteLength, Flags);
108         break;
109 
110     case DT_FIELD_TYPE_STRING:
111 
112         DtCompileString (Buffer, Field, ByteLength);
113         break;
114 
115     case DT_FIELD_TYPE_UUID:
116 
117         Status = DtCompileUuid (Buffer, Field, ByteLength);
118         if (ACPI_SUCCESS (Status))
119         {
120             break;
121         }
122 
123         /* Fall through. */
124 
125     case DT_FIELD_TYPE_BUFFER:
126 
127         DtCompileBuffer (Buffer, Field->Value, Field, ByteLength);
128         break;
129 
130     case DT_FIELD_TYPE_UNICODE:
131 
132         DtCompileUnicode (Buffer, Field, ByteLength);
133         break;
134 
135     case DT_FIELD_TYPE_DEVICE_PATH:
136 
137         break;
138 
139     default:
140 
141         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid field type");
142         break;
143     }
144 }
145 
146 
147 /******************************************************************************
148  *
149  * FUNCTION:    DtCompileString
150  *
151  * PARAMETERS:  Buffer              - Output buffer
152  *              Field               - String to be copied to buffer
153  *              ByteLength          - Maximum length of string
154  *
155  * RETURN:      None
156  *
157  * DESCRIPTION: Copy string to the buffer
158  *
159  *****************************************************************************/
160 
161 static void
162 DtCompileString (
163     UINT8                   *Buffer,
164     DT_FIELD                *Field,
165     UINT32                  ByteLength)
166 {
167     UINT32                  Length;
168 
169 
170     Length = strlen (Field->Value);
171 
172     /* Check if the string is too long for the field */
173 
174     if (Length > ByteLength)
175     {
176         sprintf (MsgBuffer, "Maximum %u characters", ByteLength);
177         DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, MsgBuffer);
178         Length = ByteLength;
179     }
180 
181     memcpy (Buffer, Field->Value, Length);
182 }
183 
184 
185 /******************************************************************************
186  *
187  * FUNCTION:    DtCompileUnicode
188  *
189  * PARAMETERS:  Buffer              - Output buffer
190  *              Field               - String to be copied to buffer
191  *              ByteLength          - Maximum length of string
192  *
193  * RETURN:      None
194  *
195  * DESCRIPTION: Convert ASCII string to Unicode string
196  *
197  * Note:  The Unicode string is 16 bits per character, no leading signature,
198  *        with a 16-bit terminating NULL.
199  *
200  *****************************************************************************/
201 
202 static void
203 DtCompileUnicode (
204     UINT8                   *Buffer,
205     DT_FIELD                *Field,
206     UINT32                  ByteLength)
207 {
208     UINT32                  Count;
209     UINT32                  i;
210     char                    *AsciiString;
211     UINT16                  *UnicodeString;
212 
213 
214     AsciiString = Field->Value;
215     UnicodeString = (UINT16 *) Buffer;
216     Count = strlen (AsciiString) + 1;
217 
218     /* Convert to Unicode string (including null terminator) */
219 
220     for (i = 0; i < Count; i++)
221     {
222         UnicodeString[i] = (UINT16) AsciiString[i];
223     }
224 }
225 
226 
227 /*******************************************************************************
228  *
229  * FUNCTION:    DtCompileUuid
230  *
231  * PARAMETERS:  Buffer              - Output buffer
232  *              Field               - String to be copied to buffer
233  *              ByteLength          - Maximum length of string
234  *
235  * RETURN:      None
236  *
237  * DESCRIPTION: Convert UUID string to 16-byte buffer
238  *
239  ******************************************************************************/
240 
241 static ACPI_STATUS
242 DtCompileUuid (
243     UINT8                   *Buffer,
244     DT_FIELD                *Field,
245     UINT32                  ByteLength)
246 {
247     char                    *InString;
248     ACPI_STATUS             Status;
249 
250 
251     InString = Field->Value;
252 
253     Status = AuValidateUuid (InString);
254     if (ACPI_FAILURE (Status))
255     {
256         sprintf (MsgBuffer, "%s", Field->Value);
257         DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, MsgBuffer);
258     }
259     else
260     {
261         AcpiUtConvertStringToUuid (InString, Buffer);
262     }
263 
264     return (Status);
265 }
266 
267 
268 /******************************************************************************
269  *
270  * FUNCTION:    DtCompileInteger
271  *
272  * PARAMETERS:  Buffer              - Output buffer
273  *              Field               - Field obj with Integer to be compiled
274  *              ByteLength          - Byte length of the integer
275  *              Flags               - Additional compile info
276  *
277  * RETURN:      None
278  *
279  * DESCRIPTION: Compile an integer. Supports integer expressions with C-style
280  *              operators.
281  *
282  *****************************************************************************/
283 
284 void
285 DtCompileInteger (
286     UINT8                   *Buffer,
287     DT_FIELD                *Field,
288     UINT32                  ByteLength,
289     UINT8                   Flags)
290 {
291     UINT64                  Value;
292     UINT64                  MaxValue;
293     ACPI_STATUS             Status;
294 
295 
296     /* Output buffer byte length must be in range 1-8 */
297 
298     if ((ByteLength > 8) || (ByteLength == 0))
299     {
300         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field,
301             "Invalid internal Byte length");
302         return;
303     }
304 
305     /* Resolve integer expression to a single integer value */
306 
307     Status = DtResolveIntegerExpression (Field, &Value);
308     if (ACPI_FAILURE (Status))
309     {
310         return;
311     }
312 
313     /*
314      * Ensure that reserved fields are set properly. Note: uses
315      * the DT_NON_ZERO flag to indicate that the reserved value
316      * must be exactly one. Otherwise, the value must be zero.
317      * This is sufficient for now.
318      */
319 
320     /* TBD: Should use a flag rather than compare "Reserved" */
321 
322     if (!strcmp (Field->Name, "Reserved"))
323     {
324         if (Flags & DT_NON_ZERO)
325         {
326             if (Value != 1)
327             {
328                 DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
329                     "Must be one, setting to one");
330                 Value = 1;
331             }
332         }
333         else if (Value != 0)
334         {
335             DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
336                 "Must be zero, setting to zero");
337             Value = 0;
338         }
339     }
340 
341     /* Check if the value must be non-zero */
342 
343     else if ((Flags & DT_NON_ZERO) && (Value == 0))
344     {
345         DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL);
346     }
347 
348     /*
349      * Generate the maximum value for the data type (ByteLength)
350      * Note: construct chosen for maximum portability
351      */
352     MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8));
353 
354     /* Validate that the input value is within range of the target */
355 
356     if (Value > MaxValue)
357     {
358         sprintf (MsgBuffer, "%8.8X%8.8X - max %u bytes",
359             ACPI_FORMAT_UINT64 (Value), ByteLength);
360         DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, MsgBuffer);
361     }
362 
363     memcpy (Buffer, &Value, ByteLength);
364     return;
365 }
366 
367 
368 /******************************************************************************
369  *
370  * FUNCTION:    DtNormalizeBuffer
371  *
372  * PARAMETERS:  Buffer              - Input buffer
373  *              Count               - Output the count of hex number in
374  *                                    the Buffer
375  *
376  * RETURN:      The normalized buffer, freed by caller
377  *
378  * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized
379  *              to 1A 2B 3C 4D
380  *
381  *****************************************************************************/
382 
383 static char *
384 DtNormalizeBuffer (
385     char                    *Buffer,
386     UINT32                  *Count)
387 {
388     char                    *NewBuffer;
389     char                    *TmpBuffer;
390     UINT32                  BufferCount = 0;
391     BOOLEAN                 Separator = TRUE;
392     char                    c;
393 
394 
395     NewBuffer = UtLocalCalloc (strlen (Buffer) + 1);
396     TmpBuffer = NewBuffer;
397 
398     while ((c = *Buffer++))
399     {
400         switch (c)
401         {
402         /* Valid separators */
403 
404         case '[':
405         case ']':
406         case ' ':
407         case ',':
408 
409             Separator = TRUE;
410             break;
411 
412         default:
413 
414             if (Separator)
415             {
416                 /* Insert blank as the standard separator */
417 
418                 if (NewBuffer[0])
419                 {
420                     *TmpBuffer++ = ' ';
421                     BufferCount++;
422                 }
423 
424                 Separator = FALSE;
425             }
426 
427             *TmpBuffer++ = c;
428             break;
429         }
430     }
431 
432     *Count = BufferCount + 1;
433     return (NewBuffer);
434 }
435 
436 
437 /******************************************************************************
438  *
439  * FUNCTION:    DtCompileBuffer
440  *
441  * PARAMETERS:  Buffer              - Output buffer
442  *              StringValue         - Integer list to be compiled
443  *              Field               - Current field object
444  *              ByteLength          - Byte length of the integer list
445  *
446  * RETURN:      Count of remaining data in the input list
447  *
448  * DESCRIPTION: Compile and pack an integer list, for example
449  *              "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B}
450  *
451  *****************************************************************************/
452 
453 UINT32
454 DtCompileBuffer (
455     UINT8                   *Buffer,
456     char                    *StringValue,
457     DT_FIELD                *Field,
458     UINT32                  ByteLength)
459 {
460     ACPI_STATUS             Status;
461     char                    Hex[3];
462     UINT64                  Value;
463     UINT32                  i;
464     UINT32                  Count;
465 
466 
467     /* Allow several different types of value separators */
468 
469     StringValue = DtNormalizeBuffer (StringValue, &Count);
470 
471     Hex[2] = 0;
472     for (i = 0; i < Count; i++)
473     {
474         /* Each element of StringValue is three chars */
475 
476         Hex[0] = StringValue[(3 * i)];
477         Hex[1] = StringValue[(3 * i) + 1];
478 
479         /* Convert one hex byte */
480 
481         Value = 0;
482         Status = DtStrtoul64 (Hex, &Value);
483         if (ACPI_FAILURE (Status))
484         {
485             DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, MsgBuffer);
486             goto Exit;
487         }
488 
489         Buffer[i] = (UINT8) Value;
490     }
491 
492 Exit:
493     ACPI_FREE (StringValue);
494     return (ByteLength - Count);
495 }
496 
497 
498 /******************************************************************************
499  *
500  * FUNCTION:    DtCompileFlag
501  *
502  * PARAMETERS:  Buffer              - Output buffer
503  *              Field               - Field to be compiled
504  *              Info                - Flag info
505  *
506  * RETURN:
507  *
508  * DESCRIPTION: Compile a flag
509  *
510  *****************************************************************************/
511 
512 void
513 DtCompileFlag (
514     UINT8                   *Buffer,
515     DT_FIELD                *Field,
516     ACPI_DMTABLE_INFO       *Info)
517 {
518     UINT64                  Value = 0;
519     UINT32                  BitLength = 1;
520     UINT8                   BitPosition = 0;
521     ACPI_STATUS             Status;
522 
523 
524     Status = DtStrtoul64 (Field->Value, &Value);
525     if (ACPI_FAILURE (Status))
526     {
527         DtError (ASL_ERROR, ASL_MSG_INVALID_HEX_INTEGER, Field, NULL);
528     }
529 
530     switch (Info->Opcode)
531     {
532     case ACPI_DMT_FLAG0:
533     case ACPI_DMT_FLAG1:
534     case ACPI_DMT_FLAG2:
535     case ACPI_DMT_FLAG3:
536     case ACPI_DMT_FLAG4:
537     case ACPI_DMT_FLAG5:
538     case ACPI_DMT_FLAG6:
539     case ACPI_DMT_FLAG7:
540 
541         BitPosition = Info->Opcode;
542         BitLength = 1;
543         break;
544 
545     case ACPI_DMT_FLAGS0:
546 
547         BitPosition = 0;
548         BitLength = 2;
549         break;
550 
551 
552     case ACPI_DMT_FLAGS1:
553 
554         BitPosition = 1;
555         BitLength = 2;
556         break;
557 
558 
559     case ACPI_DMT_FLAGS2:
560 
561         BitPosition = 2;
562         BitLength = 2;
563         break;
564 
565     case ACPI_DMT_FLAGS4:
566 
567         BitPosition = 4;
568         BitLength = 2;
569         break;
570 
571     default:
572 
573         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode");
574         break;
575     }
576 
577     /* Check range of the input flag value */
578 
579     if (Value >= ((UINT64) 1 << BitLength))
580     {
581         sprintf (MsgBuffer, "Maximum %u bit", BitLength);
582         DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, MsgBuffer);
583         Value = 0;
584     }
585 
586     *Buffer |= (UINT8) (Value << BitPosition);
587 }
588