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