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