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