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