Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: exconcat - Concatenate-type AML operators
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acinterp.h"
13 : : #include "amlresrc.h"
14 : :
15 : : #define _COMPONENT ACPI_EXECUTER
16 : : ACPI_MODULE_NAME("exconcat")
17 : :
18 : : /* Local Prototypes */
19 : : static acpi_status
20 : : acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
21 : : union acpi_operand_object **result_desc);
22 : :
23 : : /*******************************************************************************
24 : : *
25 : : * FUNCTION: acpi_ex_do_concatenate
26 : : *
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
31 : : *
32 : : * RETURN: Status
33 : : *
34 : : * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
35 : : * rules as necessary.
36 : : * NOTE:
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.
42 : : * 02/2016.
43 : : *
44 : : ******************************************************************************/
45 : :
46 : : acpi_status
47 : 0 : 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)
51 : : {
52 : 0 : union acpi_operand_object *local_operand0 = operand0;
53 : 0 : union acpi_operand_object *local_operand1 = operand1;
54 : 0 : union acpi_operand_object *temp_operand1 = NULL;
55 : 0 : union acpi_operand_object *return_desc;
56 : 0 : char *buffer;
57 : 0 : acpi_object_type operand0_type;
58 : 0 : acpi_object_type operand1_type;
59 : 0 : acpi_status status;
60 : :
61 : 0 : ACPI_FUNCTION_TRACE(ex_do_concatenate);
62 : :
63 : : /* Operand 0 preprocessing */
64 : :
65 [ # # ]: 0 : switch (operand0->common.type) {
66 : : case ACPI_TYPE_INTEGER:
67 : : case ACPI_TYPE_STRING:
68 : : case ACPI_TYPE_BUFFER:
69 : :
70 : : operand0_type = operand0->common.type;
71 : : break;
72 : :
73 : 0 : default:
74 : :
75 : : /* For all other types, get the "object type" string */
76 : :
77 : 0 : status =
78 : 0 : acpi_ex_convert_to_object_type_string(operand0,
79 : : &local_operand0);
80 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
81 : 0 : goto cleanup;
82 : : }
83 : :
84 : : operand0_type = ACPI_TYPE_STRING;
85 : : break;
86 : : }
87 : :
88 : : /* Operand 1 preprocessing */
89 : :
90 [ # # ]: 0 : switch (operand1->common.type) {
91 : : case ACPI_TYPE_INTEGER:
92 : : case ACPI_TYPE_STRING:
93 : : case ACPI_TYPE_BUFFER:
94 : :
95 : : operand1_type = operand1->common.type;
96 : : break;
97 : :
98 : 0 : default:
99 : :
100 : : /* For all other types, get the "object type" string */
101 : :
102 : 0 : status =
103 : 0 : acpi_ex_convert_to_object_type_string(operand1,
104 : : &local_operand1);
105 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
106 : 0 : goto cleanup;
107 : : }
108 : :
109 : : operand1_type = ACPI_TYPE_STRING;
110 : : break;
111 : : }
112 : :
113 : : /*
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.
119 : : */
120 [ # # # # ]: 0 : switch (operand0_type) {
121 : 0 : case ACPI_TYPE_INTEGER:
122 : :
123 : 0 : status =
124 : 0 : acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
125 : : ACPI_IMPLICIT_CONVERSION);
126 : 0 : break;
127 : :
128 : 0 : case ACPI_TYPE_BUFFER:
129 : :
130 : 0 : status =
131 : 0 : acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
132 : 0 : break;
133 : :
134 : 0 : case ACPI_TYPE_STRING:
135 : :
136 [ # # ]: 0 : switch (operand1_type) {
137 : 0 : case ACPI_TYPE_INTEGER:
138 : : case ACPI_TYPE_STRING:
139 : : case ACPI_TYPE_BUFFER:
140 : :
141 : : /* Other types have already been converted to string */
142 : :
143 : 0 : status =
144 : 0 : acpi_ex_convert_to_string(local_operand1,
145 : : &temp_operand1,
146 : : ACPI_IMPLICIT_CONVERT_HEX);
147 : 0 : break;
148 : :
149 : : default:
150 : :
151 : : status = AE_OK;
152 : : break;
153 : : }
154 : : break;
155 : :
156 : 0 : default:
157 : :
158 : 0 : ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
159 : : operand0->common.type));
160 : 0 : status = AE_AML_INTERNAL;
161 : : }
162 : :
163 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
164 : 0 : goto cleanup;
165 : : }
166 : :
167 : : /* Take care with any newly created operand objects */
168 : :
169 [ # # # # ]: 0 : if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
170 : 0 : acpi_ut_remove_reference(local_operand1);
171 : : }
172 : :
173 : 0 : local_operand1 = temp_operand1;
174 : :
175 : : /*
176 : : * Both operands are now known to be the same object type
177 : : * (Both are Integer, String, or Buffer), and we can now perform
178 : : * the concatenation.
179 : : *
180 : : * There are three cases to handle, as per the ACPI spec:
181 : : *
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
185 : : */
186 [ # # # # ]: 0 : switch (operand0_type) {
187 : 0 : case ACPI_TYPE_INTEGER:
188 : :
189 : : /* Result of two Integers is a Buffer */
190 : : /* Need enough buffer space for two integers */
191 : :
192 : 0 : return_desc = acpi_ut_create_buffer_object((acpi_size)
193 : 0 : ACPI_MUL_2
194 : : (acpi_gbl_integer_byte_width));
195 [ # # ]: 0 : if (!return_desc) {
196 : 0 : status = AE_NO_MEMORY;
197 : 0 : goto cleanup;
198 : : }
199 : :
200 : 0 : buffer = (char *)return_desc->buffer.pointer;
201 : :
202 : : /* Copy the first integer, LSB first */
203 : :
204 : 0 : memcpy(buffer, &operand0->integer.value,
205 : : acpi_gbl_integer_byte_width);
206 : :
207 : : /* Copy the second integer (LSB first) after the first */
208 : :
209 : 0 : memcpy(buffer + acpi_gbl_integer_byte_width,
210 : 0 : &local_operand1->integer.value,
211 : : acpi_gbl_integer_byte_width);
212 : 0 : break;
213 : :
214 : 0 : case ACPI_TYPE_STRING:
215 : :
216 : : /* Result of two Strings is a String */
217 : :
218 : 0 : return_desc = acpi_ut_create_string_object(((acpi_size)
219 : 0 : local_operand0->
220 : 0 : string.length +
221 : : local_operand1->
222 : 0 : string.length));
223 [ # # ]: 0 : if (!return_desc) {
224 : 0 : status = AE_NO_MEMORY;
225 : 0 : goto cleanup;
226 : : }
227 : :
228 : 0 : buffer = return_desc->string.pointer;
229 : :
230 : : /* Concatenate the strings */
231 : :
232 : 0 : strcpy(buffer, local_operand0->string.pointer);
233 : 0 : strcat(buffer, local_operand1->string.pointer);
234 : 0 : break;
235 : :
236 : 0 : case ACPI_TYPE_BUFFER:
237 : :
238 : : /* Result of two Buffers is a Buffer */
239 : :
240 : 0 : return_desc = acpi_ut_create_buffer_object(((acpi_size)
241 : 0 : operand0->buffer.
242 : : length +
243 : : local_operand1->
244 : 0 : buffer.length));
245 [ # # ]: 0 : if (!return_desc) {
246 : 0 : status = AE_NO_MEMORY;
247 : 0 : goto cleanup;
248 : : }
249 : :
250 : 0 : buffer = (char *)return_desc->buffer.pointer;
251 : :
252 : : /* Concatenate the buffers */
253 : :
254 : 0 : memcpy(buffer, operand0->buffer.pointer,
255 : 0 : operand0->buffer.length);
256 : 0 : memcpy(buffer + operand0->buffer.length,
257 : 0 : local_operand1->buffer.pointer,
258 : 0 : local_operand1->buffer.length);
259 : 0 : break;
260 : :
261 : 0 : default:
262 : :
263 : : /* Invalid object type, should not happen here */
264 : :
265 : 0 : ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
266 : : operand0->common.type));
267 : 0 : status = AE_AML_INTERNAL;
268 : 0 : goto cleanup;
269 : : }
270 : :
271 : 0 : *actual_return_desc = return_desc;
272 : :
273 : 0 : cleanup:
274 [ # # ]: 0 : if (local_operand0 != operand0) {
275 : 0 : acpi_ut_remove_reference(local_operand0);
276 : : }
277 : :
278 [ # # ]: 0 : if (local_operand1 != operand1) {
279 : 0 : acpi_ut_remove_reference(local_operand1);
280 : : }
281 : :
282 : 0 : return_ACPI_STATUS(status);
283 : : }
284 : :
285 : : /*******************************************************************************
286 : : *
287 : : * FUNCTION: acpi_ex_convert_to_object_type_string
288 : : *
289 : : * PARAMETERS: obj_desc - Object to be converted
290 : : * return_desc - Where to place the return object
291 : : *
292 : : * RETURN: Status
293 : : *
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.
297 : : *
298 : : ******************************************************************************/
299 : :
300 : : static acpi_status
301 : : acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
302 : : union acpi_operand_object **result_desc)
303 : : {
304 : : union acpi_operand_object *return_desc;
305 : : const char *type_string;
306 : :
307 : : type_string = acpi_ut_get_type_name(obj_desc->common.type);
308 : :
309 : : return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9)); /* 9 For "[ Object]" */
310 : : if (!return_desc) {
311 : : return (AE_NO_MEMORY);
312 : : }
313 : :
314 : : strcpy(return_desc->string.pointer, "[");
315 : : strcat(return_desc->string.pointer, type_string);
316 : : strcat(return_desc->string.pointer, " Object]");
317 : :
318 : : *result_desc = return_desc;
319 : : return (AE_OK);
320 : : }
321 : :
322 : : /*******************************************************************************
323 : : *
324 : : * FUNCTION: acpi_ex_concat_template
325 : : *
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
330 : : *
331 : : * RETURN: Status
332 : : *
333 : : * DESCRIPTION: Concatenate two resource templates
334 : : *
335 : : ******************************************************************************/
336 : :
337 : : acpi_status
338 : 0 : 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)
342 : : {
343 : 0 : acpi_status status;
344 : 0 : union acpi_operand_object *return_desc;
345 : 0 : u8 *new_buf;
346 : 0 : u8 *end_tag;
347 : 0 : acpi_size length0;
348 : 0 : acpi_size length1;
349 : 0 : acpi_size new_length;
350 : :
351 : 0 : ACPI_FUNCTION_TRACE(ex_concat_template);
352 : :
353 : : /*
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
357 : : */
358 : :
359 : : /* Get the length of the first resource template */
360 : :
361 : 0 : status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
362 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
363 : : return_ACPI_STATUS(status);
364 : : }
365 : :
366 : 0 : length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
367 : :
368 : : /* Get the length of the second resource template */
369 : :
370 : 0 : status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
371 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
372 : : return_ACPI_STATUS(status);
373 : : }
374 : :
375 : 0 : length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
376 : :
377 : : /* Combine both lengths, minimum size will be 2 for end_tag */
378 : :
379 : 0 : new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
380 : :
381 : : /* Create a new buffer object for the result (with one end_tag) */
382 : :
383 : 0 : return_desc = acpi_ut_create_buffer_object(new_length);
384 [ # # ]: 0 : if (!return_desc) {
385 : : return_ACPI_STATUS(AE_NO_MEMORY);
386 : : }
387 : :
388 : : /*
389 : : * Copy the templates to the new buffer, 0 first, then 1 follows. One
390 : : * end_tag descriptor is copied from Operand1.
391 : : */
392 : 0 : new_buf = return_desc->buffer.pointer;
393 : 0 : memcpy(new_buf, operand0->buffer.pointer, length0);
394 : 0 : memcpy(new_buf + length0, operand1->buffer.pointer, length1);
395 : :
396 : : /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
397 : :
398 : 0 : new_buf[new_length - 1] = 0;
399 : 0 : new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
400 : :
401 : : /* Return the completed resource template */
402 : :
403 : 0 : *actual_return_desc = return_desc;
404 : 0 : return_ACPI_STATUS(AE_OK);
405 : : }
|