xref: /freebsd/sys/contrib/dev/acpica/components/executer/exconcat.c (revision 55620f43deef5c0eb5b4b0f675de18b30c8d1c2d)
1 /******************************************************************************
2  *
3  * Module Name: exconcat - Concatenate-type AML operators
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 <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 
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, 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 
314 Cleanup:
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 
344 static ACPI_STATUS
345 AcpiExConvertToObjectTypeString (
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 
386 ACPI_STATUS
387 AcpiExConcatTemplate (
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