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