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