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