1 /******************************************************************************
2  *
3  * Module Name: exconcat - Concatenate-type AML operators
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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