1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: exoparg6 - AML execution - opcodes with 6 arguments |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acinterp.h" |
13 | #include "acparser.h" |
14 | #include "amlcode.h" |
15 | |
16 | #define _COMPONENT ACPI_EXECUTER |
17 | ACPI_MODULE_NAME("exoparg6" ) |
18 | |
19 | /*! |
20 | * Naming convention for AML interpreter execution routines. |
21 | * |
22 | * The routines that begin execution of AML opcodes are named with a common |
23 | * convention based upon the number of arguments, the number of target operands, |
24 | * and whether or not a value is returned: |
25 | * |
26 | * AcpiExOpcode_xA_yT_zR |
27 | * |
28 | * Where: |
29 | * |
30 | * xA - ARGUMENTS: The number of arguments (input operands) that are |
31 | * required for this opcode type (1 through 6 args). |
32 | * yT - TARGETS: The number of targets (output operands) that are required |
33 | * for this opcode type (0, 1, or 2 targets). |
34 | * zR - RETURN VALUE: Indicates whether this opcode type returns a value |
35 | * as the function return (0 or 1). |
36 | * |
37 | * The AcpiExOpcode* functions are called via the Dispatcher component with |
38 | * fully resolved operands. |
39 | !*/ |
40 | /* Local prototypes */ |
41 | static u8 |
42 | acpi_ex_do_match(u32 match_op, |
43 | union acpi_operand_object *package_obj, |
44 | union acpi_operand_object *match_obj); |
45 | |
46 | /******************************************************************************* |
47 | * |
48 | * FUNCTION: acpi_ex_do_match |
49 | * |
50 | * PARAMETERS: match_op - The AML match operand |
51 | * package_obj - Object from the target package |
52 | * match_obj - Object to be matched |
53 | * |
54 | * RETURN: TRUE if the match is successful, FALSE otherwise |
55 | * |
56 | * DESCRIPTION: Implements the low-level match for the ASL Match operator. |
57 | * Package elements will be implicitly converted to the type of |
58 | * the match object (Integer/Buffer/String). |
59 | * |
60 | ******************************************************************************/ |
61 | |
62 | static u8 |
63 | acpi_ex_do_match(u32 match_op, |
64 | union acpi_operand_object *package_obj, |
65 | union acpi_operand_object *match_obj) |
66 | { |
67 | u8 logical_result = TRUE; |
68 | acpi_status status; |
69 | |
70 | /* |
71 | * Note: Since the package_obj/match_obj ordering is opposite to that of |
72 | * the standard logical operators, we have to reverse them when we call |
73 | * do_logical_op in order to make the implicit conversion rules work |
74 | * correctly. However, this means we have to flip the entire equation |
75 | * also. A bit ugly perhaps, but overall, better than fussing the |
76 | * parameters around at runtime, over and over again. |
77 | * |
78 | * Below, P[i] refers to the package element, M refers to the Match object. |
79 | */ |
80 | switch (match_op) { |
81 | case MATCH_MTR: |
82 | |
83 | /* Always true */ |
84 | |
85 | break; |
86 | |
87 | case MATCH_MEQ: |
88 | /* |
89 | * True if equal: (P[i] == M) |
90 | * Change to: (M == P[i]) |
91 | */ |
92 | status = |
93 | acpi_ex_do_logical_op(AML_LOGICAL_EQUAL_OP, operand0: match_obj, |
94 | operand1: package_obj, logical_result: &logical_result); |
95 | if (ACPI_FAILURE(status)) { |
96 | return (FALSE); |
97 | } |
98 | break; |
99 | |
100 | case MATCH_MLE: |
101 | /* |
102 | * True if less than or equal: (P[i] <= M) (P[i] not_greater than M) |
103 | * Change to: (M >= P[i]) (M not_less than P[i]) |
104 | */ |
105 | status = |
106 | acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, operand0: match_obj, |
107 | operand1: package_obj, logical_result: &logical_result); |
108 | if (ACPI_FAILURE(status)) { |
109 | return (FALSE); |
110 | } |
111 | logical_result = (u8) ! logical_result; |
112 | break; |
113 | |
114 | case MATCH_MLT: |
115 | /* |
116 | * True if less than: (P[i] < M) |
117 | * Change to: (M > P[i]) |
118 | */ |
119 | status = |
120 | acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, operand0: match_obj, |
121 | operand1: package_obj, logical_result: &logical_result); |
122 | if (ACPI_FAILURE(status)) { |
123 | return (FALSE); |
124 | } |
125 | break; |
126 | |
127 | case MATCH_MGE: |
128 | /* |
129 | * True if greater than or equal: (P[i] >= M) (P[i] not_less than M) |
130 | * Change to: (M <= P[i]) (M not_greater than P[i]) |
131 | */ |
132 | status = |
133 | acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, operand0: match_obj, |
134 | operand1: package_obj, logical_result: &logical_result); |
135 | if (ACPI_FAILURE(status)) { |
136 | return (FALSE); |
137 | } |
138 | logical_result = (u8) ! logical_result; |
139 | break; |
140 | |
141 | case MATCH_MGT: |
142 | /* |
143 | * True if greater than: (P[i] > M) |
144 | * Change to: (M < P[i]) |
145 | */ |
146 | status = |
147 | acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, operand0: match_obj, |
148 | operand1: package_obj, logical_result: &logical_result); |
149 | if (ACPI_FAILURE(status)) { |
150 | return (FALSE); |
151 | } |
152 | break; |
153 | |
154 | default: |
155 | |
156 | /* Undefined */ |
157 | |
158 | return (FALSE); |
159 | } |
160 | |
161 | return (logical_result); |
162 | } |
163 | |
164 | /******************************************************************************* |
165 | * |
166 | * FUNCTION: acpi_ex_opcode_6A_0T_1R |
167 | * |
168 | * PARAMETERS: walk_state - Current walk state |
169 | * |
170 | * RETURN: Status |
171 | * |
172 | * DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value |
173 | * |
174 | ******************************************************************************/ |
175 | |
176 | acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state *walk_state) |
177 | { |
178 | union acpi_operand_object **operand = &walk_state->operands[0]; |
179 | union acpi_operand_object *return_desc = NULL; |
180 | acpi_status status = AE_OK; |
181 | u64 index; |
182 | union acpi_operand_object *this_element; |
183 | |
184 | ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, |
185 | acpi_ps_get_opcode_name(walk_state->opcode)); |
186 | |
187 | switch (walk_state->opcode) { |
188 | case AML_MATCH_OP: |
189 | /* |
190 | * Match (search_pkg[0], match_op1[1], match_obj1[2], |
191 | * match_op2[3], match_obj2[4], start_index[5]) |
192 | */ |
193 | |
194 | /* Validate both Match Term Operators (MTR, MEQ, etc.) */ |
195 | |
196 | if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || |
197 | (operand[3]->integer.value > MAX_MATCH_OPERATOR)) { |
198 | ACPI_ERROR((AE_INFO, "Match operator out of range" )); |
199 | status = AE_AML_OPERAND_VALUE; |
200 | goto cleanup; |
201 | } |
202 | |
203 | /* Get the package start_index, validate against the package length */ |
204 | |
205 | index = operand[5]->integer.value; |
206 | if (index >= operand[0]->package.count) { |
207 | ACPI_ERROR((AE_INFO, |
208 | "Index (0x%8.8X%8.8X) beyond package end (0x%X)" , |
209 | ACPI_FORMAT_UINT64(index), |
210 | operand[0]->package.count)); |
211 | status = AE_AML_PACKAGE_LIMIT; |
212 | goto cleanup; |
213 | } |
214 | |
215 | /* Create an integer for the return value */ |
216 | /* Default return value is ACPI_UINT64_MAX if no match found */ |
217 | |
218 | return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX); |
219 | if (!return_desc) { |
220 | status = AE_NO_MEMORY; |
221 | goto cleanup; |
222 | |
223 | } |
224 | |
225 | /* |
226 | * Examine each element until a match is found. Both match conditions |
227 | * must be satisfied for a match to occur. Within the loop, |
228 | * "continue" signifies that the current element does not match |
229 | * and the next should be examined. |
230 | * |
231 | * Upon finding a match, the loop will terminate via "break" at |
232 | * the bottom. If it terminates "normally", match_value will be |
233 | * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no |
234 | * match was found. |
235 | */ |
236 | for (; index < operand[0]->package.count; index++) { |
237 | |
238 | /* Get the current package element */ |
239 | |
240 | this_element = operand[0]->package.elements[index]; |
241 | |
242 | /* Treat any uninitialized (NULL) elements as non-matching */ |
243 | |
244 | if (!this_element) { |
245 | continue; |
246 | } |
247 | |
248 | /* |
249 | * Both match conditions must be satisfied. Execution of a continue |
250 | * (proceed to next iteration of enclosing for loop) signifies a |
251 | * non-match. |
252 | */ |
253 | if (!acpi_ex_do_match(match_op: (u32) operand[1]->integer.value, |
254 | package_obj: this_element, match_obj: operand[2])) { |
255 | continue; |
256 | } |
257 | |
258 | if (!acpi_ex_do_match(match_op: (u32) operand[3]->integer.value, |
259 | package_obj: this_element, match_obj: operand[4])) { |
260 | continue; |
261 | } |
262 | |
263 | /* Match found: Index is the return value */ |
264 | |
265 | return_desc->integer.value = index; |
266 | break; |
267 | } |
268 | break; |
269 | |
270 | case AML_LOAD_TABLE_OP: |
271 | |
272 | status = acpi_ex_load_table_op(walk_state, return_desc: &return_desc); |
273 | break; |
274 | |
275 | default: |
276 | |
277 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X" , |
278 | walk_state->opcode)); |
279 | |
280 | status = AE_AML_BAD_OPCODE; |
281 | goto cleanup; |
282 | } |
283 | |
284 | cleanup: |
285 | |
286 | /* Delete return object on error */ |
287 | |
288 | if (ACPI_FAILURE(status)) { |
289 | acpi_ut_remove_reference(object: return_desc); |
290 | } |
291 | |
292 | /* Save return object on success */ |
293 | |
294 | else { |
295 | walk_state->result_obj = return_desc; |
296 | } |
297 | |
298 | return_ACPI_STATUS(status); |
299 | } |
300 | |