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