xref: /openbmc/linux/drivers/acpi/acpica/dswstate.c (revision 6a87e0f0)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: dswstate - Dispatcher parse tree walk management routines
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 "acdispat.h"
14 #include "acnamesp.h"
15 
16 #define _COMPONENT          ACPI_DISPATCHER
17 ACPI_MODULE_NAME("dswstate")
18 
19   /* Local prototypes */
20 static acpi_status
21 acpi_ds_result_stack_push(struct acpi_walk_state *walk_state);
22 static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state);
23 
24 /*******************************************************************************
25  *
26  * FUNCTION:    acpi_ds_result_pop
27  *
28  * PARAMETERS:  object              - Where to return the popped object
29  *              walk_state          - Current Walk state
30  *
31  * RETURN:      Status
32  *
33  * DESCRIPTION: Pop an object off the top of this walk's result stack
34  *
35  ******************************************************************************/
36 
37 acpi_status
38 acpi_ds_result_pop(union acpi_operand_object **object,
39 		   struct acpi_walk_state *walk_state)
40 {
41 	u32 index;
42 	union acpi_generic_state *state;
43 	acpi_status status;
44 
45 	ACPI_FUNCTION_NAME(ds_result_pop);
46 
47 	state = walk_state->results;
48 
49 	/* Incorrect state of result stack */
50 
51 	if (state && !walk_state->result_count) {
52 		ACPI_ERROR((AE_INFO, "No results on result stack"));
53 		return (AE_AML_INTERNAL);
54 	}
55 
56 	if (!state && walk_state->result_count) {
57 		ACPI_ERROR((AE_INFO, "No result state for result stack"));
58 		return (AE_AML_INTERNAL);
59 	}
60 
61 	/* Empty result stack */
62 
63 	if (!state) {
64 		ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
65 			    walk_state));
66 		return (AE_AML_NO_RETURN_VALUE);
67 	}
68 
69 	/* Return object of the top element and clean that top element result stack */
70 
71 	walk_state->result_count--;
72 	index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
73 
74 	*object = state->results.obj_desc[index];
75 	if (!*object) {
76 		ACPI_ERROR((AE_INFO,
77 			    "No result objects on result stack, State=%p",
78 			    walk_state));
79 		return (AE_AML_NO_RETURN_VALUE);
80 	}
81 
82 	state->results.obj_desc[index] = NULL;
83 	if (index == 0) {
84 		status = acpi_ds_result_stack_pop(walk_state);
85 		if (ACPI_FAILURE(status)) {
86 			return (status);
87 		}
88 	}
89 
90 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
91 			  "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
92 			  acpi_ut_get_object_type_name(*object),
93 			  index, walk_state, walk_state->result_count));
94 
95 	return (AE_OK);
96 }
97 
98 /*******************************************************************************
99  *
100  * FUNCTION:    acpi_ds_result_push
101  *
102  * PARAMETERS:  object              - Where to return the popped object
103  *              walk_state          - Current Walk state
104  *
105  * RETURN:      Status
106  *
107  * DESCRIPTION: Push an object onto the current result stack
108  *
109  ******************************************************************************/
110 
111 acpi_status
112 acpi_ds_result_push(union acpi_operand_object *object,
113 		    struct acpi_walk_state *walk_state)
114 {
115 	union acpi_generic_state *state;
116 	acpi_status status;
117 	u32 index;
118 
119 	ACPI_FUNCTION_NAME(ds_result_push);
120 
121 	if (walk_state->result_count > walk_state->result_size) {
122 		ACPI_ERROR((AE_INFO, "Result stack is full"));
123 		return (AE_AML_INTERNAL);
124 	} else if (walk_state->result_count == walk_state->result_size) {
125 
126 		/* Extend the result stack */
127 
128 		status = acpi_ds_result_stack_push(walk_state);
129 		if (ACPI_FAILURE(status)) {
130 			ACPI_ERROR((AE_INFO,
131 				    "Failed to extend the result stack"));
132 			return (status);
133 		}
134 	}
135 
136 	if (!(walk_state->result_count < walk_state->result_size)) {
137 		ACPI_ERROR((AE_INFO, "No free elements in result stack"));
138 		return (AE_AML_INTERNAL);
139 	}
140 
141 	state = walk_state->results;
142 	if (!state) {
143 		ACPI_ERROR((AE_INFO, "No result stack frame during push"));
144 		return (AE_AML_INTERNAL);
145 	}
146 
147 	if (!object) {
148 		ACPI_ERROR((AE_INFO,
149 			    "Null Object! Obj=%p State=%p Num=%u",
150 			    object, walk_state, walk_state->result_count));
151 		return (AE_BAD_PARAMETER);
152 	}
153 
154 	/* Assign the address of object to the top free element of result stack */
155 
156 	index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
157 	state->results.obj_desc[index] = object;
158 	walk_state->result_count++;
159 
160 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
161 			  object,
162 			  acpi_ut_get_object_type_name((union
163 							acpi_operand_object *)
164 						       object), walk_state,
165 			  walk_state->result_count,
166 			  walk_state->current_result));
167 
168 	return (AE_OK);
169 }
170 
171 /*******************************************************************************
172  *
173  * FUNCTION:    acpi_ds_result_stack_push
174  *
175  * PARAMETERS:  walk_state          - Current Walk state
176  *
177  * RETURN:      Status
178  *
179  * DESCRIPTION: Push an object onto the walk_state result stack
180  *
181  ******************************************************************************/
182 
183 static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
184 {
185 	union acpi_generic_state *state;
186 
187 	ACPI_FUNCTION_NAME(ds_result_stack_push);
188 
189 	/* Check for stack overflow */
190 
191 	if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
192 	    ACPI_RESULTS_OBJ_NUM_MAX) {
193 		ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%u",
194 			    walk_state, walk_state->result_size));
195 		return (AE_STACK_OVERFLOW);
196 	}
197 
198 	state = acpi_ut_create_generic_state();
199 	if (!state) {
200 		return (AE_NO_MEMORY);
201 	}
202 
203 	state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
204 	acpi_ut_push_generic_state(&walk_state->results, state);
205 
206 	/* Increase the length of the result stack by the length of frame */
207 
208 	walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
209 
210 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
211 			  state, walk_state));
212 
213 	return (AE_OK);
214 }
215 
216 /*******************************************************************************
217  *
218  * FUNCTION:    acpi_ds_result_stack_pop
219  *
220  * PARAMETERS:  walk_state          - Current Walk state
221  *
222  * RETURN:      Status
223  *
224  * DESCRIPTION: Pop an object off of the walk_state result stack
225  *
226  ******************************************************************************/
227 
228 static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
229 {
230 	union acpi_generic_state *state;
231 
232 	ACPI_FUNCTION_NAME(ds_result_stack_pop);
233 
234 	/* Check for stack underflow */
235 
236 	if (walk_state->results == NULL) {
237 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
238 				  "Result stack underflow - State=%p\n",
239 				  walk_state));
240 		return (AE_AML_NO_OPERAND);
241 	}
242 
243 	if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
244 		ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
245 		return (AE_AML_INTERNAL);
246 	}
247 
248 	state = acpi_ut_pop_generic_state(&walk_state->results);
249 	acpi_ut_delete_generic_state(state);
250 
251 	/* Decrease the length of result stack by the length of frame */
252 
253 	walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
254 
255 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
256 			  "Result=%p RemainingResults=%X State=%p\n",
257 			  state, walk_state->result_count, walk_state));
258 
259 	return (AE_OK);
260 }
261 
262 /*******************************************************************************
263  *
264  * FUNCTION:    acpi_ds_obj_stack_push
265  *
266  * PARAMETERS:  object              - Object to push
267  *              walk_state          - Current Walk state
268  *
269  * RETURN:      Status
270  *
271  * DESCRIPTION: Push an object onto this walk's object/operand stack
272  *
273  ******************************************************************************/
274 
275 acpi_status
276 acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state)
277 {
278 	ACPI_FUNCTION_NAME(ds_obj_stack_push);
279 
280 	/* Check for stack overflow */
281 
282 	if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) {
283 		ACPI_ERROR((AE_INFO,
284 			    "Object stack overflow! Obj=%p State=%p #Ops=%u",
285 			    object, walk_state, walk_state->num_operands));
286 		return (AE_STACK_OVERFLOW);
287 	}
288 
289 	/* Put the object onto the stack */
290 
291 	walk_state->operands[walk_state->operand_index] = object;
292 	walk_state->num_operands++;
293 
294 	/* For the usual order of filling the operand stack */
295 
296 	walk_state->operand_index++;
297 
298 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
299 			  object,
300 			  acpi_ut_get_object_type_name((union
301 							acpi_operand_object *)
302 						       object), walk_state,
303 			  walk_state->num_operands));
304 
305 	return (AE_OK);
306 }
307 
308 /*******************************************************************************
309  *
310  * FUNCTION:    acpi_ds_obj_stack_pop
311  *
312  * PARAMETERS:  pop_count           - Number of objects/entries to pop
313  *              walk_state          - Current Walk state
314  *
315  * RETURN:      Status
316  *
317  * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
318  *              deleted by this routine.
319  *
320  ******************************************************************************/
321 
322 acpi_status
323 acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state)
324 {
325 	u32 i;
326 
327 	ACPI_FUNCTION_NAME(ds_obj_stack_pop);
328 
329 	for (i = 0; i < pop_count; i++) {
330 
331 		/* Check for stack underflow */
332 
333 		if (walk_state->num_operands == 0) {
334 			ACPI_ERROR((AE_INFO,
335 				    "Object stack underflow! Count=%X State=%p #Ops=%u",
336 				    pop_count, walk_state,
337 				    walk_state->num_operands));
338 			return (AE_STACK_UNDERFLOW);
339 		}
340 
341 		/* Just set the stack entry to null */
342 
343 		walk_state->num_operands--;
344 		walk_state->operands[walk_state->num_operands] = NULL;
345 	}
346 
347 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%u\n",
348 			  pop_count, walk_state, walk_state->num_operands));
349 
350 	return (AE_OK);
351 }
352 
353 /*******************************************************************************
354  *
355  * FUNCTION:    acpi_ds_obj_stack_pop_and_delete
356  *
357  * PARAMETERS:  pop_count           - Number of objects/entries to pop
358  *              walk_state          - Current Walk state
359  *
360  * RETURN:      Status
361  *
362  * DESCRIPTION: Pop this walk's object stack and delete each object that is
363  *              popped off.
364  *
365  ******************************************************************************/
366 
367 void
368 acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
369 				 struct acpi_walk_state *walk_state)
370 {
371 	s32 i;
372 	union acpi_operand_object *obj_desc;
373 
374 	ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
375 
376 	if (pop_count == 0) {
377 		return;
378 	}
379 
380 	for (i = (s32)pop_count - 1; i >= 0; i--) {
381 		if (walk_state->num_operands == 0) {
382 			return;
383 		}
384 
385 		/* Pop the stack and delete an object if present in this stack entry */
386 
387 		walk_state->num_operands--;
388 		obj_desc = walk_state->operands[i];
389 		if (obj_desc) {
390 			acpi_ut_remove_reference(walk_state->operands[i]);
391 			walk_state->operands[i] = NULL;
392 		}
393 	}
394 
395 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
396 			  pop_count, walk_state, walk_state->num_operands));
397 }
398 
399 /*******************************************************************************
400  *
401  * FUNCTION:    acpi_ds_get_current_walk_state
402  *
403  * PARAMETERS:  thread          - Get current active state for this Thread
404  *
405  * RETURN:      Pointer to the current walk state
406  *
407  * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
408  *              walk state.)
409  *
410  ******************************************************************************/
411 
412 struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
413 						       *thread)
414 {
415 	ACPI_FUNCTION_NAME(ds_get_current_walk_state);
416 
417 	if (!thread) {
418 		return (NULL);
419 	}
420 
421 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n",
422 			  thread->walk_state_list));
423 
424 	return (thread->walk_state_list);
425 }
426 
427 /*******************************************************************************
428  *
429  * FUNCTION:    acpi_ds_push_walk_state
430  *
431  * PARAMETERS:  walk_state      - State to push
432  *              thread          - Thread state object
433  *
434  * RETURN:      None
435  *
436  * DESCRIPTION: Place the Thread state at the head of the state list
437  *
438  ******************************************************************************/
439 
440 void
441 acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
442 			struct acpi_thread_state *thread)
443 {
444 	ACPI_FUNCTION_TRACE(ds_push_walk_state);
445 
446 	walk_state->next = thread->walk_state_list;
447 	thread->walk_state_list = walk_state;
448 
449 	return_VOID;
450 }
451 
452 /*******************************************************************************
453  *
454  * FUNCTION:    acpi_ds_pop_walk_state
455  *
456  * PARAMETERS:  thread      - Current thread state
457  *
458  * RETURN:      A walk_state object popped from the thread's stack
459  *
460  * DESCRIPTION: Remove and return the walkstate object that is at the head of
461  *              the walk stack for the given walk list. NULL indicates that
462  *              the list is empty.
463  *
464  ******************************************************************************/
465 
466 struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
467 {
468 	struct acpi_walk_state *walk_state;
469 
470 	ACPI_FUNCTION_TRACE(ds_pop_walk_state);
471 
472 	walk_state = thread->walk_state_list;
473 
474 	if (walk_state) {
475 
476 		/* Next walk state becomes the current walk state */
477 
478 		thread->walk_state_list = walk_state->next;
479 
480 		/*
481 		 * Don't clear the NEXT field, this serves as an indicator
482 		 * that there is a parent WALK STATE
483 		 * Do Not: walk_state->Next = NULL;
484 		 */
485 	}
486 
487 	return_PTR(walk_state);
488 }
489 
490 /*******************************************************************************
491  *
492  * FUNCTION:    acpi_ds_create_walk_state
493  *
494  * PARAMETERS:  owner_id        - ID for object creation
495  *              origin          - Starting point for this walk
496  *              method_desc     - Method object
497  *              thread          - Current thread state
498  *
499  * RETURN:      Pointer to the new walk state.
500  *
501  * DESCRIPTION: Allocate and initialize a new walk state. The current walk
502  *              state is set to this new state.
503  *
504  ******************************************************************************/
505 
506 struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
507 						  union acpi_parse_object
508 						  *origin,
509 						  union acpi_operand_object
510 						  *method_desc,
511 						  struct acpi_thread_state
512 						  *thread)
513 {
514 	struct acpi_walk_state *walk_state;
515 
516 	ACPI_FUNCTION_TRACE(ds_create_walk_state);
517 
518 	walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state));
519 	if (!walk_state) {
520 		return_PTR(NULL);
521 	}
522 
523 	walk_state->descriptor_type = ACPI_DESC_TYPE_WALK;
524 	walk_state->method_desc = method_desc;
525 	walk_state->owner_id = owner_id;
526 	walk_state->origin = origin;
527 	walk_state->thread = thread;
528 
529 	walk_state->parser_state.start_op = origin;
530 
531 	/* Init the method args/local */
532 
533 #ifndef ACPI_CONSTANT_EVAL_ONLY
534 	acpi_ds_method_data_init(walk_state);
535 #endif
536 
537 	/* Put the new state at the head of the walk list */
538 
539 	if (thread) {
540 		acpi_ds_push_walk_state(walk_state, thread);
541 	}
542 
543 	return_PTR(walk_state);
544 }
545 
546 /*******************************************************************************
547  *
548  * FUNCTION:    acpi_ds_init_aml_walk
549  *
550  * PARAMETERS:  walk_state      - New state to be initialized
551  *              op              - Current parse op
552  *              method_node     - Control method NS node, if any
553  *              aml_start       - Start of AML
554  *              aml_length      - Length of AML
555  *              info            - Method info block (params, etc.)
556  *              pass_number     - 1, 2, or 3
557  *
558  * RETURN:      Status
559  *
560  * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk
561  *
562  ******************************************************************************/
563 
564 acpi_status
565 acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
566 		      union acpi_parse_object *op,
567 		      struct acpi_namespace_node *method_node,
568 		      u8 * aml_start,
569 		      u32 aml_length,
570 		      struct acpi_evaluate_info *info, u8 pass_number)
571 {
572 	acpi_status status;
573 	struct acpi_parse_state *parser_state = &walk_state->parser_state;
574 	union acpi_parse_object *extra_op;
575 
576 	ACPI_FUNCTION_TRACE(ds_init_aml_walk);
577 
578 	walk_state->parser_state.aml =
579 	    walk_state->parser_state.aml_start =
580 	    walk_state->parser_state.aml_end =
581 	    walk_state->parser_state.pkg_end = aml_start;
582 	/* Avoid undefined behavior: applying zero offset to null pointer */
583 	if (aml_length != 0) {
584 		walk_state->parser_state.aml_end += aml_length;
585 		walk_state->parser_state.pkg_end += aml_length;
586 	}
587 
588 	/* The next_op of the next_walk will be the beginning of the method */
589 
590 	walk_state->next_op = NULL;
591 	walk_state->pass_number = pass_number;
592 
593 	if (info) {
594 		walk_state->params = info->parameters;
595 		walk_state->caller_return_desc = &info->return_object;
596 	}
597 
598 	status = acpi_ps_init_scope(&walk_state->parser_state, op);
599 	if (ACPI_FAILURE(status)) {
600 		return_ACPI_STATUS(status);
601 	}
602 
603 	if (method_node) {
604 		walk_state->parser_state.start_node = method_node;
605 		walk_state->walk_type = ACPI_WALK_METHOD;
606 		walk_state->method_node = method_node;
607 		walk_state->method_desc =
608 		    acpi_ns_get_attached_object(method_node);
609 
610 		/* Push start scope on scope stack and make it current  */
611 
612 		status =
613 		    acpi_ds_scope_stack_push(method_node, ACPI_TYPE_METHOD,
614 					     walk_state);
615 		if (ACPI_FAILURE(status)) {
616 			return_ACPI_STATUS(status);
617 		}
618 
619 		/* Init the method arguments */
620 
621 		status = acpi_ds_method_data_init_args(walk_state->params,
622 						       ACPI_METHOD_NUM_ARGS,
623 						       walk_state);
624 		if (ACPI_FAILURE(status)) {
625 			return_ACPI_STATUS(status);
626 		}
627 	} else {
628 		/*
629 		 * Setup the current scope.
630 		 * Find a Named Op that has a namespace node associated with it.
631 		 * search upwards from this Op. Current scope is the first
632 		 * Op with a namespace node.
633 		 */
634 		extra_op = parser_state->start_op;
635 		while (extra_op && !extra_op->common.node) {
636 			extra_op = extra_op->common.parent;
637 		}
638 
639 		if (!extra_op) {
640 			parser_state->start_node = NULL;
641 		} else {
642 			parser_state->start_node = extra_op->common.node;
643 		}
644 
645 		if (parser_state->start_node) {
646 
647 			/* Push start scope on scope stack and make it current  */
648 
649 			status =
650 			    acpi_ds_scope_stack_push(parser_state->start_node,
651 						     parser_state->start_node->
652 						     type, walk_state);
653 			if (ACPI_FAILURE(status)) {
654 				return_ACPI_STATUS(status);
655 			}
656 		}
657 	}
658 
659 	status = acpi_ds_init_callbacks(walk_state, pass_number);
660 	return_ACPI_STATUS(status);
661 }
662 
663 /*******************************************************************************
664  *
665  * FUNCTION:    acpi_ds_delete_walk_state
666  *
667  * PARAMETERS:  walk_state      - State to delete
668  *
669  * RETURN:      Status
670  *
671  * DESCRIPTION: Delete a walk state including all internal data structures
672  *
673  ******************************************************************************/
674 
675 void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
676 {
677 	union acpi_generic_state *state;
678 
679 	ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state);
680 
681 	if (!walk_state) {
682 		return_VOID;
683 	}
684 
685 	if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) {
686 		ACPI_ERROR((AE_INFO, "%p is not a valid walk state",
687 			    walk_state));
688 		return_VOID;
689 	}
690 
691 	/* There should not be any open scopes */
692 
693 	if (walk_state->parser_state.scope) {
694 		ACPI_ERROR((AE_INFO, "%p walk still has a scope list",
695 			    walk_state));
696 		acpi_ps_cleanup_scope(&walk_state->parser_state);
697 	}
698 
699 	/* Always must free any linked control states */
700 
701 	while (walk_state->control_state) {
702 		state = walk_state->control_state;
703 		walk_state->control_state = state->common.next;
704 
705 		acpi_ut_delete_generic_state(state);
706 	}
707 
708 	/* Always must free any linked parse states */
709 
710 	while (walk_state->scope_info) {
711 		state = walk_state->scope_info;
712 		walk_state->scope_info = state->common.next;
713 
714 		acpi_ut_delete_generic_state(state);
715 	}
716 
717 	/* Always must free any stacked result states */
718 
719 	while (walk_state->results) {
720 		state = walk_state->results;
721 		walk_state->results = state->common.next;
722 
723 		acpi_ut_delete_generic_state(state);
724 	}
725 
726 	ACPI_FREE(walk_state);
727 	return_VOID;
728 }
729