dtfield.c revision 281075
1/******************************************************************************
2 *
3 * Module Name: dtfield.c - Code generation for individual source fields
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, 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    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
160static void
161DtCompileString (
162    UINT8                   *Buffer,
163    DT_FIELD                *Field,
164    UINT32                  ByteLength)
165{
166    UINT32                  Length;
167
168
169    Length = ACPI_STRLEN (Field->Value);
170
171    /* Check if the string is too long for the field */
172
173    if (Length > ByteLength)
174    {
175        sprintf (MsgBuffer, "Maximum %u characters", ByteLength);
176        DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, MsgBuffer);
177        Length = ByteLength;
178    }
179
180    ACPI_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
201static void
202DtCompileUnicode (
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 = ACPI_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
240static ACPI_STATUS
241DtCompileUuid (
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        sprintf (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
283void
284DtCompileInteger (
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 (!ACPI_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        sprintf (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    ACPI_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 number in
373 *                                    the Buffer
374 *
375 * RETURN:      The normalized buffer, 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
382static char *
383DtNormalizeBuffer (
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 (ACPI_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
452UINT32
453DtCompileBuffer (
454    UINT8                   *Buffer,
455    char                    *StringValue,
456    DT_FIELD                *Field,
457    UINT32                  ByteLength)
458{
459    ACPI_STATUS             Status;
460    char                    Hex[3];
461    UINT64                  Value;
462    UINT32                  i;
463    UINT32                  Count;
464
465
466    /* Allow several different types of value separators */
467
468    StringValue = DtNormalizeBuffer (StringValue, &Count);
469
470    Hex[2] = 0;
471    for (i = 0; i < Count; i++)
472    {
473        /* Each element of StringValue is three chars */
474
475        Hex[0] = StringValue[(3 * i)];
476        Hex[1] = StringValue[(3 * i) + 1];
477
478        /* Convert one hex byte */
479
480        Value = 0;
481        Status = DtStrtoul64 (Hex, &Value);
482        if (ACPI_FAILURE (Status))
483        {
484            DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, MsgBuffer);
485            goto Exit;
486        }
487
488        Buffer[i] = (UINT8) Value;
489    }
490
491Exit:
492    ACPI_FREE (StringValue);
493    return (ByteLength - Count);
494}
495
496
497/******************************************************************************
498 *
499 * FUNCTION:    DtCompileFlag
500 *
501 * PARAMETERS:  Buffer              - Output buffer
502 *              Field               - Field to be compiled
503 *              Info                - Flag info
504 *
505 * RETURN:
506 *
507 * DESCRIPTION: Compile a flag
508 *
509 *****************************************************************************/
510
511void
512DtCompileFlag (
513    UINT8                   *Buffer,
514    DT_FIELD                *Field,
515    ACPI_DMTABLE_INFO       *Info)
516{
517    UINT64                  Value = 0;
518    UINT32                  BitLength = 1;
519    UINT8                   BitPosition = 0;
520    ACPI_STATUS             Status;
521
522
523    Status = DtStrtoul64 (Field->Value, &Value);
524    if (ACPI_FAILURE (Status))
525    {
526        DtError (ASL_ERROR, ASL_MSG_INVALID_HEX_INTEGER, Field, NULL);
527    }
528
529    switch (Info->Opcode)
530    {
531    case ACPI_DMT_FLAG0:
532    case ACPI_DMT_FLAG1:
533    case ACPI_DMT_FLAG2:
534    case ACPI_DMT_FLAG3:
535    case ACPI_DMT_FLAG4:
536    case ACPI_DMT_FLAG5:
537    case ACPI_DMT_FLAG6:
538    case ACPI_DMT_FLAG7:
539
540        BitPosition = Info->Opcode;
541        BitLength = 1;
542        break;
543
544    case ACPI_DMT_FLAGS0:
545
546        BitPosition = 0;
547        BitLength = 2;
548        break;
549
550
551    case ACPI_DMT_FLAGS1:
552
553        BitPosition = 1;
554        BitLength = 2;
555        break;
556
557
558    case ACPI_DMT_FLAGS2:
559
560        BitPosition = 2;
561        BitLength = 2;
562        break;
563
564    case ACPI_DMT_FLAGS4:
565
566        BitPosition = 4;
567        BitLength = 2;
568        break;
569
570    default:
571
572        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode");
573        break;
574    }
575
576    /* Check range of the input flag value */
577
578    if (Value >= ((UINT64) 1 << BitLength))
579    {
580        sprintf (MsgBuffer, "Maximum %u bit", BitLength);
581        DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, MsgBuffer);
582        Value = 0;
583    }
584
585    *Buffer |= (UINT8) (Value << BitPosition);
586}
587