xref: /openbmc/linux/drivers/acpi/acpica/exmisc.c (revision 95b482a8d31116f3f5c2a5089569393234d06385)
1*95b482a8SLen Brown 
2*95b482a8SLen Brown /******************************************************************************
3*95b482a8SLen Brown  *
4*95b482a8SLen Brown  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
5*95b482a8SLen Brown  *
6*95b482a8SLen Brown  *****************************************************************************/
7*95b482a8SLen Brown 
8*95b482a8SLen Brown /*
9*95b482a8SLen Brown  * Copyright (C) 2000 - 2008, Intel Corp.
10*95b482a8SLen Brown  * All rights reserved.
11*95b482a8SLen Brown  *
12*95b482a8SLen Brown  * Redistribution and use in source and binary forms, with or without
13*95b482a8SLen Brown  * modification, are permitted provided that the following conditions
14*95b482a8SLen Brown  * are met:
15*95b482a8SLen Brown  * 1. Redistributions of source code must retain the above copyright
16*95b482a8SLen Brown  *    notice, this list of conditions, and the following disclaimer,
17*95b482a8SLen Brown  *    without modification.
18*95b482a8SLen Brown  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19*95b482a8SLen Brown  *    substantially similar to the "NO WARRANTY" disclaimer below
20*95b482a8SLen Brown  *    ("Disclaimer") and any redistribution must be conditioned upon
21*95b482a8SLen Brown  *    including a substantially similar Disclaimer requirement for further
22*95b482a8SLen Brown  *    binary redistribution.
23*95b482a8SLen Brown  * 3. Neither the names of the above-listed copyright holders nor the names
24*95b482a8SLen Brown  *    of any contributors may be used to endorse or promote products derived
25*95b482a8SLen Brown  *    from this software without specific prior written permission.
26*95b482a8SLen Brown  *
27*95b482a8SLen Brown  * Alternatively, this software may be distributed under the terms of the
28*95b482a8SLen Brown  * GNU General Public License ("GPL") version 2 as published by the Free
29*95b482a8SLen Brown  * Software Foundation.
30*95b482a8SLen Brown  *
31*95b482a8SLen Brown  * NO WARRANTY
32*95b482a8SLen Brown  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33*95b482a8SLen Brown  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34*95b482a8SLen Brown  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35*95b482a8SLen Brown  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36*95b482a8SLen Brown  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37*95b482a8SLen Brown  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38*95b482a8SLen Brown  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39*95b482a8SLen Brown  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40*95b482a8SLen Brown  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41*95b482a8SLen Brown  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42*95b482a8SLen Brown  * POSSIBILITY OF SUCH DAMAGES.
43*95b482a8SLen Brown  */
44*95b482a8SLen Brown 
45*95b482a8SLen Brown #include <acpi/acpi.h>
46*95b482a8SLen Brown #include <acpi/accommon.h>
47*95b482a8SLen Brown #include <acpi/acinterp.h>
48*95b482a8SLen Brown #include <acpi/amlcode.h>
49*95b482a8SLen Brown #include <acpi/amlresrc.h>
50*95b482a8SLen Brown 
51*95b482a8SLen Brown #define _COMPONENT          ACPI_EXECUTER
52*95b482a8SLen Brown ACPI_MODULE_NAME("exmisc")
53*95b482a8SLen Brown 
54*95b482a8SLen Brown /*******************************************************************************
55*95b482a8SLen Brown  *
56*95b482a8SLen Brown  * FUNCTION:    acpi_ex_get_object_reference
57*95b482a8SLen Brown  *
58*95b482a8SLen Brown  * PARAMETERS:  obj_desc            - Create a reference to this object
59*95b482a8SLen Brown  *              return_desc         - Where to store the reference
60*95b482a8SLen Brown  *              walk_state          - Current state
61*95b482a8SLen Brown  *
62*95b482a8SLen Brown  * RETURN:      Status
63*95b482a8SLen Brown  *
64*95b482a8SLen Brown  * DESCRIPTION: Obtain and return a "reference" to the target object
65*95b482a8SLen Brown  *              Common code for the ref_of_op and the cond_ref_of_op.
66*95b482a8SLen Brown  *
67*95b482a8SLen Brown  ******************************************************************************/
68*95b482a8SLen Brown acpi_status
69*95b482a8SLen Brown acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
70*95b482a8SLen Brown 			     union acpi_operand_object **return_desc,
71*95b482a8SLen Brown 			     struct acpi_walk_state *walk_state)
72*95b482a8SLen Brown {
73*95b482a8SLen Brown 	union acpi_operand_object *reference_obj;
74*95b482a8SLen Brown 	union acpi_operand_object *referenced_obj;
75*95b482a8SLen Brown 
76*95b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
77*95b482a8SLen Brown 
78*95b482a8SLen Brown 	*return_desc = NULL;
79*95b482a8SLen Brown 
80*95b482a8SLen Brown 	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
81*95b482a8SLen Brown 	case ACPI_DESC_TYPE_OPERAND:
82*95b482a8SLen Brown 
83*95b482a8SLen Brown 		if (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_LOCAL_REFERENCE) {
84*95b482a8SLen Brown 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
85*95b482a8SLen Brown 		}
86*95b482a8SLen Brown 
87*95b482a8SLen Brown 		/*
88*95b482a8SLen Brown 		 * Must be a reference to a Local or Arg
89*95b482a8SLen Brown 		 */
90*95b482a8SLen Brown 		switch (obj_desc->reference.class) {
91*95b482a8SLen Brown 		case ACPI_REFCLASS_LOCAL:
92*95b482a8SLen Brown 		case ACPI_REFCLASS_ARG:
93*95b482a8SLen Brown 		case ACPI_REFCLASS_DEBUG:
94*95b482a8SLen Brown 
95*95b482a8SLen Brown 			/* The referenced object is the pseudo-node for the local/arg */
96*95b482a8SLen Brown 
97*95b482a8SLen Brown 			referenced_obj = obj_desc->reference.object;
98*95b482a8SLen Brown 			break;
99*95b482a8SLen Brown 
100*95b482a8SLen Brown 		default:
101*95b482a8SLen Brown 
102*95b482a8SLen Brown 			ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
103*95b482a8SLen Brown 				    obj_desc->reference.class));
104*95b482a8SLen Brown 			return_ACPI_STATUS(AE_AML_INTERNAL);
105*95b482a8SLen Brown 		}
106*95b482a8SLen Brown 		break;
107*95b482a8SLen Brown 
108*95b482a8SLen Brown 	case ACPI_DESC_TYPE_NAMED:
109*95b482a8SLen Brown 
110*95b482a8SLen Brown 		/*
111*95b482a8SLen Brown 		 * A named reference that has already been resolved to a Node
112*95b482a8SLen Brown 		 */
113*95b482a8SLen Brown 		referenced_obj = obj_desc;
114*95b482a8SLen Brown 		break;
115*95b482a8SLen Brown 
116*95b482a8SLen Brown 	default:
117*95b482a8SLen Brown 
118*95b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid descriptor type %X",
119*95b482a8SLen Brown 			    ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
120*95b482a8SLen Brown 		return_ACPI_STATUS(AE_TYPE);
121*95b482a8SLen Brown 	}
122*95b482a8SLen Brown 
123*95b482a8SLen Brown 	/* Create a new reference object */
124*95b482a8SLen Brown 
125*95b482a8SLen Brown 	reference_obj =
126*95b482a8SLen Brown 	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
127*95b482a8SLen Brown 	if (!reference_obj) {
128*95b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
129*95b482a8SLen Brown 	}
130*95b482a8SLen Brown 
131*95b482a8SLen Brown 	reference_obj->reference.class = ACPI_REFCLASS_REFOF;
132*95b482a8SLen Brown 	reference_obj->reference.object = referenced_obj;
133*95b482a8SLen Brown 	*return_desc = reference_obj;
134*95b482a8SLen Brown 
135*95b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
136*95b482a8SLen Brown 			  "Object %p Type [%s], returning Reference %p\n",
137*95b482a8SLen Brown 			  obj_desc, acpi_ut_get_object_type_name(obj_desc),
138*95b482a8SLen Brown 			  *return_desc));
139*95b482a8SLen Brown 
140*95b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
141*95b482a8SLen Brown }
142*95b482a8SLen Brown 
143*95b482a8SLen Brown /*******************************************************************************
144*95b482a8SLen Brown  *
145*95b482a8SLen Brown  * FUNCTION:    acpi_ex_concat_template
146*95b482a8SLen Brown  *
147*95b482a8SLen Brown  * PARAMETERS:  Operand0            - First source object
148*95b482a8SLen Brown  *              Operand1            - Second source object
149*95b482a8SLen Brown  *              actual_return_desc  - Where to place the return object
150*95b482a8SLen Brown  *              walk_state          - Current walk state
151*95b482a8SLen Brown  *
152*95b482a8SLen Brown  * RETURN:      Status
153*95b482a8SLen Brown  *
154*95b482a8SLen Brown  * DESCRIPTION: Concatenate two resource templates
155*95b482a8SLen Brown  *
156*95b482a8SLen Brown  ******************************************************************************/
157*95b482a8SLen Brown 
158*95b482a8SLen Brown acpi_status
159*95b482a8SLen Brown acpi_ex_concat_template(union acpi_operand_object *operand0,
160*95b482a8SLen Brown 			union acpi_operand_object *operand1,
161*95b482a8SLen Brown 			union acpi_operand_object **actual_return_desc,
162*95b482a8SLen Brown 			struct acpi_walk_state *walk_state)
163*95b482a8SLen Brown {
164*95b482a8SLen Brown 	acpi_status status;
165*95b482a8SLen Brown 	union acpi_operand_object *return_desc;
166*95b482a8SLen Brown 	u8 *new_buf;
167*95b482a8SLen Brown 	u8 *end_tag;
168*95b482a8SLen Brown 	acpi_size length0;
169*95b482a8SLen Brown 	acpi_size length1;
170*95b482a8SLen Brown 	acpi_size new_length;
171*95b482a8SLen Brown 
172*95b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_concat_template);
173*95b482a8SLen Brown 
174*95b482a8SLen Brown 	/*
175*95b482a8SLen Brown 	 * Find the end_tag descriptor in each resource template.
176*95b482a8SLen Brown 	 * Note1: returned pointers point TO the end_tag, not past it.
177*95b482a8SLen Brown 	 * Note2: zero-length buffers are allowed; treated like one end_tag
178*95b482a8SLen Brown 	 */
179*95b482a8SLen Brown 
180*95b482a8SLen Brown 	/* Get the length of the first resource template */
181*95b482a8SLen Brown 
182*95b482a8SLen Brown 	status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
183*95b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
184*95b482a8SLen Brown 		return_ACPI_STATUS(status);
185*95b482a8SLen Brown 	}
186*95b482a8SLen Brown 
187*95b482a8SLen Brown 	length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
188*95b482a8SLen Brown 
189*95b482a8SLen Brown 	/* Get the length of the second resource template */
190*95b482a8SLen Brown 
191*95b482a8SLen Brown 	status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
192*95b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
193*95b482a8SLen Brown 		return_ACPI_STATUS(status);
194*95b482a8SLen Brown 	}
195*95b482a8SLen Brown 
196*95b482a8SLen Brown 	length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
197*95b482a8SLen Brown 
198*95b482a8SLen Brown 	/* Combine both lengths, minimum size will be 2 for end_tag */
199*95b482a8SLen Brown 
200*95b482a8SLen Brown 	new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
201*95b482a8SLen Brown 
202*95b482a8SLen Brown 	/* Create a new buffer object for the result (with one end_tag) */
203*95b482a8SLen Brown 
204*95b482a8SLen Brown 	return_desc = acpi_ut_create_buffer_object(new_length);
205*95b482a8SLen Brown 	if (!return_desc) {
206*95b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
207*95b482a8SLen Brown 	}
208*95b482a8SLen Brown 
209*95b482a8SLen Brown 	/*
210*95b482a8SLen Brown 	 * Copy the templates to the new buffer, 0 first, then 1 follows. One
211*95b482a8SLen Brown 	 * end_tag descriptor is copied from Operand1.
212*95b482a8SLen Brown 	 */
213*95b482a8SLen Brown 	new_buf = return_desc->buffer.pointer;
214*95b482a8SLen Brown 	ACPI_MEMCPY(new_buf, operand0->buffer.pointer, length0);
215*95b482a8SLen Brown 	ACPI_MEMCPY(new_buf + length0, operand1->buffer.pointer, length1);
216*95b482a8SLen Brown 
217*95b482a8SLen Brown 	/* Insert end_tag and set the checksum to zero, means "ignore checksum" */
218*95b482a8SLen Brown 
219*95b482a8SLen Brown 	new_buf[new_length - 1] = 0;
220*95b482a8SLen Brown 	new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
221*95b482a8SLen Brown 
222*95b482a8SLen Brown 	/* Return the completed resource template */
223*95b482a8SLen Brown 
224*95b482a8SLen Brown 	*actual_return_desc = return_desc;
225*95b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
226*95b482a8SLen Brown }
227*95b482a8SLen Brown 
228*95b482a8SLen Brown /*******************************************************************************
229*95b482a8SLen Brown  *
230*95b482a8SLen Brown  * FUNCTION:    acpi_ex_do_concatenate
231*95b482a8SLen Brown  *
232*95b482a8SLen Brown  * PARAMETERS:  Operand0            - First source object
233*95b482a8SLen Brown  *              Operand1            - Second source object
234*95b482a8SLen Brown  *              actual_return_desc  - Where to place the return object
235*95b482a8SLen Brown  *              walk_state          - Current walk state
236*95b482a8SLen Brown  *
237*95b482a8SLen Brown  * RETURN:      Status
238*95b482a8SLen Brown  *
239*95b482a8SLen Brown  * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
240*95b482a8SLen Brown  *
241*95b482a8SLen Brown  ******************************************************************************/
242*95b482a8SLen Brown 
243*95b482a8SLen Brown acpi_status
244*95b482a8SLen Brown acpi_ex_do_concatenate(union acpi_operand_object *operand0,
245*95b482a8SLen Brown 		       union acpi_operand_object *operand1,
246*95b482a8SLen Brown 		       union acpi_operand_object **actual_return_desc,
247*95b482a8SLen Brown 		       struct acpi_walk_state *walk_state)
248*95b482a8SLen Brown {
249*95b482a8SLen Brown 	union acpi_operand_object *local_operand1 = operand1;
250*95b482a8SLen Brown 	union acpi_operand_object *return_desc;
251*95b482a8SLen Brown 	char *new_buf;
252*95b482a8SLen Brown 	acpi_status status;
253*95b482a8SLen Brown 
254*95b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_do_concatenate);
255*95b482a8SLen Brown 
256*95b482a8SLen Brown 	/*
257*95b482a8SLen Brown 	 * Convert the second operand if necessary.  The first operand
258*95b482a8SLen Brown 	 * determines the type of the second operand, (See the Data Types
259*95b482a8SLen Brown 	 * section of the ACPI specification.)  Both object types are
260*95b482a8SLen Brown 	 * guaranteed to be either Integer/String/Buffer by the operand
261*95b482a8SLen Brown 	 * resolution mechanism.
262*95b482a8SLen Brown 	 */
263*95b482a8SLen Brown 	switch (ACPI_GET_OBJECT_TYPE(operand0)) {
264*95b482a8SLen Brown 	case ACPI_TYPE_INTEGER:
265*95b482a8SLen Brown 		status =
266*95b482a8SLen Brown 		    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
267*95b482a8SLen Brown 		break;
268*95b482a8SLen Brown 
269*95b482a8SLen Brown 	case ACPI_TYPE_STRING:
270*95b482a8SLen Brown 		status = acpi_ex_convert_to_string(operand1, &local_operand1,
271*95b482a8SLen Brown 						   ACPI_IMPLICIT_CONVERT_HEX);
272*95b482a8SLen Brown 		break;
273*95b482a8SLen Brown 
274*95b482a8SLen Brown 	case ACPI_TYPE_BUFFER:
275*95b482a8SLen Brown 		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
276*95b482a8SLen Brown 		break;
277*95b482a8SLen Brown 
278*95b482a8SLen Brown 	default:
279*95b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid object type: %X",
280*95b482a8SLen Brown 			    ACPI_GET_OBJECT_TYPE(operand0)));
281*95b482a8SLen Brown 		status = AE_AML_INTERNAL;
282*95b482a8SLen Brown 	}
283*95b482a8SLen Brown 
284*95b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
285*95b482a8SLen Brown 		goto cleanup;
286*95b482a8SLen Brown 	}
287*95b482a8SLen Brown 
288*95b482a8SLen Brown 	/*
289*95b482a8SLen Brown 	 * Both operands are now known to be the same object type
290*95b482a8SLen Brown 	 * (Both are Integer, String, or Buffer), and we can now perform the
291*95b482a8SLen Brown 	 * concatenation.
292*95b482a8SLen Brown 	 */
293*95b482a8SLen Brown 
294*95b482a8SLen Brown 	/*
295*95b482a8SLen Brown 	 * There are three cases to handle:
296*95b482a8SLen Brown 	 *
297*95b482a8SLen Brown 	 * 1) Two Integers concatenated to produce a new Buffer
298*95b482a8SLen Brown 	 * 2) Two Strings concatenated to produce a new String
299*95b482a8SLen Brown 	 * 3) Two Buffers concatenated to produce a new Buffer
300*95b482a8SLen Brown 	 */
301*95b482a8SLen Brown 	switch (ACPI_GET_OBJECT_TYPE(operand0)) {
302*95b482a8SLen Brown 	case ACPI_TYPE_INTEGER:
303*95b482a8SLen Brown 
304*95b482a8SLen Brown 		/* Result of two Integers is a Buffer */
305*95b482a8SLen Brown 		/* Need enough buffer space for two integers */
306*95b482a8SLen Brown 
307*95b482a8SLen Brown 		return_desc = acpi_ut_create_buffer_object((acpi_size)
308*95b482a8SLen Brown 							   ACPI_MUL_2
309*95b482a8SLen Brown 							   (acpi_gbl_integer_byte_width));
310*95b482a8SLen Brown 		if (!return_desc) {
311*95b482a8SLen Brown 			status = AE_NO_MEMORY;
312*95b482a8SLen Brown 			goto cleanup;
313*95b482a8SLen Brown 		}
314*95b482a8SLen Brown 
315*95b482a8SLen Brown 		new_buf = (char *)return_desc->buffer.pointer;
316*95b482a8SLen Brown 
317*95b482a8SLen Brown 		/* Copy the first integer, LSB first */
318*95b482a8SLen Brown 
319*95b482a8SLen Brown 		ACPI_MEMCPY(new_buf, &operand0->integer.value,
320*95b482a8SLen Brown 			    acpi_gbl_integer_byte_width);
321*95b482a8SLen Brown 
322*95b482a8SLen Brown 		/* Copy the second integer (LSB first) after the first */
323*95b482a8SLen Brown 
324*95b482a8SLen Brown 		ACPI_MEMCPY(new_buf + acpi_gbl_integer_byte_width,
325*95b482a8SLen Brown 			    &local_operand1->integer.value,
326*95b482a8SLen Brown 			    acpi_gbl_integer_byte_width);
327*95b482a8SLen Brown 		break;
328*95b482a8SLen Brown 
329*95b482a8SLen Brown 	case ACPI_TYPE_STRING:
330*95b482a8SLen Brown 
331*95b482a8SLen Brown 		/* Result of two Strings is a String */
332*95b482a8SLen Brown 
333*95b482a8SLen Brown 		return_desc = acpi_ut_create_string_object(((acpi_size)
334*95b482a8SLen Brown 							    operand0->string.
335*95b482a8SLen Brown 							    length +
336*95b482a8SLen Brown 							    local_operand1->
337*95b482a8SLen Brown 							    string.length));
338*95b482a8SLen Brown 		if (!return_desc) {
339*95b482a8SLen Brown 			status = AE_NO_MEMORY;
340*95b482a8SLen Brown 			goto cleanup;
341*95b482a8SLen Brown 		}
342*95b482a8SLen Brown 
343*95b482a8SLen Brown 		new_buf = return_desc->string.pointer;
344*95b482a8SLen Brown 
345*95b482a8SLen Brown 		/* Concatenate the strings */
346*95b482a8SLen Brown 
347*95b482a8SLen Brown 		ACPI_STRCPY(new_buf, operand0->string.pointer);
348*95b482a8SLen Brown 		ACPI_STRCPY(new_buf + operand0->string.length,
349*95b482a8SLen Brown 			    local_operand1->string.pointer);
350*95b482a8SLen Brown 		break;
351*95b482a8SLen Brown 
352*95b482a8SLen Brown 	case ACPI_TYPE_BUFFER:
353*95b482a8SLen Brown 
354*95b482a8SLen Brown 		/* Result of two Buffers is a Buffer */
355*95b482a8SLen Brown 
356*95b482a8SLen Brown 		return_desc = acpi_ut_create_buffer_object(((acpi_size)
357*95b482a8SLen Brown 							    operand0->buffer.
358*95b482a8SLen Brown 							    length +
359*95b482a8SLen Brown 							    local_operand1->
360*95b482a8SLen Brown 							    buffer.length));
361*95b482a8SLen Brown 		if (!return_desc) {
362*95b482a8SLen Brown 			status = AE_NO_MEMORY;
363*95b482a8SLen Brown 			goto cleanup;
364*95b482a8SLen Brown 		}
365*95b482a8SLen Brown 
366*95b482a8SLen Brown 		new_buf = (char *)return_desc->buffer.pointer;
367*95b482a8SLen Brown 
368*95b482a8SLen Brown 		/* Concatenate the buffers */
369*95b482a8SLen Brown 
370*95b482a8SLen Brown 		ACPI_MEMCPY(new_buf, operand0->buffer.pointer,
371*95b482a8SLen Brown 			    operand0->buffer.length);
372*95b482a8SLen Brown 		ACPI_MEMCPY(new_buf + operand0->buffer.length,
373*95b482a8SLen Brown 			    local_operand1->buffer.pointer,
374*95b482a8SLen Brown 			    local_operand1->buffer.length);
375*95b482a8SLen Brown 		break;
376*95b482a8SLen Brown 
377*95b482a8SLen Brown 	default:
378*95b482a8SLen Brown 
379*95b482a8SLen Brown 		/* Invalid object type, should not happen here */
380*95b482a8SLen Brown 
381*95b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid object type: %X",
382*95b482a8SLen Brown 			    ACPI_GET_OBJECT_TYPE(operand0)));
383*95b482a8SLen Brown 		status = AE_AML_INTERNAL;
384*95b482a8SLen Brown 		goto cleanup;
385*95b482a8SLen Brown 	}
386*95b482a8SLen Brown 
387*95b482a8SLen Brown 	*actual_return_desc = return_desc;
388*95b482a8SLen Brown 
389*95b482a8SLen Brown       cleanup:
390*95b482a8SLen Brown 	if (local_operand1 != operand1) {
391*95b482a8SLen Brown 		acpi_ut_remove_reference(local_operand1);
392*95b482a8SLen Brown 	}
393*95b482a8SLen Brown 	return_ACPI_STATUS(status);
394*95b482a8SLen Brown }
395*95b482a8SLen Brown 
396*95b482a8SLen Brown /*******************************************************************************
397*95b482a8SLen Brown  *
398*95b482a8SLen Brown  * FUNCTION:    acpi_ex_do_math_op
399*95b482a8SLen Brown  *
400*95b482a8SLen Brown  * PARAMETERS:  Opcode              - AML opcode
401*95b482a8SLen Brown  *              Integer0            - Integer operand #0
402*95b482a8SLen Brown  *              Integer1            - Integer operand #1
403*95b482a8SLen Brown  *
404*95b482a8SLen Brown  * RETURN:      Integer result of the operation
405*95b482a8SLen Brown  *
406*95b482a8SLen Brown  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
407*95b482a8SLen Brown  *              math functions here is to prevent a lot of pointer dereferencing
408*95b482a8SLen Brown  *              to obtain the operands.
409*95b482a8SLen Brown  *
410*95b482a8SLen Brown  ******************************************************************************/
411*95b482a8SLen Brown 
412*95b482a8SLen Brown acpi_integer
413*95b482a8SLen Brown acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1)
414*95b482a8SLen Brown {
415*95b482a8SLen Brown 
416*95b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
417*95b482a8SLen Brown 
418*95b482a8SLen Brown 	switch (opcode) {
419*95b482a8SLen Brown 	case AML_ADD_OP:	/* Add (Integer0, Integer1, Result) */
420*95b482a8SLen Brown 
421*95b482a8SLen Brown 		return (integer0 + integer1);
422*95b482a8SLen Brown 
423*95b482a8SLen Brown 	case AML_BIT_AND_OP:	/* And (Integer0, Integer1, Result) */
424*95b482a8SLen Brown 
425*95b482a8SLen Brown 		return (integer0 & integer1);
426*95b482a8SLen Brown 
427*95b482a8SLen Brown 	case AML_BIT_NAND_OP:	/* NAnd (Integer0, Integer1, Result) */
428*95b482a8SLen Brown 
429*95b482a8SLen Brown 		return (~(integer0 & integer1));
430*95b482a8SLen Brown 
431*95b482a8SLen Brown 	case AML_BIT_OR_OP:	/* Or (Integer0, Integer1, Result) */
432*95b482a8SLen Brown 
433*95b482a8SLen Brown 		return (integer0 | integer1);
434*95b482a8SLen Brown 
435*95b482a8SLen Brown 	case AML_BIT_NOR_OP:	/* NOr (Integer0, Integer1, Result) */
436*95b482a8SLen Brown 
437*95b482a8SLen Brown 		return (~(integer0 | integer1));
438*95b482a8SLen Brown 
439*95b482a8SLen Brown 	case AML_BIT_XOR_OP:	/* XOr (Integer0, Integer1, Result) */
440*95b482a8SLen Brown 
441*95b482a8SLen Brown 		return (integer0 ^ integer1);
442*95b482a8SLen Brown 
443*95b482a8SLen Brown 	case AML_MULTIPLY_OP:	/* Multiply (Integer0, Integer1, Result) */
444*95b482a8SLen Brown 
445*95b482a8SLen Brown 		return (integer0 * integer1);
446*95b482a8SLen Brown 
447*95b482a8SLen Brown 	case AML_SHIFT_LEFT_OP:	/* shift_left (Operand, shift_count, Result) */
448*95b482a8SLen Brown 
449*95b482a8SLen Brown 		/*
450*95b482a8SLen Brown 		 * We need to check if the shiftcount is larger than the integer bit
451*95b482a8SLen Brown 		 * width since the behavior of this is not well-defined in the C language.
452*95b482a8SLen Brown 		 */
453*95b482a8SLen Brown 		if (integer1 >= acpi_gbl_integer_bit_width) {
454*95b482a8SLen Brown 			return (0);
455*95b482a8SLen Brown 		}
456*95b482a8SLen Brown 		return (integer0 << integer1);
457*95b482a8SLen Brown 
458*95b482a8SLen Brown 	case AML_SHIFT_RIGHT_OP:	/* shift_right (Operand, shift_count, Result) */
459*95b482a8SLen Brown 
460*95b482a8SLen Brown 		/*
461*95b482a8SLen Brown 		 * We need to check if the shiftcount is larger than the integer bit
462*95b482a8SLen Brown 		 * width since the behavior of this is not well-defined in the C language.
463*95b482a8SLen Brown 		 */
464*95b482a8SLen Brown 		if (integer1 >= acpi_gbl_integer_bit_width) {
465*95b482a8SLen Brown 			return (0);
466*95b482a8SLen Brown 		}
467*95b482a8SLen Brown 		return (integer0 >> integer1);
468*95b482a8SLen Brown 
469*95b482a8SLen Brown 	case AML_SUBTRACT_OP:	/* Subtract (Integer0, Integer1, Result) */
470*95b482a8SLen Brown 
471*95b482a8SLen Brown 		return (integer0 - integer1);
472*95b482a8SLen Brown 
473*95b482a8SLen Brown 	default:
474*95b482a8SLen Brown 
475*95b482a8SLen Brown 		return (0);
476*95b482a8SLen Brown 	}
477*95b482a8SLen Brown }
478*95b482a8SLen Brown 
479*95b482a8SLen Brown /*******************************************************************************
480*95b482a8SLen Brown  *
481*95b482a8SLen Brown  * FUNCTION:    acpi_ex_do_logical_numeric_op
482*95b482a8SLen Brown  *
483*95b482a8SLen Brown  * PARAMETERS:  Opcode              - AML opcode
484*95b482a8SLen Brown  *              Integer0            - Integer operand #0
485*95b482a8SLen Brown  *              Integer1            - Integer operand #1
486*95b482a8SLen Brown  *              logical_result      - TRUE/FALSE result of the operation
487*95b482a8SLen Brown  *
488*95b482a8SLen Brown  * RETURN:      Status
489*95b482a8SLen Brown  *
490*95b482a8SLen Brown  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
491*95b482a8SLen Brown  *              operators (LAnd and LOr), both operands must be integers.
492*95b482a8SLen Brown  *
493*95b482a8SLen Brown  *              Note: cleanest machine code seems to be produced by the code
494*95b482a8SLen Brown  *              below, rather than using statements of the form:
495*95b482a8SLen Brown  *                  Result = (Integer0 && Integer1);
496*95b482a8SLen Brown  *
497*95b482a8SLen Brown  ******************************************************************************/
498*95b482a8SLen Brown 
499*95b482a8SLen Brown acpi_status
500*95b482a8SLen Brown acpi_ex_do_logical_numeric_op(u16 opcode,
501*95b482a8SLen Brown 			      acpi_integer integer0,
502*95b482a8SLen Brown 			      acpi_integer integer1, u8 * logical_result)
503*95b482a8SLen Brown {
504*95b482a8SLen Brown 	acpi_status status = AE_OK;
505*95b482a8SLen Brown 	u8 local_result = FALSE;
506*95b482a8SLen Brown 
507*95b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
508*95b482a8SLen Brown 
509*95b482a8SLen Brown 	switch (opcode) {
510*95b482a8SLen Brown 	case AML_LAND_OP:	/* LAnd (Integer0, Integer1) */
511*95b482a8SLen Brown 
512*95b482a8SLen Brown 		if (integer0 && integer1) {
513*95b482a8SLen Brown 			local_result = TRUE;
514*95b482a8SLen Brown 		}
515*95b482a8SLen Brown 		break;
516*95b482a8SLen Brown 
517*95b482a8SLen Brown 	case AML_LOR_OP:	/* LOr (Integer0, Integer1) */
518*95b482a8SLen Brown 
519*95b482a8SLen Brown 		if (integer0 || integer1) {
520*95b482a8SLen Brown 			local_result = TRUE;
521*95b482a8SLen Brown 		}
522*95b482a8SLen Brown 		break;
523*95b482a8SLen Brown 
524*95b482a8SLen Brown 	default:
525*95b482a8SLen Brown 		status = AE_AML_INTERNAL;
526*95b482a8SLen Brown 		break;
527*95b482a8SLen Brown 	}
528*95b482a8SLen Brown 
529*95b482a8SLen Brown 	/* Return the logical result and status */
530*95b482a8SLen Brown 
531*95b482a8SLen Brown 	*logical_result = local_result;
532*95b482a8SLen Brown 	return_ACPI_STATUS(status);
533*95b482a8SLen Brown }
534*95b482a8SLen Brown 
535*95b482a8SLen Brown /*******************************************************************************
536*95b482a8SLen Brown  *
537*95b482a8SLen Brown  * FUNCTION:    acpi_ex_do_logical_op
538*95b482a8SLen Brown  *
539*95b482a8SLen Brown  * PARAMETERS:  Opcode              - AML opcode
540*95b482a8SLen Brown  *              Operand0            - operand #0
541*95b482a8SLen Brown  *              Operand1            - operand #1
542*95b482a8SLen Brown  *              logical_result      - TRUE/FALSE result of the operation
543*95b482a8SLen Brown  *
544*95b482a8SLen Brown  * RETURN:      Status
545*95b482a8SLen Brown  *
546*95b482a8SLen Brown  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
547*95b482a8SLen Brown  *              functions here is to prevent a lot of pointer dereferencing
548*95b482a8SLen Brown  *              to obtain the operands and to simplify the generation of the
549*95b482a8SLen Brown  *              logical value. For the Numeric operators (LAnd and LOr), both
550*95b482a8SLen Brown  *              operands must be integers. For the other logical operators,
551*95b482a8SLen Brown  *              operands can be any combination of Integer/String/Buffer. The
552*95b482a8SLen Brown  *              first operand determines the type to which the second operand
553*95b482a8SLen Brown  *              will be converted.
554*95b482a8SLen Brown  *
555*95b482a8SLen Brown  *              Note: cleanest machine code seems to be produced by the code
556*95b482a8SLen Brown  *              below, rather than using statements of the form:
557*95b482a8SLen Brown  *                  Result = (Operand0 == Operand1);
558*95b482a8SLen Brown  *
559*95b482a8SLen Brown  ******************************************************************************/
560*95b482a8SLen Brown 
561*95b482a8SLen Brown acpi_status
562*95b482a8SLen Brown acpi_ex_do_logical_op(u16 opcode,
563*95b482a8SLen Brown 		      union acpi_operand_object *operand0,
564*95b482a8SLen Brown 		      union acpi_operand_object *operand1, u8 * logical_result)
565*95b482a8SLen Brown {
566*95b482a8SLen Brown 	union acpi_operand_object *local_operand1 = operand1;
567*95b482a8SLen Brown 	acpi_integer integer0;
568*95b482a8SLen Brown 	acpi_integer integer1;
569*95b482a8SLen Brown 	u32 length0;
570*95b482a8SLen Brown 	u32 length1;
571*95b482a8SLen Brown 	acpi_status status = AE_OK;
572*95b482a8SLen Brown 	u8 local_result = FALSE;
573*95b482a8SLen Brown 	int compare;
574*95b482a8SLen Brown 
575*95b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_do_logical_op);
576*95b482a8SLen Brown 
577*95b482a8SLen Brown 	/*
578*95b482a8SLen Brown 	 * Convert the second operand if necessary.  The first operand
579*95b482a8SLen Brown 	 * determines the type of the second operand, (See the Data Types
580*95b482a8SLen Brown 	 * section of the ACPI 3.0+ specification.)  Both object types are
581*95b482a8SLen Brown 	 * guaranteed to be either Integer/String/Buffer by the operand
582*95b482a8SLen Brown 	 * resolution mechanism.
583*95b482a8SLen Brown 	 */
584*95b482a8SLen Brown 	switch (ACPI_GET_OBJECT_TYPE(operand0)) {
585*95b482a8SLen Brown 	case ACPI_TYPE_INTEGER:
586*95b482a8SLen Brown 		status =
587*95b482a8SLen Brown 		    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
588*95b482a8SLen Brown 		break;
589*95b482a8SLen Brown 
590*95b482a8SLen Brown 	case ACPI_TYPE_STRING:
591*95b482a8SLen Brown 		status = acpi_ex_convert_to_string(operand1, &local_operand1,
592*95b482a8SLen Brown 						   ACPI_IMPLICIT_CONVERT_HEX);
593*95b482a8SLen Brown 		break;
594*95b482a8SLen Brown 
595*95b482a8SLen Brown 	case ACPI_TYPE_BUFFER:
596*95b482a8SLen Brown 		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
597*95b482a8SLen Brown 		break;
598*95b482a8SLen Brown 
599*95b482a8SLen Brown 	default:
600*95b482a8SLen Brown 		status = AE_AML_INTERNAL;
601*95b482a8SLen Brown 		break;
602*95b482a8SLen Brown 	}
603*95b482a8SLen Brown 
604*95b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
605*95b482a8SLen Brown 		goto cleanup;
606*95b482a8SLen Brown 	}
607*95b482a8SLen Brown 
608*95b482a8SLen Brown 	/*
609*95b482a8SLen Brown 	 * Two cases: 1) Both Integers, 2) Both Strings or Buffers
610*95b482a8SLen Brown 	 */
611*95b482a8SLen Brown 	if (ACPI_GET_OBJECT_TYPE(operand0) == ACPI_TYPE_INTEGER) {
612*95b482a8SLen Brown 		/*
613*95b482a8SLen Brown 		 * 1) Both operands are of type integer
614*95b482a8SLen Brown 		 *    Note: local_operand1 may have changed above
615*95b482a8SLen Brown 		 */
616*95b482a8SLen Brown 		integer0 = operand0->integer.value;
617*95b482a8SLen Brown 		integer1 = local_operand1->integer.value;
618*95b482a8SLen Brown 
619*95b482a8SLen Brown 		switch (opcode) {
620*95b482a8SLen Brown 		case AML_LEQUAL_OP:	/* LEqual (Operand0, Operand1) */
621*95b482a8SLen Brown 
622*95b482a8SLen Brown 			if (integer0 == integer1) {
623*95b482a8SLen Brown 				local_result = TRUE;
624*95b482a8SLen Brown 			}
625*95b482a8SLen Brown 			break;
626*95b482a8SLen Brown 
627*95b482a8SLen Brown 		case AML_LGREATER_OP:	/* LGreater (Operand0, Operand1) */
628*95b482a8SLen Brown 
629*95b482a8SLen Brown 			if (integer0 > integer1) {
630*95b482a8SLen Brown 				local_result = TRUE;
631*95b482a8SLen Brown 			}
632*95b482a8SLen Brown 			break;
633*95b482a8SLen Brown 
634*95b482a8SLen Brown 		case AML_LLESS_OP:	/* LLess (Operand0, Operand1) */
635*95b482a8SLen Brown 
636*95b482a8SLen Brown 			if (integer0 < integer1) {
637*95b482a8SLen Brown 				local_result = TRUE;
638*95b482a8SLen Brown 			}
639*95b482a8SLen Brown 			break;
640*95b482a8SLen Brown 
641*95b482a8SLen Brown 		default:
642*95b482a8SLen Brown 			status = AE_AML_INTERNAL;
643*95b482a8SLen Brown 			break;
644*95b482a8SLen Brown 		}
645*95b482a8SLen Brown 	} else {
646*95b482a8SLen Brown 		/*
647*95b482a8SLen Brown 		 * 2) Both operands are Strings or both are Buffers
648*95b482a8SLen Brown 		 *    Note: Code below takes advantage of common Buffer/String
649*95b482a8SLen Brown 		 *          object fields. local_operand1 may have changed above. Use
650*95b482a8SLen Brown 		 *          memcmp to handle nulls in buffers.
651*95b482a8SLen Brown 		 */
652*95b482a8SLen Brown 		length0 = operand0->buffer.length;
653*95b482a8SLen Brown 		length1 = local_operand1->buffer.length;
654*95b482a8SLen Brown 
655*95b482a8SLen Brown 		/* Lexicographic compare: compare the data bytes */
656*95b482a8SLen Brown 
657*95b482a8SLen Brown 		compare = ACPI_MEMCMP(operand0->buffer.pointer,
658*95b482a8SLen Brown 				      local_operand1->buffer.pointer,
659*95b482a8SLen Brown 				      (length0 > length1) ? length1 : length0);
660*95b482a8SLen Brown 
661*95b482a8SLen Brown 		switch (opcode) {
662*95b482a8SLen Brown 		case AML_LEQUAL_OP:	/* LEqual (Operand0, Operand1) */
663*95b482a8SLen Brown 
664*95b482a8SLen Brown 			/* Length and all bytes must be equal */
665*95b482a8SLen Brown 
666*95b482a8SLen Brown 			if ((length0 == length1) && (compare == 0)) {
667*95b482a8SLen Brown 
668*95b482a8SLen Brown 				/* Length and all bytes match ==> TRUE */
669*95b482a8SLen Brown 
670*95b482a8SLen Brown 				local_result = TRUE;
671*95b482a8SLen Brown 			}
672*95b482a8SLen Brown 			break;
673*95b482a8SLen Brown 
674*95b482a8SLen Brown 		case AML_LGREATER_OP:	/* LGreater (Operand0, Operand1) */
675*95b482a8SLen Brown 
676*95b482a8SLen Brown 			if (compare > 0) {
677*95b482a8SLen Brown 				local_result = TRUE;
678*95b482a8SLen Brown 				goto cleanup;	/* TRUE */
679*95b482a8SLen Brown 			}
680*95b482a8SLen Brown 			if (compare < 0) {
681*95b482a8SLen Brown 				goto cleanup;	/* FALSE */
682*95b482a8SLen Brown 			}
683*95b482a8SLen Brown 
684*95b482a8SLen Brown 			/* Bytes match (to shortest length), compare lengths */
685*95b482a8SLen Brown 
686*95b482a8SLen Brown 			if (length0 > length1) {
687*95b482a8SLen Brown 				local_result = TRUE;
688*95b482a8SLen Brown 			}
689*95b482a8SLen Brown 			break;
690*95b482a8SLen Brown 
691*95b482a8SLen Brown 		case AML_LLESS_OP:	/* LLess (Operand0, Operand1) */
692*95b482a8SLen Brown 
693*95b482a8SLen Brown 			if (compare > 0) {
694*95b482a8SLen Brown 				goto cleanup;	/* FALSE */
695*95b482a8SLen Brown 			}
696*95b482a8SLen Brown 			if (compare < 0) {
697*95b482a8SLen Brown 				local_result = TRUE;
698*95b482a8SLen Brown 				goto cleanup;	/* TRUE */
699*95b482a8SLen Brown 			}
700*95b482a8SLen Brown 
701*95b482a8SLen Brown 			/* Bytes match (to shortest length), compare lengths */
702*95b482a8SLen Brown 
703*95b482a8SLen Brown 			if (length0 < length1) {
704*95b482a8SLen Brown 				local_result = TRUE;
705*95b482a8SLen Brown 			}
706*95b482a8SLen Brown 			break;
707*95b482a8SLen Brown 
708*95b482a8SLen Brown 		default:
709*95b482a8SLen Brown 			status = AE_AML_INTERNAL;
710*95b482a8SLen Brown 			break;
711*95b482a8SLen Brown 		}
712*95b482a8SLen Brown 	}
713*95b482a8SLen Brown 
714*95b482a8SLen Brown       cleanup:
715*95b482a8SLen Brown 
716*95b482a8SLen Brown 	/* New object was created if implicit conversion performed - delete */
717*95b482a8SLen Brown 
718*95b482a8SLen Brown 	if (local_operand1 != operand1) {
719*95b482a8SLen Brown 		acpi_ut_remove_reference(local_operand1);
720*95b482a8SLen Brown 	}
721*95b482a8SLen Brown 
722*95b482a8SLen Brown 	/* Return the logical result and status */
723*95b482a8SLen Brown 
724*95b482a8SLen Brown 	*logical_result = local_result;
725*95b482a8SLen Brown 	return_ACPI_STATUS(status);
726*95b482a8SLen Brown }
727