1/******************************************************************************
2 *
3 * Module Name: exconcat - Concatenate-type AML operators
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2023, 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
55static ACPI_STATUS
56AcpiExConvertToObjectTypeString (
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
84ACPI_STATUS
85AcpiExDoConcatenate (
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
315Cleanup:
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
345static ACPI_STATUS
346AcpiExConvertToObjectTypeString (
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
387ACPI_STATUS
388AcpiExConcatTemplate (
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