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