1/******************************************************************************* 2 * 3 * Module Name: utresrc - Resource management utilities 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 "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 */ 57const 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 103const 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 */ 119static 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 183ACPI_STATUS 184AcpiUtWalkAmlResources ( 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 316ACPI_STATUS 317AcpiUtValidateResource ( 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 /* Avoid undefined behavior: member access within misaligned address */ 428 429 AML_RESOURCE_COMMON_SERIALBUS CommonSerialBus; 430 memcpy(&CommonSerialBus, AmlResource, sizeof(CommonSerialBus)); 431 432 /* Validate the BusType field */ 433 434 if ((CommonSerialBus.Type == 0) || 435 (CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE)) 436 { 437 if (WalkState) 438 { 439 ACPI_ERROR ((AE_INFO, 440 "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", 441 CommonSerialBus.Type)); 442 } 443 return (AE_AML_INVALID_RESOURCE_TYPE); 444 } 445 } 446 447 /* Optionally return the resource table index */ 448 449 if (ReturnIndex) 450 { 451 *ReturnIndex = ResourceIndex; 452 } 453 454 return (AE_OK); 455 456 457InvalidResource: 458 459 if (WalkState) 460 { 461 ACPI_ERROR ((AE_INFO, 462 "Invalid/unsupported resource descriptor: Type 0x%2.2X", 463 ResourceType)); 464 } 465 return (AE_AML_INVALID_RESOURCE_TYPE); 466 467BadResourceLength: 468 469 if (WalkState) 470 { 471 ACPI_ERROR ((AE_INFO, 472 "Invalid resource descriptor length: Type " 473 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", 474 ResourceType, ResourceLength, MinimumResourceLength)); 475 } 476 return (AE_AML_BAD_RESOURCE_LENGTH); 477} 478 479 480/******************************************************************************* 481 * 482 * FUNCTION: AcpiUtGetResourceType 483 * 484 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 485 * 486 * RETURN: The Resource Type with no extraneous bits (except the 487 * Large/Small descriptor bit -- this is left alone) 488 * 489 * DESCRIPTION: Extract the Resource Type/Name from the first byte of 490 * a resource descriptor. 491 * 492 ******************************************************************************/ 493 494UINT8 495AcpiUtGetResourceType ( 496 void *Aml) 497{ 498 ACPI_FUNCTION_ENTRY (); 499 500 501 /* 502 * Byte 0 contains the descriptor name (Resource Type) 503 * Examine the large/small bit in the resource header 504 */ 505 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 506 { 507 /* Large Resource Type -- bits 6:0 contain the name */ 508 509 return (ACPI_GET8 (Aml)); 510 } 511 else 512 { 513 /* Small Resource Type -- bits 6:3 contain the name */ 514 515 return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK)); 516 } 517} 518 519 520/******************************************************************************* 521 * 522 * FUNCTION: AcpiUtGetResourceLength 523 * 524 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 525 * 526 * RETURN: Byte Length 527 * 528 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By 529 * definition, this does not include the size of the descriptor 530 * header or the length field itself. 531 * 532 ******************************************************************************/ 533 534UINT16 535AcpiUtGetResourceLength ( 536 void *Aml) 537{ 538 ACPI_RS_LENGTH ResourceLength; 539 540 541 ACPI_FUNCTION_ENTRY (); 542 543 544 /* 545 * Byte 0 contains the descriptor name (Resource Type) 546 * Examine the large/small bit in the resource header 547 */ 548 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 549 { 550 /* Large Resource type -- bytes 1-2 contain the 16-bit length */ 551 552 ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1)); 553 554 } 555 else 556 { 557 /* Small Resource type -- bits 2:0 of byte 0 contain the length */ 558 559 ResourceLength = (UINT16) (ACPI_GET8 (Aml) & 560 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK); 561 } 562 563 return (ResourceLength); 564} 565 566 567/******************************************************************************* 568 * 569 * FUNCTION: AcpiUtGetResourceHeaderLength 570 * 571 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 572 * 573 * RETURN: Length of the AML header (depends on large/small descriptor) 574 * 575 * DESCRIPTION: Get the length of the header for this resource. 576 * 577 ******************************************************************************/ 578 579UINT8 580AcpiUtGetResourceHeaderLength ( 581 void *Aml) 582{ 583 ACPI_FUNCTION_ENTRY (); 584 585 586 /* Examine the large/small bit in the resource header */ 587 588 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE) 589 { 590 return (sizeof (AML_RESOURCE_LARGE_HEADER)); 591 } 592 else 593 { 594 return (sizeof (AML_RESOURCE_SMALL_HEADER)); 595 } 596} 597 598 599/******************************************************************************* 600 * 601 * FUNCTION: AcpiUtGetDescriptorLength 602 * 603 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor 604 * 605 * RETURN: Byte length 606 * 607 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the 608 * length of the descriptor header and the length field itself. 609 * Used to walk descriptor lists. 610 * 611 ******************************************************************************/ 612 613UINT32 614AcpiUtGetDescriptorLength ( 615 void *Aml) 616{ 617 ACPI_FUNCTION_ENTRY (); 618 619 620 /* 621 * Get the Resource Length (does not include header length) and add 622 * the header length (depends on if this is a small or large resource) 623 */ 624 return (AcpiUtGetResourceLength (Aml) + 625 AcpiUtGetResourceHeaderLength (Aml)); 626} 627 628 629/******************************************************************************* 630 * 631 * FUNCTION: AcpiUtGetResourceEndTag 632 * 633 * PARAMETERS: ObjDesc - The resource template buffer object 634 * EndTag - Where the pointer to the EndTag is returned 635 * 636 * RETURN: Status, pointer to the end tag 637 * 638 * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template 639 * Note: allows a buffer length of zero. 640 * 641 ******************************************************************************/ 642 643ACPI_STATUS 644AcpiUtGetResourceEndTag ( 645 ACPI_OPERAND_OBJECT *ObjDesc, 646 UINT8 **EndTag) 647{ 648 ACPI_STATUS Status; 649 650 651 ACPI_FUNCTION_TRACE (UtGetResourceEndTag); 652 653 654 /* Allow a buffer length of zero */ 655 656 if (!ObjDesc->Buffer.Length) 657 { 658 *EndTag = ObjDesc->Buffer.Pointer; 659 return_ACPI_STATUS (AE_OK); 660 } 661 662 /* Validate the template and get a pointer to the EndTag */ 663 664 Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer, 665 ObjDesc->Buffer.Length, NULL, (void **) EndTag); 666 667 return_ACPI_STATUS (Status); 668} 669