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