xref: /openbmc/linux/drivers/acpi/acpica/exconcat.c (revision 82e6fdd6)
1 /******************************************************************************
2  *
3  * Module Name: exconcat - Concatenate-type AML operators
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 					       ACPI_IMPLICIT_CONVERSION);
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 
343 	return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9));	/* 9 For "[ Object]" */
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,
375 			struct acpi_walk_state *walk_state)
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 }
440