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