dtfield.c revision 306536
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
53static void
54DtCompileString (
55    UINT8                   *Buffer,
56    DT_FIELD                *Field,
57    UINT32                  ByteLength);
58
59static void
60DtCompileUnicode (
61    UINT8                   *Buffer,
62    DT_FIELD                *Field,
63    UINT32                  ByteLength);
64
65static ACPI_STATUS
66DtCompileUuid (
67    UINT8                   *Buffer,
68    DT_FIELD                *Field,
69    UINT32                  ByteLength);
70
71static char *
72DtNormalizeBuffer (
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
92void
93DtCompileOneField (
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
161static void
162DtCompileString (
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
202static void
203DtCompileUnicode (
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
241static ACPI_STATUS
242DtCompileUuid (
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
284void
285DtCompileInteger (
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
383static char *
384DtNormalizeBuffer (
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
453UINT32
454DtCompileBuffer (
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
492Exit:
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
512void
513DtCompileFlag (
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