162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dswstate - Dispatcher parse tree walk management routines
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acparser.h"
1362306a36Sopenharmony_ci#include "acdispat.h"
1462306a36Sopenharmony_ci#include "acnamesp.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define _COMPONENT          ACPI_DISPATCHER
1762306a36Sopenharmony_ciACPI_MODULE_NAME("dswstate")
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci  /* Local prototypes */
2062306a36Sopenharmony_cistatic acpi_status
2162306a36Sopenharmony_ciacpi_ds_result_stack_push(struct acpi_walk_state *walk_state);
2262306a36Sopenharmony_cistatic acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*******************************************************************************
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * FUNCTION:    acpi_ds_result_pop
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * PARAMETERS:  object              - Where to return the popped object
2962306a36Sopenharmony_ci *              walk_state          - Current Walk state
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * RETURN:      Status
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * DESCRIPTION: Pop an object off the top of this walk's result stack
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci ******************************************************************************/
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciacpi_status
3862306a36Sopenharmony_ciacpi_ds_result_pop(union acpi_operand_object **object,
3962306a36Sopenharmony_ci		   struct acpi_walk_state *walk_state)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	u32 index;
4262306a36Sopenharmony_ci	union acpi_generic_state *state;
4362306a36Sopenharmony_ci	acpi_status status;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_result_pop);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	state = walk_state->results;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* Incorrect state of result stack */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (state && !walk_state->result_count) {
5262306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "No results on result stack"));
5362306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (!state && walk_state->result_count) {
5762306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "No result state for result stack"));
5862306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Empty result stack */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (!state) {
6462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
6562306a36Sopenharmony_ci			    walk_state));
6662306a36Sopenharmony_ci		return (AE_AML_NO_RETURN_VALUE);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Return object of the top element and clean that top element result stack */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	walk_state->result_count--;
7262306a36Sopenharmony_ci	index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	*object = state->results.obj_desc[index];
7562306a36Sopenharmony_ci	if (!*object) {
7662306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
7762306a36Sopenharmony_ci			    "No result objects on result stack, State=%p",
7862306a36Sopenharmony_ci			    walk_state));
7962306a36Sopenharmony_ci		return (AE_AML_NO_RETURN_VALUE);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	state->results.obj_desc[index] = NULL;
8362306a36Sopenharmony_ci	if (index == 0) {
8462306a36Sopenharmony_ci		status = acpi_ds_result_stack_pop(walk_state);
8562306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
8662306a36Sopenharmony_ci			return (status);
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
9162306a36Sopenharmony_ci			  "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
9262306a36Sopenharmony_ci			  acpi_ut_get_object_type_name(*object),
9362306a36Sopenharmony_ci			  index, walk_state, walk_state->result_count));
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return (AE_OK);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*******************************************************************************
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * FUNCTION:    acpi_ds_result_push
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * PARAMETERS:  object              - Where to return the popped object
10362306a36Sopenharmony_ci *              walk_state          - Current Walk state
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * RETURN:      Status
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * DESCRIPTION: Push an object onto the current result stack
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci ******************************************************************************/
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciacpi_status
11262306a36Sopenharmony_ciacpi_ds_result_push(union acpi_operand_object *object,
11362306a36Sopenharmony_ci		    struct acpi_walk_state *walk_state)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	union acpi_generic_state *state;
11662306a36Sopenharmony_ci	acpi_status status;
11762306a36Sopenharmony_ci	u32 index;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_result_push);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (walk_state->result_count > walk_state->result_size) {
12262306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Result stack is full"));
12362306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
12462306a36Sopenharmony_ci	} else if (walk_state->result_count == walk_state->result_size) {
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		/* Extend the result stack */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		status = acpi_ds_result_stack_push(walk_state);
12962306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
13062306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
13162306a36Sopenharmony_ci				    "Failed to extend the result stack"));
13262306a36Sopenharmony_ci			return (status);
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!(walk_state->result_count < walk_state->result_size)) {
13762306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "No free elements in result stack"));
13862306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	state = walk_state->results;
14262306a36Sopenharmony_ci	if (!state) {
14362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "No result stack frame during push"));
14462306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (!object) {
14862306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
14962306a36Sopenharmony_ci			    "Null Object! State=%p Num=%u",
15062306a36Sopenharmony_ci			    walk_state, walk_state->result_count));
15162306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Assign the address of object to the top free element of result stack */
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
15762306a36Sopenharmony_ci	state->results.obj_desc[index] = object;
15862306a36Sopenharmony_ci	walk_state->result_count++;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
16162306a36Sopenharmony_ci			  object,
16262306a36Sopenharmony_ci			  acpi_ut_get_object_type_name((union
16362306a36Sopenharmony_ci							acpi_operand_object *)
16462306a36Sopenharmony_ci						       object), walk_state,
16562306a36Sopenharmony_ci			  walk_state->result_count,
16662306a36Sopenharmony_ci			  walk_state->current_result));
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return (AE_OK);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/*******************************************************************************
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * FUNCTION:    acpi_ds_result_stack_push
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current Walk state
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * RETURN:      Status
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * DESCRIPTION: Push an object onto the walk_state result stack
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci ******************************************************************************/
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	union acpi_generic_state *state;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_result_stack_push);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* Check for stack overflow */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
19262306a36Sopenharmony_ci	    ACPI_RESULTS_OBJ_NUM_MAX) {
19362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%u",
19462306a36Sopenharmony_ci			    walk_state, walk_state->result_size));
19562306a36Sopenharmony_ci		return (AE_STACK_OVERFLOW);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	state = acpi_ut_create_generic_state();
19962306a36Sopenharmony_ci	if (!state) {
20062306a36Sopenharmony_ci		return (AE_NO_MEMORY);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
20462306a36Sopenharmony_ci	acpi_ut_push_generic_state(&walk_state->results, state);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Increase the length of the result stack by the length of frame */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
21162306a36Sopenharmony_ci			  state, walk_state));
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return (AE_OK);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/*******************************************************************************
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * FUNCTION:    acpi_ds_result_stack_pop
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current Walk state
22162306a36Sopenharmony_ci *
22262306a36Sopenharmony_ci * RETURN:      Status
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * DESCRIPTION: Pop an object off of the walk_state result stack
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci ******************************************************************************/
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	union acpi_generic_state *state;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_result_stack_pop);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Check for stack underflow */
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (walk_state->results == NULL) {
23762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
23862306a36Sopenharmony_ci				  "Result stack underflow - State=%p\n",
23962306a36Sopenharmony_ci				  walk_state));
24062306a36Sopenharmony_ci		return (AE_AML_NO_OPERAND);
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
24462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
24562306a36Sopenharmony_ci		return (AE_AML_INTERNAL);
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	state = acpi_ut_pop_generic_state(&walk_state->results);
24962306a36Sopenharmony_ci	acpi_ut_delete_generic_state(state);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Decrease the length of result stack by the length of frame */
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
25662306a36Sopenharmony_ci			  "Result=%p RemainingResults=%X State=%p\n",
25762306a36Sopenharmony_ci			  state, walk_state->result_count, walk_state));
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return (AE_OK);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/*******************************************************************************
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * FUNCTION:    acpi_ds_obj_stack_push
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * PARAMETERS:  object              - Object to push
26762306a36Sopenharmony_ci *              walk_state          - Current Walk state
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci * RETURN:      Status
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * DESCRIPTION: Push an object onto this walk's object/operand stack
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci ******************************************************************************/
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciacpi_status
27662306a36Sopenharmony_ciacpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_obj_stack_push);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Check for stack overflow */
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) {
28362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
28462306a36Sopenharmony_ci			    "Object stack overflow! Obj=%p State=%p #Ops=%u",
28562306a36Sopenharmony_ci			    object, walk_state, walk_state->num_operands));
28662306a36Sopenharmony_ci		return (AE_STACK_OVERFLOW);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* Put the object onto the stack */
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	walk_state->operands[walk_state->operand_index] = object;
29262306a36Sopenharmony_ci	walk_state->num_operands++;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* For the usual order of filling the operand stack */
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	walk_state->operand_index++;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
29962306a36Sopenharmony_ci			  object,
30062306a36Sopenharmony_ci			  acpi_ut_get_object_type_name((union
30162306a36Sopenharmony_ci							acpi_operand_object *)
30262306a36Sopenharmony_ci						       object), walk_state,
30362306a36Sopenharmony_ci			  walk_state->num_operands));
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return (AE_OK);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/*******************************************************************************
30962306a36Sopenharmony_ci *
31062306a36Sopenharmony_ci * FUNCTION:    acpi_ds_obj_stack_pop
31162306a36Sopenharmony_ci *
31262306a36Sopenharmony_ci * PARAMETERS:  pop_count           - Number of objects/entries to pop
31362306a36Sopenharmony_ci *              walk_state          - Current Walk state
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * RETURN:      Status
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
31862306a36Sopenharmony_ci *              deleted by this routine.
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci ******************************************************************************/
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciacpi_status
32362306a36Sopenharmony_ciacpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	u32 i;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_obj_stack_pop);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	for (i = 0; i < pop_count; i++) {
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		/* Check for stack underflow */
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		if (walk_state->num_operands == 0) {
33462306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
33562306a36Sopenharmony_ci				    "Object stack underflow! Count=%X State=%p #Ops=%u",
33662306a36Sopenharmony_ci				    pop_count, walk_state,
33762306a36Sopenharmony_ci				    walk_state->num_operands));
33862306a36Sopenharmony_ci			return (AE_STACK_UNDERFLOW);
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		/* Just set the stack entry to null */
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		walk_state->num_operands--;
34462306a36Sopenharmony_ci		walk_state->operands[walk_state->num_operands] = NULL;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%u\n",
34862306a36Sopenharmony_ci			  pop_count, walk_state, walk_state->num_operands));
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return (AE_OK);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/*******************************************************************************
35462306a36Sopenharmony_ci *
35562306a36Sopenharmony_ci * FUNCTION:    acpi_ds_obj_stack_pop_and_delete
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * PARAMETERS:  pop_count           - Number of objects/entries to pop
35862306a36Sopenharmony_ci *              walk_state          - Current Walk state
35962306a36Sopenharmony_ci *
36062306a36Sopenharmony_ci * RETURN:      Status
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * DESCRIPTION: Pop this walk's object stack and delete each object that is
36362306a36Sopenharmony_ci *              popped off.
36462306a36Sopenharmony_ci *
36562306a36Sopenharmony_ci ******************************************************************************/
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_civoid
36862306a36Sopenharmony_ciacpi_ds_obj_stack_pop_and_delete(u32 pop_count,
36962306a36Sopenharmony_ci				 struct acpi_walk_state *walk_state)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	s32 i;
37262306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (pop_count == 0) {
37762306a36Sopenharmony_ci		return;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	for (i = (s32)pop_count - 1; i >= 0; i--) {
38162306a36Sopenharmony_ci		if (walk_state->num_operands == 0) {
38262306a36Sopenharmony_ci			return;
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		/* Pop the stack and delete an object if present in this stack entry */
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		walk_state->num_operands--;
38862306a36Sopenharmony_ci		obj_desc = walk_state->operands[i];
38962306a36Sopenharmony_ci		if (obj_desc) {
39062306a36Sopenharmony_ci			acpi_ut_remove_reference(walk_state->operands[i]);
39162306a36Sopenharmony_ci			walk_state->operands[i] = NULL;
39262306a36Sopenharmony_ci		}
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
39662306a36Sopenharmony_ci			  pop_count, walk_state, walk_state->num_operands));
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*******************************************************************************
40062306a36Sopenharmony_ci *
40162306a36Sopenharmony_ci * FUNCTION:    acpi_ds_get_current_walk_state
40262306a36Sopenharmony_ci *
40362306a36Sopenharmony_ci * PARAMETERS:  thread          - Get current active state for this Thread
40462306a36Sopenharmony_ci *
40562306a36Sopenharmony_ci * RETURN:      Pointer to the current walk state
40662306a36Sopenharmony_ci *
40762306a36Sopenharmony_ci * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
40862306a36Sopenharmony_ci *              walk state.)
40962306a36Sopenharmony_ci *
41062306a36Sopenharmony_ci ******************************************************************************/
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistruct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
41362306a36Sopenharmony_ci						       *thread)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_get_current_walk_state);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (!thread) {
41862306a36Sopenharmony_ci		return (NULL);
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n",
42262306a36Sopenharmony_ci			  thread->walk_state_list));
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return (thread->walk_state_list);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*******************************************************************************
42862306a36Sopenharmony_ci *
42962306a36Sopenharmony_ci * FUNCTION:    acpi_ds_push_walk_state
43062306a36Sopenharmony_ci *
43162306a36Sopenharmony_ci * PARAMETERS:  walk_state      - State to push
43262306a36Sopenharmony_ci *              thread          - Thread state object
43362306a36Sopenharmony_ci *
43462306a36Sopenharmony_ci * RETURN:      None
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * DESCRIPTION: Place the Thread state at the head of the state list
43762306a36Sopenharmony_ci *
43862306a36Sopenharmony_ci ******************************************************************************/
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_civoid
44162306a36Sopenharmony_ciacpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
44262306a36Sopenharmony_ci			struct acpi_thread_state *thread)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_push_walk_state);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	walk_state->next = thread->walk_state_list;
44762306a36Sopenharmony_ci	thread->walk_state_list = walk_state;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return_VOID;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/*******************************************************************************
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci * FUNCTION:    acpi_ds_pop_walk_state
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * PARAMETERS:  thread      - Current thread state
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * RETURN:      A walk_state object popped from the thread's stack
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * DESCRIPTION: Remove and return the walkstate object that is at the head of
46162306a36Sopenharmony_ci *              the walk stack for the given walk list. NULL indicates that
46262306a36Sopenharmony_ci *              the list is empty.
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci ******************************************************************************/
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistruct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct acpi_walk_state *walk_state;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_pop_walk_state);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	walk_state = thread->walk_state_list;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (walk_state) {
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		/* Next walk state becomes the current walk state */
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		thread->walk_state_list = walk_state->next;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/*
48162306a36Sopenharmony_ci		 * Don't clear the NEXT field, this serves as an indicator
48262306a36Sopenharmony_ci		 * that there is a parent WALK STATE
48362306a36Sopenharmony_ci		 * Do Not: walk_state->Next = NULL;
48462306a36Sopenharmony_ci		 */
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return_PTR(walk_state);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/*******************************************************************************
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci * FUNCTION:    acpi_ds_create_walk_state
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * PARAMETERS:  owner_id        - ID for object creation
49562306a36Sopenharmony_ci *              origin          - Starting point for this walk
49662306a36Sopenharmony_ci *              method_desc     - Method object
49762306a36Sopenharmony_ci *              thread          - Current thread state
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci * RETURN:      Pointer to the new walk state.
50062306a36Sopenharmony_ci *
50162306a36Sopenharmony_ci * DESCRIPTION: Allocate and initialize a new walk state. The current walk
50262306a36Sopenharmony_ci *              state is set to this new state.
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci ******************************************************************************/
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistruct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
50762306a36Sopenharmony_ci						  union acpi_parse_object
50862306a36Sopenharmony_ci						  *origin,
50962306a36Sopenharmony_ci						  union acpi_operand_object
51062306a36Sopenharmony_ci						  *method_desc,
51162306a36Sopenharmony_ci						  struct acpi_thread_state
51262306a36Sopenharmony_ci						  *thread)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct acpi_walk_state *walk_state;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_create_walk_state);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state));
51962306a36Sopenharmony_ci	if (!walk_state) {
52062306a36Sopenharmony_ci		return_PTR(NULL);
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	walk_state->descriptor_type = ACPI_DESC_TYPE_WALK;
52462306a36Sopenharmony_ci	walk_state->method_desc = method_desc;
52562306a36Sopenharmony_ci	walk_state->owner_id = owner_id;
52662306a36Sopenharmony_ci	walk_state->origin = origin;
52762306a36Sopenharmony_ci	walk_state->thread = thread;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	walk_state->parser_state.start_op = origin;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* Init the method args/local */
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci#ifndef ACPI_CONSTANT_EVAL_ONLY
53462306a36Sopenharmony_ci	acpi_ds_method_data_init(walk_state);
53562306a36Sopenharmony_ci#endif
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Put the new state at the head of the walk list */
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (thread) {
54062306a36Sopenharmony_ci		acpi_ds_push_walk_state(walk_state, thread);
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return_PTR(walk_state);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/*******************************************************************************
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * FUNCTION:    acpi_ds_init_aml_walk
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci * PARAMETERS:  walk_state      - New state to be initialized
55162306a36Sopenharmony_ci *              op              - Current parse op
55262306a36Sopenharmony_ci *              method_node     - Control method NS node, if any
55362306a36Sopenharmony_ci *              aml_start       - Start of AML
55462306a36Sopenharmony_ci *              aml_length      - Length of AML
55562306a36Sopenharmony_ci *              info            - Method info block (params, etc.)
55662306a36Sopenharmony_ci *              pass_number     - 1, 2, or 3
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * RETURN:      Status
55962306a36Sopenharmony_ci *
56062306a36Sopenharmony_ci * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci ******************************************************************************/
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ciacpi_status
56562306a36Sopenharmony_ciacpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
56662306a36Sopenharmony_ci		      union acpi_parse_object *op,
56762306a36Sopenharmony_ci		      struct acpi_namespace_node *method_node,
56862306a36Sopenharmony_ci		      u8 * aml_start,
56962306a36Sopenharmony_ci		      u32 aml_length,
57062306a36Sopenharmony_ci		      struct acpi_evaluate_info *info, u8 pass_number)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	acpi_status status;
57362306a36Sopenharmony_ci	struct acpi_parse_state *parser_state = &walk_state->parser_state;
57462306a36Sopenharmony_ci	union acpi_parse_object *extra_op;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_init_aml_walk);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	walk_state->parser_state.aml =
57962306a36Sopenharmony_ci	    walk_state->parser_state.aml_start =
58062306a36Sopenharmony_ci	    walk_state->parser_state.aml_end =
58162306a36Sopenharmony_ci	    walk_state->parser_state.pkg_end = aml_start;
58262306a36Sopenharmony_ci	/* Avoid undefined behavior: applying zero offset to null pointer */
58362306a36Sopenharmony_ci	if (aml_length != 0) {
58462306a36Sopenharmony_ci		walk_state->parser_state.aml_end += aml_length;
58562306a36Sopenharmony_ci		walk_state->parser_state.pkg_end += aml_length;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* The next_op of the next_walk will be the beginning of the method */
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	walk_state->next_op = NULL;
59162306a36Sopenharmony_ci	walk_state->pass_number = pass_number;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (info) {
59462306a36Sopenharmony_ci		walk_state->params = info->parameters;
59562306a36Sopenharmony_ci		walk_state->caller_return_desc = &info->return_object;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	status = acpi_ps_init_scope(&walk_state->parser_state, op);
59962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
60062306a36Sopenharmony_ci		return_ACPI_STATUS(status);
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (method_node) {
60462306a36Sopenharmony_ci		walk_state->parser_state.start_node = method_node;
60562306a36Sopenharmony_ci		walk_state->walk_type = ACPI_WALK_METHOD;
60662306a36Sopenharmony_ci		walk_state->method_node = method_node;
60762306a36Sopenharmony_ci		walk_state->method_desc =
60862306a36Sopenharmony_ci		    acpi_ns_get_attached_object(method_node);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		/* Push start scope on scope stack and make it current  */
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		status =
61362306a36Sopenharmony_ci		    acpi_ds_scope_stack_push(method_node, ACPI_TYPE_METHOD,
61462306a36Sopenharmony_ci					     walk_state);
61562306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
61662306a36Sopenharmony_ci			return_ACPI_STATUS(status);
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		/* Init the method arguments */
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		status = acpi_ds_method_data_init_args(walk_state->params,
62262306a36Sopenharmony_ci						       ACPI_METHOD_NUM_ARGS,
62362306a36Sopenharmony_ci						       walk_state);
62462306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
62562306a36Sopenharmony_ci			return_ACPI_STATUS(status);
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci	} else {
62862306a36Sopenharmony_ci		/*
62962306a36Sopenharmony_ci		 * Setup the current scope.
63062306a36Sopenharmony_ci		 * Find a Named Op that has a namespace node associated with it.
63162306a36Sopenharmony_ci		 * search upwards from this Op. Current scope is the first
63262306a36Sopenharmony_ci		 * Op with a namespace node.
63362306a36Sopenharmony_ci		 */
63462306a36Sopenharmony_ci		extra_op = parser_state->start_op;
63562306a36Sopenharmony_ci		while (extra_op && !extra_op->common.node) {
63662306a36Sopenharmony_ci			extra_op = extra_op->common.parent;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		if (!extra_op) {
64062306a36Sopenharmony_ci			parser_state->start_node = NULL;
64162306a36Sopenharmony_ci		} else {
64262306a36Sopenharmony_ci			parser_state->start_node = extra_op->common.node;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		if (parser_state->start_node) {
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci			/* Push start scope on scope stack and make it current  */
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci			status =
65062306a36Sopenharmony_ci			    acpi_ds_scope_stack_push(parser_state->start_node,
65162306a36Sopenharmony_ci						     parser_state->start_node->
65262306a36Sopenharmony_ci						     type, walk_state);
65362306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
65462306a36Sopenharmony_ci				return_ACPI_STATUS(status);
65562306a36Sopenharmony_ci			}
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	status = acpi_ds_init_callbacks(walk_state, pass_number);
66062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci/*******************************************************************************
66462306a36Sopenharmony_ci *
66562306a36Sopenharmony_ci * FUNCTION:    acpi_ds_delete_walk_state
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * PARAMETERS:  walk_state      - State to delete
66862306a36Sopenharmony_ci *
66962306a36Sopenharmony_ci * RETURN:      Status
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * DESCRIPTION: Delete a walk state including all internal data structures
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci ******************************************************************************/
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_civoid acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	union acpi_generic_state *state;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (!walk_state) {
68262306a36Sopenharmony_ci		return_VOID;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) {
68662306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "%p is not a valid walk state",
68762306a36Sopenharmony_ci			    walk_state));
68862306a36Sopenharmony_ci		return_VOID;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* There should not be any open scopes */
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	if (walk_state->parser_state.scope) {
69462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "%p walk still has a scope list",
69562306a36Sopenharmony_ci			    walk_state));
69662306a36Sopenharmony_ci		acpi_ps_cleanup_scope(&walk_state->parser_state);
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* Always must free any linked control states */
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	while (walk_state->control_state) {
70262306a36Sopenharmony_ci		state = walk_state->control_state;
70362306a36Sopenharmony_ci		walk_state->control_state = state->common.next;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		acpi_ut_delete_generic_state(state);
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Always must free any linked parse states */
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	while (walk_state->scope_info) {
71162306a36Sopenharmony_ci		state = walk_state->scope_info;
71262306a36Sopenharmony_ci		walk_state->scope_info = state->common.next;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		acpi_ut_delete_generic_state(state);
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* Always must free any stacked result states */
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	while (walk_state->results) {
72062306a36Sopenharmony_ci		state = walk_state->results;
72162306a36Sopenharmony_ci		walk_state->results = state->common.next;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		acpi_ut_delete_generic_state(state);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	ACPI_FREE(walk_state);
72762306a36Sopenharmony_ci	return_VOID;
72862306a36Sopenharmony_ci}
729