Home | History | Annotate | Line # | Download | only in executer
exconcat.c revision 1.1.1.8
      1 /******************************************************************************
      2  *
      3  * Module Name: exconcat - Concatenate-type AML operators
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 "acinterp.h"
     47 #include "amlresrc.h"
     48 
     49 
     50 #define _COMPONENT          ACPI_EXECUTER
     51         ACPI_MODULE_NAME    ("exconcat")
     52 
     53 /* Local Prototypes */
     54 
     55 static ACPI_STATUS
     56 AcpiExConvertToObjectTypeString (
     57     ACPI_OPERAND_OBJECT     *ObjDesc,
     58     ACPI_OPERAND_OBJECT     **ResultDesc);
     59 
     60 
     61 /*******************************************************************************
     62  *
     63  * FUNCTION:    AcpiExDoConcatenate
     64  *
     65  * PARAMETERS:  Operand0            - First source object
     66  *              Operand1            - Second source object
     67  *              ActualReturnDesc    - Where to place the return object
     68  *              WalkState           - Current walk state
     69  *
     70  * RETURN:      Status
     71  *
     72  * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
     73  *              rules as necessary.
     74  * NOTE:
     75  * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
     76  * String, and Buffer objects. However, we support all objects here
     77  * as an extension. This improves the usefulness of both Concatenate
     78  * and the Printf/Fprintf macros. The extension returns a string
     79  * describing the object type for the other objects.
     80  * 02/2016.
     81  *
     82  ******************************************************************************/
     83 
     84 ACPI_STATUS
     85 AcpiExDoConcatenate (
     86     ACPI_OPERAND_OBJECT     *Operand0,
     87     ACPI_OPERAND_OBJECT     *Operand1,
     88     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
     89     ACPI_WALK_STATE         *WalkState)
     90 {
     91     ACPI_OPERAND_OBJECT     *LocalOperand0 = Operand0;
     92     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
     93     ACPI_OPERAND_OBJECT     *TempOperand1 = NULL;
     94     ACPI_OPERAND_OBJECT     *ReturnDesc;
     95     char                    *Buffer;
     96     ACPI_OBJECT_TYPE        Operand0Type;
     97     ACPI_OBJECT_TYPE        Operand1Type;
     98     ACPI_STATUS             Status;
     99 
    100 
    101     ACPI_FUNCTION_TRACE (ExDoConcatenate);
    102 
    103 
    104     /* Operand 0 preprocessing */
    105 
    106     switch (Operand0->Common.Type)
    107     {
    108     case ACPI_TYPE_INTEGER:
    109     case ACPI_TYPE_STRING:
    110     case ACPI_TYPE_BUFFER:
    111 
    112         Operand0Type = Operand0->Common.Type;
    113         break;
    114 
    115     default:
    116 
    117         /* For all other types, get the "object type" string */
    118 
    119         Status = AcpiExConvertToObjectTypeString (
    120             Operand0, &LocalOperand0);
    121         if (ACPI_FAILURE (Status))
    122         {
    123             goto Cleanup;
    124         }
    125 
    126         Operand0Type = ACPI_TYPE_STRING;
    127         break;
    128     }
    129 
    130     /* Operand 1 preprocessing */
    131 
    132     switch (Operand1->Common.Type)
    133     {
    134     case ACPI_TYPE_INTEGER:
    135     case ACPI_TYPE_STRING:
    136     case ACPI_TYPE_BUFFER:
    137 
    138         Operand1Type = Operand1->Common.Type;
    139         break;
    140 
    141     default:
    142 
    143         /* For all other types, get the "object type" string */
    144 
    145         Status = AcpiExConvertToObjectTypeString (
    146             Operand1, &LocalOperand1);
    147         if (ACPI_FAILURE (Status))
    148         {
    149             goto Cleanup;
    150         }
    151 
    152         Operand1Type = ACPI_TYPE_STRING;
    153         break;
    154     }
    155 
    156     /*
    157      * Convert the second operand if necessary. The first operand (0)
    158      * determines the type of the second operand (1) (See the Data Types
    159      * section of the ACPI specification). Both object types are
    160      * guaranteed to be either Integer/String/Buffer by the operand
    161      * resolution mechanism.
    162      */
    163     switch (Operand0Type)
    164     {
    165     case ACPI_TYPE_INTEGER:
    166 
    167         Status = AcpiExConvertToInteger (LocalOperand1, &TempOperand1,
    168             ACPI_IMPLICIT_CONVERSION);
    169         break;
    170 
    171     case ACPI_TYPE_BUFFER:
    172 
    173         Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1);
    174         break;
    175 
    176     case ACPI_TYPE_STRING:
    177 
    178         switch (Operand1Type)
    179         {
    180         case ACPI_TYPE_INTEGER:
    181         case ACPI_TYPE_STRING:
    182         case ACPI_TYPE_BUFFER:
    183 
    184             /* Other types have already been converted to string */
    185 
    186             Status = AcpiExConvertToString (
    187                 LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX);
    188             break;
    189 
    190         default:
    191 
    192             Status = AE_OK;
    193             break;
    194         }
    195         break;
    196 
    197     default:
    198 
    199         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
    200             Operand0->Common.Type));
    201         Status = AE_AML_INTERNAL;
    202     }
    203 
    204     if (ACPI_FAILURE (Status))
    205     {
    206         goto Cleanup;
    207     }
    208 
    209     /* Take care with any newly created operand objects */
    210 
    211     if ((LocalOperand1 != Operand1) &&
    212         (LocalOperand1 != TempOperand1))
    213     {
    214         AcpiUtRemoveReference (LocalOperand1);
    215     }
    216 
    217     LocalOperand1 = TempOperand1;
    218 
    219     /*
    220      * Both operands are now known to be the same object type
    221      * (Both are Integer, String, or Buffer), and we can now perform
    222      * the concatenation.
    223      *
    224      * There are three cases to handle, as per the ACPI spec:
    225      *
    226      * 1) Two Integers concatenated to produce a new Buffer
    227      * 2) Two Strings concatenated to produce a new String
    228      * 3) Two Buffers concatenated to produce a new Buffer
    229      */
    230     switch (Operand0Type)
    231     {
    232     case ACPI_TYPE_INTEGER:
    233 
    234         /* Result of two Integers is a Buffer */
    235         /* Need enough buffer space for two integers */
    236 
    237         ReturnDesc = AcpiUtCreateBufferObject (
    238             (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
    239         if (!ReturnDesc)
    240         {
    241             Status = AE_NO_MEMORY;
    242             goto Cleanup;
    243         }
    244 
    245         Buffer = (char *) ReturnDesc->Buffer.Pointer;
    246 
    247         /* Copy the first integer, LSB first */
    248 
    249         memcpy (Buffer, &Operand0->Integer.Value,
    250             AcpiGbl_IntegerByteWidth);
    251 
    252         /* Copy the second integer (LSB first) after the first */
    253 
    254         memcpy (Buffer + AcpiGbl_IntegerByteWidth,
    255             &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth);
    256         break;
    257 
    258     case ACPI_TYPE_STRING:
    259 
    260         /* Result of two Strings is a String */
    261 
    262         ReturnDesc = AcpiUtCreateStringObject (
    263             ((ACPI_SIZE) LocalOperand0->String.Length +
    264             LocalOperand1->String.Length));
    265         if (!ReturnDesc)
    266         {
    267             Status = AE_NO_MEMORY;
    268             goto Cleanup;
    269         }
    270 
    271         Buffer = ReturnDesc->String.Pointer;
    272 
    273         /* Concatenate the strings */
    274 
    275         strcpy (Buffer, LocalOperand0->String.Pointer);
    276         strcat (Buffer, LocalOperand1->String.Pointer);
    277         break;
    278 
    279     case ACPI_TYPE_BUFFER:
    280 
    281         /* Result of two Buffers is a Buffer */
    282 
    283         ReturnDesc = AcpiUtCreateBufferObject (
    284             ((ACPI_SIZE) Operand0->Buffer.Length +
    285             LocalOperand1->Buffer.Length));
    286         if (!ReturnDesc)
    287         {
    288             Status = AE_NO_MEMORY;
    289             goto Cleanup;
    290         }
    291 
    292         Buffer = (char *) ReturnDesc->Buffer.Pointer;
    293 
    294         /* Concatenate the buffers */
    295 
    296         memcpy (Buffer, Operand0->Buffer.Pointer,
    297             Operand0->Buffer.Length);
    298         memcpy (Buffer + Operand0->Buffer.Length,
    299             LocalOperand1->Buffer.Pointer,
    300             LocalOperand1->Buffer.Length);
    301         break;
    302 
    303     default:
    304 
    305         /* Invalid object type, should not happen here */
    306 
    307         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
    308             Operand0->Common.Type));
    309         Status = AE_AML_INTERNAL;
    310         goto Cleanup;
    311     }
    312 
    313     *ActualReturnDesc = ReturnDesc;
    314 
    315 Cleanup:
    316     if (LocalOperand0 != Operand0)
    317     {
    318         AcpiUtRemoveReference (LocalOperand0);
    319     }
    320 
    321     if (LocalOperand1 != Operand1)
    322     {
    323         AcpiUtRemoveReference (LocalOperand1);
    324     }
    325 
    326     return_ACPI_STATUS (Status);
    327 }
    328 
    329 
    330 /*******************************************************************************
    331  *
    332  * FUNCTION:    AcpiExConvertToObjectTypeString
    333  *
    334  * PARAMETERS:  ObjDesc             - Object to be converted
    335  *              ReturnDesc          - Where to place the return object
    336  *
    337  * RETURN:      Status
    338  *
    339  * DESCRIPTION: Convert an object of arbitrary type to a string object that
    340  *              contains the namestring for the object. Used for the
    341  *              concatenate operator.
    342  *
    343  ******************************************************************************/
    344 
    345 static ACPI_STATUS
    346 AcpiExConvertToObjectTypeString (
    347     ACPI_OPERAND_OBJECT     *ObjDesc,
    348     ACPI_OPERAND_OBJECT     **ResultDesc)
    349 {
    350     ACPI_OPERAND_OBJECT     *ReturnDesc;
    351     const char              *TypeString;
    352 
    353 
    354     TypeString = AcpiUtGetTypeName (ObjDesc->Common.Type);
    355 
    356     ReturnDesc = AcpiUtCreateStringObject (
    357         ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[ Object]" */
    358     if (!ReturnDesc)
    359     {
    360         return (AE_NO_MEMORY);
    361     }
    362 
    363     strcpy (ReturnDesc->String.Pointer, "[");
    364     strcat (ReturnDesc->String.Pointer, TypeString);
    365     strcat (ReturnDesc->String.Pointer, " Object]");
    366 
    367     *ResultDesc = ReturnDesc;
    368     return (AE_OK);
    369 }
    370 
    371 
    372 /*******************************************************************************
    373  *
    374  * FUNCTION:    AcpiExConcatTemplate
    375  *
    376  * PARAMETERS:  Operand0            - First source object
    377  *              Operand1            - Second source object
    378  *              ActualReturnDesc    - Where to place the return object
    379  *              WalkState           - Current walk state
    380  *
    381  * RETURN:      Status
    382  *
    383  * DESCRIPTION: Concatenate two resource templates
    384  *
    385  ******************************************************************************/
    386 
    387 ACPI_STATUS
    388 AcpiExConcatTemplate (
    389     ACPI_OPERAND_OBJECT     *Operand0,
    390     ACPI_OPERAND_OBJECT     *Operand1,
    391     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
    392     ACPI_WALK_STATE         *WalkState)
    393 {
    394     ACPI_STATUS             Status;
    395     ACPI_OPERAND_OBJECT     *ReturnDesc;
    396     UINT8                   *NewBuf;
    397     UINT8                   *EndTag;
    398     ACPI_SIZE               Length0;
    399     ACPI_SIZE               Length1;
    400     ACPI_SIZE               NewLength;
    401 
    402 
    403     ACPI_FUNCTION_TRACE (ExConcatTemplate);
    404 
    405 
    406     /*
    407      * Find the EndTag descriptor in each resource template.
    408      * Note1: returned pointers point TO the EndTag, not past it.
    409      * Note2: zero-length buffers are allowed; treated like one EndTag
    410      */
    411 
    412     /* Get the length of the first resource template */
    413 
    414     Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
    415     if (ACPI_FAILURE (Status))
    416     {
    417         return_ACPI_STATUS (Status);
    418     }
    419 
    420     Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
    421 
    422     /* Get the length of the second resource template */
    423 
    424     Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
    425     if (ACPI_FAILURE (Status))
    426     {
    427         return_ACPI_STATUS (Status);
    428     }
    429 
    430     Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
    431 
    432     /* Combine both lengths, minimum size will be 2 for EndTag */
    433 
    434     NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
    435 
    436     /* Create a new buffer object for the result (with one EndTag) */
    437 
    438     ReturnDesc = AcpiUtCreateBufferObject (NewLength);
    439     if (!ReturnDesc)
    440     {
    441         return_ACPI_STATUS (AE_NO_MEMORY);
    442     }
    443 
    444     /*
    445      * Copy the templates to the new buffer, 0 first, then 1 follows. One
    446      * EndTag descriptor is copied from Operand1.
    447      */
    448     NewBuf = ReturnDesc->Buffer.Pointer;
    449     memcpy (NewBuf, Operand0->Buffer.Pointer, Length0);
    450     memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
    451 
    452     /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
    453 
    454     NewBuf[NewLength - 1] = 0;
    455     NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
    456 
    457     /* Return the completed resource template */
    458 
    459     *ActualReturnDesc = ReturnDesc;
    460     return_ACPI_STATUS (AE_OK);
    461 }
    462