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