dtfield.c revision 218590
1/******************************************************************************
2 *
3 * Module Name: dtfield.c - Code generation for individual source fields
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, 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
288
289    /* Output buffer byte length must be in range 1-8 */
290
291    if ((ByteLength > 8) || (ByteLength == 0))
292    {
293        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field,
294            "Invalid internal Byte length");
295        return;
296    }
297
298    /* Resolve integer expression to a single integer value */
299
300    Value = DtResolveIntegerExpression (Field);
301
302    /* Ensure that reserved fields are set to zero */
303    /* TBD: should we set to zero, or just make this an ERROR? */
304    /* TBD: Probably better to use a flag */
305
306    if (!ACPI_STRCMP (Field->Name, "Reserved") &&
307        (Value != 0))
308    {
309        DtError (ASL_WARNING, ASL_MSG_RESERVED_VALUE, Field,
310            "Setting to zero");
311        Value = 0;
312    }
313
314    /* Check if the value must be non-zero */
315
316    if ((Value == 0) && (Flags & DT_NON_ZERO))
317    {
318        DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL);
319    }
320
321    /*
322     * Generate the maximum value for the data type (ByteLength)
323     * Note: construct chosen for maximum portability
324     */
325    MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8));
326
327    /* Validate that the input value is within range of the target */
328
329    if (Value > MaxValue)
330    {
331        sprintf (MsgBuffer, "%8.8X%8.8X", ACPI_FORMAT_UINT64 (Value));
332        DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, MsgBuffer);
333    }
334
335    ACPI_MEMCPY (Buffer, &Value, ByteLength);
336    return;
337}
338
339
340/******************************************************************************
341 *
342 * FUNCTION:    DtNormalizeBuffer
343 *
344 * PARAMETERS:  Buffer              - Input buffer
345 *              Count               - Output the count of hex number in
346 *                                    the Buffer
347 *
348 * RETURN:      The normalized buffer, freed by caller
349 *
350 * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized
351 *              to 1A 2B 3C 4D
352 *
353 *****************************************************************************/
354
355static char *
356DtNormalizeBuffer (
357    char                    *Buffer,
358    UINT32                  *Count)
359{
360    char                    *NewBuffer;
361    char                    *TmpBuffer;
362    UINT32                  BufferCount = 0;
363    BOOLEAN                 Separator = TRUE;
364    char                    c;
365
366
367    NewBuffer = UtLocalCalloc (ACPI_STRLEN (Buffer) + 1);
368    TmpBuffer = NewBuffer;
369
370    while ((c = *Buffer++))
371    {
372        switch (c)
373        {
374        /* Valid separators */
375
376        case '[':
377        case ']':
378        case ' ':
379        case ',':
380            Separator = TRUE;
381            break;
382
383        default:
384            if (Separator)
385            {
386                /* Insert blank as the standard separator */
387
388                if (NewBuffer[0])
389                {
390                    *TmpBuffer++ = ' ';
391                    BufferCount++;
392                }
393
394                Separator = FALSE;
395            }
396
397            *TmpBuffer++ = c;
398            break;
399        }
400    }
401
402    *Count = BufferCount + 1;
403    return (NewBuffer);
404}
405
406
407/******************************************************************************
408 *
409 * FUNCTION:    DtCompileBuffer
410 *
411 * PARAMETERS:  Buffer              - Output buffer
412 *              StringValue         - Integer list to be compiled
413 *              Field               - Current field object
414 *              ByteLength          - Byte length of the integer list
415 *
416 * RETURN:      Count of remaining data in the input list
417 *
418 * DESCRIPTION: Compile and pack an integer list, for example
419 *              "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B}
420 *
421 *****************************************************************************/
422
423UINT32
424DtCompileBuffer (
425    UINT8                   *Buffer,
426    char                    *StringValue,
427    DT_FIELD                *Field,
428    UINT32                  ByteLength)
429{
430    ACPI_STATUS             Status;
431    char                    Hex[3];
432    UINT64                  Value;
433    UINT32                  i;
434    UINT32                  Count;
435
436
437    /* Allow several different types of value separators */
438
439    StringValue = DtNormalizeBuffer (StringValue, &Count);
440
441    Hex[2] = 0;
442    for (i = 0; i < Count; i++)
443    {
444        /* Each element of StringValue is three chars */
445
446        Hex[0] = StringValue[(3 * i)];
447        Hex[1] = StringValue[(3 * i) + 1];
448
449        /* Convert one hex byte */
450
451        Value = 0;
452        Status = DtStrtoul64 (Hex, &Value);
453        if (ACPI_FAILURE (Status))
454        {
455            DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, MsgBuffer);
456            return (ByteLength - Count);
457        }
458
459        Buffer[i] = (UINT8) Value;
460    }
461
462    ACPI_FREE (StringValue);
463    return (ByteLength - Count);
464}
465
466
467/******************************************************************************
468 *
469 * FUNCTION:    DtCompileFlag
470 *
471 * PARAMETERS:  Buffer              - Output buffer
472 *              Field               - Field to be compiled
473 *              Info                - Flag info
474 *
475 * RETURN:
476 *
477 * DESCRIPTION: Compile a flag
478 *
479 *****************************************************************************/
480
481void
482DtCompileFlag (
483    UINT8                   *Buffer,
484    DT_FIELD                *Field,
485    ACPI_DMTABLE_INFO       *Info)
486{
487    UINT64                  Value = 0;
488    UINT32                  BitLength = 1;
489    UINT8                   BitPosition = 0;
490    ACPI_STATUS             Status;
491
492
493    Status = DtStrtoul64 (Field->Value, &Value);
494    if (ACPI_FAILURE (Status))
495    {
496        DtError (ASL_ERROR, ASL_MSG_INVALID_HEX_INTEGER, Field, NULL);
497    }
498
499    switch (Info->Opcode)
500    {
501    case ACPI_DMT_FLAG0:
502    case ACPI_DMT_FLAG1:
503    case ACPI_DMT_FLAG2:
504    case ACPI_DMT_FLAG3:
505    case ACPI_DMT_FLAG4:
506    case ACPI_DMT_FLAG5:
507    case ACPI_DMT_FLAG6:
508    case ACPI_DMT_FLAG7:
509
510        BitPosition = Info->Opcode;
511        BitLength = 1;
512        break;
513
514    case ACPI_DMT_FLAGS0:
515
516        BitPosition = 0;
517        BitLength = 2;
518        break;
519
520
521    case ACPI_DMT_FLAGS2:
522
523        BitPosition = 2;
524        BitLength = 2;
525        break;
526
527    default:
528
529        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode");
530        break;
531    }
532
533    /* Check range of the input flag value */
534
535    if (Value >= ((UINT64) 1 << BitLength))
536    {
537        sprintf (MsgBuffer, "Maximum %u bit", BitLength);
538        DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, MsgBuffer);
539        Value = 0;
540    }
541
542    *Buffer |= (UINT8) (Value << BitPosition);
543}
544