GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / acpi / acpica / exconcat.c
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 - 2018, 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 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         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;
56         char *buffer;
57         acpi_object_type operand0_type;
58         acpi_object_type operand1_type;
59         acpi_status status;
60
61         ACPI_FUNCTION_TRACE(ex_do_concatenate);
62
63         /* Operand 0 preprocessing */
64
65         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         default:
74
75                 /* For all other types, get the "object type" string */
76
77                 status =
78                     acpi_ex_convert_to_object_type_string(operand0,
79                                                           &local_operand0);
80                 if (ACPI_FAILURE(status)) {
81                         goto cleanup;
82                 }
83
84                 operand0_type = ACPI_TYPE_STRING;
85                 break;
86         }
87
88         /* Operand 1 preprocessing */
89
90         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         default:
99
100                 /* For all other types, get the "object type" string */
101
102                 status =
103                     acpi_ex_convert_to_object_type_string(operand1,
104                                                           &local_operand1);
105                 if (ACPI_FAILURE(status)) {
106                         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         switch (operand0_type) {
121         case ACPI_TYPE_INTEGER:
122
123                 status =
124                     acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
125                                                ACPI_IMPLICIT_CONVERSION);
126                 break;
127
128         case ACPI_TYPE_BUFFER:
129
130                 status =
131                     acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
132                 break;
133
134         case ACPI_TYPE_STRING:
135
136                 switch (operand1_type) {
137                 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                         status =
144                             acpi_ex_convert_to_string(local_operand1,
145                                                       &temp_operand1,
146                                                       ACPI_IMPLICIT_CONVERT_HEX);
147                         break;
148
149                 default:
150
151                         status = AE_OK;
152                         break;
153                 }
154                 break;
155
156         default:
157
158                 ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
159                             operand0->common.type));
160                 status = AE_AML_INTERNAL;
161         }
162
163         if (ACPI_FAILURE(status)) {
164                 goto cleanup;
165         }
166
167         /* Take care with any newly created operand objects */
168
169         if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
170                 acpi_ut_remove_reference(local_operand1);
171         }
172
173         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         switch (operand0_type) {
187         case ACPI_TYPE_INTEGER:
188
189                 /* Result of two Integers is a Buffer */
190                 /* Need enough buffer space for two integers */
191
192                 return_desc = acpi_ut_create_buffer_object((acpi_size)
193                                                            ACPI_MUL_2
194                                                            (acpi_gbl_integer_byte_width));
195                 if (!return_desc) {
196                         status = AE_NO_MEMORY;
197                         goto cleanup;
198                 }
199
200                 buffer = (char *)return_desc->buffer.pointer;
201
202                 /* Copy the first integer, LSB first */
203
204                 memcpy(buffer, &operand0->integer.value,
205                        acpi_gbl_integer_byte_width);
206
207                 /* Copy the second integer (LSB first) after the first */
208
209                 memcpy(buffer + acpi_gbl_integer_byte_width,
210                        &local_operand1->integer.value,
211                        acpi_gbl_integer_byte_width);
212                 break;
213
214         case ACPI_TYPE_STRING:
215
216                 /* Result of two Strings is a String */
217
218                 return_desc = acpi_ut_create_string_object(((acpi_size)
219                                                             local_operand0->
220                                                             string.length +
221                                                             local_operand1->
222                                                             string.length));
223                 if (!return_desc) {
224                         status = AE_NO_MEMORY;
225                         goto cleanup;
226                 }
227
228                 buffer = return_desc->string.pointer;
229
230                 /* Concatenate the strings */
231
232                 strcpy(buffer, local_operand0->string.pointer);
233                 strcat(buffer, local_operand1->string.pointer);
234                 break;
235
236         case ACPI_TYPE_BUFFER:
237
238                 /* Result of two Buffers is a Buffer */
239
240                 return_desc = acpi_ut_create_buffer_object(((acpi_size)
241                                                             operand0->buffer.
242                                                             length +
243                                                             local_operand1->
244                                                             buffer.length));
245                 if (!return_desc) {
246                         status = AE_NO_MEMORY;
247                         goto cleanup;
248                 }
249
250                 buffer = (char *)return_desc->buffer.pointer;
251
252                 /* Concatenate the buffers */
253
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);
259                 break;
260
261         default:
262
263                 /* Invalid object type, should not happen here */
264
265                 ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
266                             operand0->common.type));
267                 status = AE_AML_INTERNAL;
268                 goto cleanup;
269         }
270
271         *actual_return_desc = return_desc;
272
273 cleanup:
274         if (local_operand0 != operand0) {
275                 acpi_ut_remove_reference(local_operand0);
276         }
277
278         if (local_operand1 != operand1) {
279                 acpi_ut_remove_reference(local_operand1);
280         }
281
282         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 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         acpi_status status;
344         union acpi_operand_object *return_desc;
345         u8 *new_buf;
346         u8 *end_tag;
347         acpi_size length0;
348         acpi_size length1;
349         acpi_size new_length;
350
351         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         status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
362         if (ACPI_FAILURE(status)) {
363                 return_ACPI_STATUS(status);
364         }
365
366         length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
367
368         /* Get the length of the second resource template */
369
370         status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
371         if (ACPI_FAILURE(status)) {
372                 return_ACPI_STATUS(status);
373         }
374
375         length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
376
377         /* Combine both lengths, minimum size will be 2 for end_tag */
378
379         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         return_desc = acpi_ut_create_buffer_object(new_length);
384         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         new_buf = return_desc->buffer.pointer;
393         memcpy(new_buf, operand0->buffer.pointer, length0);
394         memcpy(new_buf + length0, operand1->buffer.pointer, length1);
395
396         /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
397
398         new_buf[new_length - 1] = 0;
399         new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
400
401         /* Return the completed resource template */
402
403         *actual_return_desc = return_desc;
404         return_ACPI_STATUS(AE_OK);
405 }