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