File: /usr/src/linux/drivers/acpi/executer/exmisc.c

1     
2     /******************************************************************************
3      *
4      * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
5      *              $Revision: 83 $
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_triadic
42      *
43      * PARAMETERS:  Opcode              - The opcode to be executed
44      *              Walk_state          - Current walk state
45      *              Return_desc         - Where to store the return object
46      *
47      * RETURN:      Status
48      *
49      * DESCRIPTION: Execute Triadic operator (3 operands)
50      *
51      * ALLOCATION:  Deletes one operand descriptor -- other remains on stack
52      *
53      ******************************************************************************/
54     
55     acpi_status
56     acpi_ex_triadic (
57     	u16                     opcode,
58     	acpi_walk_state         *walk_state,
59     	acpi_operand_object     **return_desc)
60     {
61     	acpi_operand_object     **operand = &walk_state->operands[0];
62     	acpi_operand_object     *ret_desc = NULL;
63     	acpi_operand_object     *tmp_desc;
64     	ACPI_SIGNAL_FATAL_INFO  *fatal;
65     	acpi_status             status = AE_OK;
66     
67     
68     	FUNCTION_TRACE ("Ex_triadic");
69     
70     
71     #define obj_desc1           operand[0]
72     #define obj_desc2           operand[1]
73     #define res_desc            operand[2]
74     
75     
76     	switch (opcode) {
77     
78     	case AML_FATAL_OP:
79     
80     		/* Def_fatal   :=  Fatal_op Fatal_type  Fatal_code  Fatal_arg   */
81     
82     		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
83     			"Fatal_op: Type %x Code %x Arg %x <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
84     			(u32) obj_desc1->integer.value, (u32) obj_desc2->integer.value,
85     			(u32) res_desc->integer.value));
86     
87     
88     		fatal = ACPI_MEM_ALLOCATE (sizeof (ACPI_SIGNAL_FATAL_INFO));
89     		if (fatal) {
90     			fatal->type = (u32) obj_desc1->integer.value;
91     			fatal->code = (u32) obj_desc2->integer.value;
92     			fatal->argument = (u32) res_desc->integer.value;
93     		}
94     
95     		/*
96     		 * Signal the OS
97     		 */
98     		acpi_os_signal (ACPI_SIGNAL_FATAL, fatal);
99     
100     		/* Might return while OS is shutting down */
101     
102     		ACPI_MEM_FREE (fatal);
103     		break;
104     
105     
106     	case AML_MID_OP:
107     
108     		/* Def_mid      := Mid_op Source Index Length Result */
109     
110     		/* Create the internal return object (string or buffer) */
111     
112     		break;
113     
114     
115     	case AML_INDEX_OP:
116     
117     		/* Def_index    := Index_op Source Index Destination */
118     
119     		/* Create the internal return object */
120     
121     		ret_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE);
122     		if (!ret_desc) {
123     			status = AE_NO_MEMORY;
124     			goto cleanup;
125     		}
126     
127     		/*
128     		 * At this point, the Obj_desc1 operand is either a Package or a Buffer
129     		 */
130     		if (obj_desc1->common.type == ACPI_TYPE_PACKAGE) {
131     			/* Object to be indexed is a Package */
132     
133     			if (obj_desc2->integer.value >= obj_desc1->package.count) {
134     				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond package end\n"));
135     				status = AE_AML_PACKAGE_LIMIT;
136     				goto cleanup;
137     			}
138     
139     			if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) &&
140     				(res_desc->reference.opcode == AML_ZERO_OP)) {
141     				/*
142     				 * There is no actual result descriptor (the Zero_op Result
143     				 * descriptor is a placeholder), so just delete the placeholder and
144     				 * return a reference to the package element
145     				 */
146     				acpi_ut_remove_reference (res_desc);
147     			}
148     
149     			else {
150     				/*
151     				 * Each element of the package is an internal object.  Get the one
152     				 * we are after.
153     				 */
154     				tmp_desc                      = obj_desc1->package.elements[obj_desc2->integer.value];
155     				ret_desc->reference.opcode    = AML_INDEX_OP;
156     				ret_desc->reference.target_type = tmp_desc->common.type;
157     				ret_desc->reference.object    = tmp_desc;
158     
159     				status = acpi_ex_store (ret_desc, res_desc, walk_state);
160     				ret_desc->reference.object    = NULL;
161     			}
162     
163     			/*
164     			 * The local return object must always be a reference to the package element,
165     			 * not the element itself.
166     			 */
167     			ret_desc->reference.opcode    = AML_INDEX_OP;
168     			ret_desc->reference.target_type = ACPI_TYPE_PACKAGE;
169     			ret_desc->reference.where     = &obj_desc1->package.elements[obj_desc2->integer.value];
170     		}
171     
172     		else {
173     			/* Object to be indexed is a Buffer */
174     
175     			if (obj_desc2->integer.value >= obj_desc1->buffer.length) {
176     				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond end of buffer\n"));
177     				status = AE_AML_BUFFER_LIMIT;
178     				goto cleanup;
179     			}
180     
181     			ret_desc->reference.opcode      = AML_INDEX_OP;
182     			ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
183     			ret_desc->reference.object      = obj_desc1;
184     			ret_desc->reference.offset      = (u32) obj_desc2->integer.value;
185     
186     			status = acpi_ex_store (ret_desc, res_desc, walk_state);
187     		}
188     		break;
189     	}
190     
191     
192     cleanup:
193     
194     	/* Always delete operands */
195     
196     	acpi_ut_remove_reference (obj_desc1);
197     	acpi_ut_remove_reference (obj_desc2);
198     
199     	/* Delete return object on error */
200     
201     	if (ACPI_FAILURE (status)) {
202     		acpi_ut_remove_reference (res_desc);
203     
204     		if (ret_desc) {
205     			acpi_ut_remove_reference (ret_desc);
206     			ret_desc = NULL;
207     		}
208     	}
209     
210     	/* Set the return object and exit */
211     
212     	*return_desc = ret_desc;
213     	return_ACPI_STATUS (status);
214     }
215     
216     
217     /*******************************************************************************
218      *
219      * FUNCTION:    Acpi_ex_hexadic
220      *
221      * PARAMETERS:  Opcode              - The opcode to be executed
222      *              Walk_state          - Current walk state
223      *              Return_desc         - Where to store the return object
224      *
225      * RETURN:      Status
226      *
227      * DESCRIPTION: Execute Match operator
228      *
229      ******************************************************************************/
230     
231     acpi_status
232     acpi_ex_hexadic (
233     	u16                     opcode,
234     	acpi_walk_state         *walk_state,
235     	acpi_operand_object     **return_desc)
236     {
237     	acpi_operand_object     **operand = &walk_state->operands[0];
238     	acpi_operand_object     *ret_desc = NULL;
239     	acpi_status             status = AE_OK;
240     	u32                     index;
241     	u32                     match_value = (u32) -1;
242     
243     
244     	FUNCTION_TRACE ("Ex_hexadic");
245     
246     #define pkg_desc            operand[0]
247     #define op1_desc            operand[1]
248     #define V1_desc             operand[2]
249     #define op2_desc            operand[3]
250     #define V2_desc             operand[4]
251     #define start_desc          operand[5]
252     
253     
254     	switch (opcode) {
255     
256     		case AML_MATCH_OP:
257     
258     		/* Validate match comparison sub-opcodes */
259     
260     		if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) ||
261     			(op2_desc->integer.value > MAX_MATCH_OPERATOR)) {
262     			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "operation encoding out of range\n"));
263     			status = AE_AML_OPERAND_VALUE;
264     			goto cleanup;
265     		}
266     
267     		index = (u32) start_desc->integer.value;
268     		if (index >= (u32) pkg_desc->package.count) {
269     			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Start position value out of range\n"));
270     			status = AE_AML_PACKAGE_LIMIT;
271     			goto cleanup;
272     		}
273     
274     		ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
275     		if (!ret_desc) {
276     			status = AE_NO_MEMORY;
277     			goto cleanup;
278     
279     		}
280     
281     		/*
282     		 * Examine each element until a match is found.  Within the loop,
283     		 * "continue" signifies that the current element does not match
284     		 * and the next should be examined.
285     		 * Upon finding a match, the loop will terminate via "break" at
286     		 * the bottom.  If it terminates "normally", Match_value will be -1
287     		 * (its initial value) indicating that no match was found.  When
288     		 * returned as a Number, this will produce the Ones value as specified.
289     		 */
290     		for ( ; index < pkg_desc->package.count; ++index) {
291     			/*
292     			 * Treat any NULL or non-numeric elements as non-matching.
293     			 * TBD [Unhandled] - if an element is a Name,
294     			 *      should we examine its value?
295     			 */
296     			if (!pkg_desc->package.elements[index] ||
297     				ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) {
298     				continue;
299     			}
300     
301     			/*
302     			 * Within these switch statements:
303     			 *      "break" (exit from the switch) signifies a match;
304     			 *      "continue" (proceed to next iteration of enclosing
305     			 *          "for" loop) signifies a non-match.
306     			 */
307     			switch (op1_desc->integer.value) {
308     
309     			case MATCH_MTR:   /* always true */
310     
311     				break;
312     
313     
314     			case MATCH_MEQ:   /* true if equal   */
315     
316     				if (pkg_desc->package.elements[index]->integer.value
317     					 != V1_desc->integer.value) {
318     					continue;
319     				}
320     				break;
321     
322     
323     			case MATCH_MLE:   /* true if less than or equal  */
324     
325     				if (pkg_desc->package.elements[index]->integer.value
326     					 > V1_desc->integer.value) {
327     					continue;
328     				}
329     				break;
330     
331     
332     			case MATCH_MLT:   /* true if less than   */
333     
334     				if (pkg_desc->package.elements[index]->integer.value
335     					 >= V1_desc->integer.value) {
336     					continue;
337     				}
338     				break;
339     
340     
341     			case MATCH_MGE:   /* true if greater than or equal   */
342     
343     				if (pkg_desc->package.elements[index]->integer.value
344     					 < V1_desc->integer.value) {
345     					continue;
346     				}
347     				break;
348     
349     
350     			case MATCH_MGT:   /* true if greater than    */
351     
352     				if (pkg_desc->package.elements[index]->integer.value
353     					 <= V1_desc->integer.value) {
354     					continue;
355     				}
356     				break;
357     
358     
359     			default:    /* undefined   */
360     
361     				continue;
362     			}
363     
364     
365     			switch(op2_desc->integer.value) {
366     
367     			case MATCH_MTR:
368     
369     				break;
370     
371     
372     			case MATCH_MEQ:
373     
374     				if (pkg_desc->package.elements[index]->integer.value
375     					 != V2_desc->integer.value) {
376     					continue;
377     				}
378     				break;
379     
380     
381     			case MATCH_MLE:
382     
383     				if (pkg_desc->package.elements[index]->integer.value
384     					 > V2_desc->integer.value) {
385     					continue;
386     				}
387     				break;
388     
389     
390     			case MATCH_MLT:
391     
392     				if (pkg_desc->package.elements[index]->integer.value
393     					 >= V2_desc->integer.value) {
394     					continue;
395     				}
396     				break;
397     
398     
399     			case MATCH_MGE:
400     
401     				if (pkg_desc->package.elements[index]->integer.value
402     					 < V2_desc->integer.value) {
403     					continue;
404     				}
405     				break;
406     
407     
408     			case MATCH_MGT:
409     
410     				if (pkg_desc->package.elements[index]->integer.value
411     					 <= V2_desc->integer.value) {
412     					continue;
413     				}
414     				break;
415     
416     
417     			default:
418     
419     				continue;
420     			}
421     
422     			/* Match found: exit from loop */
423     
424     			match_value = index;
425     			break;
426     		}
427     
428     		/* Match_value is the return value */
429     
430     		ret_desc->integer.value = match_value;
431     		break;
432     
433     	}
434     
435     
436     cleanup:
437     
438     	/* Free the operands */
439     
440     	acpi_ut_remove_reference (start_desc);
441     	acpi_ut_remove_reference (V2_desc);
442     	acpi_ut_remove_reference (op2_desc);
443     	acpi_ut_remove_reference (V1_desc);
444     	acpi_ut_remove_reference (op1_desc);
445     	acpi_ut_remove_reference (pkg_desc);
446     
447     
448     	/* Delete return object on error */
449     
450     	if (ACPI_FAILURE (status) &&
451     		(ret_desc)) {
452     		acpi_ut_remove_reference (ret_desc);
453     		ret_desc = NULL;
454     	}
455     
456     
457     	/* Set the return object and exit */
458     
459     	*return_desc = ret_desc;
460     	return_ACPI_STATUS (status);
461     }
462