root/drivers/acpi/acpica/utresrc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpi_ut_walk_aml_resources
  2. acpi_ut_validate_resource
  3. acpi_ut_get_resource_type
  4. acpi_ut_get_resource_length
  5. acpi_ut_get_resource_header_length
  6. acpi_ut_get_descriptor_length
  7. acpi_ut_get_resource_end_tag

   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 }

/* [<][>][^][v][top][bottom][index][help] */