1 /****************************************************************************** 2 * 3 * Module Name: dtfield.c - Code generation for individual source fields 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 46 #define _COMPONENT DT_COMPILER 47 ACPI_MODULE_NAME ("dtfield") 48 49 50 /* Local prototypes */ 51 52 static void 53 DtCompileString ( 54 UINT8 *Buffer, 55 DT_FIELD *Field, 56 UINT32 ByteLength); 57 58 static void 59 DtCompileUnicode ( 60 UINT8 *Buffer, 61 DT_FIELD *Field, 62 UINT32 ByteLength); 63 64 static ACPI_STATUS 65 DtCompileUuid ( 66 UINT8 *Buffer, 67 DT_FIELD *Field, 68 UINT32 ByteLength); 69 70 static char * 71 DtNormalizeBuffer ( 72 char *Buffer, 73 UINT32 *Count); 74 75 76 /****************************************************************************** 77 * 78 * FUNCTION: DtCompileOneField 79 * 80 * PARAMETERS: Buffer - Output buffer 81 * Field - Field to be compiled 82 * ByteLength - Byte length of the field 83 * Type - Field type 84 * 85 * RETURN: None 86 * 87 * DESCRIPTION: Compile a field value to binary 88 * 89 *****************************************************************************/ 90 91 void 92 DtCompileOneField ( 93 UINT8 *Buffer, 94 DT_FIELD *Field, 95 UINT32 ByteLength, 96 UINT8 Type, 97 UINT8 Flags) 98 { 99 ACPI_STATUS Status; 100 101 102 switch (Type) 103 { 104 case DT_FIELD_TYPE_INTEGER: 105 106 DtCompileInteger (Buffer, Field, ByteLength, Flags); 107 break; 108 109 case DT_FIELD_TYPE_STRING: 110 111 DtCompileString (Buffer, Field, ByteLength); 112 break; 113 114 case DT_FIELD_TYPE_UUID: 115 116 Status = DtCompileUuid (Buffer, Field, ByteLength); 117 if (ACPI_SUCCESS (Status)) 118 { 119 break; 120 } 121 122 ACPI_FALLTHROUGH; 123 124 case DT_FIELD_TYPE_BUFFER: 125 126 DtCompileBuffer (Buffer, Field->Value, Field, ByteLength); 127 break; 128 129 case DT_FIELD_TYPE_UNICODE: 130 131 DtCompileUnicode (Buffer, Field, ByteLength); 132 break; 133 134 case DT_FIELD_TYPE_DEVICE_PATH: 135 136 break; 137 138 default: 139 140 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid field type"); 141 break; 142 } 143 } 144 145 146 /****************************************************************************** 147 * 148 * FUNCTION: DtCompileString 149 * 150 * PARAMETERS: Buffer - Output buffer 151 * Field - String to be copied to buffer 152 * ByteLength - Maximum length of string 153 * 154 * RETURN: None 155 * 156 * DESCRIPTION: Copy string to the buffer 157 * 158 *****************************************************************************/ 159 160 static void 161 DtCompileString ( 162 UINT8 *Buffer, 163 DT_FIELD *Field, 164 UINT32 ByteLength) 165 { 166 UINT32 Length; 167 168 169 Length = strlen (Field->Value); 170 171 /* Check if the string is too long for the field */ 172 173 if (Length > ByteLength) 174 { 175 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), 176 "Maximum %u characters, found %u characters [%.*s]", 177 ByteLength, Length, (ASL_MSG_BUFFER_SIZE / 2), Field->Value); 178 DtError (ASL_ERROR, ASL_MSG_STRING_LENGTH, Field, AslGbl_MsgBuffer); 179 Length = ByteLength; 180 } 181 182 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 203 static void 204 DtCompileUnicode ( 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 = 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 242 static ACPI_STATUS 243 DtCompileUuid ( 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 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "%s", Field->Value); 258 DtNameError (ASL_ERROR, ASL_MSG_INVALID_UUID, Field, AslGbl_MsgBuffer); 259 } 260 else 261 { 262 AcpiUtConvertStringToUuid (InString, 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 285 void 286 DtCompileInteger ( 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 /* 315 * Ensure that reserved fields are set properly. Note: uses 316 * the DT_NON_ZERO flag to indicate that the reserved value 317 * must be exactly one. Otherwise, the value must be zero. 318 * This is sufficient for now. 319 */ 320 321 /* TBD: Should use a flag rather than compare "Reserved" */ 322 323 if (!strcmp (Field->Name, "Reserved")) 324 { 325 if (Flags & DT_NON_ZERO) 326 { 327 if (Value != 1) 328 { 329 DtError (ASL_ERROR, ASL_MSG_RESERVED_FIELD, Field, 330 "Must be one, setting to one"); 331 Value = 1; 332 } 333 } 334 else if (Value != 0) 335 { 336 DtError (ASL_ERROR, ASL_MSG_RESERVED_FIELD, Field, 337 "Must be zero, setting to zero"); 338 Value = 0; 339 } 340 } 341 342 /* Check if the value must be non-zero */ 343 344 else if ((Flags & DT_NON_ZERO) && (Value == 0)) 345 { 346 DtError (ASL_ERROR, ASL_MSG_ZERO_VALUE, Field, NULL); 347 } 348 349 /* 350 * Generate the maximum value for the data type (ByteLength) 351 * Note: construct chosen for maximum portability 352 */ 353 MaxValue = ((UINT64) (-1)) >> (64 - (ByteLength * 8)); 354 355 /* Validate that the input value is within range of the target */ 356 357 if (Value > MaxValue) 358 { 359 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "%8.8X%8.8X - max %u bytes", 360 ACPI_FORMAT_UINT64 (Value), ByteLength); 361 DtError (ASL_ERROR, ASL_MSG_INTEGER_SIZE, Field, AslGbl_MsgBuffer); 362 } 363 364 memcpy (Buffer, &Value, ByteLength); 365 return; 366 } 367 368 369 /****************************************************************************** 370 * 371 * FUNCTION: DtNormalizeBuffer 372 * 373 * PARAMETERS: Buffer - Input buffer 374 * Count - Output the count of hex numbers in 375 * the Buffer 376 * 377 * RETURN: The normalized buffer, must be freed by caller 378 * 379 * DESCRIPTION: [1A,2B,3C,4D] or 1A, 2B, 3C, 4D will be normalized 380 * to 1A 2B 3C 4D 381 * 382 *****************************************************************************/ 383 384 static char * 385 DtNormalizeBuffer ( 386 char *Buffer, 387 UINT32 *Count) 388 { 389 char *NewBuffer; 390 char *TmpBuffer; 391 UINT32 BufferCount = 0; 392 BOOLEAN Separator = TRUE; 393 char c; 394 395 396 NewBuffer = UtLocalCalloc (strlen (Buffer) + 1); 397 TmpBuffer = NewBuffer; 398 399 while ((c = *Buffer++)) 400 { 401 switch (c) 402 { 403 /* Valid separators */ 404 405 case '[': 406 case ']': 407 case ' ': 408 case ',': 409 410 Separator = TRUE; 411 break; 412 413 default: 414 415 if (Separator) 416 { 417 /* Insert blank as the standard separator */ 418 419 if (NewBuffer[0]) 420 { 421 *TmpBuffer++ = ' '; 422 BufferCount++; 423 } 424 425 Separator = FALSE; 426 } 427 428 *TmpBuffer++ = c; 429 break; 430 } 431 } 432 433 *Count = BufferCount + 1; 434 return (NewBuffer); 435 } 436 437 438 /****************************************************************************** 439 * 440 * FUNCTION: DtCompileBuffer 441 * 442 * PARAMETERS: Buffer - Output buffer 443 * StringValue - Integer list to be compiled 444 * Field - Current field object 445 * ByteLength - Byte length of the integer list 446 * 447 * RETURN: Count of remaining data in the input list 448 * 449 * DESCRIPTION: Compile and pack an integer list, for example 450 * "AA 1F 20 3B" ==> Buffer[] = {0xAA,0x1F,0x20,0x3B} 451 * 452 *****************************************************************************/ 453 454 UINT32 455 DtCompileBuffer ( 456 UINT8 *Buffer, 457 char *StringValue, 458 DT_FIELD *Field, 459 UINT32 ByteLength) 460 { 461 char *Substring; 462 ACPI_STATUS Status; 463 UINT32 Count; 464 UINT32 i; 465 466 467 /* Allow several different types of value separators */ 468 469 StringValue = DtNormalizeBuffer (StringValue, &Count); 470 Substring = StringValue; 471 if (Count != ByteLength) 472 { 473 sprintf(AslGbl_MsgBuffer, 474 "Found %u values, must match expected count: %u", 475 Count, ByteLength); 476 DtError (ASL_ERROR, ASL_MSG_BUFFER_LIST, Field, AslGbl_MsgBuffer); 477 goto Exit; 478 } 479 480 /* Each element of StringValue is now three chars (2 hex + 1 space) */ 481 482 for (i = 0; i < Count; i++, Substring += 3) 483 { 484 /* Check for byte value too long */ 485 486 if (*(&Substring[2]) && 487 (*(&Substring[2]) != ' ')) 488 { 489 DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring); 490 goto Exit; 491 } 492 493 /* Convert two ASCII characters to one hex byte */ 494 495 Status = AcpiUtAsciiToHexByte (Substring, &Buffer[i]); 496 if (ACPI_FAILURE (Status)) 497 { 498 DtError (ASL_ERROR, ASL_MSG_BUFFER_ELEMENT, Field, Substring); 499 goto Exit; 500 } 501 } 502 503 Exit: 504 ACPI_FREE (StringValue); 505 return (ByteLength - Count); 506 } 507 508 509 /****************************************************************************** 510 * 511 * FUNCTION: DtCompileFlag 512 * 513 * PARAMETERS: Buffer - Output buffer 514 * Field - Field to be compiled 515 * Info - Flag info 516 * 517 * RETURN: None 518 * 519 * DESCRIPTION: Compile a flag field. Handles flags up to 64 bits. 520 * 521 *****************************************************************************/ 522 523 void 524 DtCompileFlag ( 525 UINT8 *Buffer, 526 DT_FIELD *Field, 527 ACPI_DMTABLE_INFO *Info) 528 { 529 UINT64 Value = 0; 530 UINT32 BitLength = 1; 531 UINT8 BitPosition = 0; 532 533 534 Value = AcpiUtImplicitStrtoul64 (Field->Value); 535 536 switch (Info->Opcode) 537 { 538 case ACPI_DMT_FLAG0: 539 case ACPI_DMT_FLAG1: 540 case ACPI_DMT_FLAG2: 541 case ACPI_DMT_FLAG3: 542 case ACPI_DMT_FLAG4: 543 case ACPI_DMT_FLAG5: 544 case ACPI_DMT_FLAG6: 545 case ACPI_DMT_FLAG7: 546 547 BitPosition = Info->Opcode; 548 BitLength = 1; 549 break; 550 551 case ACPI_DMT_FLAGS0: 552 553 BitPosition = 0; 554 BitLength = 2; 555 break; 556 557 558 case ACPI_DMT_FLAGS1: 559 560 BitPosition = 1; 561 BitLength = 2; 562 break; 563 564 565 case ACPI_DMT_FLAGS2: 566 567 BitPosition = 2; 568 BitLength = 2; 569 break; 570 571 case ACPI_DMT_FLAGS8_2: 572 573 BitPosition = 2; 574 BitLength = 8; 575 break; 576 577 case ACPI_DMT_FLAGS4: 578 579 BitPosition = 4; 580 BitLength = 2; 581 break; 582 583 case ACPI_DMT_FLAGS4_0: 584 585 BitPosition = 0; 586 BitLength = 4; 587 break; 588 589 case ACPI_DMT_FLAGS4_4: 590 591 BitPosition = 4; 592 BitLength = 4; 593 break; 594 595 case ACPI_DMT_FLAGS4_8: 596 597 BitPosition = 8; 598 BitLength = 4; 599 break; 600 601 case ACPI_DMT_FLAGS4_12: 602 603 BitPosition = 12; 604 BitLength = 4; 605 break; 606 607 case ACPI_DMT_FLAGS16_16: 608 609 BitPosition = 16; 610 BitLength = 16; 611 break; 612 613 default: 614 615 DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid flag opcode"); 616 break; 617 } 618 619 /* Check range of the input flag value */ 620 621 if (Value >= ((UINT64) 1 << BitLength)) 622 { 623 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Maximum %u bit", BitLength); 624 DtError (ASL_ERROR, ASL_MSG_FLAG_VALUE, Field, AslGbl_MsgBuffer); 625 Value = 0; 626 } 627 628 *Buffer |= (UINT8) (Value << BitPosition); 629 } 630 631 632 /****************************************************************************** 633 * 634 * FUNCTION: DtCreateField 635 * 636 * PARAMETERS: Name 637 * Value 638 * Line 639 * Offset 640 * Column 641 * NameColumn 642 * 643 * RETURN: None 644 * 645 * DESCRIPTION: Create a field 646 * 647 *****************************************************************************/ 648 649 void 650 DtCreateField ( 651 DT_TABLE_UNIT *FieldKey, 652 DT_TABLE_UNIT *FieldValue, 653 UINT32 Offset) 654 { 655 DT_FIELD *Field = UtFieldCacheCalloc (); 656 657 658 Field->StringLength = 0; 659 if (FieldKey->Value) 660 { 661 Field->Name = 662 strcpy (UtLocalCacheCalloc (strlen (FieldKey->Value) + 1), FieldKey->Value); 663 } 664 665 if (FieldValue->Value) 666 { 667 Field->StringLength = strlen (FieldValue->Value); 668 Field->Value = 669 strcpy (UtLocalCacheCalloc (Field->StringLength + 1), FieldValue->Value); 670 } 671 672 Field->Line = FieldValue->Line; 673 Field->ByteOffset = Offset; 674 Field->NameColumn = FieldKey->Column; 675 Field->Column = FieldValue->Column; 676 DtLinkField (Field); 677 678 DtDumpFieldList (AslGbl_FieldList); 679 } 680 681 682 /****************************************************************************** 683 * 684 * FUNCTION: DtCreateTableUnit 685 * 686 * PARAMETERS: Data 687 * Line 688 * Column 689 * 690 * RETURN: a table unit 691 * 692 * DESCRIPTION: Create a table unit 693 * 694 *****************************************************************************/ 695 696 DT_TABLE_UNIT * 697 DtCreateTableUnit ( 698 char *Data, 699 UINT32 Line, 700 UINT32 Column) 701 { 702 DT_TABLE_UNIT *Unit = (DT_TABLE_UNIT *) UtFieldCacheCalloc (); 703 704 705 Unit->Value = Data; 706 Unit->Line = Line; 707 Unit->Column = Column; 708 return (Unit); 709 } 710 711 712 /****************************************************************************** 713 * 714 * FUNCTION: DtLinkField 715 * 716 * PARAMETERS: Field - New field object to link 717 * 718 * RETURN: None 719 * 720 * DESCRIPTION: Link one field name and value to the list 721 * 722 *****************************************************************************/ 723 724 void 725 DtLinkField ( 726 DT_FIELD *Field) 727 { 728 DT_FIELD *Prev; 729 DT_FIELD *Next; 730 731 732 Prev = Next = AslGbl_FieldList; 733 734 while (Next) 735 { 736 Prev = Next; 737 Next = Next->Next; 738 } 739 740 if (Prev) 741 { 742 Prev->Next = Field; 743 } 744 else 745 { 746 AslGbl_FieldList = Field; 747 } 748 } 749