Commit | Line | Data |
---|---|---|
890b090e BM |
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/acpi.h> | |
45 | #include "accommon.h" | |
46 | #include "acinterp.h" | |
47 | #include "amlresrc.h" | |
48 | ||
49 | #define _COMPONENT ACPI_EXECUTER | |
50 | ACPI_MODULE_NAME("exconcat") | |
51 | ||
52 | /* Local Prototypes */ | |
53 | static acpi_status | |
54 | acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc, | |
55 | union acpi_operand_object **result_desc); | |
56 | ||
57 | /******************************************************************************* | |
58 | * | |
59 | * FUNCTION: acpi_ex_do_concatenate | |
60 | * | |
61 | * PARAMETERS: operand0 - First source object | |
62 | * operand1 - Second source object | |
63 | * actual_return_desc - Where to place the return object | |
64 | * walk_state - Current walk state | |
65 | * | |
66 | * RETURN: Status | |
67 | * | |
68 | * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion | |
69 | * rules as necessary. | |
70 | * NOTE: | |
71 | * Per the ACPI spec (up to 6.1), Concatenate only supports Integer, | |
72 | * String, and Buffer objects. However, we support all objects here | |
73 | * as an extension. This improves the usefulness of both Concatenate | |
74 | * and the Printf/Fprintf macros. The extension returns a string | |
75 | * describing the object type for the other objects. | |
76 | * 02/2016. | |
77 | * | |
78 | ******************************************************************************/ | |
79 | ||
80 | acpi_status | |
81 | acpi_ex_do_concatenate(union acpi_operand_object *operand0, | |
82 | union acpi_operand_object *operand1, | |
83 | union acpi_operand_object **actual_return_desc, | |
84 | struct acpi_walk_state *walk_state) | |
85 | { | |
86 | union acpi_operand_object *local_operand0 = operand0; | |
87 | union acpi_operand_object *local_operand1 = operand1; | |
88 | union acpi_operand_object *temp_operand1 = NULL; | |
89 | union acpi_operand_object *return_desc; | |
90 | char *buffer; | |
91 | acpi_object_type operand0_type; | |
92 | acpi_object_type operand1_type; | |
93 | acpi_status status; | |
94 | ||
95 | ACPI_FUNCTION_TRACE(ex_do_concatenate); | |
96 | ||
97 | /* Operand 0 preprocessing */ | |
98 | ||
99 | switch (operand0->common.type) { | |
100 | case ACPI_TYPE_INTEGER: | |
101 | case ACPI_TYPE_STRING: | |
102 | case ACPI_TYPE_BUFFER: | |
103 | ||
104 | operand0_type = operand0->common.type; | |
105 | break; | |
106 | ||
107 | default: | |
108 | ||
109 | /* For all other types, get the "object type" string */ | |
110 | ||
111 | status = | |
112 | acpi_ex_convert_to_object_type_string(operand0, | |
113 | &local_operand0); | |
114 | if (ACPI_FAILURE(status)) { | |
115 | goto cleanup; | |
116 | } | |
117 | ||
118 | operand0_type = ACPI_TYPE_STRING; | |
119 | break; | |
120 | } | |
121 | ||
122 | /* Operand 1 preprocessing */ | |
123 | ||
124 | switch (operand1->common.type) { | |
125 | case ACPI_TYPE_INTEGER: | |
126 | case ACPI_TYPE_STRING: | |
127 | case ACPI_TYPE_BUFFER: | |
128 | ||
129 | operand1_type = operand1->common.type; | |
130 | break; | |
131 | ||
132 | default: | |
133 | ||
134 | /* For all other types, get the "object type" string */ | |
135 | ||
136 | status = | |
137 | acpi_ex_convert_to_object_type_string(operand1, | |
138 | &local_operand1); | |
139 | if (ACPI_FAILURE(status)) { | |
140 | goto cleanup; | |
141 | } | |
142 | ||
143 | operand1_type = ACPI_TYPE_STRING; | |
144 | break; | |
145 | } | |
146 | ||
147 | /* | |
148 | * Convert the second operand if necessary. The first operand (0) | |
149 | * determines the type of the second operand (1) (See the Data Types | |
150 | * section of the ACPI specification). Both object types are | |
151 | * guaranteed to be either Integer/String/Buffer by the operand | |
152 | * resolution mechanism. | |
153 | */ | |
154 | switch (operand0_type) { | |
155 | case ACPI_TYPE_INTEGER: | |
156 | ||
157 | status = | |
158 | acpi_ex_convert_to_integer(local_operand1, &temp_operand1, | |
159 | 16); | |
160 | break; | |
161 | ||
162 | case ACPI_TYPE_BUFFER: | |
163 | ||
164 | status = | |
165 | acpi_ex_convert_to_buffer(local_operand1, &temp_operand1); | |
166 | break; | |
167 | ||
168 | case ACPI_TYPE_STRING: | |
169 | ||
170 | switch (operand1_type) { | |
171 | case ACPI_TYPE_INTEGER: | |
172 | case ACPI_TYPE_STRING: | |
173 | case ACPI_TYPE_BUFFER: | |
174 | ||
175 | /* Other types have already been converted to string */ | |
176 | ||
177 | status = | |
178 | acpi_ex_convert_to_string(local_operand1, | |
179 | &temp_operand1, | |
180 | ACPI_IMPLICIT_CONVERT_HEX); | |
181 | break; | |
182 | ||
183 | default: | |
184 | ||
185 | status = AE_OK; | |
186 | break; | |
187 | } | |
188 | break; | |
189 | ||
190 | default: | |
191 | ||
192 | ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", | |
193 | operand0->common.type)); | |
194 | status = AE_AML_INTERNAL; | |
195 | } | |
196 | ||
197 | if (ACPI_FAILURE(status)) { | |
198 | goto cleanup; | |
199 | } | |
200 | ||
201 | /* Take care with any newly created operand objects */ | |
202 | ||
203 | if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) { | |
204 | acpi_ut_remove_reference(local_operand1); | |
205 | } | |
206 | ||
207 | local_operand1 = temp_operand1; | |
208 | ||
209 | /* | |
210 | * Both operands are now known to be the same object type | |
211 | * (Both are Integer, String, or Buffer), and we can now perform | |
212 | * the concatenation. | |
213 | * | |
214 | * There are three cases to handle, as per the ACPI spec: | |
215 | * | |
216 | * 1) Two Integers concatenated to produce a new Buffer | |
217 | * 2) Two Strings concatenated to produce a new String | |
218 | * 3) Two Buffers concatenated to produce a new Buffer | |
219 | */ | |
220 | switch (operand0_type) { | |
221 | case ACPI_TYPE_INTEGER: | |
222 | ||
223 | /* Result of two Integers is a Buffer */ | |
224 | /* Need enough buffer space for two integers */ | |
225 | ||
226 | return_desc = acpi_ut_create_buffer_object((acpi_size) | |
227 | ACPI_MUL_2 | |
228 | (acpi_gbl_integer_byte_width)); | |
229 | if (!return_desc) { | |
230 | status = AE_NO_MEMORY; | |
231 | goto cleanup; | |
232 | } | |
233 | ||
234 | buffer = (char *)return_desc->buffer.pointer; | |
235 | ||
236 | /* Copy the first integer, LSB first */ | |
237 | ||
238 | memcpy(buffer, &operand0->integer.value, | |
239 | acpi_gbl_integer_byte_width); | |
240 | ||
241 | /* Copy the second integer (LSB first) after the first */ | |
242 | ||
243 | memcpy(buffer + acpi_gbl_integer_byte_width, | |
244 | &local_operand1->integer.value, | |
245 | acpi_gbl_integer_byte_width); | |
246 | break; | |
247 | ||
248 | case ACPI_TYPE_STRING: | |
249 | ||
250 | /* Result of two Strings is a String */ | |
251 | ||
252 | return_desc = acpi_ut_create_string_object(((acpi_size) | |
253 | local_operand0-> | |
254 | string.length + | |
255 | local_operand1-> | |
256 | string.length)); | |
257 | if (!return_desc) { | |
258 | status = AE_NO_MEMORY; | |
259 | goto cleanup; | |
260 | } | |
261 | ||
262 | buffer = return_desc->string.pointer; | |
263 | ||
264 | /* Concatenate the strings */ | |
265 | ||
266 | strcpy(buffer, local_operand0->string.pointer); | |
267 | strcat(buffer, local_operand1->string.pointer); | |
268 | break; | |
269 | ||
270 | case ACPI_TYPE_BUFFER: | |
271 | ||
272 | /* Result of two Buffers is a Buffer */ | |
273 | ||
274 | return_desc = acpi_ut_create_buffer_object(((acpi_size) | |
275 | operand0->buffer. | |
276 | length + | |
277 | local_operand1-> | |
278 | buffer.length)); | |
279 | if (!return_desc) { | |
280 | status = AE_NO_MEMORY; | |
281 | goto cleanup; | |
282 | } | |
283 | ||
284 | buffer = (char *)return_desc->buffer.pointer; | |
285 | ||
286 | /* Concatenate the buffers */ | |
287 | ||
288 | memcpy(buffer, operand0->buffer.pointer, | |
289 | operand0->buffer.length); | |
290 | memcpy(buffer + operand0->buffer.length, | |
291 | local_operand1->buffer.pointer, | |
292 | local_operand1->buffer.length); | |
293 | break; | |
294 | ||
295 | default: | |
296 | ||
297 | /* Invalid object type, should not happen here */ | |
298 | ||
299 | ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", | |
300 | operand0->common.type)); | |
301 | status = AE_AML_INTERNAL; | |
302 | goto cleanup; | |
303 | } | |
304 | ||
305 | *actual_return_desc = return_desc; | |
306 | ||
307 | cleanup: | |
308 | if (local_operand0 != operand0) { | |
309 | acpi_ut_remove_reference(local_operand0); | |
310 | } | |
311 | ||
312 | if (local_operand1 != operand1) { | |
313 | acpi_ut_remove_reference(local_operand1); | |
314 | } | |
315 | ||
316 | return_ACPI_STATUS(status); | |
317 | } | |
318 | ||
319 | /******************************************************************************* | |
320 | * | |
321 | * FUNCTION: acpi_ex_convert_to_object_type_string | |
322 | * | |
323 | * PARAMETERS: obj_desc - Object to be converted | |
324 | * return_desc - Where to place the return object | |
325 | * | |
326 | * RETURN: Status | |
327 | * | |
328 | * DESCRIPTION: Convert an object of arbitrary type to a string object that | |
329 | * contains the namestring for the object. Used for the | |
330 | * concatenate operator. | |
331 | * | |
332 | ******************************************************************************/ | |
333 | ||
334 | static acpi_status | |
335 | acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc, | |
336 | union acpi_operand_object **result_desc) | |
337 | { | |
338 | union acpi_operand_object *return_desc; | |
339 | const char *type_string; | |
340 | ||
341 | type_string = acpi_ut_get_type_name(obj_desc->common.type); | |
342 | ||
f5c1e1c5 | 343 | return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9)); /* 9 For "[ Object]" */ |
890b090e BM |
344 | if (!return_desc) { |
345 | return (AE_NO_MEMORY); | |
346 | } | |
347 | ||
348 | strcpy(return_desc->string.pointer, "["); | |
349 | strcat(return_desc->string.pointer, type_string); | |
350 | strcat(return_desc->string.pointer, " Object]"); | |
351 | ||
352 | *result_desc = return_desc; | |
353 | return (AE_OK); | |
354 | } | |
355 | ||
356 | /******************************************************************************* | |
357 | * | |
358 | * FUNCTION: acpi_ex_concat_template | |
359 | * | |
360 | * PARAMETERS: operand0 - First source object | |
361 | * operand1 - Second source object | |
362 | * actual_return_desc - Where to place the return object | |
363 | * walk_state - Current walk state | |
364 | * | |
365 | * RETURN: Status | |
366 | * | |
367 | * DESCRIPTION: Concatenate two resource templates | |
368 | * | |
369 | ******************************************************************************/ | |
370 | ||
371 | acpi_status | |
372 | acpi_ex_concat_template(union acpi_operand_object *operand0, | |
373 | union acpi_operand_object *operand1, | |
374 | union acpi_operand_object **actual_return_desc, | |
f5c1e1c5 | 375 | struct acpi_walk_state *walk_state) |
890b090e BM |
376 | { |
377 | acpi_status status; | |
378 | union acpi_operand_object *return_desc; | |
379 | u8 *new_buf; | |
380 | u8 *end_tag; | |
381 | acpi_size length0; | |
382 | acpi_size length1; | |
383 | acpi_size new_length; | |
384 | ||
385 | ACPI_FUNCTION_TRACE(ex_concat_template); | |
386 | ||
387 | /* | |
388 | * Find the end_tag descriptor in each resource template. | |
389 | * Note1: returned pointers point TO the end_tag, not past it. | |
390 | * Note2: zero-length buffers are allowed; treated like one end_tag | |
391 | */ | |
392 | ||
393 | /* Get the length of the first resource template */ | |
394 | ||
395 | status = acpi_ut_get_resource_end_tag(operand0, &end_tag); | |
396 | if (ACPI_FAILURE(status)) { | |
397 | return_ACPI_STATUS(status); | |
398 | } | |
399 | ||
400 | length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer); | |
401 | ||
402 | /* Get the length of the second resource template */ | |
403 | ||
404 | status = acpi_ut_get_resource_end_tag(operand1, &end_tag); | |
405 | if (ACPI_FAILURE(status)) { | |
406 | return_ACPI_STATUS(status); | |
407 | } | |
408 | ||
409 | length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer); | |
410 | ||
411 | /* Combine both lengths, minimum size will be 2 for end_tag */ | |
412 | ||
413 | new_length = length0 + length1 + sizeof(struct aml_resource_end_tag); | |
414 | ||
415 | /* Create a new buffer object for the result (with one end_tag) */ | |
416 | ||
417 | return_desc = acpi_ut_create_buffer_object(new_length); | |
418 | if (!return_desc) { | |
419 | return_ACPI_STATUS(AE_NO_MEMORY); | |
420 | } | |
421 | ||
422 | /* | |
423 | * Copy the templates to the new buffer, 0 first, then 1 follows. One | |
424 | * end_tag descriptor is copied from Operand1. | |
425 | */ | |
426 | new_buf = return_desc->buffer.pointer; | |
427 | memcpy(new_buf, operand0->buffer.pointer, length0); | |
428 | memcpy(new_buf + length0, operand1->buffer.pointer, length1); | |
429 | ||
430 | /* Insert end_tag and set the checksum to zero, means "ignore checksum" */ | |
431 | ||
432 | new_buf[new_length - 1] = 0; | |
433 | new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1; | |
434 | ||
435 | /* Return the completed resource template */ | |
436 | ||
437 | *actual_return_desc = return_desc; | |
438 | return_ACPI_STATUS(AE_OK); | |
439 | } |