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
16ACPI_MODULE_NAME("exconcat")
17
18/* Local Prototypes */
19static acpi_status
20acpi_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
46acpi_status
47acpi_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
273cleanup:
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
300static acpi_status
301acpi_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
337acpi_status
338acpi_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