exconcat.c revision 306536
150091Sken/******************************************************************************
250073Sken *
350073Sken * Module Name: exconcat - Concatenate-type AML operators
450073Sken *
550073Sken *****************************************************************************/
650073Sken
750073Sken/*
850073Sken * Copyright (C) 2000 - 2016, Intel Corp.
950073Sken * All rights reserved.
1050073Sken *
1150073Sken * Redistribution and use in source and binary forms, with or without
1250073Sken * modification, are permitted provided that the following conditions
1350073Sken * are met:
1450073Sken * 1. Redistributions of source code must retain the above copyright
1550073Sken *    notice, this list of conditions, and the following disclaimer,
1650073Sken *    without modification.
1750073Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1850073Sken *    substantially similar to the "NO WARRANTY" disclaimer below
1950073Sken *    ("Disclaimer") and any redistribution must be conditioned upon
2050073Sken *    including a substantially similar Disclaimer requirement for further
2150073Sken *    binary redistribution.
2250073Sken * 3. Neither the names of the above-listed copyright holders nor the names
2350073Sken *    of any contributors may be used to endorse or promote products derived
2450073Sken *    from this software without specific prior written permission.
2550073Sken *
2650477Speter * Alternatively, this software may be distributed under the terms of the
2750073Sken * GNU General Public License ("GPL") version 2 as published by the Free
2850073Sken * Software Foundation.
2950091Sken *
3050091Sken * NO WARRANTY
3150091Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3250073Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3350073Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3450091Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3550091Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3650073Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3750091Sken * 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 <contrib/dev/acpica/include/acpi.h>
45#include <contrib/dev/acpica/include/accommon.h>
46#include <contrib/dev/acpica/include/acinterp.h>
47#include <contrib/dev/acpica/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, 16);
168        break;
169
170    case ACPI_TYPE_BUFFER:
171
172        Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1);
173        break;
174
175    case ACPI_TYPE_STRING:
176
177        switch (Operand1Type)
178        {
179        case ACPI_TYPE_INTEGER:
180        case ACPI_TYPE_STRING:
181        case ACPI_TYPE_BUFFER:
182
183            /* Other types have already been converted to string */
184
185            Status = AcpiExConvertToString (
186                LocalOperand1, &TempOperand1, ACPI_IMPLICIT_CONVERT_HEX);
187            break;
188
189        default:
190
191            Status = AE_OK;
192            break;
193        }
194        break;
195
196    default:
197
198        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
199            Operand0->Common.Type));
200        Status = AE_AML_INTERNAL;
201    }
202
203    if (ACPI_FAILURE (Status))
204    {
205        goto Cleanup;
206    }
207
208    /* Take care with any newly created operand objects */
209
210    if ((LocalOperand1 != Operand1) &&
211        (LocalOperand1 != TempOperand1))
212    {
213        AcpiUtRemoveReference (LocalOperand1);
214    }
215
216    LocalOperand1 = TempOperand1;
217
218    /*
219     * Both operands are now known to be the same object type
220     * (Both are Integer, String, or Buffer), and we can now perform
221     * the concatenation.
222     *
223     * There are three cases to handle, as per the ACPI spec:
224     *
225     * 1) Two Integers concatenated to produce a new Buffer
226     * 2) Two Strings concatenated to produce a new String
227     * 3) Two Buffers concatenated to produce a new Buffer
228     */
229    switch (Operand0Type)
230    {
231    case ACPI_TYPE_INTEGER:
232
233        /* Result of two Integers is a Buffer */
234        /* Need enough buffer space for two integers */
235
236        ReturnDesc = AcpiUtCreateBufferObject (
237            (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
238        if (!ReturnDesc)
239        {
240            Status = AE_NO_MEMORY;
241            goto Cleanup;
242        }
243
244        Buffer = (char *) ReturnDesc->Buffer.Pointer;
245
246        /* Copy the first integer, LSB first */
247
248        memcpy (Buffer, &Operand0->Integer.Value,
249            AcpiGbl_IntegerByteWidth);
250
251        /* Copy the second integer (LSB first) after the first */
252
253        memcpy (Buffer + AcpiGbl_IntegerByteWidth,
254            &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth);
255        break;
256
257    case ACPI_TYPE_STRING:
258
259        /* Result of two Strings is a String */
260
261        ReturnDesc = AcpiUtCreateStringObject (
262            ((ACPI_SIZE) LocalOperand0->String.Length +
263            LocalOperand1->String.Length));
264        if (!ReturnDesc)
265        {
266            Status = AE_NO_MEMORY;
267            goto Cleanup;
268        }
269
270        Buffer = ReturnDesc->String.Pointer;
271
272        /* Concatenate the strings */
273
274        strcpy (Buffer, LocalOperand0->String.Pointer);
275        strcat (Buffer, LocalOperand1->String.Pointer);
276        break;
277
278    case ACPI_TYPE_BUFFER:
279
280        /* Result of two Buffers is a Buffer */
281
282        ReturnDesc = AcpiUtCreateBufferObject (
283            ((ACPI_SIZE) Operand0->Buffer.Length +
284            LocalOperand1->Buffer.Length));
285        if (!ReturnDesc)
286        {
287            Status = AE_NO_MEMORY;
288            goto Cleanup;
289        }
290
291        Buffer = (char *) ReturnDesc->Buffer.Pointer;
292
293        /* Concatenate the buffers */
294
295        memcpy (Buffer, Operand0->Buffer.Pointer,
296            Operand0->Buffer.Length);
297        memcpy (Buffer + Operand0->Buffer.Length,
298            LocalOperand1->Buffer.Pointer,
299            LocalOperand1->Buffer.Length);
300        break;
301
302    default:
303
304        /* Invalid object type, should not happen here */
305
306        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
307            Operand0->Common.Type));
308        Status = AE_AML_INTERNAL;
309        goto Cleanup;
310    }
311
312    *ActualReturnDesc = ReturnDesc;
313
314Cleanup:
315    if (LocalOperand0 != Operand0)
316    {
317        AcpiUtRemoveReference (LocalOperand0);
318    }
319
320    if (LocalOperand1 != Operand1)
321    {
322        AcpiUtRemoveReference (LocalOperand1);
323    }
324
325    return_ACPI_STATUS (Status);
326}
327
328
329/*******************************************************************************
330 *
331 * FUNCTION:    AcpiExConvertToObjectTypeString
332 *
333 * PARAMETERS:  ObjDesc             - Object to be converted
334 *              ReturnDesc          - Where to place the return object
335 *
336 * RETURN:      Status
337 *
338 * DESCRIPTION: Convert an object of arbitrary type to a string object that
339 *              contains the namestring for the object. Used for the
340 *              concatenate operator.
341 *
342 ******************************************************************************/
343
344static ACPI_STATUS
345AcpiExConvertToObjectTypeString (
346    ACPI_OPERAND_OBJECT     *ObjDesc,
347    ACPI_OPERAND_OBJECT     **ResultDesc)
348{
349    ACPI_OPERAND_OBJECT     *ReturnDesc;
350    const char              *TypeString;
351
352
353    TypeString = AcpiUtGetTypeName (ObjDesc->Common.Type);
354
355    ReturnDesc = AcpiUtCreateStringObject (
356        ((ACPI_SIZE) strlen (TypeString) + 9)); /* 9 For "[ Object]" */
357    if (!ReturnDesc)
358    {
359        return (AE_NO_MEMORY);
360    }
361
362    strcpy (ReturnDesc->String.Pointer, "[");
363    strcat (ReturnDesc->String.Pointer, TypeString);
364    strcat (ReturnDesc->String.Pointer, " Object]");
365
366    *ResultDesc = ReturnDesc;
367    return (AE_OK);
368}
369
370
371/*******************************************************************************
372 *
373 * FUNCTION:    AcpiExConcatTemplate
374 *
375 * PARAMETERS:  Operand0            - First source object
376 *              Operand1            - Second source object
377 *              ActualReturnDesc    - Where to place the return object
378 *              WalkState           - Current walk state
379 *
380 * RETURN:      Status
381 *
382 * DESCRIPTION: Concatenate two resource templates
383 *
384 ******************************************************************************/
385
386ACPI_STATUS
387AcpiExConcatTemplate (
388    ACPI_OPERAND_OBJECT     *Operand0,
389    ACPI_OPERAND_OBJECT     *Operand1,
390    ACPI_OPERAND_OBJECT     **ActualReturnDesc,
391    ACPI_WALK_STATE         *WalkState)
392{
393    ACPI_STATUS             Status;
394    ACPI_OPERAND_OBJECT     *ReturnDesc;
395    UINT8                   *NewBuf;
396    UINT8                   *EndTag;
397    ACPI_SIZE               Length0;
398    ACPI_SIZE               Length1;
399    ACPI_SIZE               NewLength;
400
401
402    ACPI_FUNCTION_TRACE (ExConcatTemplate);
403
404
405    /*
406     * Find the EndTag descriptor in each resource template.
407     * Note1: returned pointers point TO the EndTag, not past it.
408     * Note2: zero-length buffers are allowed; treated like one EndTag
409     */
410
411    /* Get the length of the first resource template */
412
413    Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
414    if (ACPI_FAILURE (Status))
415    {
416        return_ACPI_STATUS (Status);
417    }
418
419    Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
420
421    /* Get the length of the second resource template */
422
423    Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
424    if (ACPI_FAILURE (Status))
425    {
426        return_ACPI_STATUS (Status);
427    }
428
429    Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
430
431    /* Combine both lengths, minimum size will be 2 for EndTag */
432
433    NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
434
435    /* Create a new buffer object for the result (with one EndTag) */
436
437    ReturnDesc = AcpiUtCreateBufferObject (NewLength);
438    if (!ReturnDesc)
439    {
440        return_ACPI_STATUS (AE_NO_MEMORY);
441    }
442
443    /*
444     * Copy the templates to the new buffer, 0 first, then 1 follows. One
445     * EndTag descriptor is copied from Operand1.
446     */
447    NewBuf = ReturnDesc->Buffer.Pointer;
448    memcpy (NewBuf, Operand0->Buffer.Pointer, Length0);
449    memcpy (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
450
451    /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
452
453    NewBuf[NewLength - 1] = 0;
454    NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
455
456    /* Return the completed resource template */
457
458    *ActualReturnDesc = ReturnDesc;
459    return_ACPI_STATUS (AE_OK);
460}
461