brintos

brintos / linux-shallow public Read only

0
0
Text · 19.3 KiB · 75338a1 Raw
729 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: dswstate - Dispatcher parse tree walk management routines5 *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_DISPATCHER17ACPI_MODULE_NAME("dswstate")18 19  /* Local prototypes */20static acpi_status21acpi_ds_result_stack_push(struct acpi_walk_state *walk_state);22static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state);23 24/*******************************************************************************25 *26 * FUNCTION:    acpi_ds_result_pop27 *28 * PARAMETERS:  object              - Where to return the popped object29 *              walk_state          - Current Walk state30 *31 * RETURN:      Status32 *33 * DESCRIPTION: Pop an object off the top of this walk's result stack34 *35 ******************************************************************************/36 37acpi_status38acpi_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_push101 *102 * PARAMETERS:  object              - Where to return the popped object103 *              walk_state          - Current Walk state104 *105 * RETURN:      Status106 *107 * DESCRIPTION: Push an object onto the current result stack108 *109 ******************************************************************************/110 111acpi_status112acpi_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! State=%p Num=%u",150			    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((union163							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_push174 *175 * PARAMETERS:  walk_state          - Current Walk state176 *177 * RETURN:      Status178 *179 * DESCRIPTION: Push an object onto the walk_state result stack180 *181 ******************************************************************************/182 183static 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_pop219 *220 * PARAMETERS:  walk_state          - Current Walk state221 *222 * RETURN:      Status223 *224 * DESCRIPTION: Pop an object off of the walk_state result stack225 *226 ******************************************************************************/227 228static 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_push265 *266 * PARAMETERS:  object              - Object to push267 *              walk_state          - Current Walk state268 *269 * RETURN:      Status270 *271 * DESCRIPTION: Push an object onto this walk's object/operand stack272 *273 ******************************************************************************/274 275acpi_status276acpi_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((union301							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_pop311 *312 * PARAMETERS:  pop_count           - Number of objects/entries to pop313 *              walk_state          - Current Walk state314 *315 * RETURN:      Status316 *317 * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT318 *              deleted by this routine.319 *320 ******************************************************************************/321 322acpi_status323acpi_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_delete356 *357 * PARAMETERS:  pop_count           - Number of objects/entries to pop358 *              walk_state          - Current Walk state359 *360 * RETURN:      Status361 *362 * DESCRIPTION: Pop this walk's object stack and delete each object that is363 *              popped off.364 *365 ******************************************************************************/366 367void368acpi_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_state402 *403 * PARAMETERS:  thread          - Get current active state for this Thread404 *405 * RETURN:      Pointer to the current walk state406 *407 * DESCRIPTION: Get the walk state that is at the head of the list (the "current"408 *              walk state.)409 *410 ******************************************************************************/411 412struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state413						       *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_state430 *431 * PARAMETERS:  walk_state      - State to push432 *              thread          - Thread state object433 *434 * RETURN:      None435 *436 * DESCRIPTION: Place the Thread state at the head of the state list437 *438 ******************************************************************************/439 440void441acpi_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_state455 *456 * PARAMETERS:  thread      - Current thread state457 *458 * RETURN:      A walk_state object popped from the thread's stack459 *460 * DESCRIPTION: Remove and return the walkstate object that is at the head of461 *              the walk stack for the given walk list. NULL indicates that462 *              the list is empty.463 *464 ******************************************************************************/465 466struct 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 indicator482		 * that there is a parent WALK STATE483		 * Do Not: walk_state->Next = NULL;484		 */485	}486 487	return_PTR(walk_state);488}489 490/*******************************************************************************491 *492 * FUNCTION:    acpi_ds_create_walk_state493 *494 * PARAMETERS:  owner_id        - ID for object creation495 *              origin          - Starting point for this walk496 *              method_desc     - Method object497 *              thread          - Current thread state498 *499 * RETURN:      Pointer to the new walk state.500 *501 * DESCRIPTION: Allocate and initialize a new walk state. The current walk502 *              state is set to this new state.503 *504 ******************************************************************************/505 506struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,507						  union acpi_parse_object508						  *origin,509						  union acpi_operand_object510						  *method_desc,511						  struct acpi_thread_state512						  *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_ONLY534	acpi_ds_method_data_init(walk_state);535#endif536 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_walk549 *550 * PARAMETERS:  walk_state      - New state to be initialized551 *              op              - Current parse op552 *              method_node     - Control method NS node, if any553 *              aml_start       - Start of AML554 *              aml_length      - Length of AML555 *              info            - Method info block (params, etc.)556 *              pass_number     - 1, 2, or 3557 *558 * RETURN:      Status559 *560 * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk561 *562 ******************************************************************************/563 564acpi_status565acpi_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 first632		 * 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_state666 *667 * PARAMETERS:  walk_state      - State to delete668 *669 * RETURN:      Status670 *671 * DESCRIPTION: Delete a walk state including all internal data structures672 *673 ******************************************************************************/674 675void 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