1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: dbexec - debugger control method execution 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 #include "acdebug.h" 11 #include "acnamesp.h" 12 13 #define _COMPONENT ACPI_CA_DEBUGGER 14 ACPI_MODULE_NAME("dbexec") 15 16 static struct acpi_db_method_info acpi_gbl_db_method_info; 17 18 /* Local prototypes */ 19 20 static acpi_status 21 acpi_db_execute_method(struct acpi_db_method_info *info, 22 struct acpi_buffer *return_obj); 23 24 static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info); 25 26 static u32 acpi_db_get_outstanding_allocations(void); 27 28 static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context); 29 30 static acpi_status 31 acpi_db_execution_walk(acpi_handle obj_handle, 32 u32 nesting_level, void *context, void **return_value); 33 34 static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context); 35 36 /******************************************************************************* 37 * 38 * FUNCTION: acpi_db_delete_objects 39 * 40 * PARAMETERS: count - Count of objects in the list 41 * objects - Array of ACPI_OBJECTs to be deleted 42 * 43 * RETURN: None 44 * 45 * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested 46 * packages via recursion. 47 * 48 ******************************************************************************/ 49 50 void acpi_db_delete_objects(u32 count, union acpi_object *objects) 51 { 52 u32 i; 53 54 for (i = 0; i < count; i++) { 55 switch (objects[i].type) { 56 case ACPI_TYPE_BUFFER: 57 58 ACPI_FREE(objects[i].buffer.pointer); 59 break; 60 61 case ACPI_TYPE_PACKAGE: 62 63 /* Recursive call to delete package elements */ 64 65 acpi_db_delete_objects(objects[i].package.count, 66 objects[i].package.elements); 67 68 /* Free the elements array */ 69 70 ACPI_FREE(objects[i].package.elements); 71 break; 72 73 default: 74 75 break; 76 } 77 } 78 } 79 80 /******************************************************************************* 81 * 82 * FUNCTION: acpi_db_execute_method 83 * 84 * PARAMETERS: info - Valid info segment 85 * return_obj - Where to put return object 86 * 87 * RETURN: Status 88 * 89 * DESCRIPTION: Execute a control method. 90 * 91 ******************************************************************************/ 92 93 static acpi_status 94 acpi_db_execute_method(struct acpi_db_method_info *info, 95 struct acpi_buffer *return_obj) 96 { 97 acpi_status status; 98 struct acpi_object_list param_objects; 99 union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1]; 100 u32 i; 101 102 ACPI_FUNCTION_TRACE(db_execute_method); 103 104 if (acpi_gbl_db_output_to_file && !acpi_dbg_level) { 105 acpi_os_printf("Warning: debug output is not enabled!\n"); 106 } 107 108 param_objects.count = 0; 109 param_objects.pointer = NULL; 110 111 /* Pass through any command-line arguments */ 112 113 if (info->args && info->args[0]) { 114 115 /* Get arguments passed on the command line */ 116 117 for (i = 0; (info->args[i] && *(info->args[i])); i++) { 118 119 /* Convert input string (token) to an actual union acpi_object */ 120 121 status = acpi_db_convert_to_object(info->types[i], 122 info->args[i], 123 ¶ms[i]); 124 if (ACPI_FAILURE(status)) { 125 ACPI_EXCEPTION((AE_INFO, status, 126 "While parsing method arguments")); 127 goto cleanup; 128 } 129 } 130 131 param_objects.count = i; 132 param_objects.pointer = params; 133 } 134 135 /* Prepare for a return object of arbitrary size */ 136 137 return_obj->pointer = acpi_gbl_db_buffer; 138 return_obj->length = ACPI_DEBUG_BUFFER_SIZE; 139 140 /* Do the actual method execution */ 141 142 acpi_gbl_method_executing = TRUE; 143 status = acpi_evaluate_object(NULL, info->pathname, 144 ¶m_objects, return_obj); 145 146 acpi_gbl_cm_single_step = FALSE; 147 acpi_gbl_method_executing = FALSE; 148 149 if (ACPI_FAILURE(status)) { 150 if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) { 151 152 /* Clear the abort and fall back to the debugger prompt */ 153 154 ACPI_EXCEPTION((AE_INFO, status, 155 "Aborting top-level method")); 156 157 acpi_gbl_abort_method = FALSE; 158 status = AE_OK; 159 goto cleanup; 160 } 161 162 ACPI_EXCEPTION((AE_INFO, status, 163 "while executing %s from AML Debugger", 164 info->pathname)); 165 166 if (status == AE_BUFFER_OVERFLOW) { 167 ACPI_ERROR((AE_INFO, 168 "Possible buffer overflow within AML Debugger " 169 "buffer (size 0x%X needed 0x%X)", 170 ACPI_DEBUG_BUFFER_SIZE, 171 (u32)return_obj->length)); 172 } 173 } 174 175 cleanup: 176 acpi_db_delete_objects(param_objects.count, params); 177 return_ACPI_STATUS(status); 178 } 179 180 /******************************************************************************* 181 * 182 * FUNCTION: acpi_db_execute_setup 183 * 184 * PARAMETERS: info - Valid method info 185 * 186 * RETURN: None 187 * 188 * DESCRIPTION: Setup info segment prior to method execution 189 * 190 ******************************************************************************/ 191 192 static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info) 193 { 194 acpi_status status; 195 196 ACPI_FUNCTION_NAME(db_execute_setup); 197 198 /* Concatenate the current scope to the supplied name */ 199 200 info->pathname[0] = 0; 201 if ((info->name[0] != '\\') && (info->name[0] != '/')) { 202 if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), 203 acpi_gbl_db_scope_buf)) { 204 status = AE_BUFFER_OVERFLOW; 205 goto error_exit; 206 } 207 } 208 209 if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), 210 info->name)) { 211 status = AE_BUFFER_OVERFLOW; 212 goto error_exit; 213 } 214 215 acpi_db_prep_namestring(info->pathname); 216 217 acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); 218 acpi_os_printf("Evaluating %s\n", info->pathname); 219 220 if (info->flags & EX_SINGLE_STEP) { 221 acpi_gbl_cm_single_step = TRUE; 222 acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); 223 } 224 225 else { 226 /* No single step, allow redirection to a file */ 227 228 acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); 229 } 230 231 return (AE_OK); 232 233 error_exit: 234 235 ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution")); 236 return (status); 237 } 238 239 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 240 u32 acpi_db_get_cache_info(struct acpi_memory_list *cache) 241 { 242 243 return (cache->total_allocated - cache->total_freed - 244 cache->current_depth); 245 } 246 #endif 247 248 /******************************************************************************* 249 * 250 * FUNCTION: acpi_db_get_outstanding_allocations 251 * 252 * PARAMETERS: None 253 * 254 * RETURN: Current global allocation count minus cache entries 255 * 256 * DESCRIPTION: Determine the current number of "outstanding" allocations -- 257 * those allocations that have not been freed and also are not 258 * in one of the various object caches. 259 * 260 ******************************************************************************/ 261 262 static u32 acpi_db_get_outstanding_allocations(void) 263 { 264 u32 outstanding = 0; 265 266 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 267 268 outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache); 269 outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache); 270 outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache); 271 outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache); 272 #endif 273 274 return (outstanding); 275 } 276 277 /******************************************************************************* 278 * 279 * FUNCTION: acpi_db_execution_walk 280 * 281 * PARAMETERS: WALK_CALLBACK 282 * 283 * RETURN: Status 284 * 285 * DESCRIPTION: Execute a control method. Name is relative to the current 286 * scope. 287 * 288 ******************************************************************************/ 289 290 static acpi_status 291 acpi_db_execution_walk(acpi_handle obj_handle, 292 u32 nesting_level, void *context, void **return_value) 293 { 294 union acpi_operand_object *obj_desc; 295 struct acpi_namespace_node *node = 296 (struct acpi_namespace_node *)obj_handle; 297 struct acpi_buffer return_obj; 298 acpi_status status; 299 300 obj_desc = acpi_ns_get_attached_object(node); 301 if (obj_desc->method.param_count) { 302 return (AE_OK); 303 } 304 305 return_obj.pointer = NULL; 306 return_obj.length = ACPI_ALLOCATE_BUFFER; 307 308 acpi_ns_print_node_pathname(node, "Evaluating"); 309 310 /* Do the actual method execution */ 311 312 acpi_os_printf("\n"); 313 acpi_gbl_method_executing = TRUE; 314 315 status = acpi_evaluate_object(node, NULL, NULL, &return_obj); 316 317 acpi_os_printf("Evaluation of [%4.4s] returned %s\n", 318 acpi_ut_get_node_name(node), 319 acpi_format_exception(status)); 320 321 acpi_gbl_method_executing = FALSE; 322 return (AE_OK); 323 } 324 325 /******************************************************************************* 326 * 327 * FUNCTION: acpi_db_execute 328 * 329 * PARAMETERS: name - Name of method to execute 330 * args - Parameters to the method 331 * Types - 332 * flags - single step/no single step 333 * 334 * RETURN: None 335 * 336 * DESCRIPTION: Execute a control method. Name is relative to the current 337 * scope. 338 * 339 ******************************************************************************/ 340 341 void 342 acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags) 343 { 344 acpi_status status; 345 struct acpi_buffer return_obj; 346 char *name_string; 347 348 #ifdef ACPI_DEBUG_OUTPUT 349 u32 previous_allocations; 350 u32 allocations; 351 #endif 352 353 /* 354 * Allow one execution to be performed by debugger or single step 355 * execution will be dead locked by the interpreter mutexes. 356 */ 357 if (acpi_gbl_method_executing) { 358 acpi_os_printf("Only one debugger execution is allowed.\n"); 359 return; 360 } 361 #ifdef ACPI_DEBUG_OUTPUT 362 /* Memory allocation tracking */ 363 364 previous_allocations = acpi_db_get_outstanding_allocations(); 365 #endif 366 367 if (*name == '*') { 368 (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT, 369 ACPI_UINT32_MAX, 370 acpi_db_execution_walk, NULL, NULL, 371 NULL); 372 return; 373 } 374 375 name_string = ACPI_ALLOCATE(strlen(name) + 1); 376 if (!name_string) { 377 return; 378 } 379 380 memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); 381 strcpy(name_string, name); 382 acpi_ut_strupr(name_string); 383 384 /* Subcommand to Execute all predefined names in the namespace */ 385 386 if (!strncmp(name_string, "PREDEF", 6)) { 387 acpi_db_evaluate_predefined_names(); 388 ACPI_FREE(name_string); 389 return; 390 } 391 392 acpi_gbl_db_method_info.name = name_string; 393 acpi_gbl_db_method_info.args = args; 394 acpi_gbl_db_method_info.types = types; 395 acpi_gbl_db_method_info.flags = flags; 396 397 return_obj.pointer = NULL; 398 return_obj.length = ACPI_ALLOCATE_BUFFER; 399 400 status = acpi_db_execute_setup(&acpi_gbl_db_method_info); 401 if (ACPI_FAILURE(status)) { 402 ACPI_FREE(name_string); 403 return; 404 } 405 406 /* Get the NS node, determines existence also */ 407 408 status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, 409 &acpi_gbl_db_method_info.method); 410 if (ACPI_SUCCESS(status)) { 411 status = acpi_db_execute_method(&acpi_gbl_db_method_info, 412 &return_obj); 413 } 414 ACPI_FREE(name_string); 415 416 /* 417 * Allow any handlers in separate threads to complete. 418 * (Such as Notify handlers invoked from AML executed above). 419 */ 420 acpi_os_sleep((u64)10); 421 422 #ifdef ACPI_DEBUG_OUTPUT 423 424 /* Memory allocation tracking */ 425 426 allocations = 427 acpi_db_get_outstanding_allocations() - previous_allocations; 428 429 acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); 430 431 if (allocations > 0) { 432 acpi_os_printf 433 ("0x%X Outstanding allocations after evaluation of %s\n", 434 allocations, acpi_gbl_db_method_info.pathname); 435 } 436 #endif 437 438 if (ACPI_FAILURE(status)) { 439 acpi_os_printf("Evaluation of %s failed with status %s\n", 440 acpi_gbl_db_method_info.pathname, 441 acpi_format_exception(status)); 442 } else { 443 /* Display a return object, if any */ 444 445 if (return_obj.length) { 446 acpi_os_printf("Evaluation of %s returned object %p, " 447 "external buffer length %X\n", 448 acpi_gbl_db_method_info.pathname, 449 return_obj.pointer, 450 (u32)return_obj.length); 451 452 acpi_db_dump_external_object(return_obj.pointer, 1); 453 454 /* Dump a _PLD buffer if present */ 455 456 if (ACPI_COMPARE_NAME 457 ((ACPI_CAST_PTR 458 (struct acpi_namespace_node, 459 acpi_gbl_db_method_info.method)->name.ascii), 460 METHOD_NAME__PLD)) { 461 acpi_db_dump_pld_buffer(return_obj.pointer); 462 } 463 } else { 464 acpi_os_printf 465 ("No object was returned from evaluation of %s\n", 466 acpi_gbl_db_method_info.pathname); 467 } 468 } 469 470 acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); 471 } 472 473 /******************************************************************************* 474 * 475 * FUNCTION: acpi_db_method_thread 476 * 477 * PARAMETERS: context - Execution info segment 478 * 479 * RETURN: None 480 * 481 * DESCRIPTION: Debugger execute thread. Waits for a command line, then 482 * simply dispatches it. 483 * 484 ******************************************************************************/ 485 486 static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context) 487 { 488 acpi_status status; 489 struct acpi_db_method_info *info = context; 490 struct acpi_db_method_info local_info; 491 u32 i; 492 u8 allow; 493 struct acpi_buffer return_obj; 494 495 /* 496 * acpi_gbl_db_method_info.Arguments will be passed as method arguments. 497 * Prevent acpi_gbl_db_method_info from being modified by multiple threads 498 * concurrently. 499 * 500 * Note: The arguments we are passing are used by the ASL test suite 501 * (aslts). Do not change them without updating the tests. 502 */ 503 (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER); 504 505 if (info->init_args) { 506 acpi_db_uint32_to_hex_string(info->num_created, 507 info->index_of_thread_str); 508 acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(), 509 info->id_of_thread_str); 510 } 511 512 if (info->threads && (info->num_created < info->num_threads)) { 513 info->threads[info->num_created++] = acpi_os_get_thread_id(); 514 } 515 516 local_info = *info; 517 local_info.args = local_info.arguments; 518 local_info.arguments[0] = local_info.num_threads_str; 519 local_info.arguments[1] = local_info.id_of_thread_str; 520 local_info.arguments[2] = local_info.index_of_thread_str; 521 local_info.arguments[3] = NULL; 522 523 local_info.types = local_info.arg_types; 524 525 (void)acpi_os_signal_semaphore(info->info_gate, 1); 526 527 for (i = 0; i < info->num_loops; i++) { 528 status = acpi_db_execute_method(&local_info, &return_obj); 529 if (ACPI_FAILURE(status)) { 530 acpi_os_printf 531 ("%s During evaluation of %s at iteration %X\n", 532 acpi_format_exception(status), info->pathname, i); 533 if (status == AE_ABORT_METHOD) { 534 break; 535 } 536 } 537 #if 0 538 if ((i % 100) == 0) { 539 acpi_os_printf("%u loops, Thread 0x%x\n", 540 i, acpi_os_get_thread_id()); 541 } 542 543 if (return_obj.length) { 544 acpi_os_printf 545 ("Evaluation of %s returned object %p Buflen %X\n", 546 info->pathname, return_obj.pointer, 547 (u32)return_obj.length); 548 acpi_db_dump_external_object(return_obj.pointer, 1); 549 } 550 #endif 551 } 552 553 /* Signal our completion */ 554 555 allow = 0; 556 (void)acpi_os_wait_semaphore(info->thread_complete_gate, 557 1, ACPI_WAIT_FOREVER); 558 info->num_completed++; 559 560 if (info->num_completed == info->num_threads) { 561 562 /* Do signal for main thread once only */ 563 allow = 1; 564 } 565 566 (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1); 567 568 if (allow) { 569 status = acpi_os_signal_semaphore(info->main_thread_gate, 1); 570 if (ACPI_FAILURE(status)) { 571 acpi_os_printf 572 ("Could not signal debugger thread sync semaphore, %s\n", 573 acpi_format_exception(status)); 574 } 575 } 576 } 577 578 /******************************************************************************* 579 * 580 * FUNCTION: acpi_db_single_execution_thread 581 * 582 * PARAMETERS: context - Method info struct 583 * 584 * RETURN: None 585 * 586 * DESCRIPTION: Create one thread and execute a method 587 * 588 ******************************************************************************/ 589 590 static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context) 591 { 592 struct acpi_db_method_info *info = context; 593 acpi_status status; 594 struct acpi_buffer return_obj; 595 596 acpi_os_printf("\n"); 597 598 status = acpi_db_execute_method(info, &return_obj); 599 if (ACPI_FAILURE(status)) { 600 acpi_os_printf("%s During evaluation of %s\n", 601 acpi_format_exception(status), info->pathname); 602 return; 603 } 604 605 /* Display a return object, if any */ 606 607 if (return_obj.length) { 608 acpi_os_printf("Evaluation of %s returned object %p, " 609 "external buffer length %X\n", 610 acpi_gbl_db_method_info.pathname, 611 return_obj.pointer, (u32)return_obj.length); 612 613 acpi_db_dump_external_object(return_obj.pointer, 1); 614 } 615 616 acpi_os_printf("\nBackground thread completed\n%c ", 617 ACPI_DEBUGGER_COMMAND_PROMPT); 618 } 619 620 /******************************************************************************* 621 * 622 * FUNCTION: acpi_db_create_execution_thread 623 * 624 * PARAMETERS: method_name_arg - Control method to execute 625 * arguments - Array of arguments to the method 626 * types - Corresponding array of object types 627 * 628 * RETURN: None 629 * 630 * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles 631 * arguments passed on command line for control methods. 632 * 633 ******************************************************************************/ 634 635 void 636 acpi_db_create_execution_thread(char *method_name_arg, 637 char **arguments, acpi_object_type *types) 638 { 639 acpi_status status; 640 u32 i; 641 642 memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); 643 acpi_gbl_db_method_info.name = method_name_arg; 644 acpi_gbl_db_method_info.init_args = 1; 645 acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments; 646 acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types; 647 648 /* Setup method arguments, up to 7 (0-6) */ 649 650 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) { 651 acpi_gbl_db_method_info.arguments[i] = *arguments; 652 arguments++; 653 654 acpi_gbl_db_method_info.arg_types[i] = *types; 655 types++; 656 } 657 658 status = acpi_db_execute_setup(&acpi_gbl_db_method_info); 659 if (ACPI_FAILURE(status)) { 660 return; 661 } 662 663 /* Get the NS node, determines existence also */ 664 665 status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, 666 &acpi_gbl_db_method_info.method); 667 if (ACPI_FAILURE(status)) { 668 acpi_os_printf("%s Could not get handle for %s\n", 669 acpi_format_exception(status), 670 acpi_gbl_db_method_info.pathname); 671 return; 672 } 673 674 status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD, 675 acpi_db_single_execution_thread, 676 &acpi_gbl_db_method_info); 677 if (ACPI_FAILURE(status)) { 678 return; 679 } 680 681 acpi_os_printf("\nBackground thread started\n"); 682 } 683 684 /******************************************************************************* 685 * 686 * FUNCTION: acpi_db_create_execution_threads 687 * 688 * PARAMETERS: num_threads_arg - Number of threads to create 689 * num_loops_arg - Loop count for the thread(s) 690 * method_name_arg - Control method to execute 691 * 692 * RETURN: None 693 * 694 * DESCRIPTION: Create threads to execute method(s) 695 * 696 ******************************************************************************/ 697 698 void 699 acpi_db_create_execution_threads(char *num_threads_arg, 700 char *num_loops_arg, char *method_name_arg) 701 { 702 acpi_status status; 703 u32 num_threads; 704 u32 num_loops; 705 u32 i; 706 u32 size; 707 acpi_mutex main_thread_gate; 708 acpi_mutex thread_complete_gate; 709 acpi_mutex info_gate; 710 711 /* Get the arguments */ 712 713 num_threads = strtoul(num_threads_arg, NULL, 0); 714 num_loops = strtoul(num_loops_arg, NULL, 0); 715 716 if (!num_threads || !num_loops) { 717 acpi_os_printf("Bad argument: Threads %X, Loops %X\n", 718 num_threads, num_loops); 719 return; 720 } 721 722 /* 723 * Create the semaphore for synchronization of 724 * the created threads with the main thread. 725 */ 726 status = acpi_os_create_semaphore(1, 0, &main_thread_gate); 727 if (ACPI_FAILURE(status)) { 728 acpi_os_printf("Could not create semaphore for " 729 "synchronization with the main thread, %s\n", 730 acpi_format_exception(status)); 731 return; 732 } 733 734 /* 735 * Create the semaphore for synchronization 736 * between the created threads. 737 */ 738 status = acpi_os_create_semaphore(1, 1, &thread_complete_gate); 739 if (ACPI_FAILURE(status)) { 740 acpi_os_printf("Could not create semaphore for " 741 "synchronization between the created threads, %s\n", 742 acpi_format_exception(status)); 743 744 (void)acpi_os_delete_semaphore(main_thread_gate); 745 return; 746 } 747 748 status = acpi_os_create_semaphore(1, 1, &info_gate); 749 if (ACPI_FAILURE(status)) { 750 acpi_os_printf("Could not create semaphore for " 751 "synchronization of AcpiGbl_DbMethodInfo, %s\n", 752 acpi_format_exception(status)); 753 754 (void)acpi_os_delete_semaphore(thread_complete_gate); 755 (void)acpi_os_delete_semaphore(main_thread_gate); 756 return; 757 } 758 759 memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); 760 761 /* Array to store IDs of threads */ 762 763 acpi_gbl_db_method_info.num_threads = num_threads; 764 size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads; 765 766 acpi_gbl_db_method_info.threads = acpi_os_allocate(size); 767 if (acpi_gbl_db_method_info.threads == NULL) { 768 acpi_os_printf("No memory for thread IDs array\n"); 769 (void)acpi_os_delete_semaphore(main_thread_gate); 770 (void)acpi_os_delete_semaphore(thread_complete_gate); 771 (void)acpi_os_delete_semaphore(info_gate); 772 return; 773 } 774 memset(acpi_gbl_db_method_info.threads, 0, size); 775 776 /* Setup the context to be passed to each thread */ 777 778 acpi_gbl_db_method_info.name = method_name_arg; 779 acpi_gbl_db_method_info.flags = 0; 780 acpi_gbl_db_method_info.num_loops = num_loops; 781 acpi_gbl_db_method_info.main_thread_gate = main_thread_gate; 782 acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate; 783 acpi_gbl_db_method_info.info_gate = info_gate; 784 785 /* Init arguments to be passed to method */ 786 787 acpi_gbl_db_method_info.init_args = 1; 788 acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments; 789 acpi_gbl_db_method_info.arguments[0] = 790 acpi_gbl_db_method_info.num_threads_str; 791 acpi_gbl_db_method_info.arguments[1] = 792 acpi_gbl_db_method_info.id_of_thread_str; 793 acpi_gbl_db_method_info.arguments[2] = 794 acpi_gbl_db_method_info.index_of_thread_str; 795 acpi_gbl_db_method_info.arguments[3] = NULL; 796 797 acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types; 798 acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER; 799 acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER; 800 acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER; 801 802 acpi_db_uint32_to_hex_string(num_threads, 803 acpi_gbl_db_method_info.num_threads_str); 804 805 status = acpi_db_execute_setup(&acpi_gbl_db_method_info); 806 if (ACPI_FAILURE(status)) { 807 goto cleanup_and_exit; 808 } 809 810 /* Get the NS node, determines existence also */ 811 812 status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, 813 &acpi_gbl_db_method_info.method); 814 if (ACPI_FAILURE(status)) { 815 acpi_os_printf("%s Could not get handle for %s\n", 816 acpi_format_exception(status), 817 acpi_gbl_db_method_info.pathname); 818 goto cleanup_and_exit; 819 } 820 821 /* Create the threads */ 822 823 acpi_os_printf("Creating %X threads to execute %X times each\n", 824 num_threads, num_loops); 825 826 for (i = 0; i < (num_threads); i++) { 827 status = 828 acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD, 829 acpi_db_method_thread, 830 &acpi_gbl_db_method_info); 831 if (ACPI_FAILURE(status)) { 832 break; 833 } 834 } 835 836 /* Wait for all threads to complete */ 837 838 (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER); 839 840 acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); 841 acpi_os_printf("All threads (%X) have completed\n", num_threads); 842 acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); 843 844 cleanup_and_exit: 845 846 /* Cleanup and exit */ 847 848 (void)acpi_os_delete_semaphore(main_thread_gate); 849 (void)acpi_os_delete_semaphore(thread_complete_gate); 850 (void)acpi_os_delete_semaphore(info_gate); 851 852 acpi_os_free(acpi_gbl_db_method_info.threads); 853 acpi_gbl_db_method_info.threads = NULL; 854 } 855