Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: dbexec - debugger control method execution
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "acdebug.h"
0011 #include "acnamesp.h"
0012 
0013 #define _COMPONENT          ACPI_CA_DEBUGGER
0014 ACPI_MODULE_NAME("dbexec")
0015 
0016 static struct acpi_db_method_info acpi_gbl_db_method_info;
0017 
0018 /* Local prototypes */
0019 
0020 static acpi_status
0021 acpi_db_execute_method(struct acpi_db_method_info *info,
0022                struct acpi_buffer *return_obj);
0023 
0024 static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
0025 
0026 static u32 acpi_db_get_outstanding_allocations(void);
0027 
0028 static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
0029 
0030 static acpi_status
0031 acpi_db_execution_walk(acpi_handle obj_handle,
0032                u32 nesting_level, void *context, void **return_value);
0033 
0034 static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context);
0035 
0036 /*******************************************************************************
0037  *
0038  * FUNCTION:    acpi_db_delete_objects
0039  *
0040  * PARAMETERS:  count               - Count of objects in the list
0041  *              objects             - Array of ACPI_OBJECTs to be deleted
0042  *
0043  * RETURN:      None
0044  *
0045  * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
0046  *              packages via recursion.
0047  *
0048  ******************************************************************************/
0049 
0050 void acpi_db_delete_objects(u32 count, union acpi_object *objects)
0051 {
0052     u32 i;
0053 
0054     for (i = 0; i < count; i++) {
0055         switch (objects[i].type) {
0056         case ACPI_TYPE_BUFFER:
0057 
0058             ACPI_FREE(objects[i].buffer.pointer);
0059             break;
0060 
0061         case ACPI_TYPE_PACKAGE:
0062 
0063             /* Recursive call to delete package elements */
0064 
0065             acpi_db_delete_objects(objects[i].package.count,
0066                            objects[i].package.elements);
0067 
0068             /* Free the elements array */
0069 
0070             ACPI_FREE(objects[i].package.elements);
0071             break;
0072 
0073         default:
0074 
0075             break;
0076         }
0077     }
0078 }
0079 
0080 /*******************************************************************************
0081  *
0082  * FUNCTION:    acpi_db_execute_method
0083  *
0084  * PARAMETERS:  info            - Valid info segment
0085  *              return_obj      - Where to put return object
0086  *
0087  * RETURN:      Status
0088  *
0089  * DESCRIPTION: Execute a control method. Used to evaluate objects via the
0090  *              "EXECUTE" or "EVALUATE" commands.
0091  *
0092  ******************************************************************************/
0093 
0094 static acpi_status
0095 acpi_db_execute_method(struct acpi_db_method_info *info,
0096                struct acpi_buffer *return_obj)
0097 {
0098     acpi_status status;
0099     struct acpi_object_list param_objects;
0100     union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
0101     u32 i;
0102 
0103     ACPI_FUNCTION_TRACE(db_execute_method);
0104 
0105     if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
0106         acpi_os_printf("Warning: debug output is not enabled!\n");
0107     }
0108 
0109     param_objects.count = 0;
0110     param_objects.pointer = NULL;
0111 
0112     /* Pass through any command-line arguments */
0113 
0114     if (info->args && info->args[0]) {
0115 
0116         /* Get arguments passed on the command line */
0117 
0118         for (i = 0; (info->args[i] && *(info->args[i])); i++) {
0119 
0120             /* Convert input string (token) to an actual union acpi_object */
0121 
0122             status = acpi_db_convert_to_object(info->types[i],
0123                                info->args[i],
0124                                &params[i]);
0125             if (ACPI_FAILURE(status)) {
0126                 ACPI_EXCEPTION((AE_INFO, status,
0127                         "While parsing method arguments"));
0128                 goto cleanup;
0129             }
0130         }
0131 
0132         param_objects.count = i;
0133         param_objects.pointer = params;
0134     }
0135 
0136     /* Prepare for a return object of arbitrary size */
0137 
0138     return_obj->pointer = acpi_gbl_db_buffer;
0139     return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
0140 
0141     /* Do the actual method execution */
0142 
0143     acpi_gbl_method_executing = TRUE;
0144     status = acpi_evaluate_object(NULL, info->pathname,
0145                       &param_objects, return_obj);
0146 
0147     acpi_gbl_cm_single_step = FALSE;
0148     acpi_gbl_method_executing = FALSE;
0149 
0150     if (ACPI_FAILURE(status)) {
0151         if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) {
0152 
0153             /* Clear the abort and fall back to the debugger prompt */
0154 
0155             ACPI_EXCEPTION((AE_INFO, status,
0156                     "Aborting top-level method"));
0157 
0158             acpi_gbl_abort_method = FALSE;
0159             status = AE_OK;
0160             goto cleanup;
0161         }
0162 
0163         ACPI_EXCEPTION((AE_INFO, status,
0164                 "while executing %s from AML Debugger",
0165                 info->pathname));
0166 
0167         if (status == AE_BUFFER_OVERFLOW) {
0168             ACPI_ERROR((AE_INFO,
0169                     "Possible buffer overflow within AML Debugger "
0170                     "buffer (size 0x%X needed 0x%X)",
0171                     ACPI_DEBUG_BUFFER_SIZE,
0172                     (u32)return_obj->length));
0173         }
0174     }
0175 
0176 cleanup:
0177     acpi_db_delete_objects(param_objects.count, params);
0178     return_ACPI_STATUS(status);
0179 }
0180 
0181 /*******************************************************************************
0182  *
0183  * FUNCTION:    acpi_db_execute_setup
0184  *
0185  * PARAMETERS:  info            - Valid method info
0186  *
0187  * RETURN:      None
0188  *
0189  * DESCRIPTION: Setup info segment prior to method execution
0190  *
0191  ******************************************************************************/
0192 
0193 static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
0194 {
0195     acpi_status status;
0196 
0197     ACPI_FUNCTION_NAME(db_execute_setup);
0198 
0199     /* Concatenate the current scope to the supplied name */
0200 
0201     info->pathname[0] = 0;
0202     if ((info->name[0] != '\\') && (info->name[0] != '/')) {
0203         if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
0204                     acpi_gbl_db_scope_buf)) {
0205             status = AE_BUFFER_OVERFLOW;
0206             goto error_exit;
0207         }
0208     }
0209 
0210     if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
0211                 info->name)) {
0212         status = AE_BUFFER_OVERFLOW;
0213         goto error_exit;
0214     }
0215 
0216     acpi_db_prep_namestring(info->pathname);
0217 
0218     acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
0219     acpi_os_printf("Evaluating %s\n", info->pathname);
0220 
0221     if (info->flags & EX_SINGLE_STEP) {
0222         acpi_gbl_cm_single_step = TRUE;
0223         acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
0224     }
0225 
0226     else {
0227         /* No single step, allow redirection to a file */
0228 
0229         acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
0230     }
0231 
0232     return (AE_OK);
0233 
0234 error_exit:
0235 
0236     ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
0237     return (status);
0238 }
0239 
0240 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
0241 u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
0242 {
0243 
0244     return (cache->total_allocated - cache->total_freed -
0245         cache->current_depth);
0246 }
0247 #endif
0248 
0249 /*******************************************************************************
0250  *
0251  * FUNCTION:    acpi_db_get_outstanding_allocations
0252  *
0253  * PARAMETERS:  None
0254  *
0255  * RETURN:      Current global allocation count minus cache entries
0256  *
0257  * DESCRIPTION: Determine the current number of "outstanding" allocations --
0258  *              those allocations that have not been freed and also are not
0259  *              in one of the various object caches.
0260  *
0261  ******************************************************************************/
0262 
0263 static u32 acpi_db_get_outstanding_allocations(void)
0264 {
0265     u32 outstanding = 0;
0266 
0267 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
0268 
0269     outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
0270     outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
0271     outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
0272     outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
0273 #endif
0274 
0275     return (outstanding);
0276 }
0277 
0278 /*******************************************************************************
0279  *
0280  * FUNCTION:    acpi_db_execution_walk
0281  *
0282  * PARAMETERS:  WALK_CALLBACK
0283  *
0284  * RETURN:      Status
0285  *
0286  * DESCRIPTION: Execute a control method. Name is relative to the current
0287  *              scope.
0288  *
0289  ******************************************************************************/
0290 
0291 static acpi_status
0292 acpi_db_execution_walk(acpi_handle obj_handle,
0293                u32 nesting_level, void *context, void **return_value)
0294 {
0295     union acpi_operand_object *obj_desc;
0296     struct acpi_namespace_node *node =
0297         (struct acpi_namespace_node *)obj_handle;
0298     struct acpi_buffer return_obj;
0299     acpi_status status;
0300 
0301     obj_desc = acpi_ns_get_attached_object(node);
0302     if (obj_desc->method.param_count) {
0303         return (AE_OK);
0304     }
0305 
0306     return_obj.pointer = NULL;
0307     return_obj.length = ACPI_ALLOCATE_BUFFER;
0308 
0309     acpi_ns_print_node_pathname(node, "Evaluating");
0310 
0311     /* Do the actual method execution */
0312 
0313     acpi_os_printf("\n");
0314     acpi_gbl_method_executing = TRUE;
0315 
0316     status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
0317 
0318     acpi_gbl_method_executing = FALSE;
0319 
0320     acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
0321                acpi_ut_get_node_name(node),
0322                acpi_format_exception(status));
0323 
0324     return (AE_OK);
0325 }
0326 
0327 /*******************************************************************************
0328  *
0329  * FUNCTION:    acpi_db_execute
0330  *
0331  * PARAMETERS:  name                - Name of method to execute
0332  *              args                - Parameters to the method
0333  *              Types               -
0334  *              flags               - single step/no single step
0335  *
0336  * RETURN:      None
0337  *
0338  * DESCRIPTION: Execute a control method. Name is relative to the current
0339  *              scope. Function used for the "EXECUTE", "EVALUATE", and
0340  *              "ALL" commands
0341  *
0342  ******************************************************************************/
0343 
0344 void
0345 acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
0346 {
0347     acpi_status status;
0348     struct acpi_buffer return_obj;
0349     char *name_string;
0350 
0351 #ifdef ACPI_DEBUG_OUTPUT
0352     u32 previous_allocations;
0353     u32 allocations;
0354 #endif
0355 
0356     /*
0357      * Allow one execution to be performed by debugger or single step
0358      * execution will be dead locked by the interpreter mutexes.
0359      */
0360     if (acpi_gbl_method_executing) {
0361         acpi_os_printf("Only one debugger execution is allowed.\n");
0362         return;
0363     }
0364 #ifdef ACPI_DEBUG_OUTPUT
0365     /* Memory allocation tracking */
0366 
0367     previous_allocations = acpi_db_get_outstanding_allocations();
0368 #endif
0369 
0370     if (*name == '*') {
0371         (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
0372                       ACPI_UINT32_MAX,
0373                       acpi_db_execution_walk, NULL, NULL,
0374                       NULL);
0375         return;
0376     }
0377 
0378     if ((flags & EX_ALL) && (strlen(name) > 4)) {
0379         acpi_os_printf("Input name (%s) must be a 4-char NameSeg\n",
0380                    name);
0381         return;
0382     }
0383 
0384     name_string = ACPI_ALLOCATE(strlen(name) + 1);
0385     if (!name_string) {
0386         return;
0387     }
0388 
0389     memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
0390     strcpy(name_string, name);
0391     acpi_ut_strupr(name_string);
0392 
0393     /* Subcommand to Execute all predefined names in the namespace */
0394 
0395     if (!strncmp(name_string, "PREDEF", 6)) {
0396         acpi_db_evaluate_predefined_names();
0397         ACPI_FREE(name_string);
0398         return;
0399     }
0400 
0401     /* Command (ALL <nameseg>) to execute all methods of a particular name */
0402 
0403     else if (flags & EX_ALL) {
0404         acpi_gbl_db_method_info.name = name_string;
0405         return_obj.pointer = NULL;
0406         return_obj.length = ACPI_ALLOCATE_BUFFER;
0407         acpi_db_evaluate_all(name_string);
0408         ACPI_FREE(name_string);
0409         return;
0410     } else {
0411         acpi_gbl_db_method_info.name = name_string;
0412         acpi_gbl_db_method_info.args = args;
0413         acpi_gbl_db_method_info.types = types;
0414         acpi_gbl_db_method_info.flags = flags;
0415 
0416         return_obj.pointer = NULL;
0417         return_obj.length = ACPI_ALLOCATE_BUFFER;
0418     }
0419 
0420     status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
0421     if (ACPI_FAILURE(status)) {
0422         ACPI_FREE(name_string);
0423         return;
0424     }
0425 
0426     /* Get the NS node, determines existence also */
0427 
0428     status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
0429                  &acpi_gbl_db_method_info.method);
0430     if (ACPI_SUCCESS(status)) {
0431         status = acpi_db_execute_method(&acpi_gbl_db_method_info,
0432                         &return_obj);
0433     }
0434     ACPI_FREE(name_string);
0435 
0436     /*
0437      * Allow any handlers in separate threads to complete.
0438      * (Such as Notify handlers invoked from AML executed above).
0439      */
0440     acpi_os_sleep((u64)10);
0441 
0442 #ifdef ACPI_DEBUG_OUTPUT
0443 
0444     /* Memory allocation tracking */
0445 
0446     allocations =
0447         acpi_db_get_outstanding_allocations() - previous_allocations;
0448 
0449     acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
0450 
0451     if (allocations > 0) {
0452         acpi_os_printf
0453             ("0x%X Outstanding allocations after evaluation of %s\n",
0454              allocations, acpi_gbl_db_method_info.pathname);
0455     }
0456 #endif
0457 
0458     if (ACPI_FAILURE(status)) {
0459         acpi_os_printf("Evaluation of %s failed with status %s\n",
0460                    acpi_gbl_db_method_info.pathname,
0461                    acpi_format_exception(status));
0462     } else {
0463         /* Display a return object, if any */
0464 
0465         if (return_obj.length) {
0466             acpi_os_printf("Evaluation of %s returned object %p, "
0467                        "external buffer length %X\n",
0468                        acpi_gbl_db_method_info.pathname,
0469                        return_obj.pointer,
0470                        (u32)return_obj.length);
0471 
0472             acpi_db_dump_external_object(return_obj.pointer, 1);
0473             acpi_os_printf("\n");
0474 
0475             /* Dump a _PLD buffer if present */
0476 
0477             if (ACPI_COMPARE_NAMESEG
0478                 ((ACPI_CAST_PTR
0479                   (struct acpi_namespace_node,
0480                    acpi_gbl_db_method_info.method)->name.ascii),
0481                  METHOD_NAME__PLD)) {
0482                 acpi_db_dump_pld_buffer(return_obj.pointer);
0483             }
0484         } else {
0485             acpi_os_printf
0486                 ("No object was returned from evaluation of %s\n",
0487                  acpi_gbl_db_method_info.pathname);
0488         }
0489     }
0490 
0491     acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
0492 }
0493 
0494 /*******************************************************************************
0495  *
0496  * FUNCTION:    acpi_db_method_thread
0497  *
0498  * PARAMETERS:  context             - Execution info segment
0499  *
0500  * RETURN:      None
0501  *
0502  * DESCRIPTION: Debugger execute thread. Waits for a command line, then
0503  *              simply dispatches it.
0504  *
0505  ******************************************************************************/
0506 
0507 static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
0508 {
0509     acpi_status status;
0510     struct acpi_db_method_info *info = context;
0511     struct acpi_db_method_info local_info;
0512     u32 i;
0513     u8 allow;
0514     struct acpi_buffer return_obj;
0515 
0516     /*
0517      * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
0518      * Prevent acpi_gbl_db_method_info from being modified by multiple threads
0519      * concurrently.
0520      *
0521      * Note: The arguments we are passing are used by the ASL test suite
0522      * (aslts). Do not change them without updating the tests.
0523      */
0524     (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
0525 
0526     if (info->init_args) {
0527         acpi_db_uint32_to_hex_string(info->num_created,
0528                          info->index_of_thread_str);
0529         acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
0530                          info->id_of_thread_str);
0531     }
0532 
0533     if (info->threads && (info->num_created < info->num_threads)) {
0534         info->threads[info->num_created++] = acpi_os_get_thread_id();
0535     }
0536 
0537     local_info = *info;
0538     local_info.args = local_info.arguments;
0539     local_info.arguments[0] = local_info.num_threads_str;
0540     local_info.arguments[1] = local_info.id_of_thread_str;
0541     local_info.arguments[2] = local_info.index_of_thread_str;
0542     local_info.arguments[3] = NULL;
0543 
0544     local_info.types = local_info.arg_types;
0545 
0546     (void)acpi_os_signal_semaphore(info->info_gate, 1);
0547 
0548     for (i = 0; i < info->num_loops; i++) {
0549         status = acpi_db_execute_method(&local_info, &return_obj);
0550         if (ACPI_FAILURE(status)) {
0551             acpi_os_printf
0552                 ("%s During evaluation of %s at iteration %X\n",
0553                  acpi_format_exception(status), info->pathname, i);
0554             if (status == AE_ABORT_METHOD) {
0555                 break;
0556             }
0557         }
0558 #if 0
0559         if ((i % 100) == 0) {
0560             acpi_os_printf("%u loops, Thread 0x%x\n",
0561                        i, acpi_os_get_thread_id());
0562         }
0563 
0564         if (return_obj.length) {
0565             acpi_os_printf
0566                 ("Evaluation of %s returned object %p Buflen %X\n",
0567                  info->pathname, return_obj.pointer,
0568                  (u32)return_obj.length);
0569             acpi_db_dump_external_object(return_obj.pointer, 1);
0570         }
0571 #endif
0572     }
0573 
0574     /* Signal our completion */
0575 
0576     allow = 0;
0577     (void)acpi_os_wait_semaphore(info->thread_complete_gate,
0578                      1, ACPI_WAIT_FOREVER);
0579     info->num_completed++;
0580 
0581     if (info->num_completed == info->num_threads) {
0582 
0583         /* Do signal for main thread once only */
0584         allow = 1;
0585     }
0586 
0587     (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
0588 
0589     if (allow) {
0590         status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
0591         if (ACPI_FAILURE(status)) {
0592             acpi_os_printf
0593                 ("Could not signal debugger thread sync semaphore, %s\n",
0594                  acpi_format_exception(status));
0595         }
0596     }
0597 }
0598 
0599 /*******************************************************************************
0600  *
0601  * FUNCTION:    acpi_db_single_execution_thread
0602  *
0603  * PARAMETERS:  context                 - Method info struct
0604  *
0605  * RETURN:      None
0606  *
0607  * DESCRIPTION: Create one thread and execute a method
0608  *
0609  ******************************************************************************/
0610 
0611 static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context)
0612 {
0613     struct acpi_db_method_info *info = context;
0614     acpi_status status;
0615     struct acpi_buffer return_obj;
0616 
0617     acpi_os_printf("\n");
0618 
0619     status = acpi_db_execute_method(info, &return_obj);
0620     if (ACPI_FAILURE(status)) {
0621         acpi_os_printf("%s During evaluation of %s\n",
0622                    acpi_format_exception(status), info->pathname);
0623         return;
0624     }
0625 
0626     /* Display a return object, if any */
0627 
0628     if (return_obj.length) {
0629         acpi_os_printf("Evaluation of %s returned object %p, "
0630                    "external buffer length %X\n",
0631                    acpi_gbl_db_method_info.pathname,
0632                    return_obj.pointer, (u32)return_obj.length);
0633 
0634         acpi_db_dump_external_object(return_obj.pointer, 1);
0635     }
0636 
0637     acpi_os_printf("\nBackground thread completed\n%c ",
0638                ACPI_DEBUGGER_COMMAND_PROMPT);
0639 }
0640 
0641 /*******************************************************************************
0642  *
0643  * FUNCTION:    acpi_db_create_execution_thread
0644  *
0645  * PARAMETERS:  method_name_arg         - Control method to execute
0646  *              arguments               - Array of arguments to the method
0647  *              types                   - Corresponding array of object types
0648  *
0649  * RETURN:      None
0650  *
0651  * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
0652  *              arguments passed on command line for control methods.
0653  *
0654  ******************************************************************************/
0655 
0656 void
0657 acpi_db_create_execution_thread(char *method_name_arg,
0658                 char **arguments, acpi_object_type *types)
0659 {
0660     acpi_status status;
0661     u32 i;
0662 
0663     memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
0664     acpi_gbl_db_method_info.name = method_name_arg;
0665     acpi_gbl_db_method_info.init_args = 1;
0666     acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
0667     acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
0668 
0669     /* Setup method arguments, up to 7 (0-6) */
0670 
0671     for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) {
0672         acpi_gbl_db_method_info.arguments[i] = *arguments;
0673         arguments++;
0674 
0675         acpi_gbl_db_method_info.arg_types[i] = *types;
0676         types++;
0677     }
0678 
0679     status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
0680     if (ACPI_FAILURE(status)) {
0681         return;
0682     }
0683 
0684     /* Get the NS node, determines existence also */
0685 
0686     status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
0687                  &acpi_gbl_db_method_info.method);
0688     if (ACPI_FAILURE(status)) {
0689         acpi_os_printf("%s Could not get handle for %s\n",
0690                    acpi_format_exception(status),
0691                    acpi_gbl_db_method_info.pathname);
0692         return;
0693     }
0694 
0695     status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
0696                  acpi_db_single_execution_thread,
0697                  &acpi_gbl_db_method_info);
0698     if (ACPI_FAILURE(status)) {
0699         return;
0700     }
0701 
0702     acpi_os_printf("\nBackground thread started\n");
0703 }
0704 
0705 /*******************************************************************************
0706  *
0707  * FUNCTION:    acpi_db_create_execution_threads
0708  *
0709  * PARAMETERS:  num_threads_arg         - Number of threads to create
0710  *              num_loops_arg           - Loop count for the thread(s)
0711  *              method_name_arg         - Control method to execute
0712  *
0713  * RETURN:      None
0714  *
0715  * DESCRIPTION: Create threads to execute method(s)
0716  *
0717  ******************************************************************************/
0718 
0719 void
0720 acpi_db_create_execution_threads(char *num_threads_arg,
0721                  char *num_loops_arg, char *method_name_arg)
0722 {
0723     acpi_status status;
0724     u32 num_threads;
0725     u32 num_loops;
0726     u32 i;
0727     u32 size;
0728     acpi_mutex main_thread_gate;
0729     acpi_mutex thread_complete_gate;
0730     acpi_mutex info_gate;
0731 
0732     /* Get the arguments */
0733 
0734     num_threads = strtoul(num_threads_arg, NULL, 0);
0735     num_loops = strtoul(num_loops_arg, NULL, 0);
0736 
0737     if (!num_threads || !num_loops) {
0738         acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
0739                    num_threads, num_loops);
0740         return;
0741     }
0742 
0743     /*
0744      * Create the semaphore for synchronization of
0745      * the created threads with the main thread.
0746      */
0747     status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
0748     if (ACPI_FAILURE(status)) {
0749         acpi_os_printf("Could not create semaphore for "
0750                    "synchronization with the main thread, %s\n",
0751                    acpi_format_exception(status));
0752         return;
0753     }
0754 
0755     /*
0756      * Create the semaphore for synchronization
0757      * between the created threads.
0758      */
0759     status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
0760     if (ACPI_FAILURE(status)) {
0761         acpi_os_printf("Could not create semaphore for "
0762                    "synchronization between the created threads, %s\n",
0763                    acpi_format_exception(status));
0764 
0765         (void)acpi_os_delete_semaphore(main_thread_gate);
0766         return;
0767     }
0768 
0769     status = acpi_os_create_semaphore(1, 1, &info_gate);
0770     if (ACPI_FAILURE(status)) {
0771         acpi_os_printf("Could not create semaphore for "
0772                    "synchronization of AcpiGbl_DbMethodInfo, %s\n",
0773                    acpi_format_exception(status));
0774 
0775         (void)acpi_os_delete_semaphore(thread_complete_gate);
0776         (void)acpi_os_delete_semaphore(main_thread_gate);
0777         return;
0778     }
0779 
0780     memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
0781 
0782     /* Array to store IDs of threads */
0783 
0784     acpi_gbl_db_method_info.num_threads = num_threads;
0785     size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
0786 
0787     acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
0788     if (acpi_gbl_db_method_info.threads == NULL) {
0789         acpi_os_printf("No memory for thread IDs array\n");
0790         (void)acpi_os_delete_semaphore(main_thread_gate);
0791         (void)acpi_os_delete_semaphore(thread_complete_gate);
0792         (void)acpi_os_delete_semaphore(info_gate);
0793         return;
0794     }
0795     memset(acpi_gbl_db_method_info.threads, 0, size);
0796 
0797     /* Setup the context to be passed to each thread */
0798 
0799     acpi_gbl_db_method_info.name = method_name_arg;
0800     acpi_gbl_db_method_info.flags = 0;
0801     acpi_gbl_db_method_info.num_loops = num_loops;
0802     acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
0803     acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
0804     acpi_gbl_db_method_info.info_gate = info_gate;
0805 
0806     /* Init arguments to be passed to method */
0807 
0808     acpi_gbl_db_method_info.init_args = 1;
0809     acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
0810     acpi_gbl_db_method_info.arguments[0] =
0811         acpi_gbl_db_method_info.num_threads_str;
0812     acpi_gbl_db_method_info.arguments[1] =
0813         acpi_gbl_db_method_info.id_of_thread_str;
0814     acpi_gbl_db_method_info.arguments[2] =
0815         acpi_gbl_db_method_info.index_of_thread_str;
0816     acpi_gbl_db_method_info.arguments[3] = NULL;
0817 
0818     acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
0819     acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
0820     acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
0821     acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
0822 
0823     acpi_db_uint32_to_hex_string(num_threads,
0824                      acpi_gbl_db_method_info.num_threads_str);
0825 
0826     status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
0827     if (ACPI_FAILURE(status)) {
0828         goto cleanup_and_exit;
0829     }
0830 
0831     /* Get the NS node, determines existence also */
0832 
0833     status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
0834                  &acpi_gbl_db_method_info.method);
0835     if (ACPI_FAILURE(status)) {
0836         acpi_os_printf("%s Could not get handle for %s\n",
0837                    acpi_format_exception(status),
0838                    acpi_gbl_db_method_info.pathname);
0839         goto cleanup_and_exit;
0840     }
0841 
0842     /* Create the threads */
0843 
0844     acpi_os_printf("Creating %X threads to execute %X times each\n",
0845                num_threads, num_loops);
0846 
0847     for (i = 0; i < (num_threads); i++) {
0848         status =
0849             acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
0850                     acpi_db_method_thread,
0851                     &acpi_gbl_db_method_info);
0852         if (ACPI_FAILURE(status)) {
0853             break;
0854         }
0855     }
0856 
0857     /* Wait for all threads to complete */
0858 
0859     (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
0860 
0861     acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
0862     acpi_os_printf("All threads (%X) have completed\n", num_threads);
0863     acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
0864 
0865 cleanup_and_exit:
0866 
0867     /* Cleanup and exit */
0868 
0869     (void)acpi_os_delete_semaphore(main_thread_gate);
0870     (void)acpi_os_delete_semaphore(thread_complete_gate);
0871     (void)acpi_os_delete_semaphore(info_gate);
0872 
0873     acpi_os_free(acpi_gbl_db_method_info.threads);
0874     acpi_gbl_db_method_info.threads = NULL;
0875 }