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