1 /******************************************************************************* 2 * 3 * Module Name: utresrc - Resource management utilities 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2025, 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 "acpi.h" 45 #include "accommon.h" 46 #include "acresrc.h" 47 48 49 #define _COMPONENT ACPI_UTILITIES 50 ACPI_MODULE_NAME ("utresrc") 51 52 53 /* 54 * Base sizes of the raw AML resource descriptors, indexed by resource type. 55 * Zero indicates a reserved (and therefore invalid) resource type. 56 */ 57 const UINT8 AcpiGbl_ResourceAmlSizes[] = 58 { 59 /* Small descriptors */ 60 61 0, 62 0, 63 0, 64 0, 65 ACPI_AML_SIZE_SMALL (AML_RESOURCE_IRQ), 66 ACPI_AML_SIZE_SMALL (AML_RESOURCE_DMA), 67 ACPI_AML_SIZE_SMALL (AML_RESOURCE_START_DEPENDENT), 68 ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_DEPENDENT), 69 ACPI_AML_SIZE_SMALL (AML_RESOURCE_IO), 70 ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_IO), 71 ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_DMA), 72 0, 73 0, 74 0, 75 ACPI_AML_SIZE_SMALL (AML_RESOURCE_VENDOR_SMALL), 76 ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_TAG), 77 78 /* Large descriptors */ 79 80 0, 81 ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY24), 82 ACPI_AML_SIZE_LARGE (AML_RESOURCE_GENERIC_REGISTER), 83 0, 84 ACPI_AML_SIZE_LARGE (AML_RESOURCE_VENDOR_LARGE), 85 ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY32), 86 ACPI_AML_SIZE_LARGE (AML_RESOURCE_FIXED_MEMORY32), 87 ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS32), 88 ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS16), 89 ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_IRQ), 90 ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS64), 91 ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_ADDRESS64), 92 ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO), 93 ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_FUNCTION), 94 ACPI_AML_SIZE_LARGE (AML_RESOURCE_COMMON_SERIALBUS), 95 ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_CONFIG), 96 ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP), 97 ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_FUNCTION), 98 ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_CONFIG), 99 ACPI_AML_SIZE_LARGE (AML_RESOURCE_CLOCK_INPUT), 100 101 }; 102 103 const UINT8 AcpiGbl_ResourceAmlSerialBusSizes[] = 104 { 105 0, 106 ACPI_AML_SIZE_LARGE (AML_RESOURCE_I2C_SERIALBUS), 107 ACPI_AML_SIZE_LARGE (AML_RESOURCE_SPI_SERIALBUS), 108 ACPI_AML_SIZE_LARGE (AML_RESOURCE_UART_SERIALBUS), 109 ACPI_AML_SIZE_LARGE (AML_RESOURCE_CSI2_SERIALBUS), 110 }; 111 112 113 /* 114 * Resource types, used to validate the resource length field. 115 * The length of fixed-length types must match exactly, variable 116 * lengths must meet the minimum required length, etc. 117 * Zero indicates a reserved (and therefore invalid) resource type. 118 */ 119 static const UINT8 AcpiGbl_ResourceTypes[] = 120 { 121 /* Small descriptors */ 122 123 0, 124 0, 125 0, 126 0, 127 ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ 128 ACPI_FIXED_LENGTH, /* 05 DMA */ 129 ACPI_SMALL_VARIABLE_LENGTH, /* 06 StartDependentFunctions */ 130 ACPI_FIXED_LENGTH, /* 07 EndDependentFunctions */ 131 ACPI_FIXED_LENGTH, /* 08 IO */ 132 ACPI_FIXED_LENGTH, /* 09 FixedIO */ 133 ACPI_FIXED_LENGTH, /* 0A FixedDMA */ 134 0, 135 0, 136 0, 137 ACPI_VARIABLE_LENGTH, /* 0E VendorShort */ 138 ACPI_FIXED_LENGTH, /* 0F EndTag */ 139 140 /* Large descriptors */ 141 142 0, 143 ACPI_FIXED_LENGTH, /* 01 Memory24 */ 144 ACPI_FIXED_LENGTH, /* 02 GenericRegister */ 145 0, 146 ACPI_VARIABLE_LENGTH, /* 04 VendorLong */ 147 ACPI_FIXED_LENGTH, /* 05 Memory32 */ 148 ACPI_FIXED_LENGTH, /* 06 Memory32Fixed */ 149 ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ 150 ACPI_VARIABLE_LENGTH, /* 08 Word* address */ 151 ACPI_VARIABLE_LENGTH, /* 09 ExtendedIRQ */ 152 ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ 153 ACPI_FIXED_LENGTH, /* 0B Extended* address */ 154 ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ 155 ACPI_VARIABLE_LENGTH, /* 0D PinFunction */ 156 ACPI_VARIABLE_LENGTH, /* 0E *SerialBus */ 157 ACPI_VARIABLE_LENGTH, /* 0F PinConfig */ 158 ACPI_VARIABLE_LENGTH, /* 10 PinGroup */ 159 ACPI_VARIABLE_LENGTH, /* 11 PinGroupFunction */ 160 ACPI_VARIABLE_LENGTH, /* 12 PinGroupConfig */ 161 ACPI_VARIABLE_LENGTH, /* 13 ClockInput */ 162 }; 163 164 165 /******************************************************************************* 166 * 167 * FUNCTION: AcpiUtWalkAmlResources 168 * 169 * PARAMETERS: WalkState - Current walk info 170 * PARAMETERS: Aml - Pointer to the raw AML resource template 171 * AmlLength - Length of the entire template 172 * UserFunction - Called once for each descriptor found. If 173 * NULL, a pointer to the EndTag is returned 174 * Context - Passed to UserFunction 175 * 176 * RETURN: Status 177 * 178 * DESCRIPTION: Walk a raw AML resource list(buffer). User function called 179 * once for each resource found. 180 * 181 ******************************************************************************/ 182 183 ACPI_STATUS 184 AcpiUtWalkAmlResources ( 185 ACPI_WALK_STATE *WalkState, 186 UINT8 *Aml, 187 ACPI_SIZE AmlLength, 188 ACPI_WALK_AML_CALLBACK UserFunction, 189 void **Context) 190 { 191 ACPI_STATUS Status; 192 UINT8 *EndAml; 193 UINT8 ResourceIndex; 194 UINT32 Length; 195 UINT32 Offset = 0; 196 UINT8 EndTag[2] = {0x79, 0x00}; 197 198 199 ACPI_FUNCTION_TRACE (UtWalkAmlResources); 200 201 202 /* The absolute minimum resource template is one EndTag descriptor */ 203 204 if (AmlLength < sizeof (AML_RESOURCE_END_TAG)) 205 { 206 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 207 } 208 209 /* Point to the end of the resource template buffer */ 210 211 EndAml = Aml + AmlLength; 212 213 /* Walk the byte list, abort on any invalid descriptor type or length */ 214 215 while (Aml < EndAml) 216 { 217 /* Validate the Resource Type and Resource Length */ 218 219 Status = AcpiUtValidateResource (WalkState, Aml, &ResourceIndex); 220 if (ACPI_FAILURE (Status)) 221 { 222 /* 223 * Exit on failure. Cannot continue because the descriptor 224 * length may be bogus also. 225 */ 226 return_ACPI_STATUS (Status); 227 } 228 229 /* Get the length of this descriptor */ 230 231 Length = AcpiUtGetDescriptorLength (Aml); 232 233 /* Invoke the user function */ 234 235 if (UserFunction) 236 { 237 Status = UserFunction ( 238 Aml, Length, Offset, ResourceIndex, Context); 239 if (ACPI_FAILURE (Status)) 240 { 241 return_ACPI_STATUS (Status); 242 } 243 } 244 245 /* An EndTag descriptor terminates this resource template */ 246 247 if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_END_TAG) 248 { 249 /* 250 * There must be at least one more byte in the buffer for 251 * the 2nd byte of the EndTag 252 */ 253 if ((Aml + 1) >= EndAml) 254 { 255 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 256 } 257 258 /* 259 * Don't attempt to perform any validation on the 2nd byte. 260 * Although all known ASL compilers insert a zero for the 2nd 261 * byte, it can also be a checksum (as per the ACPI spec), 262 * and this is occasionally seen in the field. July 2017. 263 */ 264 265 /* Return the pointer to the EndTag if requested */ 266 267 if (!UserFunction) 268 { 269 *Context = Aml; 270 } 271 272 /* Normal exit */ 273 274 return_ACPI_STATUS (AE_OK); 275 } 276 277 Aml += Length; 278 Offset += Length; 279 } 280 281 /* Did not find an EndTag descriptor */ 282 283 if (UserFunction) 284 { 285 /* Insert an EndTag anyway. AcpiRsGetListLength always leaves room */ 286 287 (void) AcpiUtValidateResource (WalkState, EndTag, &ResourceIndex); 288 Status = UserFunction (EndTag, 2, Offset, ResourceIndex, Context); 289 if (ACPI_FAILURE (Status)) 290 { 291 return_ACPI_STATUS (Status); 292 } 293 } 294 295 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 296 } 297 298 299 /******************************************************************************* 300 * 301 * FUNCTION: AcpiUtValidateResource 302 * 303 * PARAMETERS: WalkState - Current walk info 304 * Aml - Pointer to the raw AML resource descriptor 305 * ReturnIndex - Where the resource index is returned. NULL 306 * if the index is not required. 307 * 308 * RETURN: Status, and optionally the Index into the global resource tables 309 * 310 * DESCRIPTION: Validate an AML resource descriptor by checking the Resource 311 * Type and Resource Length. Returns an index into the global 312 * resource information/dispatch tables for later use. 313 * 314 ******************************************************************************/ 315 316 ACPI_STATUS 317 AcpiUtValidateResource ( 318 ACPI_WALK_STATE *WalkState, 319 void *Aml, 320 UINT8 *ReturnIndex) 321 { 322 AML_RESOURCE *AmlResource; 323 UINT8 ResourceType; 324 UINT8 ResourceIndex; 325 ACPI_RS_LENGTH ResourceLength; 326 ACPI_RS_LENGTH MinimumResourceLength; 327 328 329 ACPI_FUNCTION_ENTRY (); 330 331 332 /* 333 * 1) Validate the ResourceType field (Byte 0) 334 */ 335 ResourceType = ACPI_GET8 (Aml); 336 337 /* 338 * Byte 0 contains the descriptor name (Resource Type) 339 * Examine the large/small bit in the resource header 340 */ 341 if (ResourceType & ACPI_RESOURCE_NAME_LARGE) 342 { 343 /* Verify the large resource type (name) against the max */ 344 345 if (ResourceType > ACPI_RESOURCE_NAME_LARGE_MAX) 346 { 347 goto InvalidResource; 348 } 349 350 /* 351 * Large Resource Type -- bits 6:0 contain the name 352 * Translate range 0x80-0x8B to index range 0x10-0x1B 353 */ 354 ResourceIndex = (UINT8) (ResourceType - 0x70); 355 } 356 else 357 { 358 /* 359 * Small Resource Type -- bits 6:3 contain the name 360 * Shift range to index range 0x00-0x0F 361 */ 362 ResourceIndex = (UINT8) 363 ((ResourceType & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); 364 } 365 366 /* 367 * Check validity of the resource type, via AcpiGbl_ResourceTypes. 368 * Zero indicates an invalid resource. 369 */ 370 if (!AcpiGbl_ResourceTypes[ResourceIndex]) 371 { 372 goto InvalidResource; 373 } 374 375 /* 376 * Validate the ResourceLength field. This ensures that the length 377 * is at least reasonable, and guarantees that it is non-zero. 378 */ 379 ResourceLength = AcpiUtGetResourceLength (Aml); 380 MinimumResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; 381 382 /* Validate based upon the type of resource - fixed length or variable */ 383 384 switch (AcpiGbl_ResourceTypes[ResourceIndex]) 385 { 386 case ACPI_FIXED_LENGTH: 387 388 /* Fixed length resource, length must match exactly */ 389 390 if (ResourceLength != MinimumResourceLength) 391 { 392 goto BadResourceLength; 393 } 394 break; 395 396 case ACPI_VARIABLE_LENGTH: 397 398 /* Variable length resource, length must be at least the minimum */ 399 400 if (ResourceLength < MinimumResourceLength) 401 { 402 goto BadResourceLength; 403 } 404 break; 405 406 case ACPI_SMALL_VARIABLE_LENGTH: 407 408 /* Small variable length resource, length can be (Min) or (Min-1) */ 409 410 if ((ResourceLength > MinimumResourceLength) || 411 (ResourceLength < (MinimumResourceLength - 1))) 412 { 413 goto BadResourceLength; 414 } 415 break; 416 417 default: 418 419 /* Shouldn't happen (because of validation earlier), but be sure */ 420 421 goto InvalidResource; 422 } 423 424 AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml); 425 if (ResourceType == ACPI_RESOURCE_NAME_SERIAL_BUS) 426 { 427 /* Validate the BusType field */ 428 429 if ((AmlResource->CommonSerialBus.Type == 0) || 430 (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE)) 431 { 432 if (WalkState) 433 { 434 ACPI_ERROR ((AE_INFO, 435 "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", 436 AmlResource->CommonSerialBus.Type)); 437 } 438 return (AE_AML_INVALID_RESOURCE_TYPE); 439 } 440 } 441 442 /* Optionally return the resource table index */ 443 444 if (ReturnIndex) 445 { 446 *ReturnIndex = ResourceIndex; 447 } 448 449 return (AE_OK); 450 451 452 InvalidResource: 453 454 if (WalkState) 455 { 456 ACPI_ERROR ((AE_INFO, 457 "Invalid/unsupported resource descriptor: Type 0x%2.2X", 458 ResourceType)); 459 } 460 return (AE_AML_INVALID_RESOURCE_TYPE); 461 462 BadResourceLength: 463 464 if (WalkState) 465 { 466 ACPI_ERROR ((AE_INFO, 467 "Invalid resource descriptor length: Type " 468 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", 469 ResourceType, ResourceLength, MinimumResourceLength)); 470 } 471 return (AE_AML_BAD_RESOURCE_LENGTH); 472 } 473 474 475 /******************************************************************************* 476 * 477 * FUNCTION: AcpiUtGetResourceType 478 * 479 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 480 * 481 * RETURN: The Resource Type with no extraneous bits (except the 482 * Large/Small descriptor bit -- this is left alone) 483 * 484 * DESCRIPTION: Extract the Resource Type/Name from the first byte of 485 * a resource descriptor. 486 * 487 ******************************************************************************/ 488 489 UINT8 490 AcpiUtGetResourceType ( 491 void *Aml) 492 { 493 ACPI_FUNCTION_ENTRY (); 494 495 496 /* 497 * Byte 0 contains the descriptor name (Resource Type) 498 * Examine the large/small bit in the resource header 499 */ 500 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 501 { 502 /* Large Resource Type -- bits 6:0 contain the name */ 503 504 return (ACPI_GET8 (Aml)); 505 } 506 else 507 { 508 /* Small Resource Type -- bits 6:3 contain the name */ 509 510 return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK)); 511 } 512 } 513 514 515 /******************************************************************************* 516 * 517 * FUNCTION: AcpiUtGetResourceLength 518 * 519 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 520 * 521 * RETURN: Byte Length 522 * 523 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By 524 * definition, this does not include the size of the descriptor 525 * header or the length field itself. 526 * 527 ******************************************************************************/ 528 529 UINT16 530 AcpiUtGetResourceLength ( 531 void *Aml) 532 { 533 ACPI_RS_LENGTH ResourceLength; 534 535 536 ACPI_FUNCTION_ENTRY (); 537 538 539 /* 540 * Byte 0 contains the descriptor name (Resource Type) 541 * Examine the large/small bit in the resource header 542 */ 543 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 544 { 545 /* Large Resource type -- bytes 1-2 contain the 16-bit length */ 546 547 ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1)); 548 549 } 550 else 551 { 552 /* Small Resource type -- bits 2:0 of byte 0 contain the length */ 553 554 ResourceLength = (UINT16) (ACPI_GET8 (Aml) & 555 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK); 556 } 557 558 return (ResourceLength); 559 } 560 561 562 /******************************************************************************* 563 * 564 * FUNCTION: AcpiUtGetResourceHeaderLength 565 * 566 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 567 * 568 * RETURN: Length of the AML header (depends on large/small descriptor) 569 * 570 * DESCRIPTION: Get the length of the header for this resource. 571 * 572 ******************************************************************************/ 573 574 UINT8 575 AcpiUtGetResourceHeaderLength ( 576 void *Aml) 577 { 578 ACPI_FUNCTION_ENTRY (); 579 580 581 /* Examine the large/small bit in the resource header */ 582 583 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 584 { 585 return (sizeof (AML_RESOURCE_LARGE_HEADER)); 586 } 587 else 588 { 589 return (sizeof (AML_RESOURCE_SMALL_HEADER)); 590 } 591 } 592 593 594 /******************************************************************************* 595 * 596 * FUNCTION: AcpiUtGetDescriptorLength 597 * 598 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 599 * 600 * RETURN: Byte length 601 * 602 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the 603 * length of the descriptor header and the length field itself. 604 * Used to walk descriptor lists. 605 * 606 ******************************************************************************/ 607 608 UINT32 609 AcpiUtGetDescriptorLength ( 610 void *Aml) 611 { 612 ACPI_FUNCTION_ENTRY (); 613 614 615 /* 616 * Get the Resource Length (does not include header length) and add 617 * the header length (depends on if this is a small or large resource) 618 */ 619 return (AcpiUtGetResourceLength (Aml) + 620 AcpiUtGetResourceHeaderLength (Aml)); 621 } 622 623 624 /******************************************************************************* 625 * 626 * FUNCTION: AcpiUtGetResourceEndTag 627 * 628 * PARAMETERS: ObjDesc - The resource template buffer object 629 * EndTag - Where the pointer to the EndTag is returned 630 * 631 * RETURN: Status, pointer to the end tag 632 * 633 * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template 634 * Note: allows a buffer length of zero. 635 * 636 ******************************************************************************/ 637 638 ACPI_STATUS 639 AcpiUtGetResourceEndTag ( 640 ACPI_OPERAND_OBJECT *ObjDesc, 641 UINT8 **EndTag) 642 { 643 ACPI_STATUS Status; 644 645 646 ACPI_FUNCTION_TRACE (UtGetResourceEndTag); 647 648 649 /* Allow a buffer length of zero */ 650 651 if (!ObjDesc->Buffer.Length) 652 { 653 *EndTag = ObjDesc->Buffer.Pointer; 654 return_ACPI_STATUS (AE_OK); 655 } 656 657 /* Validate the template and get a pointer to the EndTag */ 658 659 Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer, 660 ObjDesc->Buffer.Length, NULL, (void **) EndTag); 661 662 return_ACPI_STATUS (Status); 663 } 664