Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acinterp.h"
13 : : #include "amlcode.h"
14 : :
15 : : #define _COMPONENT ACPI_EXECUTER
16 : : ACPI_MODULE_NAME("exmisc")
17 : :
18 : : /*******************************************************************************
19 : : *
20 : : * FUNCTION: acpi_ex_get_object_reference
21 : : *
22 : : * PARAMETERS: obj_desc - Create a reference to this object
23 : : * return_desc - Where to store the reference
24 : : * walk_state - Current state
25 : : *
26 : : * RETURN: Status
27 : : *
28 : : * DESCRIPTION: Obtain and return a "reference" to the target object
29 : : * Common code for the ref_of_op and the cond_ref_of_op.
30 : : *
31 : : ******************************************************************************/
32 : : acpi_status
33 : 0 : acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
34 : : union acpi_operand_object **return_desc,
35 : : struct acpi_walk_state *walk_state)
36 : : {
37 : 0 : union acpi_operand_object *reference_obj;
38 : 0 : union acpi_operand_object *referenced_obj;
39 : :
40 : 0 : ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
41 : :
42 : 0 : *return_desc = NULL;
43 : :
44 [ # # # ]: 0 : switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
45 : 0 : case ACPI_DESC_TYPE_OPERAND:
46 : :
47 [ # # ]: 0 : if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
48 : : return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
49 : : }
50 : :
51 : : /*
52 : : * Must be a reference to a Local or Arg
53 : : */
54 [ # # ]: 0 : switch (obj_desc->reference.class) {
55 : 0 : case ACPI_REFCLASS_LOCAL:
56 : : case ACPI_REFCLASS_ARG:
57 : : case ACPI_REFCLASS_DEBUG:
58 : :
59 : : /* The referenced object is the pseudo-node for the local/arg */
60 : :
61 : 0 : referenced_obj = obj_desc->reference.object;
62 : 0 : break;
63 : :
64 : 0 : default:
65 : :
66 : 0 : ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
67 : : obj_desc->reference.class));
68 : 0 : return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
69 : : }
70 : 0 : break;
71 : :
72 : : case ACPI_DESC_TYPE_NAMED:
73 : : /*
74 : : * A named reference that has already been resolved to a Node
75 : : */
76 : : referenced_obj = obj_desc;
77 : : break;
78 : :
79 : 0 : default:
80 : :
81 : 0 : ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
82 : : ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
83 : 0 : return_ACPI_STATUS(AE_TYPE);
84 : : }
85 : :
86 : : /* Create a new reference object */
87 : :
88 : 0 : reference_obj =
89 : 0 : acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
90 [ # # ]: 0 : if (!reference_obj) {
91 : : return_ACPI_STATUS(AE_NO_MEMORY);
92 : : }
93 : :
94 : 0 : reference_obj->reference.class = ACPI_REFCLASS_REFOF;
95 : 0 : reference_obj->reference.object = referenced_obj;
96 : 0 : *return_desc = reference_obj;
97 : :
98 : : ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
99 : : "Object %p Type [%s], returning Reference %p\n",
100 : : obj_desc, acpi_ut_get_object_type_name(obj_desc),
101 : 0 : *return_desc));
102 : :
103 : 0 : return_ACPI_STATUS(AE_OK);
104 : : }
105 : :
106 : : /*******************************************************************************
107 : : *
108 : : * FUNCTION: acpi_ex_do_math_op
109 : : *
110 : : * PARAMETERS: opcode - AML opcode
111 : : * integer0 - Integer operand #0
112 : : * integer1 - Integer operand #1
113 : : *
114 : : * RETURN: Integer result of the operation
115 : : *
116 : : * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
117 : : * math functions here is to prevent a lot of pointer dereferencing
118 : : * to obtain the operands.
119 : : *
120 : : ******************************************************************************/
121 : :
122 : 2379 : u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
123 : : {
124 : :
125 : 2379 : ACPI_FUNCTION_ENTRY();
126 : :
127 [ + + - + : 2379 : switch (opcode) {
- - - + +
- - ]
128 : 384 : case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */
129 : :
130 : 384 : return (integer0 + integer1);
131 : :
132 : 819 : case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */
133 : :
134 : 819 : return (integer0 & integer1);
135 : :
136 : 0 : case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */
137 : :
138 : 0 : return (~(integer0 & integer1));
139 : :
140 : 396 : case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */
141 : :
142 : 396 : return (integer0 | integer1);
143 : :
144 : 0 : case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */
145 : :
146 : 0 : return (~(integer0 | integer1));
147 : :
148 : 0 : case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */
149 : :
150 : 0 : return (integer0 ^ integer1);
151 : :
152 : 0 : case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */
153 : :
154 : 0 : return (integer0 * integer1);
155 : :
156 : 384 : case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
157 : :
158 : : /*
159 : : * We need to check if the shiftcount is larger than the integer bit
160 : : * width since the behavior of this is not well-defined in the C language.
161 : : */
162 [ + - ]: 384 : if (integer1 >= acpi_gbl_integer_bit_width) {
163 : : return (0);
164 : : }
165 : 384 : return (integer0 << integer1);
166 : :
167 : 396 : case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */
168 : :
169 : : /*
170 : : * We need to check if the shiftcount is larger than the integer bit
171 : : * width since the behavior of this is not well-defined in the C language.
172 : : */
173 [ + - ]: 396 : if (integer1 >= acpi_gbl_integer_bit_width) {
174 : : return (0);
175 : : }
176 : 396 : return (integer0 >> integer1);
177 : :
178 : 0 : case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */
179 : :
180 : 0 : return (integer0 - integer1);
181 : :
182 : : default:
183 : :
184 : : return (0);
185 : : }
186 : : }
187 : :
188 : : /*******************************************************************************
189 : : *
190 : : * FUNCTION: acpi_ex_do_logical_numeric_op
191 : : *
192 : : * PARAMETERS: opcode - AML opcode
193 : : * integer0 - Integer operand #0
194 : : * integer1 - Integer operand #1
195 : : * logical_result - TRUE/FALSE result of the operation
196 : : *
197 : : * RETURN: Status
198 : : *
199 : : * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
200 : : * operators (LAnd and LOr), both operands must be integers.
201 : : *
202 : : * Note: cleanest machine code seems to be produced by the code
203 : : * below, rather than using statements of the form:
204 : : * Result = (Integer0 && Integer1);
205 : : *
206 : : ******************************************************************************/
207 : :
208 : : acpi_status
209 : 24 : acpi_ex_do_logical_numeric_op(u16 opcode,
210 : : u64 integer0, u64 integer1, u8 *logical_result)
211 : : {
212 : 24 : acpi_status status = AE_OK;
213 : 24 : u8 local_result = FALSE;
214 : :
215 : 24 : ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
216 : :
217 [ - + - ]: 24 : switch (opcode) {
218 : 0 : case AML_LOGICAL_AND_OP: /* LAnd (Integer0, Integer1) */
219 : :
220 [ # # ]: 0 : if (integer0 && integer1) {
221 : 0 : local_result = TRUE;
222 : : }
223 : : break;
224 : :
225 : 24 : case AML_LOGICAL_OR_OP: /* LOr (Integer0, Integer1) */
226 : :
227 [ - + ]: 24 : if (integer0 || integer1) {
228 : 0 : local_result = TRUE;
229 : : }
230 : : break;
231 : :
232 : 0 : default:
233 : :
234 : 0 : ACPI_ERROR((AE_INFO,
235 : : "Invalid numeric logical opcode: %X", opcode));
236 : 0 : status = AE_AML_INTERNAL;
237 : 0 : break;
238 : : }
239 : :
240 : : /* Return the logical result and status */
241 : :
242 : 24 : *logical_result = local_result;
243 : 24 : return_ACPI_STATUS(status);
244 : : }
245 : :
246 : : /*******************************************************************************
247 : : *
248 : : * FUNCTION: acpi_ex_do_logical_op
249 : : *
250 : : * PARAMETERS: opcode - AML opcode
251 : : * operand0 - operand #0
252 : : * operand1 - operand #1
253 : : * logical_result - TRUE/FALSE result of the operation
254 : : *
255 : : * RETURN: Status
256 : : *
257 : : * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
258 : : * functions here is to prevent a lot of pointer dereferencing
259 : : * to obtain the operands and to simplify the generation of the
260 : : * logical value. For the Numeric operators (LAnd and LOr), both
261 : : * operands must be integers. For the other logical operators,
262 : : * operands can be any combination of Integer/String/Buffer. The
263 : : * first operand determines the type to which the second operand
264 : : * will be converted.
265 : : *
266 : : * Note: cleanest machine code seems to be produced by the code
267 : : * below, rather than using statements of the form:
268 : : * Result = (Operand0 == Operand1);
269 : : *
270 : : ******************************************************************************/
271 : :
272 : : acpi_status
273 : 2136 : acpi_ex_do_logical_op(u16 opcode,
274 : : union acpi_operand_object *operand0,
275 : : union acpi_operand_object *operand1, u8 * logical_result)
276 : : {
277 : 2136 : union acpi_operand_object *local_operand1 = operand1;
278 : 2136 : u64 integer0;
279 : 2136 : u64 integer1;
280 : 2136 : u32 length0;
281 : 2136 : u32 length1;
282 : 2136 : acpi_status status = AE_OK;
283 : 2136 : u8 local_result = FALSE;
284 : 2136 : int compare;
285 : :
286 : 2136 : ACPI_FUNCTION_TRACE(ex_do_logical_op);
287 : :
288 : : /*
289 : : * Convert the second operand if necessary. The first operand
290 : : * determines the type of the second operand, (See the Data Types
291 : : * section of the ACPI 3.0+ specification.) Both object types are
292 : : * guaranteed to be either Integer/String/Buffer by the operand
293 : : * resolution mechanism.
294 : : */
295 [ + - - - ]: 2136 : switch (operand0->common.type) {
296 : 2136 : case ACPI_TYPE_INTEGER:
297 : :
298 : 2136 : status = acpi_ex_convert_to_integer(operand1, &local_operand1,
299 : : ACPI_IMPLICIT_CONVERSION);
300 : 2136 : break;
301 : :
302 : 0 : case ACPI_TYPE_STRING:
303 : :
304 : 0 : status =
305 : 0 : acpi_ex_convert_to_string(operand1, &local_operand1,
306 : : ACPI_IMPLICIT_CONVERT_HEX);
307 : 0 : break;
308 : :
309 : 0 : case ACPI_TYPE_BUFFER:
310 : :
311 : 0 : status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
312 : 0 : break;
313 : :
314 : 0 : default:
315 : :
316 : 0 : ACPI_ERROR((AE_INFO,
317 : : "Invalid object type for logical operator: %X",
318 : : operand0->common.type));
319 : 0 : status = AE_AML_INTERNAL;
320 : 0 : break;
321 : : }
322 : :
323 [ - + ]: 2136 : if (ACPI_FAILURE(status)) {
324 : 0 : goto cleanup;
325 : : }
326 : :
327 : : /*
328 : : * Two cases: 1) Both Integers, 2) Both Strings or Buffers
329 : : */
330 [ + - ]: 2136 : if (operand0->common.type == ACPI_TYPE_INTEGER) {
331 : : /*
332 : : * 1) Both operands are of type integer
333 : : * Note: local_operand1 may have changed above
334 : : */
335 : 2136 : integer0 = operand0->integer.value;
336 : 2136 : integer1 = local_operand1->integer.value;
337 : :
338 [ + + + - ]: 2136 : switch (opcode) {
339 : 1710 : case AML_LOGICAL_EQUAL_OP: /* LEqual (Operand0, Operand1) */
340 : :
341 [ + + ]: 1710 : if (integer0 == integer1) {
342 : 405 : local_result = TRUE;
343 : : }
344 : : break;
345 : :
346 : 12 : case AML_LOGICAL_GREATER_OP: /* LGreater (Operand0, Operand1) */
347 : :
348 [ - + ]: 12 : if (integer0 > integer1) {
349 : 0 : local_result = TRUE;
350 : : }
351 : : break;
352 : :
353 : 414 : case AML_LOGICAL_LESS_OP: /* LLess (Operand0, Operand1) */
354 : :
355 [ + + ]: 414 : if (integer0 < integer1) {
356 : 411 : local_result = TRUE;
357 : : }
358 : : break;
359 : :
360 : 0 : default:
361 : :
362 : 0 : ACPI_ERROR((AE_INFO,
363 : : "Invalid comparison opcode: %X", opcode));
364 : 0 : status = AE_AML_INTERNAL;
365 : 0 : break;
366 : : }
367 : : } else {
368 : : /*
369 : : * 2) Both operands are Strings or both are Buffers
370 : : * Note: Code below takes advantage of common Buffer/String
371 : : * object fields. local_operand1 may have changed above. Use
372 : : * memcmp to handle nulls in buffers.
373 : : */
374 : 0 : length0 = operand0->buffer.length;
375 : 0 : length1 = local_operand1->buffer.length;
376 : :
377 : : /* Lexicographic compare: compare the data bytes */
378 : :
379 : 0 : compare = memcmp(operand0->buffer.pointer,
380 : 0 : local_operand1->buffer.pointer,
381 : 0 : (length0 > length1) ? length1 : length0);
382 : :
383 [ # # # # ]: 0 : switch (opcode) {
384 : 0 : case AML_LOGICAL_EQUAL_OP: /* LEqual (Operand0, Operand1) */
385 : :
386 : : /* Length and all bytes must be equal */
387 : :
388 [ # # ]: 0 : if ((length0 == length1) && (compare == 0)) {
389 : :
390 : : /* Length and all bytes match ==> TRUE */
391 : :
392 : 0 : local_result = TRUE;
393 : : }
394 : : break;
395 : :
396 : 0 : case AML_LOGICAL_GREATER_OP: /* LGreater (Operand0, Operand1) */
397 : :
398 [ # # ]: 0 : if (compare > 0) {
399 : 0 : local_result = TRUE;
400 : 0 : goto cleanup; /* TRUE */
401 : : }
402 [ # # ]: 0 : if (compare < 0) {
403 : 0 : goto cleanup; /* FALSE */
404 : : }
405 : :
406 : : /* Bytes match (to shortest length), compare lengths */
407 : :
408 [ # # ]: 0 : if (length0 > length1) {
409 : 0 : local_result = TRUE;
410 : : }
411 : : break;
412 : :
413 : 0 : case AML_LOGICAL_LESS_OP: /* LLess (Operand0, Operand1) */
414 : :
415 [ # # ]: 0 : if (compare > 0) {
416 : 0 : goto cleanup; /* FALSE */
417 : : }
418 [ # # ]: 0 : if (compare < 0) {
419 : 0 : local_result = TRUE;
420 : 0 : goto cleanup; /* TRUE */
421 : : }
422 : :
423 : : /* Bytes match (to shortest length), compare lengths */
424 : :
425 [ # # ]: 0 : if (length0 < length1) {
426 : 0 : local_result = TRUE;
427 : : }
428 : : break;
429 : :
430 : 0 : default:
431 : :
432 : 0 : ACPI_ERROR((AE_INFO,
433 : : "Invalid comparison opcode: %X", opcode));
434 : 0 : status = AE_AML_INTERNAL;
435 : 0 : break;
436 : : }
437 : : }
438 : :
439 : 2136 : cleanup:
440 : :
441 : : /* New object was created if implicit conversion performed - delete */
442 : :
443 [ - + ]: 2136 : if (local_operand1 != operand1) {
444 : 0 : acpi_ut_remove_reference(local_operand1);
445 : : }
446 : :
447 : : /* Return the logical result and status */
448 : :
449 : 2136 : *logical_result = local_result;
450 : 2136 : return_ACPI_STATUS(status);
451 : : }
|