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