1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
4 * Module Name: exconcat - Concatenate-type AML operators
6 * Copyright (C) 2000 - 2019, Intel Corp.
8 *****************************************************************************/
10 #include <acpi/acpi.h>
15 #define _COMPONENT ACPI_EXECUTER
16 ACPI_MODULE_NAME("exconcat")
18 /* Local Prototypes */
20 acpi_ex_convert_to_object_type_string(union acpi_operand_object
*obj_desc
,
21 union acpi_operand_object
**result_desc
);
23 /*******************************************************************************
25 * FUNCTION: acpi_ex_do_concatenate
27 * PARAMETERS: operand0 - First source object
28 * operand1 - Second source object
29 * actual_return_desc - Where to place the return object
30 * walk_state - Current walk state
34 * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
37 * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
38 * String, and Buffer objects. However, we support all objects here
39 * as an extension. This improves the usefulness of both Concatenate
40 * and the Printf/Fprintf macros. The extension returns a string
41 * describing the object type for the other objects.
44 ******************************************************************************/
47 acpi_ex_do_concatenate(union acpi_operand_object
*operand0
,
48 union acpi_operand_object
*operand1
,
49 union acpi_operand_object
**actual_return_desc
,
50 struct acpi_walk_state
*walk_state
)
52 union acpi_operand_object
*local_operand0
= operand0
;
53 union acpi_operand_object
*local_operand1
= operand1
;
54 union acpi_operand_object
*temp_operand1
= NULL
;
55 union acpi_operand_object
*return_desc
;
57 acpi_object_type operand0_type
;
58 acpi_object_type operand1_type
;
61 ACPI_FUNCTION_TRACE(ex_do_concatenate
);
63 /* Operand 0 preprocessing */
65 switch (operand0
->common
.type
) {
66 case ACPI_TYPE_INTEGER
:
67 case ACPI_TYPE_STRING
:
68 case ACPI_TYPE_BUFFER
:
70 operand0_type
= operand0
->common
.type
;
75 /* For all other types, get the "object type" string */
78 acpi_ex_convert_to_object_type_string(operand0
,
80 if (ACPI_FAILURE(status
)) {
84 operand0_type
= ACPI_TYPE_STRING
;
88 /* Operand 1 preprocessing */
90 switch (operand1
->common
.type
) {
91 case ACPI_TYPE_INTEGER
:
92 case ACPI_TYPE_STRING
:
93 case ACPI_TYPE_BUFFER
:
95 operand1_type
= operand1
->common
.type
;
100 /* For all other types, get the "object type" string */
103 acpi_ex_convert_to_object_type_string(operand1
,
105 if (ACPI_FAILURE(status
)) {
109 operand1_type
= ACPI_TYPE_STRING
;
114 * Convert the second operand if necessary. The first operand (0)
115 * determines the type of the second operand (1) (See the Data Types
116 * section of the ACPI specification). Both object types are
117 * guaranteed to be either Integer/String/Buffer by the operand
118 * resolution mechanism.
120 switch (operand0_type
) {
121 case ACPI_TYPE_INTEGER
:
124 acpi_ex_convert_to_integer(local_operand1
, &temp_operand1
,
125 ACPI_IMPLICIT_CONVERSION
);
128 case ACPI_TYPE_BUFFER
:
131 acpi_ex_convert_to_buffer(local_operand1
, &temp_operand1
);
134 case ACPI_TYPE_STRING
:
136 switch (operand1_type
) {
137 case ACPI_TYPE_INTEGER
:
138 case ACPI_TYPE_STRING
:
139 case ACPI_TYPE_BUFFER
:
141 /* Other types have already been converted to string */
144 acpi_ex_convert_to_string(local_operand1
,
146 ACPI_IMPLICIT_CONVERT_HEX
);
158 ACPI_ERROR((AE_INFO
, "Invalid object type: 0x%X",
159 operand0
->common
.type
));
160 status
= AE_AML_INTERNAL
;
163 if (ACPI_FAILURE(status
)) {
167 /* Take care with any newly created operand objects */
169 if ((local_operand1
!= operand1
) && (local_operand1
!= temp_operand1
)) {
170 acpi_ut_remove_reference(local_operand1
);
173 local_operand1
= temp_operand1
;
176 * Both operands are now known to be the same object type
177 * (Both are Integer, String, or Buffer), and we can now perform
180 * There are three cases to handle, as per the ACPI spec:
182 * 1) Two Integers concatenated to produce a new Buffer
183 * 2) Two Strings concatenated to produce a new String
184 * 3) Two Buffers concatenated to produce a new Buffer
186 switch (operand0_type
) {
187 case ACPI_TYPE_INTEGER
:
189 /* Result of two Integers is a Buffer */
190 /* Need enough buffer space for two integers */
192 return_desc
= acpi_ut_create_buffer_object((acpi_size
)
194 (acpi_gbl_integer_byte_width
));
196 status
= AE_NO_MEMORY
;
200 buffer
= (char *)return_desc
->buffer
.pointer
;
202 /* Copy the first integer, LSB first */
204 memcpy(buffer
, &operand0
->integer
.value
,
205 acpi_gbl_integer_byte_width
);
207 /* Copy the second integer (LSB first) after the first */
209 memcpy(buffer
+ acpi_gbl_integer_byte_width
,
210 &local_operand1
->integer
.value
,
211 acpi_gbl_integer_byte_width
);
214 case ACPI_TYPE_STRING
:
216 /* Result of two Strings is a String */
218 return_desc
= acpi_ut_create_string_object(((acpi_size
)
224 status
= AE_NO_MEMORY
;
228 buffer
= return_desc
->string
.pointer
;
230 /* Concatenate the strings */
232 strcpy(buffer
, local_operand0
->string
.pointer
);
233 strcat(buffer
, local_operand1
->string
.pointer
);
236 case ACPI_TYPE_BUFFER
:
238 /* Result of two Buffers is a Buffer */
240 return_desc
= acpi_ut_create_buffer_object(((acpi_size
)
246 status
= AE_NO_MEMORY
;
250 buffer
= (char *)return_desc
->buffer
.pointer
;
252 /* Concatenate the buffers */
254 memcpy(buffer
, operand0
->buffer
.pointer
,
255 operand0
->buffer
.length
);
256 memcpy(buffer
+ operand0
->buffer
.length
,
257 local_operand1
->buffer
.pointer
,
258 local_operand1
->buffer
.length
);
263 /* Invalid object type, should not happen here */
265 ACPI_ERROR((AE_INFO
, "Invalid object type: 0x%X",
266 operand0
->common
.type
));
267 status
= AE_AML_INTERNAL
;
271 *actual_return_desc
= return_desc
;
274 if (local_operand0
!= operand0
) {
275 acpi_ut_remove_reference(local_operand0
);
278 if (local_operand1
!= operand1
) {
279 acpi_ut_remove_reference(local_operand1
);
282 return_ACPI_STATUS(status
);
285 /*******************************************************************************
287 * FUNCTION: acpi_ex_convert_to_object_type_string
289 * PARAMETERS: obj_desc - Object to be converted
290 * return_desc - Where to place the return object
294 * DESCRIPTION: Convert an object of arbitrary type to a string object that
295 * contains the namestring for the object. Used for the
296 * concatenate operator.
298 ******************************************************************************/
301 acpi_ex_convert_to_object_type_string(union acpi_operand_object
*obj_desc
,
302 union acpi_operand_object
**result_desc
)
304 union acpi_operand_object
*return_desc
;
305 const char *type_string
;
307 type_string
= acpi_ut_get_type_name(obj_desc
->common
.type
);
309 return_desc
= acpi_ut_create_string_object(((acpi_size
)strlen(type_string
) + 9)); /* 9 For "[ Object]" */
311 return (AE_NO_MEMORY
);
314 strcpy(return_desc
->string
.pointer
, "[");
315 strcat(return_desc
->string
.pointer
, type_string
);
316 strcat(return_desc
->string
.pointer
, " Object]");
318 *result_desc
= return_desc
;
322 /*******************************************************************************
324 * FUNCTION: acpi_ex_concat_template
326 * PARAMETERS: operand0 - First source object
327 * operand1 - Second source object
328 * actual_return_desc - Where to place the return object
329 * walk_state - Current walk state
333 * DESCRIPTION: Concatenate two resource templates
335 ******************************************************************************/
338 acpi_ex_concat_template(union acpi_operand_object
*operand0
,
339 union acpi_operand_object
*operand1
,
340 union acpi_operand_object
**actual_return_desc
,
341 struct acpi_walk_state
*walk_state
)
344 union acpi_operand_object
*return_desc
;
349 acpi_size new_length
;
351 ACPI_FUNCTION_TRACE(ex_concat_template
);
354 * Find the end_tag descriptor in each resource template.
355 * Note1: returned pointers point TO the end_tag, not past it.
356 * Note2: zero-length buffers are allowed; treated like one end_tag
359 /* Get the length of the first resource template */
361 status
= acpi_ut_get_resource_end_tag(operand0
, &end_tag
);
362 if (ACPI_FAILURE(status
)) {
363 return_ACPI_STATUS(status
);
366 length0
= ACPI_PTR_DIFF(end_tag
, operand0
->buffer
.pointer
);
368 /* Get the length of the second resource template */
370 status
= acpi_ut_get_resource_end_tag(operand1
, &end_tag
);
371 if (ACPI_FAILURE(status
)) {
372 return_ACPI_STATUS(status
);
375 length1
= ACPI_PTR_DIFF(end_tag
, operand1
->buffer
.pointer
);
377 /* Combine both lengths, minimum size will be 2 for end_tag */
379 new_length
= length0
+ length1
+ sizeof(struct aml_resource_end_tag
);
381 /* Create a new buffer object for the result (with one end_tag) */
383 return_desc
= acpi_ut_create_buffer_object(new_length
);
385 return_ACPI_STATUS(AE_NO_MEMORY
);
389 * Copy the templates to the new buffer, 0 first, then 1 follows. One
390 * end_tag descriptor is copied from Operand1.
392 new_buf
= return_desc
->buffer
.pointer
;
393 memcpy(new_buf
, operand0
->buffer
.pointer
, length0
);
394 memcpy(new_buf
+ length0
, operand1
->buffer
.pointer
, length1
);
396 /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
398 new_buf
[new_length
- 1] = 0;
399 new_buf
[new_length
- 2] = ACPI_RESOURCE_NAME_END_TAG
| 1;
401 /* Return the completed resource template */
403 *actual_return_desc
= return_desc
;
404 return_ACPI_STATUS(AE_OK
);