GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / acpi / acpica / exmisc.c
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 - 2018, 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 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         union acpi_operand_object *reference_obj;
38         union acpi_operand_object *referenced_obj;
39
40         ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
41
42         *return_desc = NULL;
43
44         switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
45         case ACPI_DESC_TYPE_OPERAND:
46
47                 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                 switch (obj_desc->reference.class) {
55                 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                         referenced_obj = obj_desc->reference.object;
62                         break;
63
64                 default:
65
66                         ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
67                                     obj_desc->reference.class));
68                         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
69                 }
70                 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         default:
80
81                 ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
82                             ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
83                 return_ACPI_STATUS(AE_TYPE);
84         }
85
86         /* Create a new reference object */
87
88         reference_obj =
89             acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
90         if (!reference_obj) {
91                 return_ACPI_STATUS(AE_NO_MEMORY);
92         }
93
94         reference_obj->reference.class = ACPI_REFCLASS_REFOF;
95         reference_obj->reference.object = referenced_obj;
96         *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                           *return_desc));
102
103         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 u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
123 {
124
125         ACPI_FUNCTION_ENTRY();
126
127         switch (opcode) {
128         case AML_ADD_OP:        /* Add (Integer0, Integer1, Result) */
129
130                 return (integer0 + integer1);
131
132         case AML_BIT_AND_OP:    /* And (Integer0, Integer1, Result) */
133
134                 return (integer0 & integer1);
135
136         case AML_BIT_NAND_OP:   /* NAnd (Integer0, Integer1, Result) */
137
138                 return (~(integer0 & integer1));
139
140         case AML_BIT_OR_OP:     /* Or (Integer0, Integer1, Result) */
141
142                 return (integer0 | integer1);
143
144         case AML_BIT_NOR_OP:    /* NOr (Integer0, Integer1, Result) */
145
146                 return (~(integer0 | integer1));
147
148         case AML_BIT_XOR_OP:    /* XOr (Integer0, Integer1, Result) */
149
150                 return (integer0 ^ integer1);
151
152         case AML_MULTIPLY_OP:   /* Multiply (Integer0, Integer1, Result) */
153
154                 return (integer0 * integer1);
155
156         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                 if (integer1 >= acpi_gbl_integer_bit_width) {
163                         return (0);
164                 }
165                 return (integer0 << integer1);
166
167         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                 if (integer1 >= acpi_gbl_integer_bit_width) {
174                         return (0);
175                 }
176                 return (integer0 >> integer1);
177
178         case AML_SUBTRACT_OP:   /* Subtract (Integer0, Integer1, Result) */
179
180                 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 acpi_ex_do_logical_numeric_op(u16 opcode,
210                               u64 integer0, u64 integer1, u8 *logical_result)
211 {
212         acpi_status status = AE_OK;
213         u8 local_result = FALSE;
214
215         ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
216
217         switch (opcode) {
218         case AML_LOGICAL_AND_OP:        /* LAnd (Integer0, Integer1) */
219
220                 if (integer0 && integer1) {
221                         local_result = TRUE;
222                 }
223                 break;
224
225         case AML_LOGICAL_OR_OP: /* LOr (Integer0, Integer1) */
226
227                 if (integer0 || integer1) {
228                         local_result = TRUE;
229                 }
230                 break;
231
232         default:
233
234                 ACPI_ERROR((AE_INFO,
235                             "Invalid numeric logical opcode: %X", opcode));
236                 status = AE_AML_INTERNAL;
237                 break;
238         }
239
240         /* Return the logical result and status */
241
242         *logical_result = local_result;
243         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 acpi_ex_do_logical_op(u16 opcode,
274                       union acpi_operand_object *operand0,
275                       union acpi_operand_object *operand1, u8 * logical_result)
276 {
277         union acpi_operand_object *local_operand1 = operand1;
278         u64 integer0;
279         u64 integer1;
280         u32 length0;
281         u32 length1;
282         acpi_status status = AE_OK;
283         u8 local_result = FALSE;
284         int compare;
285
286         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         switch (operand0->common.type) {
296         case ACPI_TYPE_INTEGER:
297
298                 status = acpi_ex_convert_to_integer(operand1, &local_operand1,
299                                                     ACPI_IMPLICIT_CONVERSION);
300                 break;
301
302         case ACPI_TYPE_STRING:
303
304                 status =
305                     acpi_ex_convert_to_string(operand1, &local_operand1,
306                                               ACPI_IMPLICIT_CONVERT_HEX);
307                 break;
308
309         case ACPI_TYPE_BUFFER:
310
311                 status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
312                 break;
313
314         default:
315
316                 ACPI_ERROR((AE_INFO,
317                             "Invalid object type for logical operator: %X",
318                             operand0->common.type));
319                 status = AE_AML_INTERNAL;
320                 break;
321         }
322
323         if (ACPI_FAILURE(status)) {
324                 goto cleanup;
325         }
326
327         /*
328          * Two cases: 1) Both Integers, 2) Both Strings or Buffers
329          */
330         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                 integer0 = operand0->integer.value;
336                 integer1 = local_operand1->integer.value;
337
338                 switch (opcode) {
339                 case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
340
341                         if (integer0 == integer1) {
342                                 local_result = TRUE;
343                         }
344                         break;
345
346                 case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
347
348                         if (integer0 > integer1) {
349                                 local_result = TRUE;
350                         }
351                         break;
352
353                 case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
354
355                         if (integer0 < integer1) {
356                                 local_result = TRUE;
357                         }
358                         break;
359
360                 default:
361
362                         ACPI_ERROR((AE_INFO,
363                                     "Invalid comparison opcode: %X", opcode));
364                         status = AE_AML_INTERNAL;
365                         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                 length0 = operand0->buffer.length;
375                 length1 = local_operand1->buffer.length;
376
377                 /* Lexicographic compare: compare the data bytes */
378
379                 compare = memcmp(operand0->buffer.pointer,
380                                  local_operand1->buffer.pointer,
381                                  (length0 > length1) ? length1 : length0);
382
383                 switch (opcode) {
384                 case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
385
386                         /* Length and all bytes must be equal */
387
388                         if ((length0 == length1) && (compare == 0)) {
389
390                                 /* Length and all bytes match ==> TRUE */
391
392                                 local_result = TRUE;
393                         }
394                         break;
395
396                 case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
397
398                         if (compare > 0) {
399                                 local_result = TRUE;
400                                 goto cleanup;   /* TRUE */
401                         }
402                         if (compare < 0) {
403                                 goto cleanup;   /* FALSE */
404                         }
405
406                         /* Bytes match (to shortest length), compare lengths */
407
408                         if (length0 > length1) {
409                                 local_result = TRUE;
410                         }
411                         break;
412
413                 case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
414
415                         if (compare > 0) {
416                                 goto cleanup;   /* FALSE */
417                         }
418                         if (compare < 0) {
419                                 local_result = TRUE;
420                                 goto cleanup;   /* TRUE */
421                         }
422
423                         /* Bytes match (to shortest length), compare lengths */
424
425                         if (length0 < length1) {
426                                 local_result = TRUE;
427                         }
428                         break;
429
430                 default:
431
432                         ACPI_ERROR((AE_INFO,
433                                     "Invalid comparison opcode: %X", opcode));
434                         status = AE_AML_INTERNAL;
435                         break;
436                 }
437         }
438
439 cleanup:
440
441         /* New object was created if implicit conversion performed - delete */
442
443         if (local_operand1 != operand1) {
444                 acpi_ut_remove_reference(local_operand1);
445         }
446
447         /* Return the logical result and status */
448
449         *logical_result = local_result;
450         return_ACPI_STATUS(status);
451 }