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