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 - 2023, 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
acpi_ex_do_concatenate(union acpi_operand_object * operand0,union acpi_operand_object * operand1,union acpi_operand_object ** actual_return_desc,struct acpi_walk_state * walk_state)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
acpi_ex_convert_to_object_type_string(union acpi_operand_object * obj_desc,union acpi_operand_object ** result_desc)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
acpi_ex_concat_template(union acpi_operand_object * operand0,union acpi_operand_object * operand1,union acpi_operand_object ** actual_return_desc,struct acpi_walk_state * walk_state)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 }
406