1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: rsmisc - Miscellaneous resource descriptors 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 #include "acresrc.h" 11 12 #define _COMPONENT ACPI_RESOURCES 13 ACPI_MODULE_NAME("rsmisc") 14 #define INIT_RESOURCE_TYPE(i) i->resource_offset 15 #define INIT_RESOURCE_LENGTH(i) i->aml_offset 16 #define INIT_TABLE_LENGTH(i) i->value 17 #define COMPARE_OPCODE(i) i->resource_offset 18 #define COMPARE_TARGET(i) i->aml_offset 19 #define COMPARE_VALUE(i) i->value 20 /******************************************************************************* 21 * 22 * FUNCTION: acpi_rs_convert_aml_to_resource 23 * 24 * PARAMETERS: resource - Pointer to the resource descriptor 25 * aml - Where the AML descriptor is returned 26 * info - Pointer to appropriate conversion table 27 * 28 * RETURN: Status 29 * 30 * DESCRIPTION: Convert an external AML resource descriptor to the corresponding 31 * internal resource descriptor 32 * 33 ******************************************************************************/ 34 acpi_status 35 acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, 36 union aml_resource *aml, 37 struct acpi_rsconvert_info *info) 38 { 39 acpi_rs_length aml_resource_length; 40 void *source; 41 void *destination; 42 char *target; 43 u8 count; 44 u8 flags_mode = FALSE; 45 u16 item_count = 0; 46 u16 temp16 = 0; 47 48 ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); 49 50 if (!info) { 51 return_ACPI_STATUS(AE_BAD_PARAMETER); 52 } 53 54 if (((acpi_size)resource) & 0x3) { 55 56 /* Each internal resource struct is expected to be 32-bit aligned */ 57 58 ACPI_WARNING((AE_INFO, 59 "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", 60 resource, resource->type, resource->length)); 61 } 62 63 /* Extract the resource Length field (does not include header length) */ 64 65 aml_resource_length = acpi_ut_get_resource_length(aml); 66 67 /* 68 * First table entry must be ACPI_RSC_INITxxx and must contain the 69 * table length (# of table entries) 70 */ 71 count = INIT_TABLE_LENGTH(info); 72 while (count) { 73 /* 74 * Source is the external AML byte stream buffer, 75 * destination is the internal resource descriptor 76 */ 77 source = ACPI_ADD_PTR(void, aml, info->aml_offset); 78 destination = 79 ACPI_ADD_PTR(void, resource, info->resource_offset); 80 81 switch (info->opcode) { 82 case ACPI_RSC_INITGET: 83 /* 84 * Get the resource type and the initial (minimum) length 85 */ 86 memset(resource, 0, INIT_RESOURCE_LENGTH(info)); 87 resource->type = INIT_RESOURCE_TYPE(info); 88 resource->length = INIT_RESOURCE_LENGTH(info); 89 break; 90 91 case ACPI_RSC_INITSET: 92 break; 93 94 case ACPI_RSC_FLAGINIT: 95 96 flags_mode = TRUE; 97 break; 98 99 case ACPI_RSC_1BITFLAG: 100 /* 101 * Mask and shift the flag bit 102 */ 103 ACPI_SET8(destination, 104 ((ACPI_GET8(source) >> info->value) & 0x01)); 105 break; 106 107 case ACPI_RSC_2BITFLAG: 108 /* 109 * Mask and shift the flag bits 110 */ 111 ACPI_SET8(destination, 112 ((ACPI_GET8(source) >> info->value) & 0x03)); 113 break; 114 115 case ACPI_RSC_3BITFLAG: 116 /* 117 * Mask and shift the flag bits 118 */ 119 ACPI_SET8(destination, 120 ((ACPI_GET8(source) >> info->value) & 0x07)); 121 break; 122 123 case ACPI_RSC_COUNT: 124 125 item_count = ACPI_GET8(source); 126 ACPI_SET8(destination, item_count); 127 128 resource->length = resource->length + 129 (info->value * (item_count - 1)); 130 break; 131 132 case ACPI_RSC_COUNT16: 133 134 item_count = aml_resource_length; 135 ACPI_SET16(destination, item_count); 136 137 resource->length = resource->length + 138 (info->value * (item_count - 1)); 139 break; 140 141 case ACPI_RSC_COUNT_GPIO_PIN: 142 143 target = ACPI_ADD_PTR(void, aml, info->value); 144 item_count = ACPI_GET16(target) - ACPI_GET16(source); 145 146 resource->length = resource->length + item_count; 147 item_count = item_count / 2; 148 ACPI_SET16(destination, item_count); 149 break; 150 151 case ACPI_RSC_COUNT_GPIO_VEN: 152 153 item_count = ACPI_GET8(source); 154 ACPI_SET8(destination, item_count); 155 156 resource->length = 157 resource->length + (info->value * item_count); 158 break; 159 160 case ACPI_RSC_COUNT_GPIO_RES: 161 /* 162 * Vendor data is optional (length/offset may both be zero) 163 * Examine vendor data length field first 164 */ 165 target = ACPI_ADD_PTR(void, aml, (info->value + 2)); 166 if (ACPI_GET16(target)) { 167 168 /* Use vendor offset to get resource source length */ 169 170 target = ACPI_ADD_PTR(void, aml, info->value); 171 item_count = 172 ACPI_GET16(target) - ACPI_GET16(source); 173 } else { 174 /* No vendor data to worry about */ 175 176 item_count = aml->large_header.resource_length + 177 sizeof(struct aml_resource_large_header) - 178 ACPI_GET16(source); 179 } 180 181 resource->length = resource->length + item_count; 182 ACPI_SET16(destination, item_count); 183 break; 184 185 case ACPI_RSC_COUNT_SERIAL_VEN: 186 187 item_count = ACPI_GET16(source) - info->value; 188 189 resource->length = resource->length + item_count; 190 ACPI_SET16(destination, item_count); 191 break; 192 193 case ACPI_RSC_COUNT_SERIAL_RES: 194 195 item_count = (aml_resource_length + 196 sizeof(struct aml_resource_large_header)) 197 - ACPI_GET16(source) - info->value; 198 199 resource->length = resource->length + item_count; 200 ACPI_SET16(destination, item_count); 201 break; 202 203 case ACPI_RSC_LENGTH: 204 205 resource->length = resource->length + info->value; 206 break; 207 208 case ACPI_RSC_MOVE8: 209 case ACPI_RSC_MOVE16: 210 case ACPI_RSC_MOVE32: 211 case ACPI_RSC_MOVE64: 212 /* 213 * Raw data move. Use the Info value field unless item_count has 214 * been previously initialized via a COUNT opcode 215 */ 216 if (info->value) { 217 item_count = info->value; 218 } 219 acpi_rs_move_data(destination, source, item_count, 220 info->opcode); 221 break; 222 223 case ACPI_RSC_MOVE_GPIO_PIN: 224 225 /* Generate and set the PIN data pointer */ 226 227 target = (char *)ACPI_ADD_PTR(void, resource, 228 (resource->length - 229 item_count * 2)); 230 *(u16 **)destination = ACPI_CAST_PTR(u16, target); 231 232 /* Copy the PIN data */ 233 234 source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 235 acpi_rs_move_data(target, source, item_count, 236 info->opcode); 237 break; 238 239 case ACPI_RSC_MOVE_GPIO_RES: 240 241 /* Generate and set the resource_source string pointer */ 242 243 target = (char *)ACPI_ADD_PTR(void, resource, 244 (resource->length - 245 item_count)); 246 *(u8 **)destination = ACPI_CAST_PTR(u8, target); 247 248 /* Copy the resource_source string */ 249 250 source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 251 acpi_rs_move_data(target, source, item_count, 252 info->opcode); 253 break; 254 255 case ACPI_RSC_MOVE_SERIAL_VEN: 256 257 /* Generate and set the Vendor Data pointer */ 258 259 target = (char *)ACPI_ADD_PTR(void, resource, 260 (resource->length - 261 item_count)); 262 *(u8 **)destination = ACPI_CAST_PTR(u8, target); 263 264 /* Copy the Vendor Data */ 265 266 source = ACPI_ADD_PTR(void, aml, info->value); 267 acpi_rs_move_data(target, source, item_count, 268 info->opcode); 269 break; 270 271 case ACPI_RSC_MOVE_SERIAL_RES: 272 273 /* Generate and set the resource_source string pointer */ 274 275 target = (char *)ACPI_ADD_PTR(void, resource, 276 (resource->length - 277 item_count)); 278 *(u8 **)destination = ACPI_CAST_PTR(u8, target); 279 280 /* Copy the resource_source string */ 281 282 source = 283 ACPI_ADD_PTR(void, aml, 284 (ACPI_GET16(source) + info->value)); 285 acpi_rs_move_data(target, source, item_count, 286 info->opcode); 287 break; 288 289 case ACPI_RSC_SET8: 290 291 memset(destination, info->aml_offset, info->value); 292 break; 293 294 case ACPI_RSC_DATA8: 295 296 target = ACPI_ADD_PTR(char, resource, info->value); 297 memcpy(destination, source, ACPI_GET16(target)); 298 break; 299 300 case ACPI_RSC_ADDRESS: 301 /* 302 * Common handler for address descriptor flags 303 */ 304 if (!acpi_rs_get_address_common(resource, aml)) { 305 return_ACPI_STATUS 306 (AE_AML_INVALID_RESOURCE_TYPE); 307 } 308 break; 309 310 case ACPI_RSC_SOURCE: 311 /* 312 * Optional resource_source (Index and String) 313 */ 314 resource->length += 315 acpi_rs_get_resource_source(aml_resource_length, 316 info->value, 317 destination, aml, NULL); 318 break; 319 320 case ACPI_RSC_SOURCEX: 321 /* 322 * Optional resource_source (Index and String). This is the more 323 * complicated case used by the Interrupt() macro 324 */ 325 target = ACPI_ADD_PTR(char, resource, 326 info->aml_offset + 327 (item_count * 4)); 328 329 resource->length += 330 acpi_rs_get_resource_source(aml_resource_length, 331 (acpi_rs_length) 332 (((item_count - 333 1) * sizeof(u32)) + 334 info->value), 335 destination, aml, 336 target); 337 break; 338 339 case ACPI_RSC_BITMASK: 340 /* 341 * 8-bit encoded bitmask (DMA macro) 342 */ 343 item_count = 344 acpi_rs_decode_bitmask(ACPI_GET8(source), 345 destination); 346 if (item_count) { 347 resource->length += (item_count - 1); 348 } 349 350 target = ACPI_ADD_PTR(char, resource, info->value); 351 ACPI_SET8(target, item_count); 352 break; 353 354 case ACPI_RSC_BITMASK16: 355 /* 356 * 16-bit encoded bitmask (IRQ macro) 357 */ 358 ACPI_MOVE_16_TO_16(&temp16, source); 359 360 item_count = 361 acpi_rs_decode_bitmask(temp16, destination); 362 if (item_count) { 363 resource->length += (item_count - 1); 364 } 365 366 target = ACPI_ADD_PTR(char, resource, info->value); 367 ACPI_SET8(target, item_count); 368 break; 369 370 case ACPI_RSC_EXIT_NE: 371 /* 372 * control - Exit conversion if not equal 373 */ 374 switch (info->resource_offset) { 375 case ACPI_RSC_COMPARE_AML_LENGTH: 376 377 if (aml_resource_length != info->value) { 378 goto exit; 379 } 380 break; 381 382 case ACPI_RSC_COMPARE_VALUE: 383 384 if (ACPI_GET8(source) != info->value) { 385 goto exit; 386 } 387 break; 388 389 default: 390 391 ACPI_ERROR((AE_INFO, 392 "Invalid conversion sub-opcode")); 393 return_ACPI_STATUS(AE_BAD_PARAMETER); 394 } 395 break; 396 397 default: 398 399 ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 400 return_ACPI_STATUS(AE_BAD_PARAMETER); 401 } 402 403 count--; 404 info++; 405 } 406 407 exit: 408 if (!flags_mode) { 409 410 /* Round the resource struct length up to the next boundary (32 or 64) */ 411 412 resource->length = (u32) 413 ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); 414 } 415 return_ACPI_STATUS(AE_OK); 416 } 417 418 /******************************************************************************* 419 * 420 * FUNCTION: acpi_rs_convert_resource_to_aml 421 * 422 * PARAMETERS: resource - Pointer to the resource descriptor 423 * aml - Where the AML descriptor is returned 424 * info - Pointer to appropriate conversion table 425 * 426 * RETURN: Status 427 * 428 * DESCRIPTION: Convert an internal resource descriptor to the corresponding 429 * external AML resource descriptor. 430 * 431 ******************************************************************************/ 432 433 acpi_status 434 acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, 435 union aml_resource *aml, 436 struct acpi_rsconvert_info *info) 437 { 438 void *source = NULL; 439 void *destination; 440 char *target; 441 acpi_rsdesc_size aml_length = 0; 442 u8 count; 443 u16 temp16 = 0; 444 u16 item_count = 0; 445 446 ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); 447 448 if (!info) { 449 return_ACPI_STATUS(AE_BAD_PARAMETER); 450 } 451 452 /* 453 * First table entry must be ACPI_RSC_INITxxx and must contain the 454 * table length (# of table entries) 455 */ 456 count = INIT_TABLE_LENGTH(info); 457 458 while (count) { 459 /* 460 * Source is the internal resource descriptor, 461 * destination is the external AML byte stream buffer 462 */ 463 source = ACPI_ADD_PTR(void, resource, info->resource_offset); 464 destination = ACPI_ADD_PTR(void, aml, info->aml_offset); 465 466 switch (info->opcode) { 467 case ACPI_RSC_INITSET: 468 469 memset(aml, 0, INIT_RESOURCE_LENGTH(info)); 470 aml_length = INIT_RESOURCE_LENGTH(info); 471 acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), 472 aml_length, aml); 473 break; 474 475 case ACPI_RSC_INITGET: 476 break; 477 478 case ACPI_RSC_FLAGINIT: 479 /* 480 * Clear the flag byte 481 */ 482 ACPI_SET8(destination, 0); 483 break; 484 485 case ACPI_RSC_1BITFLAG: 486 /* 487 * Mask and shift the flag bit 488 */ 489 ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 490 ((ACPI_GET8(source) & 0x01) << info-> 491 value)); 492 break; 493 494 case ACPI_RSC_2BITFLAG: 495 /* 496 * Mask and shift the flag bits 497 */ 498 ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 499 ((ACPI_GET8(source) & 0x03) << info-> 500 value)); 501 break; 502 503 case ACPI_RSC_3BITFLAG: 504 /* 505 * Mask and shift the flag bits 506 */ 507 ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 508 ((ACPI_GET8(source) & 0x07) << info-> 509 value)); 510 break; 511 512 case ACPI_RSC_COUNT: 513 514 item_count = ACPI_GET8(source); 515 ACPI_SET8(destination, item_count); 516 517 aml_length = (u16) 518 (aml_length + (info->value * (item_count - 1))); 519 break; 520 521 case ACPI_RSC_COUNT16: 522 523 item_count = ACPI_GET16(source); 524 aml_length = (u16) (aml_length + item_count); 525 acpi_rs_set_resource_length(aml_length, aml); 526 break; 527 528 case ACPI_RSC_COUNT_GPIO_PIN: 529 530 item_count = ACPI_GET16(source); 531 ACPI_SET16(destination, aml_length); 532 533 aml_length = (u16)(aml_length + item_count * 2); 534 target = ACPI_ADD_PTR(void, aml, info->value); 535 ACPI_SET16(target, aml_length); 536 acpi_rs_set_resource_length(aml_length, aml); 537 break; 538 539 case ACPI_RSC_COUNT_GPIO_VEN: 540 541 item_count = ACPI_GET16(source); 542 ACPI_SET16(destination, item_count); 543 544 aml_length = 545 (u16)(aml_length + (info->value * item_count)); 546 acpi_rs_set_resource_length(aml_length, aml); 547 break; 548 549 case ACPI_RSC_COUNT_GPIO_RES: 550 551 /* Set resource source string length */ 552 553 item_count = ACPI_GET16(source); 554 ACPI_SET16(destination, aml_length); 555 556 /* Compute offset for the Vendor Data */ 557 558 aml_length = (u16)(aml_length + item_count); 559 target = ACPI_ADD_PTR(void, aml, info->value); 560 561 /* Set vendor offset only if there is vendor data */ 562 563 ACPI_SET16(target, aml_length); 564 565 acpi_rs_set_resource_length(aml_length, aml); 566 break; 567 568 case ACPI_RSC_COUNT_SERIAL_VEN: 569 570 item_count = ACPI_GET16(source); 571 ACPI_SET16(destination, item_count + info->value); 572 aml_length = (u16)(aml_length + item_count); 573 acpi_rs_set_resource_length(aml_length, aml); 574 break; 575 576 case ACPI_RSC_COUNT_SERIAL_RES: 577 578 item_count = ACPI_GET16(source); 579 aml_length = (u16)(aml_length + item_count); 580 acpi_rs_set_resource_length(aml_length, aml); 581 break; 582 583 case ACPI_RSC_LENGTH: 584 585 acpi_rs_set_resource_length(info->value, aml); 586 break; 587 588 case ACPI_RSC_MOVE8: 589 case ACPI_RSC_MOVE16: 590 case ACPI_RSC_MOVE32: 591 case ACPI_RSC_MOVE64: 592 593 if (info->value) { 594 item_count = info->value; 595 } 596 acpi_rs_move_data(destination, source, item_count, 597 info->opcode); 598 break; 599 600 case ACPI_RSC_MOVE_GPIO_PIN: 601 602 destination = (char *)ACPI_ADD_PTR(void, aml, 603 ACPI_GET16 604 (destination)); 605 source = *(u16 **)source; 606 acpi_rs_move_data(destination, source, item_count, 607 info->opcode); 608 break; 609 610 case ACPI_RSC_MOVE_GPIO_RES: 611 612 /* Used for both resource_source string and vendor_data */ 613 614 destination = (char *)ACPI_ADD_PTR(void, aml, 615 ACPI_GET16 616 (destination)); 617 source = *(u8 **)source; 618 acpi_rs_move_data(destination, source, item_count, 619 info->opcode); 620 break; 621 622 case ACPI_RSC_MOVE_SERIAL_VEN: 623 624 destination = (char *)ACPI_ADD_PTR(void, aml, 625 (aml_length - 626 item_count)); 627 source = *(u8 **)source; 628 acpi_rs_move_data(destination, source, item_count, 629 info->opcode); 630 break; 631 632 case ACPI_RSC_MOVE_SERIAL_RES: 633 634 destination = (char *)ACPI_ADD_PTR(void, aml, 635 (aml_length - 636 item_count)); 637 source = *(u8 **)source; 638 acpi_rs_move_data(destination, source, item_count, 639 info->opcode); 640 break; 641 642 case ACPI_RSC_ADDRESS: 643 644 /* Set the Resource Type, General Flags, and Type-Specific Flags */ 645 646 acpi_rs_set_address_common(aml, resource); 647 break; 648 649 case ACPI_RSC_SOURCEX: 650 /* 651 * Optional resource_source (Index and String) 652 */ 653 aml_length = 654 acpi_rs_set_resource_source(aml, 655 (acpi_rs_length) 656 aml_length, source); 657 acpi_rs_set_resource_length(aml_length, aml); 658 break; 659 660 case ACPI_RSC_SOURCE: 661 /* 662 * Optional resource_source (Index and String). This is the more 663 * complicated case used by the Interrupt() macro 664 */ 665 aml_length = 666 acpi_rs_set_resource_source(aml, info->value, 667 source); 668 acpi_rs_set_resource_length(aml_length, aml); 669 break; 670 671 case ACPI_RSC_BITMASK: 672 /* 673 * 8-bit encoded bitmask (DMA macro) 674 */ 675 ACPI_SET8(destination, 676 acpi_rs_encode_bitmask(source, 677 *ACPI_ADD_PTR(u8, 678 resource, 679 info-> 680 value))); 681 break; 682 683 case ACPI_RSC_BITMASK16: 684 /* 685 * 16-bit encoded bitmask (IRQ macro) 686 */ 687 temp16 = 688 acpi_rs_encode_bitmask(source, 689 *ACPI_ADD_PTR(u8, resource, 690 info->value)); 691 ACPI_MOVE_16_TO_16(destination, &temp16); 692 break; 693 694 case ACPI_RSC_EXIT_LE: 695 /* 696 * control - Exit conversion if less than or equal 697 */ 698 if (item_count <= info->value) { 699 goto exit; 700 } 701 break; 702 703 case ACPI_RSC_EXIT_NE: 704 /* 705 * control - Exit conversion if not equal 706 */ 707 switch (COMPARE_OPCODE(info)) { 708 case ACPI_RSC_COMPARE_VALUE: 709 710 if (*ACPI_ADD_PTR(u8, resource, 711 COMPARE_TARGET(info)) != 712 COMPARE_VALUE(info)) { 713 goto exit; 714 } 715 break; 716 717 default: 718 719 ACPI_ERROR((AE_INFO, 720 "Invalid conversion sub-opcode")); 721 return_ACPI_STATUS(AE_BAD_PARAMETER); 722 } 723 break; 724 725 case ACPI_RSC_EXIT_EQ: 726 /* 727 * control - Exit conversion if equal 728 */ 729 if (*ACPI_ADD_PTR(u8, resource, 730 COMPARE_TARGET(info)) == 731 COMPARE_VALUE(info)) { 732 goto exit; 733 } 734 break; 735 736 default: 737 738 ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 739 return_ACPI_STATUS(AE_BAD_PARAMETER); 740 } 741 742 count--; 743 info++; 744 } 745 746 exit: 747 return_ACPI_STATUS(AE_OK); 748 } 749 750 #if 0 751 /* Previous resource validations */ 752 753 if (aml->ext_address64.revision_ID != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) { 754 return_ACPI_STATUS(AE_SUPPORT); 755 } 756 757 if (resource->data.start_dpf.performance_robustness >= 3) { 758 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE); 759 } 760 761 if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { 762 /* 763 * Only [active_high, edge_sensitive] or [active_low, level_sensitive] 764 * polarity/trigger interrupts are allowed (ACPI spec, section 765 * "IRQ Format"), so 0x00 and 0x09 are illegal. 766 */ 767 ACPI_ERROR((AE_INFO, 768 "Invalid interrupt polarity/trigger in resource list, 0x%X", 769 aml->irq.flags)); 770 return_ACPI_STATUS(AE_BAD_DATA); 771 } 772 773 resource->data.extended_irq.interrupt_count = temp8; 774 if (temp8 < 1) { 775 776 /* Must have at least one IRQ */ 777 778 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); 779 } 780 781 if (resource->data.dma.transfer == 0x03) { 782 ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)")); 783 return_ACPI_STATUS(AE_BAD_DATA); 784 } 785 #endif 786