1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: utresrc - Resource management utilities 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 #include "acresrc.h" 11 12 #define _COMPONENT ACPI_UTILITIES 13 ACPI_MODULE_NAME("utresrc") 14 15 /* 16 * Base sizes of the raw AML resource descriptors, indexed by resource type. 17 * Zero indicates a reserved (and therefore invalid) resource type. 18 */ 19 const u8 acpi_gbl_resource_aml_sizes[] = { 20 /* Small descriptors */ 21 22 0, 23 0, 24 0, 25 0, 26 ACPI_AML_SIZE_SMALL(struct aml_resource_irq), 27 ACPI_AML_SIZE_SMALL(struct aml_resource_dma), 28 ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent), 29 ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent), 30 ACPI_AML_SIZE_SMALL(struct aml_resource_io), 31 ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io), 32 ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma), 33 0, 34 0, 35 0, 36 ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small), 37 ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag), 38 39 /* Large descriptors */ 40 41 0, 42 ACPI_AML_SIZE_LARGE(struct aml_resource_memory24), 43 ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register), 44 0, 45 ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large), 46 ACPI_AML_SIZE_LARGE(struct aml_resource_memory32), 47 ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32), 48 ACPI_AML_SIZE_LARGE(struct aml_resource_address32), 49 ACPI_AML_SIZE_LARGE(struct aml_resource_address16), 50 ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq), 51 ACPI_AML_SIZE_LARGE(struct aml_resource_address64), 52 ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), 53 ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), 54 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function), 55 ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), 56 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config), 57 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group), 58 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function), 59 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config), 60 ACPI_AML_SIZE_LARGE(struct aml_resource_clock_input), 61 62 }; 63 64 const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { 65 0, 66 ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus), 67 ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus), 68 ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus), 69 ACPI_AML_SIZE_LARGE(struct aml_resource_csi2_serialbus), 70 }; 71 72 /* 73 * Resource types, used to validate the resource length field. 74 * The length of fixed-length types must match exactly, variable 75 * lengths must meet the minimum required length, etc. 76 * Zero indicates a reserved (and therefore invalid) resource type. 77 */ 78 static const u8 acpi_gbl_resource_types[] = { 79 /* Small descriptors */ 80 81 0, 82 0, 83 0, 84 0, 85 ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ 86 ACPI_FIXED_LENGTH, /* 05 DMA */ 87 ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */ 88 ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */ 89 ACPI_FIXED_LENGTH, /* 08 IO */ 90 ACPI_FIXED_LENGTH, /* 09 fixed_IO */ 91 ACPI_FIXED_LENGTH, /* 0A fixed_DMA */ 92 0, 93 0, 94 0, 95 ACPI_VARIABLE_LENGTH, /* 0E vendor_short */ 96 ACPI_FIXED_LENGTH, /* 0F end_tag */ 97 98 /* Large descriptors */ 99 100 0, 101 ACPI_FIXED_LENGTH, /* 01 Memory24 */ 102 ACPI_FIXED_LENGTH, /* 02 generic_register */ 103 0, 104 ACPI_VARIABLE_LENGTH, /* 04 vendor_long */ 105 ACPI_FIXED_LENGTH, /* 05 Memory32 */ 106 ACPI_FIXED_LENGTH, /* 06 memory32_fixed */ 107 ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ 108 ACPI_VARIABLE_LENGTH, /* 08 Word* address */ 109 ACPI_VARIABLE_LENGTH, /* 09 extended_IRQ */ 110 ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ 111 ACPI_FIXED_LENGTH, /* 0B Extended* address */ 112 ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ 113 ACPI_VARIABLE_LENGTH, /* 0D pin_function */ 114 ACPI_VARIABLE_LENGTH, /* 0E *serial_bus */ 115 ACPI_VARIABLE_LENGTH, /* 0F pin_config */ 116 ACPI_VARIABLE_LENGTH, /* 10 pin_group */ 117 ACPI_VARIABLE_LENGTH, /* 11 pin_group_function */ 118 ACPI_VARIABLE_LENGTH, /* 12 pin_group_config */ 119 ACPI_VARIABLE_LENGTH, /* 13 clock_input */ 120 }; 121 122 /******************************************************************************* 123 * 124 * FUNCTION: acpi_ut_walk_aml_resources 125 * 126 * PARAMETERS: walk_state - Current walk info 127 * PARAMETERS: aml - Pointer to the raw AML resource template 128 * aml_length - Length of the entire template 129 * user_function - Called once for each descriptor found. If 130 * NULL, a pointer to the end_tag is returned 131 * context - Passed to user_function 132 * 133 * RETURN: Status 134 * 135 * DESCRIPTION: Walk a raw AML resource list(buffer). User function called 136 * once for each resource found. 137 * 138 ******************************************************************************/ 139 140 acpi_status 141 acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, 142 u8 *aml, 143 acpi_size aml_length, 144 acpi_walk_aml_callback user_function, void **context) 145 { 146 acpi_status status; 147 u8 *end_aml; 148 u8 resource_index; 149 u32 length; 150 u32 offset = 0; 151 u8 end_tag[2] = { 0x79, 0x00 }; 152 153 ACPI_FUNCTION_TRACE(ut_walk_aml_resources); 154 155 /* The absolute minimum resource template is one end_tag descriptor */ 156 157 if (aml_length < sizeof(struct aml_resource_end_tag)) { 158 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); 159 } 160 161 /* Point to the end of the resource template buffer */ 162 163 end_aml = aml + aml_length; 164 165 /* Walk the byte list, abort on any invalid descriptor type or length */ 166 167 while (aml < end_aml) { 168 169 /* Validate the Resource Type and Resource Length */ 170 171 status = 172 acpi_ut_validate_resource(walk_state, aml, &resource_index); 173 if (ACPI_FAILURE(status)) { 174 /* 175 * Exit on failure. Cannot continue because the descriptor 176 * length may be bogus also. 177 */ 178 return_ACPI_STATUS(status); 179 } 180 181 /* Get the length of this descriptor */ 182 183 length = acpi_ut_get_descriptor_length(aml); 184 185 /* Invoke the user function */ 186 187 if (user_function) { 188 status = 189 user_function(aml, length, offset, resource_index, 190 context); 191 if (ACPI_FAILURE(status)) { 192 return_ACPI_STATUS(status); 193 } 194 } 195 196 /* An end_tag descriptor terminates this resource template */ 197 198 if (acpi_ut_get_resource_type(aml) == 199 ACPI_RESOURCE_NAME_END_TAG) { 200 /* 201 * There must be at least one more byte in the buffer for 202 * the 2nd byte of the end_tag 203 */ 204 if ((aml + 1) >= end_aml) { 205 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); 206 } 207 208 /* 209 * Don't attempt to perform any validation on the 2nd byte. 210 * Although all known ASL compilers insert a zero for the 2nd 211 * byte, it can also be a checksum (as per the ACPI spec), 212 * and this is occasionally seen in the field. July 2017. 213 */ 214 215 /* Return the pointer to the end_tag if requested */ 216 217 if (!user_function) { 218 *context = aml; 219 } 220 221 /* Normal exit */ 222 223 return_ACPI_STATUS(AE_OK); 224 } 225 226 aml += length; 227 offset += length; 228 } 229 230 /* Did not find an end_tag descriptor */ 231 232 if (user_function) { 233 234 /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */ 235 236 (void)acpi_ut_validate_resource(walk_state, end_tag, 237 &resource_index); 238 status = 239 user_function(end_tag, 2, offset, resource_index, context); 240 if (ACPI_FAILURE(status)) { 241 return_ACPI_STATUS(status); 242 } 243 } 244 245 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); 246 } 247 248 /******************************************************************************* 249 * 250 * FUNCTION: acpi_ut_validate_resource 251 * 252 * PARAMETERS: walk_state - Current walk info 253 * aml - Pointer to the raw AML resource descriptor 254 * return_index - Where the resource index is returned. NULL 255 * if the index is not required. 256 * 257 * RETURN: Status, and optionally the Index into the global resource tables 258 * 259 * DESCRIPTION: Validate an AML resource descriptor by checking the Resource 260 * Type and Resource Length. Returns an index into the global 261 * resource information/dispatch tables for later use. 262 * 263 ******************************************************************************/ 264 265 acpi_status 266 acpi_ut_validate_resource(struct acpi_walk_state *walk_state, 267 void *aml, u8 *return_index) 268 { 269 union aml_resource *aml_resource; 270 u8 resource_type; 271 u8 resource_index; 272 acpi_rs_length resource_length; 273 acpi_rs_length minimum_resource_length; 274 275 ACPI_FUNCTION_ENTRY(); 276 277 /* 278 * 1) Validate the resource_type field (Byte 0) 279 */ 280 resource_type = ACPI_GET8(aml); 281 282 /* 283 * Byte 0 contains the descriptor name (Resource Type) 284 * Examine the large/small bit in the resource header 285 */ 286 if (resource_type & ACPI_RESOURCE_NAME_LARGE) { 287 288 /* Verify the large resource type (name) against the max */ 289 290 if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) { 291 goto invalid_resource; 292 } 293 294 /* 295 * Large Resource Type -- bits 6:0 contain the name 296 * Translate range 0x80-0x8B to index range 0x10-0x1B 297 */ 298 resource_index = (u8) (resource_type - 0x70); 299 } else { 300 /* 301 * Small Resource Type -- bits 6:3 contain the name 302 * Shift range to index range 0x00-0x0F 303 */ 304 resource_index = (u8) 305 ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); 306 } 307 308 /* 309 * Check validity of the resource type, via acpi_gbl_resource_types. 310 * Zero indicates an invalid resource. 311 */ 312 if (!acpi_gbl_resource_types[resource_index]) { 313 goto invalid_resource; 314 } 315 316 /* 317 * Validate the resource_length field. This ensures that the length 318 * is at least reasonable, and guarantees that it is non-zero. 319 */ 320 resource_length = acpi_ut_get_resource_length(aml); 321 minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index]; 322 323 /* Validate based upon the type of resource - fixed length or variable */ 324 325 switch (acpi_gbl_resource_types[resource_index]) { 326 case ACPI_FIXED_LENGTH: 327 328 /* Fixed length resource, length must match exactly */ 329 330 if (resource_length != minimum_resource_length) { 331 goto bad_resource_length; 332 } 333 break; 334 335 case ACPI_VARIABLE_LENGTH: 336 337 /* Variable length resource, length must be at least the minimum */ 338 339 if (resource_length < minimum_resource_length) { 340 goto bad_resource_length; 341 } 342 break; 343 344 case ACPI_SMALL_VARIABLE_LENGTH: 345 346 /* Small variable length resource, length can be (Min) or (Min-1) */ 347 348 if ((resource_length > minimum_resource_length) || 349 (resource_length < (minimum_resource_length - 1))) { 350 goto bad_resource_length; 351 } 352 break; 353 354 default: 355 356 /* Shouldn't happen (because of validation earlier), but be sure */ 357 358 goto invalid_resource; 359 } 360 361 aml_resource = ACPI_CAST_PTR(union aml_resource, aml); 362 if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) { 363 364 /* Avoid undefined behavior: member access within misaligned address */ 365 366 struct aml_resource_common_serialbus common_serial_bus; 367 memcpy(&common_serial_bus, aml_resource, 368 sizeof(common_serial_bus)); 369 370 /* Validate the bus_type field */ 371 372 if ((common_serial_bus.type == 0) || 373 (common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE)) { 374 if (walk_state) { 375 ACPI_ERROR((AE_INFO, 376 "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", 377 common_serial_bus.type)); 378 } 379 return (AE_AML_INVALID_RESOURCE_TYPE); 380 } 381 } 382 383 /* Optionally return the resource table index */ 384 385 if (return_index) { 386 *return_index = resource_index; 387 } 388 389 return (AE_OK); 390 391 invalid_resource: 392 393 if (walk_state) { 394 ACPI_ERROR((AE_INFO, 395 "Invalid/unsupported resource descriptor: Type 0x%2.2X", 396 resource_type)); 397 } 398 return (AE_AML_INVALID_RESOURCE_TYPE); 399 400 bad_resource_length: 401 402 if (walk_state) { 403 ACPI_ERROR((AE_INFO, 404 "Invalid resource descriptor length: Type " 405 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", 406 resource_type, resource_length, 407 minimum_resource_length)); 408 } 409 return (AE_AML_BAD_RESOURCE_LENGTH); 410 } 411 412 /******************************************************************************* 413 * 414 * FUNCTION: acpi_ut_get_resource_type 415 * 416 * PARAMETERS: aml - Pointer to the raw AML resource descriptor 417 * 418 * RETURN: The Resource Type with no extraneous bits (except the 419 * Large/Small descriptor bit -- this is left alone) 420 * 421 * DESCRIPTION: Extract the Resource Type/Name from the first byte of 422 * a resource descriptor. 423 * 424 ******************************************************************************/ 425 426 u8 acpi_ut_get_resource_type(void *aml) 427 { 428 ACPI_FUNCTION_ENTRY(); 429 430 /* 431 * Byte 0 contains the descriptor name (Resource Type) 432 * Examine the large/small bit in the resource header 433 */ 434 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { 435 436 /* Large Resource Type -- bits 6:0 contain the name */ 437 438 return (ACPI_GET8(aml)); 439 } else { 440 /* Small Resource Type -- bits 6:3 contain the name */ 441 442 return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK)); 443 } 444 } 445 446 /******************************************************************************* 447 * 448 * FUNCTION: acpi_ut_get_resource_length 449 * 450 * PARAMETERS: aml - Pointer to the raw AML resource descriptor 451 * 452 * RETURN: Byte Length 453 * 454 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By 455 * definition, this does not include the size of the descriptor 456 * header or the length field itself. 457 * 458 ******************************************************************************/ 459 460 u16 acpi_ut_get_resource_length(void *aml) 461 { 462 acpi_rs_length resource_length; 463 464 ACPI_FUNCTION_ENTRY(); 465 466 /* 467 * Byte 0 contains the descriptor name (Resource Type) 468 * Examine the large/small bit in the resource header 469 */ 470 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { 471 472 /* Large Resource type -- bytes 1-2 contain the 16-bit length */ 473 474 ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1)); 475 476 } else { 477 /* Small Resource type -- bits 2:0 of byte 0 contain the length */ 478 479 resource_length = (u16) (ACPI_GET8(aml) & 480 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK); 481 } 482 483 return (resource_length); 484 } 485 486 /******************************************************************************* 487 * 488 * FUNCTION: acpi_ut_get_resource_header_length 489 * 490 * PARAMETERS: aml - Pointer to the raw AML resource descriptor 491 * 492 * RETURN: Length of the AML header (depends on large/small descriptor) 493 * 494 * DESCRIPTION: Get the length of the header for this resource. 495 * 496 ******************************************************************************/ 497 498 u8 acpi_ut_get_resource_header_length(void *aml) 499 { 500 ACPI_FUNCTION_ENTRY(); 501 502 /* Examine the large/small bit in the resource header */ 503 504 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { 505 return (sizeof(struct aml_resource_large_header)); 506 } else { 507 return (sizeof(struct aml_resource_small_header)); 508 } 509 } 510 511 /******************************************************************************* 512 * 513 * FUNCTION: acpi_ut_get_descriptor_length 514 * 515 * PARAMETERS: aml - Pointer to the raw AML resource descriptor 516 * 517 * RETURN: Byte length 518 * 519 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the 520 * length of the descriptor header and the length field itself. 521 * Used to walk descriptor lists. 522 * 523 ******************************************************************************/ 524 525 u32 acpi_ut_get_descriptor_length(void *aml) 526 { 527 ACPI_FUNCTION_ENTRY(); 528 529 /* 530 * Get the Resource Length (does not include header length) and add 531 * the header length (depends on if this is a small or large resource) 532 */ 533 return (acpi_ut_get_resource_length(aml) + 534 acpi_ut_get_resource_header_length(aml)); 535 } 536 537 /******************************************************************************* 538 * 539 * FUNCTION: acpi_ut_get_resource_end_tag 540 * 541 * PARAMETERS: obj_desc - The resource template buffer object 542 * end_tag - Where the pointer to the end_tag is returned 543 * 544 * RETURN: Status, pointer to the end tag 545 * 546 * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template 547 * Note: allows a buffer length of zero. 548 * 549 ******************************************************************************/ 550 551 acpi_status 552 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag) 553 { 554 acpi_status status; 555 556 ACPI_FUNCTION_TRACE(ut_get_resource_end_tag); 557 558 /* Allow a buffer length of zero */ 559 560 if (!obj_desc->buffer.length) { 561 *end_tag = obj_desc->buffer.pointer; 562 return_ACPI_STATUS(AE_OK); 563 } 564 565 /* Validate the template and get a pointer to the end_tag */ 566 567 status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer, 568 obj_desc->buffer.length, NULL, 569 (void **)end_tag); 570 571 return_ACPI_STATUS(status); 572 } 573