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