Home | History | Annotate | Line # | Download | only in utilities
utresrc.c revision 1.1.1.9
      1 /*******************************************************************************
      2  *
      3  * Module Name: utresrc - Resource management utilities
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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.h"
     45 #include "accommon.h"
     46 #include "acresrc.h"
     47 
     48 
     49 #define _COMPONENT          ACPI_UTILITIES
     50         ACPI_MODULE_NAME    ("utresrc")
     51 
     52 
     53 /*
     54  * Base sizes of the raw AML resource descriptors, indexed by resource type.
     55  * Zero indicates a reserved (and therefore invalid) resource type.
     56  */
     57 const UINT8                 AcpiGbl_ResourceAmlSizes[] =
     58 {
     59     /* Small descriptors */
     60 
     61     0,
     62     0,
     63     0,
     64     0,
     65     ACPI_AML_SIZE_SMALL (AML_RESOURCE_IRQ),
     66     ACPI_AML_SIZE_SMALL (AML_RESOURCE_DMA),
     67     ACPI_AML_SIZE_SMALL (AML_RESOURCE_START_DEPENDENT),
     68     ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_DEPENDENT),
     69     ACPI_AML_SIZE_SMALL (AML_RESOURCE_IO),
     70     ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_IO),
     71     ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_DMA),
     72     0,
     73     0,
     74     0,
     75     ACPI_AML_SIZE_SMALL (AML_RESOURCE_VENDOR_SMALL),
     76     ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_TAG),
     77 
     78     /* Large descriptors */
     79 
     80     0,
     81     ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY24),
     82     ACPI_AML_SIZE_LARGE (AML_RESOURCE_GENERIC_REGISTER),
     83     0,
     84     ACPI_AML_SIZE_LARGE (AML_RESOURCE_VENDOR_LARGE),
     85     ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY32),
     86     ACPI_AML_SIZE_LARGE (AML_RESOURCE_FIXED_MEMORY32),
     87     ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS32),
     88     ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS16),
     89     ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_IRQ),
     90     ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS64),
     91     ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_ADDRESS64),
     92     ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO),
     93     ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_FUNCTION),
     94     ACPI_AML_SIZE_LARGE (AML_RESOURCE_COMMON_SERIALBUS),
     95     ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_CONFIG),
     96     ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP),
     97     ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_FUNCTION),
     98     ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_CONFIG),
     99 };
    100 
    101 const UINT8                 AcpiGbl_ResourceAmlSerialBusSizes[] =
    102 {
    103     0,
    104     ACPI_AML_SIZE_LARGE (AML_RESOURCE_I2C_SERIALBUS),
    105     ACPI_AML_SIZE_LARGE (AML_RESOURCE_SPI_SERIALBUS),
    106     ACPI_AML_SIZE_LARGE (AML_RESOURCE_UART_SERIALBUS),
    107 };
    108 
    109 
    110 /*
    111  * Resource types, used to validate the resource length field.
    112  * The length of fixed-length types must match exactly, variable
    113  * lengths must meet the minimum required length, etc.
    114  * Zero indicates a reserved (and therefore invalid) resource type.
    115  */
    116 static const UINT8          AcpiGbl_ResourceTypes[] =
    117 {
    118     /* Small descriptors */
    119 
    120     0,
    121     0,
    122     0,
    123     0,
    124     ACPI_SMALL_VARIABLE_LENGTH,     /* 04 IRQ */
    125     ACPI_FIXED_LENGTH,              /* 05 DMA */
    126     ACPI_SMALL_VARIABLE_LENGTH,     /* 06 StartDependentFunctions */
    127     ACPI_FIXED_LENGTH,              /* 07 EndDependentFunctions */
    128     ACPI_FIXED_LENGTH,              /* 08 IO */
    129     ACPI_FIXED_LENGTH,              /* 09 FixedIO */
    130     ACPI_FIXED_LENGTH,              /* 0A FixedDMA */
    131     0,
    132     0,
    133     0,
    134     ACPI_VARIABLE_LENGTH,           /* 0E VendorShort */
    135     ACPI_FIXED_LENGTH,              /* 0F EndTag */
    136 
    137     /* Large descriptors */
    138 
    139     0,
    140     ACPI_FIXED_LENGTH,              /* 01 Memory24 */
    141     ACPI_FIXED_LENGTH,              /* 02 GenericRegister */
    142     0,
    143     ACPI_VARIABLE_LENGTH,           /* 04 VendorLong */
    144     ACPI_FIXED_LENGTH,              /* 05 Memory32 */
    145     ACPI_FIXED_LENGTH,              /* 06 Memory32Fixed */
    146     ACPI_VARIABLE_LENGTH,           /* 07 Dword* address */
    147     ACPI_VARIABLE_LENGTH,           /* 08 Word* address */
    148     ACPI_VARIABLE_LENGTH,           /* 09 ExtendedIRQ */
    149     ACPI_VARIABLE_LENGTH,           /* 0A Qword* address */
    150     ACPI_FIXED_LENGTH,              /* 0B Extended* address */
    151     ACPI_VARIABLE_LENGTH,           /* 0C Gpio* */
    152     ACPI_VARIABLE_LENGTH,           /* 0D PinFunction */
    153     ACPI_VARIABLE_LENGTH,           /* 0E *SerialBus */
    154     ACPI_VARIABLE_LENGTH,           /* 0F PinConfig */
    155     ACPI_VARIABLE_LENGTH,           /* 10 PinGroup */
    156     ACPI_VARIABLE_LENGTH,           /* 11 PinGroupFunction */
    157     ACPI_VARIABLE_LENGTH,           /* 12 PinGroupConfig */
    158 };
    159 
    160 
    161 /*******************************************************************************
    162  *
    163  * FUNCTION:    AcpiUtWalkAmlResources
    164  *
    165  * PARAMETERS:  WalkState           - Current walk info
    166  * PARAMETERS:  Aml                 - Pointer to the raw AML resource template
    167  *              AmlLength           - Length of the entire template
    168  *              UserFunction        - Called once for each descriptor found. If
    169  *                                    NULL, a pointer to the EndTag is returned
    170  *              Context             - Passed to UserFunction
    171  *
    172  * RETURN:      Status
    173  *
    174  * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
    175  *              once for each resource found.
    176  *
    177  ******************************************************************************/
    178 
    179 ACPI_STATUS
    180 AcpiUtWalkAmlResources (
    181     ACPI_WALK_STATE         *WalkState,
    182     UINT8                   *Aml,
    183     ACPI_SIZE               AmlLength,
    184     ACPI_WALK_AML_CALLBACK  UserFunction,
    185     void                    **Context)
    186 {
    187     ACPI_STATUS             Status;
    188     UINT8                   *EndAml;
    189     UINT8                   ResourceIndex;
    190     UINT32                  Length;
    191     UINT32                  Offset = 0;
    192     UINT8                   EndTag[2] = {0x79, 0x00};
    193 
    194 
    195     ACPI_FUNCTION_TRACE (UtWalkAmlResources);
    196 
    197 
    198     /* The absolute minimum resource template is one EndTag descriptor */
    199 
    200     if (AmlLength < sizeof (AML_RESOURCE_END_TAG))
    201     {
    202         return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
    203     }
    204 
    205     /* Point to the end of the resource template buffer */
    206 
    207     EndAml = Aml + AmlLength;
    208 
    209     /* Walk the byte list, abort on any invalid descriptor type or length */
    210 
    211     while (Aml < EndAml)
    212     {
    213         /* Validate the Resource Type and Resource Length */
    214 
    215         Status = AcpiUtValidateResource (WalkState, Aml, &ResourceIndex);
    216         if (ACPI_FAILURE (Status))
    217         {
    218             /*
    219              * Exit on failure. Cannot continue because the descriptor
    220              * length may be bogus also.
    221              */
    222             return_ACPI_STATUS (Status);
    223         }
    224 
    225         /* Get the length of this descriptor */
    226 
    227         Length = AcpiUtGetDescriptorLength (Aml);
    228 
    229         /* Invoke the user function */
    230 
    231         if (UserFunction)
    232         {
    233             Status = UserFunction (
    234                 Aml, Length, Offset, ResourceIndex, Context);
    235             if (ACPI_FAILURE (Status))
    236             {
    237                 return_ACPI_STATUS (Status);
    238             }
    239         }
    240 
    241         /* An EndTag descriptor terminates this resource template */
    242 
    243         if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_END_TAG)
    244         {
    245             /*
    246              * There must be at least one more byte in the buffer for
    247              * the 2nd byte of the EndTag
    248              */
    249             if ((Aml + 1) >= EndAml)
    250             {
    251                 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
    252             }
    253 
    254             /*
    255              * Don't attempt to perform any validation on the 2nd byte.
    256              * Although all known ASL compilers insert a zero for the 2nd
    257              * byte, it can also be a checksum (as per the ACPI spec),
    258              * and this is occasionally seen in the field. July 2017.
    259              */
    260 
    261             /* Return the pointer to the EndTag if requested */
    262 
    263             if (!UserFunction)
    264             {
    265                 *Context = Aml;
    266             }
    267 
    268             /* Normal exit */
    269 
    270             return_ACPI_STATUS (AE_OK);
    271         }
    272 
    273         Aml += Length;
    274         Offset += Length;
    275     }
    276 
    277     /* Did not find an EndTag descriptor */
    278 
    279     if (UserFunction)
    280     {
    281         /* Insert an EndTag anyway. AcpiRsGetListLength always leaves room */
    282 
    283         (void) AcpiUtValidateResource (WalkState, EndTag, &ResourceIndex);
    284         Status = UserFunction (EndTag, 2, Offset, ResourceIndex, Context);
    285         if (ACPI_FAILURE (Status))
    286         {
    287             return_ACPI_STATUS (Status);
    288         }
    289     }
    290 
    291     return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
    292 }
    293 
    294 
    295 /*******************************************************************************
    296  *
    297  * FUNCTION:    AcpiUtValidateResource
    298  *
    299  * PARAMETERS:  WalkState           - Current walk info
    300  *              Aml                 - Pointer to the raw AML resource descriptor
    301  *              ReturnIndex         - Where the resource index is returned. NULL
    302  *                                    if the index is not required.
    303  *
    304  * RETURN:      Status, and optionally the Index into the global resource tables
    305  *
    306  * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
    307  *              Type and Resource Length. Returns an index into the global
    308  *              resource information/dispatch tables for later use.
    309  *
    310  ******************************************************************************/
    311 
    312 ACPI_STATUS
    313 AcpiUtValidateResource (
    314     ACPI_WALK_STATE         *WalkState,
    315     void                    *Aml,
    316     UINT8                   *ReturnIndex)
    317 {
    318     AML_RESOURCE            *AmlResource;
    319     UINT8                   ResourceType;
    320     UINT8                   ResourceIndex;
    321     ACPI_RS_LENGTH          ResourceLength;
    322     ACPI_RS_LENGTH          MinimumResourceLength;
    323 
    324 
    325     ACPI_FUNCTION_ENTRY ();
    326 
    327 
    328     /*
    329      * 1) Validate the ResourceType field (Byte 0)
    330      */
    331     ResourceType = ACPI_GET8 (Aml);
    332 
    333     /*
    334      * Byte 0 contains the descriptor name (Resource Type)
    335      * Examine the large/small bit in the resource header
    336      */
    337     if (ResourceType & ACPI_RESOURCE_NAME_LARGE)
    338     {
    339         /* Verify the large resource type (name) against the max */
    340 
    341         if (ResourceType > ACPI_RESOURCE_NAME_LARGE_MAX)
    342         {
    343             goto InvalidResource;
    344         }
    345 
    346         /*
    347          * Large Resource Type -- bits 6:0 contain the name
    348          * Translate range 0x80-0x8B to index range 0x10-0x1B
    349          */
    350         ResourceIndex = (UINT8) (ResourceType - 0x70);
    351     }
    352     else
    353     {
    354         /*
    355          * Small Resource Type -- bits 6:3 contain the name
    356          * Shift range to index range 0x00-0x0F
    357          */
    358         ResourceIndex = (UINT8)
    359             ((ResourceType & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
    360     }
    361 
    362     /*
    363      * Check validity of the resource type, via AcpiGbl_ResourceTypes.
    364      * Zero indicates an invalid resource.
    365      */
    366     if (!AcpiGbl_ResourceTypes[ResourceIndex])
    367     {
    368         goto InvalidResource;
    369     }
    370 
    371     /*
    372      * Validate the ResourceLength field. This ensures that the length
    373      * is at least reasonable, and guarantees that it is non-zero.
    374      */
    375     ResourceLength = AcpiUtGetResourceLength (Aml);
    376     MinimumResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex];
    377 
    378     /* Validate based upon the type of resource - fixed length or variable */
    379 
    380     switch (AcpiGbl_ResourceTypes[ResourceIndex])
    381     {
    382     case ACPI_FIXED_LENGTH:
    383 
    384         /* Fixed length resource, length must match exactly */
    385 
    386         if (ResourceLength != MinimumResourceLength)
    387         {
    388             goto BadResourceLength;
    389         }
    390         break;
    391 
    392     case ACPI_VARIABLE_LENGTH:
    393 
    394         /* Variable length resource, length must be at least the minimum */
    395 
    396         if (ResourceLength < MinimumResourceLength)
    397         {
    398             goto BadResourceLength;
    399         }
    400         break;
    401 
    402     case ACPI_SMALL_VARIABLE_LENGTH:
    403 
    404         /* Small variable length resource, length can be (Min) or (Min-1) */
    405 
    406         if ((ResourceLength > MinimumResourceLength) ||
    407             (ResourceLength < (MinimumResourceLength - 1)))
    408         {
    409             goto BadResourceLength;
    410         }
    411         break;
    412 
    413     default:
    414 
    415         /* Shouldn't happen (because of validation earlier), but be sure */
    416 
    417         goto InvalidResource;
    418     }
    419 
    420     AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml);
    421     if (ResourceType == ACPI_RESOURCE_NAME_SERIAL_BUS)
    422     {
    423         /* Validate the BusType field */
    424 
    425         if ((AmlResource->CommonSerialBus.Type == 0) ||
    426             (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE))
    427         {
    428             if (WalkState)
    429             {
    430                 ACPI_ERROR ((AE_INFO,
    431                     "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
    432                     AmlResource->CommonSerialBus.Type));
    433             }
    434             return (AE_AML_INVALID_RESOURCE_TYPE);
    435         }
    436     }
    437 
    438     /* Optionally return the resource table index */
    439 
    440     if (ReturnIndex)
    441     {
    442         *ReturnIndex = ResourceIndex;
    443     }
    444 
    445     return (AE_OK);
    446 
    447 
    448 InvalidResource:
    449 
    450     if (WalkState)
    451     {
    452         ACPI_ERROR ((AE_INFO,
    453             "Invalid/unsupported resource descriptor: Type 0x%2.2X",
    454             ResourceType));
    455     }
    456     return (AE_AML_INVALID_RESOURCE_TYPE);
    457 
    458 BadResourceLength:
    459 
    460     if (WalkState)
    461     {
    462         ACPI_ERROR ((AE_INFO,
    463             "Invalid resource descriptor length: Type "
    464             "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
    465             ResourceType, ResourceLength, MinimumResourceLength));
    466     }
    467     return (AE_AML_BAD_RESOURCE_LENGTH);
    468 }
    469 
    470 
    471 /*******************************************************************************
    472  *
    473  * FUNCTION:    AcpiUtGetResourceType
    474  *
    475  * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
    476  *
    477  * RETURN:      The Resource Type with no extraneous bits (except the
    478  *              Large/Small descriptor bit -- this is left alone)
    479  *
    480  * DESCRIPTION: Extract the Resource Type/Name from the first byte of
    481  *              a resource descriptor.
    482  *
    483  ******************************************************************************/
    484 
    485 UINT8
    486 AcpiUtGetResourceType (
    487     void                    *Aml)
    488 {
    489     ACPI_FUNCTION_ENTRY ();
    490 
    491 
    492     /*
    493      * Byte 0 contains the descriptor name (Resource Type)
    494      * Examine the large/small bit in the resource header
    495      */
    496     if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
    497     {
    498         /* Large Resource Type -- bits 6:0 contain the name */
    499 
    500         return (ACPI_GET8 (Aml));
    501     }
    502     else
    503     {
    504         /* Small Resource Type -- bits 6:3 contain the name */
    505 
    506         return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
    507     }
    508 }
    509 
    510 
    511 /*******************************************************************************
    512  *
    513  * FUNCTION:    AcpiUtGetResourceLength
    514  *
    515  * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
    516  *
    517  * RETURN:      Byte Length
    518  *
    519  * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
    520  *              definition, this does not include the size of the descriptor
    521  *              header or the length field itself.
    522  *
    523  ******************************************************************************/
    524 
    525 UINT16
    526 AcpiUtGetResourceLength (
    527     void                    *Aml)
    528 {
    529     ACPI_RS_LENGTH          ResourceLength;
    530 
    531 
    532     ACPI_FUNCTION_ENTRY ();
    533 
    534 
    535     /*
    536      * Byte 0 contains the descriptor name (Resource Type)
    537      * Examine the large/small bit in the resource header
    538      */
    539     if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
    540     {
    541         /* Large Resource type -- bytes 1-2 contain the 16-bit length */
    542 
    543         ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1));
    544 
    545     }
    546     else
    547     {
    548         /* Small Resource type -- bits 2:0 of byte 0 contain the length */
    549 
    550         ResourceLength = (UINT16) (ACPI_GET8 (Aml) &
    551             ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
    552     }
    553 
    554     return (ResourceLength);
    555 }
    556 
    557 
    558 /*******************************************************************************
    559  *
    560  * FUNCTION:    AcpiUtGetResourceHeaderLength
    561  *
    562  * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
    563  *
    564  * RETURN:      Length of the AML header (depends on large/small descriptor)
    565  *
    566  * DESCRIPTION: Get the length of the header for this resource.
    567  *
    568  ******************************************************************************/
    569 
    570 UINT8
    571 AcpiUtGetResourceHeaderLength (
    572     void                    *Aml)
    573 {
    574     ACPI_FUNCTION_ENTRY ();
    575 
    576 
    577     /* Examine the large/small bit in the resource header */
    578 
    579     if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
    580     {
    581         return (sizeof (AML_RESOURCE_LARGE_HEADER));
    582     }
    583     else
    584     {
    585         return (sizeof (AML_RESOURCE_SMALL_HEADER));
    586     }
    587 }
    588 
    589 
    590 /*******************************************************************************
    591  *
    592  * FUNCTION:    AcpiUtGetDescriptorLength
    593  *
    594  * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
    595  *
    596  * RETURN:      Byte length
    597  *
    598  * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
    599  *              length of the descriptor header and the length field itself.
    600  *              Used to walk descriptor lists.
    601  *
    602  ******************************************************************************/
    603 
    604 UINT32
    605 AcpiUtGetDescriptorLength (
    606     void                    *Aml)
    607 {
    608     ACPI_FUNCTION_ENTRY ();
    609 
    610 
    611     /*
    612      * Get the Resource Length (does not include header length) and add
    613      * the header length (depends on if this is a small or large resource)
    614      */
    615     return (AcpiUtGetResourceLength (Aml) +
    616         AcpiUtGetResourceHeaderLength (Aml));
    617 }
    618 
    619 
    620 /*******************************************************************************
    621  *
    622  * FUNCTION:    AcpiUtGetResourceEndTag
    623  *
    624  * PARAMETERS:  ObjDesc         - The resource template buffer object
    625  *              EndTag          - Where the pointer to the EndTag is returned
    626  *
    627  * RETURN:      Status, pointer to the end tag
    628  *
    629  * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template
    630  *              Note: allows a buffer length of zero.
    631  *
    632  ******************************************************************************/
    633 
    634 ACPI_STATUS
    635 AcpiUtGetResourceEndTag (
    636     ACPI_OPERAND_OBJECT     *ObjDesc,
    637     UINT8                   **EndTag)
    638 {
    639     ACPI_STATUS             Status;
    640 
    641 
    642     ACPI_FUNCTION_TRACE (UtGetResourceEndTag);
    643 
    644 
    645     /* Allow a buffer length of zero */
    646 
    647     if (!ObjDesc->Buffer.Length)
    648     {
    649         *EndTag = ObjDesc->Buffer.Pointer;
    650         return_ACPI_STATUS (AE_OK);
    651     }
    652 
    653     /* Validate the template and get a pointer to the EndTag */
    654 
    655     Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer,
    656         ObjDesc->Buffer.Length, NULL, (void **) EndTag);
    657 
    658     return_ACPI_STATUS (Status);
    659 }
    660