xref: /openbmc/linux/drivers/acpi/acpica/exoparg2.c (revision 2a598d0b)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
5  *
6  * Copyright (C) 2000 - 2023, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acparser.h"
13 #include "acinterp.h"
14 #include "acevents.h"
15 #include "amlcode.h"
16 
17 #define _COMPONENT          ACPI_EXECUTER
18 ACPI_MODULE_NAME("exoparg2")
19 
20 /*!
21  * Naming convention for AML interpreter execution routines.
22  *
23  * The routines that begin execution of AML opcodes are named with a common
24  * convention based upon the number of arguments, the number of target operands,
25  * and whether or not a value is returned:
26  *
27  *      AcpiExOpcode_xA_yT_zR
28  *
29  * Where:
30  *
31  * xA - ARGUMENTS:    The number of arguments (input operands) that are
32  *                    required for this opcode type (1 through 6 args).
33  * yT - TARGETS:      The number of targets (output operands) that are required
34  *                    for this opcode type (0, 1, or 2 targets).
35  * zR - RETURN VALUE: Indicates whether this opcode type returns a value
36  *                    as the function return (0 or 1).
37  *
38  * The AcpiExOpcode* functions are called via the Dispatcher component with
39  * fully resolved operands.
40 !*/
41 /*******************************************************************************
42  *
43  * FUNCTION:    acpi_ex_opcode_2A_0T_0R
44  *
45  * PARAMETERS:  walk_state          - Current walk state
46  *
47  * RETURN:      Status
48  *
49  * DESCRIPTION: Execute opcode with two arguments, no target, and no return
50  *              value.
51  *
52  * ALLOCATION:  Deletes both operands
53  *
54  ******************************************************************************/
55 acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state)
56 {
57 	union acpi_operand_object **operand = &walk_state->operands[0];
58 	struct acpi_namespace_node *node;
59 	u32 value;
60 	acpi_status status = AE_OK;
61 
62 	ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R,
63 				acpi_ps_get_opcode_name(walk_state->opcode));
64 
65 	/* Examine the opcode */
66 
67 	switch (walk_state->opcode) {
68 	case AML_NOTIFY_OP:	/* Notify (notify_object, notify_value) */
69 
70 		/* The first operand is a namespace node */
71 
72 		node = (struct acpi_namespace_node *)operand[0];
73 
74 		/* Second value is the notify value */
75 
76 		value = (u32) operand[1]->integer.value;
77 
78 		/* Are notifies allowed on this object? */
79 
80 		if (!acpi_ev_is_notify_object(node)) {
81 			ACPI_ERROR((AE_INFO,
82 				    "Unexpected notify object type [%s]",
83 				    acpi_ut_get_type_name(node->type)));
84 
85 			status = AE_AML_OPERAND_TYPE;
86 			break;
87 		}
88 
89 		/*
90 		 * Dispatch the notify to the appropriate handler
91 		 * NOTE: the request is queued for execution after this method
92 		 * completes. The notify handlers are NOT invoked synchronously
93 		 * from this thread -- because handlers may in turn run other
94 		 * control methods.
95 		 */
96 		status = acpi_ev_queue_notify_request(node, value);
97 		break;
98 
99 	default:
100 
101 		ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
102 			    walk_state->opcode));
103 		status = AE_AML_BAD_OPCODE;
104 	}
105 
106 	return_ACPI_STATUS(status);
107 }
108 
109 /*******************************************************************************
110  *
111  * FUNCTION:    acpi_ex_opcode_2A_2T_1R
112  *
113  * PARAMETERS:  walk_state          - Current walk state
114  *
115  * RETURN:      Status
116  *
117  * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets
118  *              and one implicit return value.
119  *
120  ******************************************************************************/
121 
122 acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
123 {
124 	union acpi_operand_object **operand = &walk_state->operands[0];
125 	union acpi_operand_object *return_desc1 = NULL;
126 	union acpi_operand_object *return_desc2 = NULL;
127 	acpi_status status;
128 
129 	ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R,
130 				acpi_ps_get_opcode_name(walk_state->opcode));
131 
132 	/* Execute the opcode */
133 
134 	switch (walk_state->opcode) {
135 	case AML_DIVIDE_OP:
136 
137 		/* Divide (Dividend, Divisor, remainder_result quotient_result) */
138 
139 		return_desc1 =
140 		    acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
141 		if (!return_desc1) {
142 			status = AE_NO_MEMORY;
143 			goto cleanup;
144 		}
145 
146 		return_desc2 =
147 		    acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
148 		if (!return_desc2) {
149 			status = AE_NO_MEMORY;
150 			goto cleanup;
151 		}
152 
153 		/* Quotient to return_desc1, remainder to return_desc2 */
154 
155 		status = acpi_ut_divide(operand[0]->integer.value,
156 					operand[1]->integer.value,
157 					&return_desc1->integer.value,
158 					&return_desc2->integer.value);
159 		if (ACPI_FAILURE(status)) {
160 			goto cleanup;
161 		}
162 		break;
163 
164 	default:
165 
166 		ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
167 			    walk_state->opcode));
168 
169 		status = AE_AML_BAD_OPCODE;
170 		goto cleanup;
171 	}
172 
173 	/* Store the results to the target reference operands */
174 
175 	status = acpi_ex_store(return_desc2, operand[2], walk_state);
176 	if (ACPI_FAILURE(status)) {
177 		goto cleanup;
178 	}
179 
180 	status = acpi_ex_store(return_desc1, operand[3], walk_state);
181 	if (ACPI_FAILURE(status)) {
182 		goto cleanup;
183 	}
184 
185 cleanup:
186 	/*
187 	 * Since the remainder is not returned indirectly, remove a reference to
188 	 * it. Only the quotient is returned indirectly.
189 	 */
190 	acpi_ut_remove_reference(return_desc2);
191 
192 	if (ACPI_FAILURE(status)) {
193 
194 		/* Delete the return object */
195 
196 		acpi_ut_remove_reference(return_desc1);
197 	}
198 
199 	/* Save return object (the remainder) on success */
200 
201 	else {
202 		walk_state->result_obj = return_desc1;
203 	}
204 
205 	return_ACPI_STATUS(status);
206 }
207 
208 /*******************************************************************************
209  *
210  * FUNCTION:    acpi_ex_opcode_2A_1T_1R
211  *
212  * PARAMETERS:  walk_state          - Current walk state
213  *
214  * RETURN:      Status
215  *
216  * DESCRIPTION: Execute opcode with two arguments, one target, and a return
217  *              value.
218  *
219  ******************************************************************************/
220 
221 acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
222 {
223 	union acpi_operand_object **operand = &walk_state->operands[0];
224 	union acpi_operand_object *return_desc = NULL;
225 	u64 index;
226 	acpi_status status = AE_OK;
227 	acpi_size length = 0;
228 
229 	ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R,
230 				acpi_ps_get_opcode_name(walk_state->opcode));
231 
232 	/* Execute the opcode */
233 
234 	if (walk_state->op_info->flags & AML_MATH) {
235 
236 		/* All simple math opcodes (add, etc.) */
237 
238 		return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
239 		if (!return_desc) {
240 			status = AE_NO_MEMORY;
241 			goto cleanup;
242 		}
243 
244 		return_desc->integer.value =
245 		    acpi_ex_do_math_op(walk_state->opcode,
246 				       operand[0]->integer.value,
247 				       operand[1]->integer.value);
248 		goto store_result_to_target;
249 	}
250 
251 	switch (walk_state->opcode) {
252 	case AML_MOD_OP:	/* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */
253 
254 		return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
255 		if (!return_desc) {
256 			status = AE_NO_MEMORY;
257 			goto cleanup;
258 		}
259 
260 		/* return_desc will contain the remainder */
261 
262 		status = acpi_ut_divide(operand[0]->integer.value,
263 					operand[1]->integer.value,
264 					NULL, &return_desc->integer.value);
265 		break;
266 
267 	case AML_CONCATENATE_OP:	/* Concatenate (Data1, Data2, Result) */
268 
269 		status =
270 		    acpi_ex_do_concatenate(operand[0], operand[1], &return_desc,
271 					   walk_state);
272 		break;
273 
274 	case AML_TO_STRING_OP:	/* to_string (Buffer, Length, Result) (ACPI 2.0) */
275 		/*
276 		 * Input object is guaranteed to be a buffer at this point (it may have
277 		 * been converted.)  Copy the raw buffer data to a new object of
278 		 * type String.
279 		 */
280 
281 		/*
282 		 * Get the length of the new string. It is the smallest of:
283 		 * 1) Length of the input buffer
284 		 * 2) Max length as specified in the to_string operator
285 		 * 3) Length of input buffer up to a zero byte (null terminator)
286 		 *
287 		 * NOTE: A length of zero is ok, and will create a zero-length, null
288 		 *       terminated string.
289 		 */
290 		while ((length < operand[0]->buffer.length) &&	/* Length of input buffer */
291 		       (length < operand[1]->integer.value) &&	/* Length operand */
292 		       (operand[0]->buffer.pointer[length])) {	/* Null terminator */
293 			length++;
294 		}
295 
296 		/* Allocate a new string object */
297 
298 		return_desc = acpi_ut_create_string_object(length);
299 		if (!return_desc) {
300 			status = AE_NO_MEMORY;
301 			goto cleanup;
302 		}
303 
304 		/*
305 		 * Copy the raw buffer data with no transform.
306 		 * (NULL terminated already)
307 		 */
308 		memcpy(return_desc->string.pointer,
309 		       operand[0]->buffer.pointer, length);
310 		break;
311 
312 	case AML_CONCATENATE_TEMPLATE_OP:
313 
314 		/* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */
315 
316 		status =
317 		    acpi_ex_concat_template(operand[0], operand[1],
318 					    &return_desc, walk_state);
319 		break;
320 
321 	case AML_INDEX_OP:	/* Index (Source Index Result) */
322 
323 		/* Create the internal return object */
324 
325 		return_desc =
326 		    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
327 		if (!return_desc) {
328 			status = AE_NO_MEMORY;
329 			goto cleanup;
330 		}
331 
332 		/* Initialize the Index reference object */
333 
334 		index = operand[1]->integer.value;
335 		return_desc->reference.value = (u32) index;
336 		return_desc->reference.class = ACPI_REFCLASS_INDEX;
337 
338 		/*
339 		 * At this point, the Source operand is a String, Buffer, or Package.
340 		 * Verify that the index is within range.
341 		 */
342 		switch ((operand[0])->common.type) {
343 		case ACPI_TYPE_STRING:
344 
345 			if (index >= operand[0]->string.length) {
346 				length = operand[0]->string.length;
347 				status = AE_AML_STRING_LIMIT;
348 			}
349 
350 			return_desc->reference.target_type =
351 			    ACPI_TYPE_BUFFER_FIELD;
352 			return_desc->reference.index_pointer =
353 			    &(operand[0]->buffer.pointer[index]);
354 			break;
355 
356 		case ACPI_TYPE_BUFFER:
357 
358 			if (index >= operand[0]->buffer.length) {
359 				length = operand[0]->buffer.length;
360 				status = AE_AML_BUFFER_LIMIT;
361 			}
362 
363 			return_desc->reference.target_type =
364 			    ACPI_TYPE_BUFFER_FIELD;
365 			return_desc->reference.index_pointer =
366 			    &(operand[0]->buffer.pointer[index]);
367 			break;
368 
369 		case ACPI_TYPE_PACKAGE:
370 
371 			if (index >= operand[0]->package.count) {
372 				length = operand[0]->package.count;
373 				status = AE_AML_PACKAGE_LIMIT;
374 			}
375 
376 			return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
377 			return_desc->reference.where =
378 			    &operand[0]->package.elements[index];
379 			break;
380 
381 		default:
382 
383 			ACPI_ERROR((AE_INFO,
384 				    "Invalid object type: %X",
385 				    (operand[0])->common.type));
386 			status = AE_AML_INTERNAL;
387 			goto cleanup;
388 		}
389 
390 		/* Failure means that the Index was beyond the end of the object */
391 
392 		if (ACPI_FAILURE(status)) {
393 			ACPI_BIOS_EXCEPTION((AE_INFO, status,
394 					     "Index (0x%X%8.8X) is beyond end of object (length 0x%X)",
395 					     ACPI_FORMAT_UINT64(index),
396 					     (u32)length));
397 			goto cleanup;
398 		}
399 
400 		/*
401 		 * Save the target object and add a reference to it for the life
402 		 * of the index
403 		 */
404 		return_desc->reference.object = operand[0];
405 		acpi_ut_add_reference(operand[0]);
406 
407 		/* Store the reference to the Target */
408 
409 		status = acpi_ex_store(return_desc, operand[2], walk_state);
410 
411 		/* Return the reference */
412 
413 		walk_state->result_obj = return_desc;
414 		goto cleanup;
415 
416 	default:
417 
418 		ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
419 			    walk_state->opcode));
420 		status = AE_AML_BAD_OPCODE;
421 		break;
422 	}
423 
424 store_result_to_target:
425 
426 	if (ACPI_SUCCESS(status)) {
427 		/*
428 		 * Store the result of the operation (which is now in return_desc) into
429 		 * the Target descriptor.
430 		 */
431 		status = acpi_ex_store(return_desc, operand[2], walk_state);
432 		if (ACPI_FAILURE(status)) {
433 			goto cleanup;
434 		}
435 
436 		if (!walk_state->result_obj) {
437 			walk_state->result_obj = return_desc;
438 		}
439 	}
440 
441 cleanup:
442 
443 	/* Delete return object on error */
444 
445 	if (ACPI_FAILURE(status)) {
446 		acpi_ut_remove_reference(return_desc);
447 		walk_state->result_obj = NULL;
448 	}
449 
450 	return_ACPI_STATUS(status);
451 }
452 
453 /*******************************************************************************
454  *
455  * FUNCTION:    acpi_ex_opcode_2A_0T_1R
456  *
457  * PARAMETERS:  walk_state          - Current walk state
458  *
459  * RETURN:      Status
460  *
461  * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value
462  *
463  ******************************************************************************/
464 
465 acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
466 {
467 	union acpi_operand_object **operand = &walk_state->operands[0];
468 	union acpi_operand_object *return_desc = NULL;
469 	acpi_status status = AE_OK;
470 	u8 logical_result = FALSE;
471 
472 	ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R,
473 				acpi_ps_get_opcode_name(walk_state->opcode));
474 
475 	/* Create the internal return object */
476 
477 	return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
478 	if (!return_desc) {
479 		status = AE_NO_MEMORY;
480 		goto cleanup;
481 	}
482 
483 	/* Execute the Opcode */
484 
485 	if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) {
486 
487 		/* logical_op (Operand0, Operand1) */
488 
489 		status = acpi_ex_do_logical_numeric_op(walk_state->opcode,
490 						       operand[0]->integer.
491 						       value,
492 						       operand[1]->integer.
493 						       value, &logical_result);
494 		goto store_logical_result;
495 	} else if (walk_state->op_info->flags & AML_LOGICAL) {
496 
497 		/* logical_op (Operand0, Operand1) */
498 
499 		status = acpi_ex_do_logical_op(walk_state->opcode, operand[0],
500 					       operand[1], &logical_result);
501 		goto store_logical_result;
502 	}
503 
504 	switch (walk_state->opcode) {
505 	case AML_ACQUIRE_OP:	/* Acquire (mutex_object, Timeout) */
506 
507 		status =
508 		    acpi_ex_acquire_mutex(operand[1], operand[0], walk_state);
509 		if (status == AE_TIME) {
510 			logical_result = TRUE;	/* TRUE = Acquire timed out */
511 			status = AE_OK;
512 		}
513 		break;
514 
515 	case AML_WAIT_OP:	/* Wait (event_object, Timeout) */
516 
517 		status = acpi_ex_system_wait_event(operand[1], operand[0]);
518 		if (status == AE_TIME) {
519 			logical_result = TRUE;	/* TRUE, Wait timed out */
520 			status = AE_OK;
521 		}
522 		break;
523 
524 	default:
525 
526 		ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
527 			    walk_state->opcode));
528 
529 		status = AE_AML_BAD_OPCODE;
530 		goto cleanup;
531 	}
532 
533 store_logical_result:
534 	/*
535 	 * Set return value to according to logical_result. logical TRUE (all ones)
536 	 * Default is FALSE (zero)
537 	 */
538 	if (logical_result) {
539 		return_desc->integer.value = ACPI_UINT64_MAX;
540 	}
541 
542 cleanup:
543 
544 	/* Delete return object on error */
545 
546 	if (ACPI_FAILURE(status)) {
547 		acpi_ut_remove_reference(return_desc);
548 	}
549 
550 	/* Save return object on success */
551 
552 	else {
553 		walk_state->result_obj = return_desc;
554 	}
555 
556 	return_ACPI_STATUS(status);
557 }
558