Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: utresrc - Resource management utilities
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "acresrc.h"
0011 
0012 #define _COMPONENT          ACPI_UTILITIES
0013 ACPI_MODULE_NAME("utresrc")
0014 
0015 /*
0016  * Base sizes of the raw AML resource descriptors, indexed by resource type.
0017  * Zero indicates a reserved (and therefore invalid) resource type.
0018  */
0019 const u8 acpi_gbl_resource_aml_sizes[] = {
0020     /* Small descriptors */
0021 
0022     0,
0023     0,
0024     0,
0025     0,
0026     ACPI_AML_SIZE_SMALL(struct aml_resource_irq),
0027     ACPI_AML_SIZE_SMALL(struct aml_resource_dma),
0028     ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent),
0029     ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent),
0030     ACPI_AML_SIZE_SMALL(struct aml_resource_io),
0031     ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io),
0032     ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma),
0033     0,
0034     0,
0035     0,
0036     ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small),
0037     ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag),
0038 
0039     /* Large descriptors */
0040 
0041     0,
0042     ACPI_AML_SIZE_LARGE(struct aml_resource_memory24),
0043     ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register),
0044     0,
0045     ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large),
0046     ACPI_AML_SIZE_LARGE(struct aml_resource_memory32),
0047     ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32),
0048     ACPI_AML_SIZE_LARGE(struct aml_resource_address32),
0049     ACPI_AML_SIZE_LARGE(struct aml_resource_address16),
0050     ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq),
0051     ACPI_AML_SIZE_LARGE(struct aml_resource_address64),
0052     ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64),
0053     ACPI_AML_SIZE_LARGE(struct aml_resource_gpio),
0054     ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function),
0055     ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus),
0056     ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config),
0057     ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group),
0058     ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function),
0059     ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config),
0060 };
0061 
0062 const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = {
0063     0,
0064     ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus),
0065     ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus),
0066     ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus),
0067     ACPI_AML_SIZE_LARGE(struct aml_resource_csi2_serialbus),
0068 };
0069 
0070 /*
0071  * Resource types, used to validate the resource length field.
0072  * The length of fixed-length types must match exactly, variable
0073  * lengths must meet the minimum required length, etc.
0074  * Zero indicates a reserved (and therefore invalid) resource type.
0075  */
0076 static const u8 acpi_gbl_resource_types[] = {
0077     /* Small descriptors */
0078 
0079     0,
0080     0,
0081     0,
0082     0,
0083     ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */
0084     ACPI_FIXED_LENGTH,  /* 05 DMA */
0085     ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */
0086     ACPI_FIXED_LENGTH,  /* 07 end_dependent_functions */
0087     ACPI_FIXED_LENGTH,  /* 08 IO */
0088     ACPI_FIXED_LENGTH,  /* 09 fixed_IO */
0089     ACPI_FIXED_LENGTH,  /* 0A fixed_DMA */
0090     0,
0091     0,
0092     0,
0093     ACPI_VARIABLE_LENGTH,   /* 0E vendor_short */
0094     ACPI_FIXED_LENGTH,  /* 0F end_tag */
0095 
0096     /* Large descriptors */
0097 
0098     0,
0099     ACPI_FIXED_LENGTH,  /* 01 Memory24 */
0100     ACPI_FIXED_LENGTH,  /* 02 generic_register */
0101     0,
0102     ACPI_VARIABLE_LENGTH,   /* 04 vendor_long */
0103     ACPI_FIXED_LENGTH,  /* 05 Memory32 */
0104     ACPI_FIXED_LENGTH,  /* 06 memory32_fixed */
0105     ACPI_VARIABLE_LENGTH,   /* 07 Dword* address */
0106     ACPI_VARIABLE_LENGTH,   /* 08 Word* address */
0107     ACPI_VARIABLE_LENGTH,   /* 09 extended_IRQ */
0108     ACPI_VARIABLE_LENGTH,   /* 0A Qword* address */
0109     ACPI_FIXED_LENGTH,  /* 0B Extended* address */
0110     ACPI_VARIABLE_LENGTH,   /* 0C Gpio* */
0111     ACPI_VARIABLE_LENGTH,   /* 0D pin_function */
0112     ACPI_VARIABLE_LENGTH,   /* 0E *serial_bus */
0113     ACPI_VARIABLE_LENGTH,   /* 0F pin_config */
0114     ACPI_VARIABLE_LENGTH,   /* 10 pin_group */
0115     ACPI_VARIABLE_LENGTH,   /* 11 pin_group_function */
0116     ACPI_VARIABLE_LENGTH,   /* 12 pin_group_config */
0117 };
0118 
0119 /*******************************************************************************
0120  *
0121  * FUNCTION:    acpi_ut_walk_aml_resources
0122  *
0123  * PARAMETERS:  walk_state          - Current walk info
0124  * PARAMETERS:  aml                 - Pointer to the raw AML resource template
0125  *              aml_length          - Length of the entire template
0126  *              user_function       - Called once for each descriptor found. If
0127  *                                    NULL, a pointer to the end_tag is returned
0128  *              context             - Passed to user_function
0129  *
0130  * RETURN:      Status
0131  *
0132  * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
0133  *              once for each resource found.
0134  *
0135  ******************************************************************************/
0136 
0137 acpi_status
0138 acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
0139                u8 *aml,
0140                acpi_size aml_length,
0141                acpi_walk_aml_callback user_function, void **context)
0142 {
0143     acpi_status status;
0144     u8 *end_aml;
0145     u8 resource_index;
0146     u32 length;
0147     u32 offset = 0;
0148     u8 end_tag[2] = { 0x79, 0x00 };
0149 
0150     ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
0151 
0152     /* The absolute minimum resource template is one end_tag descriptor */
0153 
0154     if (aml_length < sizeof(struct aml_resource_end_tag)) {
0155         return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0156     }
0157 
0158     /* Point to the end of the resource template buffer */
0159 
0160     end_aml = aml + aml_length;
0161 
0162     /* Walk the byte list, abort on any invalid descriptor type or length */
0163 
0164     while (aml < end_aml) {
0165 
0166         /* Validate the Resource Type and Resource Length */
0167 
0168         status =
0169             acpi_ut_validate_resource(walk_state, aml, &resource_index);
0170         if (ACPI_FAILURE(status)) {
0171             /*
0172              * Exit on failure. Cannot continue because the descriptor
0173              * length may be bogus also.
0174              */
0175             return_ACPI_STATUS(status);
0176         }
0177 
0178         /* Get the length of this descriptor */
0179 
0180         length = acpi_ut_get_descriptor_length(aml);
0181 
0182         /* Invoke the user function */
0183 
0184         if (user_function) {
0185             status =
0186                 user_function(aml, length, offset, resource_index,
0187                       context);
0188             if (ACPI_FAILURE(status)) {
0189                 return_ACPI_STATUS(status);
0190             }
0191         }
0192 
0193         /* An end_tag descriptor terminates this resource template */
0194 
0195         if (acpi_ut_get_resource_type(aml) ==
0196             ACPI_RESOURCE_NAME_END_TAG) {
0197             /*
0198              * There must be at least one more byte in the buffer for
0199              * the 2nd byte of the end_tag
0200              */
0201             if ((aml + 1) >= end_aml) {
0202                 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0203             }
0204 
0205             /*
0206              * Don't attempt to perform any validation on the 2nd byte.
0207              * Although all known ASL compilers insert a zero for the 2nd
0208              * byte, it can also be a checksum (as per the ACPI spec),
0209              * and this is occasionally seen in the field. July 2017.
0210              */
0211 
0212             /* Return the pointer to the end_tag if requested */
0213 
0214             if (!user_function) {
0215                 *context = aml;
0216             }
0217 
0218             /* Normal exit */
0219 
0220             return_ACPI_STATUS(AE_OK);
0221         }
0222 
0223         aml += length;
0224         offset += length;
0225     }
0226 
0227     /* Did not find an end_tag descriptor */
0228 
0229     if (user_function) {
0230 
0231         /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
0232 
0233         (void)acpi_ut_validate_resource(walk_state, end_tag,
0234                         &resource_index);
0235         status =
0236             user_function(end_tag, 2, offset, resource_index, context);
0237         if (ACPI_FAILURE(status)) {
0238             return_ACPI_STATUS(status);
0239         }
0240     }
0241 
0242     return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0243 }
0244 
0245 /*******************************************************************************
0246  *
0247  * FUNCTION:    acpi_ut_validate_resource
0248  *
0249  * PARAMETERS:  walk_state          - Current walk info
0250  *              aml                 - Pointer to the raw AML resource descriptor
0251  *              return_index        - Where the resource index is returned. NULL
0252  *                                    if the index is not required.
0253  *
0254  * RETURN:      Status, and optionally the Index into the global resource tables
0255  *
0256  * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
0257  *              Type and Resource Length. Returns an index into the global
0258  *              resource information/dispatch tables for later use.
0259  *
0260  ******************************************************************************/
0261 
0262 acpi_status
0263 acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
0264               void *aml, u8 *return_index)
0265 {
0266     union aml_resource *aml_resource;
0267     u8 resource_type;
0268     u8 resource_index;
0269     acpi_rs_length resource_length;
0270     acpi_rs_length minimum_resource_length;
0271 
0272     ACPI_FUNCTION_ENTRY();
0273 
0274     /*
0275      * 1) Validate the resource_type field (Byte 0)
0276      */
0277     resource_type = ACPI_GET8(aml);
0278 
0279     /*
0280      * Byte 0 contains the descriptor name (Resource Type)
0281      * Examine the large/small bit in the resource header
0282      */
0283     if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
0284 
0285         /* Verify the large resource type (name) against the max */
0286 
0287         if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
0288             goto invalid_resource;
0289         }
0290 
0291         /*
0292          * Large Resource Type -- bits 6:0 contain the name
0293          * Translate range 0x80-0x8B to index range 0x10-0x1B
0294          */
0295         resource_index = (u8) (resource_type - 0x70);
0296     } else {
0297         /*
0298          * Small Resource Type -- bits 6:3 contain the name
0299          * Shift range to index range 0x00-0x0F
0300          */
0301         resource_index = (u8)
0302             ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
0303     }
0304 
0305     /*
0306      * Check validity of the resource type, via acpi_gbl_resource_types.
0307      * Zero indicates an invalid resource.
0308      */
0309     if (!acpi_gbl_resource_types[resource_index]) {
0310         goto invalid_resource;
0311     }
0312 
0313     /*
0314      * Validate the resource_length field. This ensures that the length
0315      * is at least reasonable, and guarantees that it is non-zero.
0316      */
0317     resource_length = acpi_ut_get_resource_length(aml);
0318     minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index];
0319 
0320     /* Validate based upon the type of resource - fixed length or variable */
0321 
0322     switch (acpi_gbl_resource_types[resource_index]) {
0323     case ACPI_FIXED_LENGTH:
0324 
0325         /* Fixed length resource, length must match exactly */
0326 
0327         if (resource_length != minimum_resource_length) {
0328             goto bad_resource_length;
0329         }
0330         break;
0331 
0332     case ACPI_VARIABLE_LENGTH:
0333 
0334         /* Variable length resource, length must be at least the minimum */
0335 
0336         if (resource_length < minimum_resource_length) {
0337             goto bad_resource_length;
0338         }
0339         break;
0340 
0341     case ACPI_SMALL_VARIABLE_LENGTH:
0342 
0343         /* Small variable length resource, length can be (Min) or (Min-1) */
0344 
0345         if ((resource_length > minimum_resource_length) ||
0346             (resource_length < (minimum_resource_length - 1))) {
0347             goto bad_resource_length;
0348         }
0349         break;
0350 
0351     default:
0352 
0353         /* Shouldn't happen (because of validation earlier), but be sure */
0354 
0355         goto invalid_resource;
0356     }
0357 
0358     aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
0359     if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) {
0360 
0361         /* Validate the bus_type field */
0362 
0363         if ((aml_resource->common_serial_bus.type == 0) ||
0364             (aml_resource->common_serial_bus.type >
0365              AML_RESOURCE_MAX_SERIALBUSTYPE)) {
0366             if (walk_state) {
0367                 ACPI_ERROR((AE_INFO,
0368                         "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
0369                         aml_resource->common_serial_bus.
0370                         type));
0371             }
0372             return (AE_AML_INVALID_RESOURCE_TYPE);
0373         }
0374     }
0375 
0376     /* Optionally return the resource table index */
0377 
0378     if (return_index) {
0379         *return_index = resource_index;
0380     }
0381 
0382     return (AE_OK);
0383 
0384 invalid_resource:
0385 
0386     if (walk_state) {
0387         ACPI_ERROR((AE_INFO,
0388                 "Invalid/unsupported resource descriptor: Type 0x%2.2X",
0389                 resource_type));
0390     }
0391     return (AE_AML_INVALID_RESOURCE_TYPE);
0392 
0393 bad_resource_length:
0394 
0395     if (walk_state) {
0396         ACPI_ERROR((AE_INFO,
0397                 "Invalid resource descriptor length: Type "
0398                 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
0399                 resource_type, resource_length,
0400                 minimum_resource_length));
0401     }
0402     return (AE_AML_BAD_RESOURCE_LENGTH);
0403 }
0404 
0405 /*******************************************************************************
0406  *
0407  * FUNCTION:    acpi_ut_get_resource_type
0408  *
0409  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
0410  *
0411  * RETURN:      The Resource Type with no extraneous bits (except the
0412  *              Large/Small descriptor bit -- this is left alone)
0413  *
0414  * DESCRIPTION: Extract the Resource Type/Name from the first byte of
0415  *              a resource descriptor.
0416  *
0417  ******************************************************************************/
0418 
0419 u8 acpi_ut_get_resource_type(void *aml)
0420 {
0421     ACPI_FUNCTION_ENTRY();
0422 
0423     /*
0424      * Byte 0 contains the descriptor name (Resource Type)
0425      * Examine the large/small bit in the resource header
0426      */
0427     if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0428 
0429         /* Large Resource Type -- bits 6:0 contain the name */
0430 
0431         return (ACPI_GET8(aml));
0432     } else {
0433         /* Small Resource Type -- bits 6:3 contain the name */
0434 
0435         return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
0436     }
0437 }
0438 
0439 /*******************************************************************************
0440  *
0441  * FUNCTION:    acpi_ut_get_resource_length
0442  *
0443  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
0444  *
0445  * RETURN:      Byte Length
0446  *
0447  * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
0448  *              definition, this does not include the size of the descriptor
0449  *              header or the length field itself.
0450  *
0451  ******************************************************************************/
0452 
0453 u16 acpi_ut_get_resource_length(void *aml)
0454 {
0455     acpi_rs_length resource_length;
0456 
0457     ACPI_FUNCTION_ENTRY();
0458 
0459     /*
0460      * Byte 0 contains the descriptor name (Resource Type)
0461      * Examine the large/small bit in the resource header
0462      */
0463     if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0464 
0465         /* Large Resource type -- bytes 1-2 contain the 16-bit length */
0466 
0467         ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
0468 
0469     } else {
0470         /* Small Resource type -- bits 2:0 of byte 0 contain the length */
0471 
0472         resource_length = (u16) (ACPI_GET8(aml) &
0473                      ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
0474     }
0475 
0476     return (resource_length);
0477 }
0478 
0479 /*******************************************************************************
0480  *
0481  * FUNCTION:    acpi_ut_get_resource_header_length
0482  *
0483  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
0484  *
0485  * RETURN:      Length of the AML header (depends on large/small descriptor)
0486  *
0487  * DESCRIPTION: Get the length of the header for this resource.
0488  *
0489  ******************************************************************************/
0490 
0491 u8 acpi_ut_get_resource_header_length(void *aml)
0492 {
0493     ACPI_FUNCTION_ENTRY();
0494 
0495     /* Examine the large/small bit in the resource header */
0496 
0497     if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0498         return (sizeof(struct aml_resource_large_header));
0499     } else {
0500         return (sizeof(struct aml_resource_small_header));
0501     }
0502 }
0503 
0504 /*******************************************************************************
0505  *
0506  * FUNCTION:    acpi_ut_get_descriptor_length
0507  *
0508  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
0509  *
0510  * RETURN:      Byte length
0511  *
0512  * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
0513  *              length of the descriptor header and the length field itself.
0514  *              Used to walk descriptor lists.
0515  *
0516  ******************************************************************************/
0517 
0518 u32 acpi_ut_get_descriptor_length(void *aml)
0519 {
0520     ACPI_FUNCTION_ENTRY();
0521 
0522     /*
0523      * Get the Resource Length (does not include header length) and add
0524      * the header length (depends on if this is a small or large resource)
0525      */
0526     return (acpi_ut_get_resource_length(aml) +
0527         acpi_ut_get_resource_header_length(aml));
0528 }
0529 
0530 /*******************************************************************************
0531  *
0532  * FUNCTION:    acpi_ut_get_resource_end_tag
0533  *
0534  * PARAMETERS:  obj_desc        - The resource template buffer object
0535  *              end_tag         - Where the pointer to the end_tag is returned
0536  *
0537  * RETURN:      Status, pointer to the end tag
0538  *
0539  * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template
0540  *              Note: allows a buffer length of zero.
0541  *
0542  ******************************************************************************/
0543 
0544 acpi_status
0545 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
0546 {
0547     acpi_status status;
0548 
0549     ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
0550 
0551     /* Allow a buffer length of zero */
0552 
0553     if (!obj_desc->buffer.length) {
0554         *end_tag = obj_desc->buffer.pointer;
0555         return_ACPI_STATUS(AE_OK);
0556     }
0557 
0558     /* Validate the template and get a pointer to the end_tag */
0559 
0560     status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
0561                         obj_desc->buffer.length, NULL,
0562                         (void **)end_tag);
0563 
0564     return_ACPI_STATUS(status);
0565 }