1
2/******************************************************************************
3 *
4 * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
5 *              $Revision: 1.1.1.1 $
6 *
7 *****************************************************************************/
8
9/*
10 *  Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 *  This program is free software; you can redistribute it and/or modify
13 *  it under the terms of the GNU General Public License as published by
14 *  the Free Software Foundation; either version 2 of the License, or
15 *  (at your option) any later version.
16 *
17 *  This program is distributed in the hope that it will be useful,
18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 *  GNU General Public License for more details.
21 *
22 *  You should have received a copy of the GNU General Public License
23 *  along with this program; if not, write to the Free Software
24 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 */
26
27
28#include "acpi.h"
29#include "acparser.h"
30#include "acinterp.h"
31#include "amlcode.h"
32#include "acdispat.h"
33
34
35#define _COMPONENT          ACPI_EXECUTER
36	 MODULE_NAME         ("exmisc")
37
38
39/*******************************************************************************
40 *
41 * FUNCTION:    Acpi_ex_get_object_reference
42 *
43 * PARAMETERS:  Obj_desc        - Create a reference to this object
44 *              Return_desc        - Where to store the reference
45 *
46 * RETURN:      Status
47 *
48 * DESCRIPTION: Obtain and return a "reference" to the target object
49 *              Common code for the Ref_of_op and the Cond_ref_of_op.
50 *
51 ******************************************************************************/
52
53acpi_status
54acpi_ex_get_object_reference (
55	acpi_operand_object     *obj_desc,
56	acpi_operand_object     **return_desc,
57	acpi_walk_state         *walk_state)
58{
59	acpi_status             status = AE_OK;
60
61
62	FUNCTION_TRACE_PTR ("Ex_get_object_reference", obj_desc);
63
64
65	if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) {
66		if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) {
67			*return_desc = NULL;
68			status = AE_TYPE;
69			goto cleanup;
70		}
71
72		/*
73		 * Not a Name -- an indirect name pointer would have
74		 * been converted to a direct name pointer in Acpi_ex_resolve_operands
75		 */
76		switch (obj_desc->reference.opcode) {
77		case AML_LOCAL_OP:
78		case AML_ARG_OP:
79
80			*return_desc = (void *) acpi_ds_method_data_get_node (obj_desc->reference.opcode,
81					  obj_desc->reference.offset, walk_state);
82			break;
83
84		default:
85
86			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(Internal) Unknown Ref subtype %02x\n",
87				obj_desc->reference.opcode));
88			*return_desc = NULL;
89			status = AE_AML_INTERNAL;
90			goto cleanup;
91		}
92
93	}
94
95	else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
96		/* Must be a named object;  Just return the Node */
97
98		*return_desc = obj_desc;
99	}
100
101	else {
102		*return_desc = NULL;
103		status = AE_TYPE;
104	}
105
106
107cleanup:
108
109	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p Ref=%p\n", obj_desc, *return_desc));
110	return_ACPI_STATUS (status);
111}
112
113
114/*******************************************************************************
115 *
116 * FUNCTION:    Acpi_ex_do_concatenate
117 *
118 * PARAMETERS:  *Obj_desc           - Object to be converted.  Must be an
119 *                                    Integer, Buffer, or String
120 *              Walk_state          - Current walk state
121 *
122 * RETURN:      Status
123 *
124 * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
125 *
126 ******************************************************************************/
127
128acpi_status
129acpi_ex_do_concatenate (
130	acpi_operand_object     *obj_desc,
131	acpi_operand_object     *obj_desc2,
132	acpi_operand_object     **actual_return_desc,
133	acpi_walk_state         *walk_state)
134{
135	acpi_status             status;
136	u32                     i;
137	acpi_integer            this_integer;
138	acpi_operand_object     *return_desc;
139	NATIVE_CHAR             *new_buf;
140	u32                     integer_size = sizeof (acpi_integer);
141
142
143	FUNCTION_ENTRY ();
144
145
146	/*
147	 * There are three cases to handle:
148	 * 1) Two Integers concatenated to produce a buffer
149	 * 2) Two Strings concatenated to produce a string
150	 * 3) Two Buffers concatenated to produce a buffer
151	 */
152	switch (obj_desc->common.type) {
153	case ACPI_TYPE_INTEGER:
154
155		/* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */
156
157		if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) {
158			/*
159			 * We are running a method that exists in a 32-bit ACPI table.
160			 * Truncate the value to 32 bits by zeroing out the upper
161			 * 32-bit field
162			 */
163			integer_size = sizeof (u32);
164		}
165
166		/* Result of two integers is a buffer */
167
168		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
169		if (!return_desc) {
170			return (AE_NO_MEMORY);
171		}
172
173		/* Need enough space for two integers */
174
175		return_desc->buffer.length = integer_size * 2;
176		new_buf = ACPI_MEM_CALLOCATE (return_desc->buffer.length);
177		if (!new_buf) {
178			REPORT_ERROR
179				(("Ex_do_concatenate: Buffer allocation failure\n"));
180			status = AE_NO_MEMORY;
181			goto cleanup;
182		}
183
184		return_desc->buffer.pointer = (u8 *) new_buf;
185
186		/* Convert the first integer */
187
188		this_integer = obj_desc->integer.value;
189		for (i = 0; i < integer_size; i++) {
190			new_buf[i] = (u8) this_integer;
191			this_integer >>= 8;
192		}
193
194		/* Convert the second integer */
195
196		this_integer = obj_desc2->integer.value;
197		for (; i < (integer_size * 2); i++) {
198			new_buf[i] = (u8) this_integer;
199			this_integer >>= 8;
200		}
201
202		break;
203
204
205	case ACPI_TYPE_STRING:
206
207		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
208		if (!return_desc) {
209			return (AE_NO_MEMORY);
210		}
211
212		/* Operand0 is string  */
213
214		new_buf = ACPI_MEM_ALLOCATE (obj_desc->string.length +
215				  obj_desc2->string.length + 1);
216		if (!new_buf) {
217			REPORT_ERROR
218				(("Ex_do_concatenate: String allocation failure\n"));
219			status = AE_NO_MEMORY;
220			goto cleanup;
221		}
222
223		STRCPY (new_buf, obj_desc->string.pointer);
224		STRCPY (new_buf + obj_desc->string.length,
225				  obj_desc2->string.pointer);
226
227		/* Point the return object to the new string */
228
229		return_desc->string.pointer = new_buf;
230		return_desc->string.length = obj_desc->string.length +=
231				  obj_desc2->string.length;
232		break;
233
234
235	case ACPI_TYPE_BUFFER:
236
237		/* Operand0 is a buffer */
238
239		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
240		if (!return_desc) {
241			return (AE_NO_MEMORY);
242		}
243
244		new_buf = ACPI_MEM_ALLOCATE (obj_desc->buffer.length +
245				  obj_desc2->buffer.length);
246		if (!new_buf) {
247			REPORT_ERROR
248				(("Ex_do_concatenate: Buffer allocation failure\n"));
249			status = AE_NO_MEMORY;
250			goto cleanup;
251		}
252
253		MEMCPY (new_buf, obj_desc->buffer.pointer,
254				  obj_desc->buffer.length);
255		MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer,
256				   obj_desc2->buffer.length);
257
258		/*
259		 * Point the return object to the new buffer
260		 */
261
262		return_desc->buffer.pointer    = (u8 *) new_buf;
263		return_desc->buffer.length     = obj_desc->buffer.length +
264				 obj_desc2->buffer.length;
265		break;
266
267
268	default:
269		status = AE_AML_INTERNAL;
270		return_desc = NULL;
271	}
272
273
274	*actual_return_desc = return_desc;
275	return (AE_OK);
276
277
278cleanup:
279
280	acpi_ut_remove_reference (return_desc);
281	return (status);
282}
283
284
285/*******************************************************************************
286 *
287 * FUNCTION:    Acpi_ex_do_math_op
288 *
289 * PARAMETERS:  Opcode              - AML opcode
290 *              Operand0            - Integer operand #0
291 *              Operand0            - Integer operand #1
292 *
293 * RETURN:      Integer result of the operation
294 *
295 * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
296 *              math functions here is to prevent a lot of pointer dereferencing
297 *              to obtain the operands.
298 *
299 ******************************************************************************/
300
301acpi_integer
302acpi_ex_do_math_op (
303	u16                     opcode,
304	acpi_integer            operand0,
305	acpi_integer            operand1)
306{
307
308
309	switch (opcode) {
310	case AML_ADD_OP:                /* Add (Operand0, Operand1, Result) */
311
312		return (operand0 + operand1);
313
314
315	case AML_BIT_AND_OP:            /* And (Operand0, Operand1, Result) */
316
317		return (operand0 & operand1);
318
319
320	case AML_BIT_NAND_OP:           /* NAnd (Operand0, Operand1, Result) */
321
322		return (~(operand0 & operand1));
323
324
325	case AML_BIT_OR_OP:             /* Or (Operand0, Operand1, Result) */
326
327		return (operand0 | operand1);
328
329
330	case AML_BIT_NOR_OP:            /* NOr (Operand0, Operand1, Result) */
331
332		return (~(operand0 | operand1));
333
334
335	case AML_BIT_XOR_OP:            /* XOr (Operand0, Operand1, Result) */
336
337		return (operand0 ^ operand1);
338
339
340	case AML_MULTIPLY_OP:           /* Multiply (Operand0, Operand1, Result) */
341
342		return (operand0 * operand1);
343
344
345	case AML_SHIFT_LEFT_OP:         /* Shift_left (Operand, Shift_count, Result) */
346
347		return (operand0 << operand1);
348
349
350	case AML_SHIFT_RIGHT_OP:        /* Shift_right (Operand, Shift_count, Result) */
351
352		return (operand0 >> operand1);
353
354
355	case AML_SUBTRACT_OP:           /* Subtract (Operand0, Operand1, Result) */
356
357		return (operand0 - operand1);
358
359	default:
360
361		return (0);
362	}
363}
364
365
366/*******************************************************************************
367 *
368 * FUNCTION:    Acpi_ex_do_logical_op
369 *
370 * PARAMETERS:  Opcode              - AML opcode
371 *              Operand0            - Integer operand #0
372 *              Operand0            - Integer operand #1
373 *
374 * RETURN:      TRUE/FALSE result of the operation
375 *
376 * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
377 *              functions here is to prevent a lot of pointer dereferencing
378 *              to obtain the operands and to simplify the generation of the
379 *              logical value.
380 *
381 *              Note: cleanest machine code seems to be produced by the code
382 *              below, rather than using statements of the form:
383 *                  Result = (Operand0 == Operand1);
384 *
385 ******************************************************************************/
386
387u8
388acpi_ex_do_logical_op (
389	u16                     opcode,
390	acpi_integer            operand0,
391	acpi_integer            operand1)
392{
393
394
395	switch (opcode) {
396
397	case AML_LAND_OP:               /* LAnd (Operand0, Operand1) */
398
399		if (operand0 && operand1) {
400			return (TRUE);
401		}
402		break;
403
404
405	case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
406
407		if (operand0 == operand1) {
408			return (TRUE);
409		}
410		break;
411
412
413	case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
414
415		if (operand0 > operand1) {
416			return (TRUE);
417		}
418		break;
419
420
421	case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
422
423		if (operand0 < operand1) {
424			return (TRUE);
425		}
426		break;
427
428
429	case AML_LOR_OP:                 /* LOr (Operand0, Operand1) */
430
431		if (operand0 || operand1) {
432			return (TRUE);
433		}
434		break;
435	}
436
437	return (FALSE);
438}
439
440
441