xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/dtfield.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /******************************************************************************
2  *
3  * Module Name: dtfield.c - Code generation for individual source fields
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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 
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         /* Fall through. */
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         snprintf (MsgBuffer, sizeof(MsgBuffer), "Maximum %u characters", ByteLength);
176         DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, MsgBuffer);
177         Length = ByteLength;
178     }
179 
180     memcpy (Buffer, Field->Value, Length);
181 }
182 
183 
184 /******************************************************************************
185  *
186  * FUNCTION:    DtCompileUnicode
187  *
188  * PARAMETERS:  Buffer              - Output buffer
189  *              Field               - String to be copied to buffer
190  *              ByteLength          - Maximum length of string
191  *
192  * RETURN:      None
193  *
194  * DESCRIPTION: Convert ASCII string to Unicode string
195  *
196  * Note:  The Unicode string is 16 bits per character, no leading signature,
197  *        with a 16-bit terminating NULL.
198  *
199  *****************************************************************************/
200 
201 static void
202 DtCompileUnicode (
203     UINT8                   *Buffer,
204     DT_FIELD                *Field,
205     UINT32                  ByteLength)
206 {
207     UINT32                  Count;
208     UINT32                  i;
209     char                    *AsciiString;
210     UINT16                  *UnicodeString;
211 
212 
213     AsciiString = Field->Value;
214     UnicodeString = (UINT16 *) Buffer;
215     Count = strlen (AsciiString) + 1;
216 
217     /* Convert to Unicode string (including null terminator) */
218 
219     for (i = 0; i < Count; i++)
220     {
221         UnicodeString[i] = (UINT16) AsciiString[i];
222     }
223 }
224 
225 
226 /*******************************************************************************
227  *
228  * FUNCTION:    DtCompileUuid
229  *
230  * PARAMETERS:  Buffer              - Output buffer
231  *              Field               - String to be copied to buffer
232  *              ByteLength          - Maximum length of string
233  *
234  * RETURN:      None
235  *
236  * DESCRIPTION: Convert UUID string to 16-byte buffer
237  *
238  ******************************************************************************/
239 
240 static ACPI_STATUS
241 DtCompileUuid (
242     UINT8                   *Buffer,
243     DT_FIELD                *Field,
244     UINT32                  ByteLength)
245 {
246     char                    *InString;
247     ACPI_STATUS             Status;
248 
249 
250     InString = Field->Value;
251 
252     Status = AuValidateUuid (InString);
253     if (ACPI_FAILURE (Status))
254     {
255         snprintf (MsgBuffer, sizeof(MsgBuffer), "%s", Field->Value);
256         DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, MsgBuffer);
257     }
258     else
259     {
260         AcpiUtConvertStringToUuid (InString, Buffer);
261     }
262 
263     return (Status);
264 }
265 
266 
267 /******************************************************************************
268  *
269  * FUNCTION:    DtCompileInteger
270  *
271  * PARAMETERS:  Buffer              - Output buffer
272  *              Field               - Field obj with Integer to be compiled
273  *              ByteLength          - Byte length of the integer
274  *              Flags               - Additional compile info
275  *
276  * RETURN:      None
277  *
278  * DESCRIPTION: Compile an integer. Supports integer expressions with C-style
279  *              operators.
280  *
281  *****************************************************************************/
282 
283 void
284 DtCompileInteger (
285     UINT8                   *Buffer,
286     DT_FIELD                *Field,
287     UINT32                  ByteLength,
288     UINT8                   Flags)
289 {
290     UINT64                  Value;
291     UINT64                  MaxValue;
292     ACPI_STATUS             Status;
293 
294 
295     /* Output buffer byte length must be in range 1-8 */
296 
297     if ((ByteLength > 8) || (ByteLength == 0))
298     {
299         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field,
300             "Invalid internal Byte length");
301         return;
302     }
303 
304     /* Resolve integer expression to a single integer value */
305 
306     Status = DtResolveIntegerExpression (Field, &Value);
307     if (ACPI_FAILURE (Status))
308     {
309         return;
310     }
311 
312     /*
313      * Ensure that reserved fields are set properly. Note: uses
314      * the DT_NON_ZERO flag to indicate that the reserved value
315      * must be exactly one. Otherwise, the value must be zero.
316      * This is sufficient for now.
317      */
318 
319     /* TBD: Should use a flag rather than compare "Reserved" */
320 
321     if (!strcmp (Field->Name, "Reserved"))
322     {
323         if (Flags & DT_NON_ZERO)
324         {
325             if (Value != 1)
326             {
327                 DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
328                     "Must be one, setting to one");
329                 Value = 1;
330             }
331         }
332         else if (Value != 0)
333         {
334             DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
335                 "Must be zero, setting to zero");
336             Value = 0;
337         }
338     }
339 
340     /* Check if the value must be non-zero */
341 
342     else if ((Flags & DT_NON_ZERO) && (Value == 0))
343     {
344         DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL);
345     }
346 
347     /*
348      * Generate the maximum value for the data type (ByteLength)
349      * Note: construct chosen for maximum portability
350      */
351     MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8));
352 
353     /* Validate that the input value is within range of the target */
354 
355     if (Value > MaxValue)
356     {
357         snprintf (MsgBuffer, sizeof(MsgBuffer), "%8.8X%8.8X - max %u bytes",
358             ACPI_FORMAT_UINT64 (Value), ByteLength);
359         DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, MsgBuffer);
360     }
361 
362     memcpy (Buffer, &Value, ByteLength);
363     return;
364 }
365 
366 
367 /******************************************************************************
368  *
369  * FUNCTION:    DtNormalizeBuffer
370  *
371  * PARAMETERS:  Buffer              - Input buffer
372  *              Count               - Output the count of hex numbers in
373  *                                    the Buffer
374  *
375  * RETURN:      The normalized buffer, must be freed by caller
376  *
377  * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized
378  *              to 1A 2B 3C 4D
379  *
380  *****************************************************************************/
381 
382 static char *
383 DtNormalizeBuffer (
384     char                    *Buffer,
385     UINT32                  *Count)
386 {
387     char                    *NewBuffer;
388     char                    *TmpBuffer;
389     UINT32                  BufferCount = 0;
390     BOOLEAN                 Separator = TRUE;
391     char                    c;
392 
393 
394     NewBuffer = UtLocalCalloc (strlen (Buffer) + 1);
395     TmpBuffer = NewBuffer;
396 
397     while ((c = *Buffer++))
398     {
399         switch (c)
400         {
401         /* Valid separators */
402 
403         case '[':
404         case ']':
405         case ' ':
406         case ',':
407 
408             Separator = TRUE;
409             break;
410 
411         default:
412 
413             if (Separator)
414             {
415                 /* Insert blank as the standard separator */
416 
417                 if (NewBuffer[0])
418                 {
419                     *TmpBuffer++ = ' ';
420                     BufferCount++;
421                 }
422 
423                 Separator = FALSE;
424             }
425 
426             *TmpBuffer++ = c;
427             break;
428         }
429     }
430 
431     *Count = BufferCount + 1;
432     return (NewBuffer);
433 }
434 
435 
436 /******************************************************************************
437  *
438  * FUNCTION:    DtCompileBuffer
439  *
440  * PARAMETERS:  Buffer              - Output buffer
441  *              StringValue         - Integer list to be compiled
442  *              Field               - Current field object
443  *              ByteLength          - Byte length of the integer list
444  *
445  * RETURN:      Count of remaining data in the input list
446  *
447  * DESCRIPTION: Compile and pack an integer list, for example
448  *              "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B}
449  *
450  *****************************************************************************/
451 
452 UINT32
453 DtCompileBuffer (
454     UINT8                   *Buffer,
455     char                    *StringValue,
456     DT_FIELD                *Field,
457     UINT32                  ByteLength)
458 {
459     char                    *Substring;
460     ACPI_STATUS             Status;
461     UINT32                  Count;
462     UINT32                  i;
463 
464 
465     /* Allow several different types of value separators */
466 
467     StringValue = DtNormalizeBuffer (StringValue, &Count);
468     Substring = StringValue;
469 
470     /* Each element of StringValue is now three chars (2 hex + 1 space) */
471 
472     for (i = 0; i < Count; i++, Substring += 3)
473     {
474         /* Check for byte value too long */
475 
476         if (*(&Substring[2]) &&
477            (*(&Substring[2]) != ' '))
478         {
479             DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring);
480             goto Exit;
481         }
482 
483         /* Convert two ASCII characters to one hex byte */
484 
485         Status = AcpiUtAsciiToHexByte (Substring, &Buffer[i]);
486         if (ACPI_FAILURE (Status))
487         {
488             DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring);
489             goto Exit;
490         }
491     }
492 
493 Exit:
494     ACPI_FREE (StringValue);
495     return (ByteLength - Count);
496 }
497 
498 
499 /******************************************************************************
500  *
501  * FUNCTION:    DtCompileFlag
502  *
503  * PARAMETERS:  Buffer                      - Output buffer
504  *              Field                       - Field to be compiled
505  *              Info                        - Flag info
506  *
507  * RETURN:      None
508  *
509  * DESCRIPTION: Compile a flag field. Handles flags up to 64 bits.
510  *
511  *****************************************************************************/
512 
513 void
514 DtCompileFlag (
515     UINT8                   *Buffer,
516     DT_FIELD                *Field,
517     ACPI_DMTABLE_INFO       *Info)
518 {
519     UINT64                  Value = 0;
520     UINT32                  BitLength = 1;
521     UINT8                   BitPosition = 0;
522 
523 
524     Value = AcpiUtImplicitStrtoul64 (Field->Value);
525 
526     switch (Info->Opcode)
527     {
528     case ACPI_DMT_FLAG0:
529     case ACPI_DMT_FLAG1:
530     case ACPI_DMT_FLAG2:
531     case ACPI_DMT_FLAG3:
532     case ACPI_DMT_FLAG4:
533     case ACPI_DMT_FLAG5:
534     case ACPI_DMT_FLAG6:
535     case ACPI_DMT_FLAG7:
536 
537         BitPosition = Info->Opcode;
538         BitLength = 1;
539         break;
540 
541     case ACPI_DMT_FLAGS0:
542 
543         BitPosition = 0;
544         BitLength = 2;
545         break;
546 
547 
548     case ACPI_DMT_FLAGS1:
549 
550         BitPosition = 1;
551         BitLength = 2;
552         break;
553 
554 
555     case ACPI_DMT_FLAGS2:
556 
557         BitPosition = 2;
558         BitLength = 2;
559         break;
560 
561     case ACPI_DMT_FLAGS4:
562 
563         BitPosition = 4;
564         BitLength = 2;
565         break;
566 
567     case ACPI_DMT_FLAGS4_0:
568 
569         BitPosition = 0;
570         BitLength = 4;
571         break;
572 
573     case ACPI_DMT_FLAGS4_4:
574 
575         BitPosition = 4;
576         BitLength = 4;
577         break;
578 
579     case ACPI_DMT_FLAGS4_8:
580 
581         BitPosition = 8;
582         BitLength = 4;
583         break;
584 
585     case ACPI_DMT_FLAGS4_12:
586 
587         BitPosition = 12;
588         BitLength = 4;
589         break;
590 
591     case ACPI_DMT_FLAGS16_16:
592 
593         BitPosition = 16;
594         BitLength = 16;
595         break;
596 
597     default:
598 
599         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode");
600         break;
601     }
602 
603     /* Check range of the input flag value */
604 
605     if (Value >= ((UINT64) 1 << BitLength))
606     {
607         snprintf (MsgBuffer, sizeof(MsgBuffer), "Maximum %u bit", BitLength);
608         DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, MsgBuffer);
609         Value = 0;
610     }
611 
612     *Buffer |= (UINT8) (Value << BitPosition);
613 }
614