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 "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
AcpiExDoConcatenate(ACPI_OPERAND_OBJECT * Operand0,ACPI_OPERAND_OBJECT * Operand1,ACPI_OPERAND_OBJECT ** ActualReturnDesc,ACPI_WALK_STATE * WalkState)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
AcpiExConvertToObjectTypeString(ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc)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
AcpiExConcatTemplate(ACPI_OPERAND_OBJECT * Operand0,ACPI_OPERAND_OBJECT * Operand1,ACPI_OPERAND_OBJECT ** ActualReturnDesc,ACPI_WALK_STATE * WalkState)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