162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dbexec - debugger control method execution
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci ******************************************************************************/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <acpi/acpi.h>
962306a36Sopenharmony_ci#include "accommon.h"
1062306a36Sopenharmony_ci#include "acdebug.h"
1162306a36Sopenharmony_ci#include "acnamesp.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define _COMPONENT          ACPI_CA_DEBUGGER
1462306a36Sopenharmony_ciACPI_MODULE_NAME("dbexec")
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic struct acpi_db_method_info acpi_gbl_db_method_info;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Local prototypes */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic acpi_status
2162306a36Sopenharmony_ciacpi_db_execute_method(struct acpi_db_method_info *info,
2262306a36Sopenharmony_ci		       struct acpi_buffer *return_obj);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic u32 acpi_db_get_outstanding_allocations(void);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic acpi_status
3162306a36Sopenharmony_ciacpi_db_execution_walk(acpi_handle obj_handle,
3262306a36Sopenharmony_ci		       u32 nesting_level, void *context, void **return_value);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*******************************************************************************
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * FUNCTION:    acpi_db_delete_objects
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * PARAMETERS:  count               - Count of objects in the list
4162306a36Sopenharmony_ci *              objects             - Array of ACPI_OBJECTs to be deleted
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * RETURN:      None
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
4662306a36Sopenharmony_ci *              packages via recursion.
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci ******************************************************************************/
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid acpi_db_delete_objects(u32 count, union acpi_object *objects)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	u32 i;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
5562306a36Sopenharmony_ci		switch (objects[i].type) {
5662306a36Sopenharmony_ci		case ACPI_TYPE_BUFFER:
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci			ACPI_FREE(objects[i].buffer.pointer);
5962306a36Sopenharmony_ci			break;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		case ACPI_TYPE_PACKAGE:
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci			/* Recursive call to delete package elements */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci			acpi_db_delete_objects(objects[i].package.count,
6662306a36Sopenharmony_ci					       objects[i].package.elements);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci			/* Free the elements array */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci			ACPI_FREE(objects[i].package.elements);
7162306a36Sopenharmony_ci			break;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		default:
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci			break;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/*******************************************************************************
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * FUNCTION:    acpi_db_execute_method
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * PARAMETERS:  info            - Valid info segment
8562306a36Sopenharmony_ci *              return_obj      - Where to put return object
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * RETURN:      Status
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * DESCRIPTION: Execute a control method. Used to evaluate objects via the
9062306a36Sopenharmony_ci *              "EXECUTE" or "EVALUATE" commands.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci ******************************************************************************/
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic acpi_status
9562306a36Sopenharmony_ciacpi_db_execute_method(struct acpi_db_method_info *info,
9662306a36Sopenharmony_ci		       struct acpi_buffer *return_obj)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	acpi_status status;
9962306a36Sopenharmony_ci	struct acpi_object_list param_objects;
10062306a36Sopenharmony_ci	union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
10162306a36Sopenharmony_ci	u32 i;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(db_execute_method);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
10662306a36Sopenharmony_ci		acpi_os_printf("Warning: debug output is not enabled!\n");
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	param_objects.count = 0;
11062306a36Sopenharmony_ci	param_objects.pointer = NULL;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Pass through any command-line arguments */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (info->args && info->args[0]) {
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		/* Get arguments passed on the command line */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		for (i = 0; (info->args[i] && *(info->args[i])); i++) {
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci			/* Convert input string (token) to an actual union acpi_object */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci			status = acpi_db_convert_to_object(info->types[i],
12362306a36Sopenharmony_ci							   info->args[i],
12462306a36Sopenharmony_ci							   &params[i]);
12562306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
12662306a36Sopenharmony_ci				ACPI_EXCEPTION((AE_INFO, status,
12762306a36Sopenharmony_ci						"While parsing method arguments"));
12862306a36Sopenharmony_ci				goto cleanup;
12962306a36Sopenharmony_ci			}
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		param_objects.count = i;
13362306a36Sopenharmony_ci		param_objects.pointer = params;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* Prepare for a return object of arbitrary size */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return_obj->pointer = acpi_gbl_db_buffer;
13962306a36Sopenharmony_ci	return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Do the actual method execution */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	acpi_gbl_method_executing = TRUE;
14462306a36Sopenharmony_ci	status = acpi_evaluate_object(NULL, info->pathname,
14562306a36Sopenharmony_ci				      &param_objects, return_obj);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	acpi_gbl_cm_single_step = FALSE;
14862306a36Sopenharmony_ci	acpi_gbl_method_executing = FALSE;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
15162306a36Sopenharmony_ci		if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) {
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci			/* Clear the abort and fall back to the debugger prompt */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status,
15662306a36Sopenharmony_ci					"Aborting top-level method"));
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci			acpi_gbl_abort_method = FALSE;
15962306a36Sopenharmony_ci			status = AE_OK;
16062306a36Sopenharmony_ci			goto cleanup;
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
16462306a36Sopenharmony_ci				"while executing %s from AML Debugger",
16562306a36Sopenharmony_ci				info->pathname));
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		if (status == AE_BUFFER_OVERFLOW) {
16862306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
16962306a36Sopenharmony_ci				    "Possible buffer overflow within AML Debugger "
17062306a36Sopenharmony_ci				    "buffer (size 0x%X needed 0x%X)",
17162306a36Sopenharmony_ci				    ACPI_DEBUG_BUFFER_SIZE,
17262306a36Sopenharmony_ci				    (u32)return_obj->length));
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cicleanup:
17762306a36Sopenharmony_ci	acpi_db_delete_objects(param_objects.count, params);
17862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/*******************************************************************************
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * FUNCTION:    acpi_db_execute_setup
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * PARAMETERS:  info            - Valid method info
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * RETURN:      None
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * DESCRIPTION: Setup info segment prior to method execution
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci ******************************************************************************/
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	acpi_status status;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(db_execute_setup);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Concatenate the current scope to the supplied name */
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	info->pathname[0] = 0;
20262306a36Sopenharmony_ci	if ((info->name[0] != '\\') && (info->name[0] != '/')) {
20362306a36Sopenharmony_ci		if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
20462306a36Sopenharmony_ci					acpi_gbl_db_scope_buf)) {
20562306a36Sopenharmony_ci			status = AE_BUFFER_OVERFLOW;
20662306a36Sopenharmony_ci			goto error_exit;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
21162306a36Sopenharmony_ci				info->name)) {
21262306a36Sopenharmony_ci		status = AE_BUFFER_OVERFLOW;
21362306a36Sopenharmony_ci		goto error_exit;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	acpi_db_prep_namestring(info->pathname);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
21962306a36Sopenharmony_ci	acpi_os_printf("Evaluating %s\n", info->pathname);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (info->flags & EX_SINGLE_STEP) {
22262306a36Sopenharmony_ci		acpi_gbl_cm_single_step = TRUE;
22362306a36Sopenharmony_ci		acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	else {
22762306a36Sopenharmony_ci		/* No single step, allow redirection to a file */
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return (AE_OK);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cierror_exit:
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
23762306a36Sopenharmony_ci	return (status);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS
24162306a36Sopenharmony_ciu32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return (cache->total_allocated - cache->total_freed -
24562306a36Sopenharmony_ci		cache->current_depth);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci#endif
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*******************************************************************************
25062306a36Sopenharmony_ci *
25162306a36Sopenharmony_ci * FUNCTION:    acpi_db_get_outstanding_allocations
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci * PARAMETERS:  None
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * RETURN:      Current global allocation count minus cache entries
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * DESCRIPTION: Determine the current number of "outstanding" allocations --
25862306a36Sopenharmony_ci *              those allocations that have not been freed and also are not
25962306a36Sopenharmony_ci *              in one of the various object caches.
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci ******************************************************************************/
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic u32 acpi_db_get_outstanding_allocations(void)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	u32 outstanding = 0;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
27062306a36Sopenharmony_ci	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
27162306a36Sopenharmony_ci	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
27262306a36Sopenharmony_ci	outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
27362306a36Sopenharmony_ci#endif
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return (outstanding);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/*******************************************************************************
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * FUNCTION:    acpi_db_execution_walk
28162306a36Sopenharmony_ci *
28262306a36Sopenharmony_ci * PARAMETERS:  WALK_CALLBACK
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci * RETURN:      Status
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * DESCRIPTION: Execute a control method. Name is relative to the current
28762306a36Sopenharmony_ci *              scope.
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci ******************************************************************************/
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic acpi_status
29262306a36Sopenharmony_ciacpi_db_execution_walk(acpi_handle obj_handle,
29362306a36Sopenharmony_ci		       u32 nesting_level, void *context, void **return_value)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
29662306a36Sopenharmony_ci	struct acpi_namespace_node *node =
29762306a36Sopenharmony_ci	    (struct acpi_namespace_node *)obj_handle;
29862306a36Sopenharmony_ci	struct acpi_buffer return_obj;
29962306a36Sopenharmony_ci	acpi_status status;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	obj_desc = acpi_ns_get_attached_object(node);
30262306a36Sopenharmony_ci	if (obj_desc->method.param_count) {
30362306a36Sopenharmony_ci		return (AE_OK);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return_obj.pointer = NULL;
30762306a36Sopenharmony_ci	return_obj.length = ACPI_ALLOCATE_BUFFER;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	acpi_ns_print_node_pathname(node, "Evaluating");
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Do the actual method execution */
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	acpi_os_printf("\n");
31462306a36Sopenharmony_ci	acpi_gbl_method_executing = TRUE;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	acpi_gbl_method_executing = FALSE;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
32162306a36Sopenharmony_ci		       acpi_ut_get_node_name(node),
32262306a36Sopenharmony_ci		       acpi_format_exception(status));
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return (AE_OK);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/*******************************************************************************
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci * FUNCTION:    acpi_db_execute
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * PARAMETERS:  name                - Name of method to execute
33262306a36Sopenharmony_ci *              args                - Parameters to the method
33362306a36Sopenharmony_ci *              Types               -
33462306a36Sopenharmony_ci *              flags               - single step/no single step
33562306a36Sopenharmony_ci *
33662306a36Sopenharmony_ci * RETURN:      None
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * DESCRIPTION: Execute a control method. Name is relative to the current
33962306a36Sopenharmony_ci *              scope. Function used for the "EXECUTE", "EVALUATE", and
34062306a36Sopenharmony_ci *              "ALL" commands
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci ******************************************************************************/
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_civoid
34562306a36Sopenharmony_ciacpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	acpi_status status;
34862306a36Sopenharmony_ci	struct acpi_buffer return_obj;
34962306a36Sopenharmony_ci	char *name_string;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT
35262306a36Sopenharmony_ci	u32 previous_allocations;
35362306a36Sopenharmony_ci	u32 allocations;
35462306a36Sopenharmony_ci#endif
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/*
35762306a36Sopenharmony_ci	 * Allow one execution to be performed by debugger or single step
35862306a36Sopenharmony_ci	 * execution will be dead locked by the interpreter mutexes.
35962306a36Sopenharmony_ci	 */
36062306a36Sopenharmony_ci	if (acpi_gbl_method_executing) {
36162306a36Sopenharmony_ci		acpi_os_printf("Only one debugger execution is allowed.\n");
36262306a36Sopenharmony_ci		return;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT
36562306a36Sopenharmony_ci	/* Memory allocation tracking */
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	previous_allocations = acpi_db_get_outstanding_allocations();
36862306a36Sopenharmony_ci#endif
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (*name == '*') {
37162306a36Sopenharmony_ci		(void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
37262306a36Sopenharmony_ci					  ACPI_UINT32_MAX,
37362306a36Sopenharmony_ci					  acpi_db_execution_walk, NULL, NULL,
37462306a36Sopenharmony_ci					  NULL);
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if ((flags & EX_ALL) && (strlen(name) > 4)) {
37962306a36Sopenharmony_ci		acpi_os_printf("Input name (%s) must be a 4-char NameSeg\n",
38062306a36Sopenharmony_ci			       name);
38162306a36Sopenharmony_ci		return;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	name_string = ACPI_ALLOCATE(strlen(name) + 1);
38562306a36Sopenharmony_ci	if (!name_string) {
38662306a36Sopenharmony_ci		return;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
39062306a36Sopenharmony_ci	strcpy(name_string, name);
39162306a36Sopenharmony_ci	acpi_ut_strupr(name_string);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Subcommand to Execute all predefined names in the namespace */
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (!strncmp(name_string, "PREDEF", 6)) {
39662306a36Sopenharmony_ci		acpi_db_evaluate_predefined_names();
39762306a36Sopenharmony_ci		ACPI_FREE(name_string);
39862306a36Sopenharmony_ci		return;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Command (ALL <nameseg>) to execute all methods of a particular name */
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	else if (flags & EX_ALL) {
40462306a36Sopenharmony_ci		acpi_gbl_db_method_info.name = name_string;
40562306a36Sopenharmony_ci		return_obj.pointer = NULL;
40662306a36Sopenharmony_ci		return_obj.length = ACPI_ALLOCATE_BUFFER;
40762306a36Sopenharmony_ci		acpi_db_evaluate_all(name_string);
40862306a36Sopenharmony_ci		ACPI_FREE(name_string);
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci	} else {
41162306a36Sopenharmony_ci		acpi_gbl_db_method_info.name = name_string;
41262306a36Sopenharmony_ci		acpi_gbl_db_method_info.args = args;
41362306a36Sopenharmony_ci		acpi_gbl_db_method_info.types = types;
41462306a36Sopenharmony_ci		acpi_gbl_db_method_info.flags = flags;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		return_obj.pointer = NULL;
41762306a36Sopenharmony_ci		return_obj.length = ACPI_ALLOCATE_BUFFER;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
42162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
42262306a36Sopenharmony_ci		ACPI_FREE(name_string);
42362306a36Sopenharmony_ci		return;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Get the NS node, determines existence also */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
42962306a36Sopenharmony_ci				 &acpi_gbl_db_method_info.method);
43062306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
43162306a36Sopenharmony_ci		status = acpi_db_execute_method(&acpi_gbl_db_method_info,
43262306a36Sopenharmony_ci						&return_obj);
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci	ACPI_FREE(name_string);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/*
43762306a36Sopenharmony_ci	 * Allow any handlers in separate threads to complete.
43862306a36Sopenharmony_ci	 * (Such as Notify handlers invoked from AML executed above).
43962306a36Sopenharmony_ci	 */
44062306a36Sopenharmony_ci	acpi_os_sleep((u64)10);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/* Memory allocation tracking */
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	allocations =
44762306a36Sopenharmony_ci	    acpi_db_get_outstanding_allocations() - previous_allocations;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (allocations > 0) {
45262306a36Sopenharmony_ci		acpi_os_printf
45362306a36Sopenharmony_ci		    ("0x%X Outstanding allocations after evaluation of %s\n",
45462306a36Sopenharmony_ci		     allocations, acpi_gbl_db_method_info.pathname);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci#endif
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
45962306a36Sopenharmony_ci		acpi_os_printf("Evaluation of %s failed with status %s\n",
46062306a36Sopenharmony_ci			       acpi_gbl_db_method_info.pathname,
46162306a36Sopenharmony_ci			       acpi_format_exception(status));
46262306a36Sopenharmony_ci	} else {
46362306a36Sopenharmony_ci		/* Display a return object, if any */
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (return_obj.length) {
46662306a36Sopenharmony_ci			acpi_os_printf("Evaluation of %s returned object %p, "
46762306a36Sopenharmony_ci				       "external buffer length %X\n",
46862306a36Sopenharmony_ci				       acpi_gbl_db_method_info.pathname,
46962306a36Sopenharmony_ci				       return_obj.pointer,
47062306a36Sopenharmony_ci				       (u32)return_obj.length);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci			acpi_db_dump_external_object(return_obj.pointer, 1);
47362306a36Sopenharmony_ci			acpi_os_printf("\n");
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci			/* Dump a _PLD buffer if present */
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci			if (ACPI_COMPARE_NAMESEG
47862306a36Sopenharmony_ci			    ((ACPI_CAST_PTR
47962306a36Sopenharmony_ci			      (struct acpi_namespace_node,
48062306a36Sopenharmony_ci			       acpi_gbl_db_method_info.method)->name.ascii),
48162306a36Sopenharmony_ci			     METHOD_NAME__PLD)) {
48262306a36Sopenharmony_ci				acpi_db_dump_pld_buffer(return_obj.pointer);
48362306a36Sopenharmony_ci			}
48462306a36Sopenharmony_ci		} else {
48562306a36Sopenharmony_ci			acpi_os_printf
48662306a36Sopenharmony_ci			    ("No object was returned from evaluation of %s\n",
48762306a36Sopenharmony_ci			     acpi_gbl_db_method_info.pathname);
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/*******************************************************************************
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * FUNCTION:    acpi_db_method_thread
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * PARAMETERS:  context             - Execution info segment
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * RETURN:      None
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci * DESCRIPTION: Debugger execute thread. Waits for a command line, then
50362306a36Sopenharmony_ci *              simply dispatches it.
50462306a36Sopenharmony_ci *
50562306a36Sopenharmony_ci ******************************************************************************/
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	acpi_status status;
51062306a36Sopenharmony_ci	struct acpi_db_method_info *info = context;
51162306a36Sopenharmony_ci	struct acpi_db_method_info local_info;
51262306a36Sopenharmony_ci	u32 i;
51362306a36Sopenharmony_ci	u8 allow;
51462306a36Sopenharmony_ci	struct acpi_buffer return_obj;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/*
51762306a36Sopenharmony_ci	 * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
51862306a36Sopenharmony_ci	 * Prevent acpi_gbl_db_method_info from being modified by multiple threads
51962306a36Sopenharmony_ci	 * concurrently.
52062306a36Sopenharmony_ci	 *
52162306a36Sopenharmony_ci	 * Note: The arguments we are passing are used by the ASL test suite
52262306a36Sopenharmony_ci	 * (aslts). Do not change them without updating the tests.
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	(void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (info->init_args) {
52762306a36Sopenharmony_ci		acpi_db_uint32_to_hex_string(info->num_created,
52862306a36Sopenharmony_ci					     info->index_of_thread_str);
52962306a36Sopenharmony_ci		acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
53062306a36Sopenharmony_ci					     info->id_of_thread_str);
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (info->threads && (info->num_created < info->num_threads)) {
53462306a36Sopenharmony_ci		info->threads[info->num_created++] = acpi_os_get_thread_id();
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	local_info = *info;
53862306a36Sopenharmony_ci	local_info.args = local_info.arguments;
53962306a36Sopenharmony_ci	local_info.arguments[0] = local_info.num_threads_str;
54062306a36Sopenharmony_ci	local_info.arguments[1] = local_info.id_of_thread_str;
54162306a36Sopenharmony_ci	local_info.arguments[2] = local_info.index_of_thread_str;
54262306a36Sopenharmony_ci	local_info.arguments[3] = NULL;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	local_info.types = local_info.arg_types;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	(void)acpi_os_signal_semaphore(info->info_gate, 1);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	for (i = 0; i < info->num_loops; i++) {
54962306a36Sopenharmony_ci		status = acpi_db_execute_method(&local_info, &return_obj);
55062306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
55162306a36Sopenharmony_ci			acpi_os_printf
55262306a36Sopenharmony_ci			    ("%s During evaluation of %s at iteration %X\n",
55362306a36Sopenharmony_ci			     acpi_format_exception(status), info->pathname, i);
55462306a36Sopenharmony_ci			if (status == AE_ABORT_METHOD) {
55562306a36Sopenharmony_ci				break;
55662306a36Sopenharmony_ci			}
55762306a36Sopenharmony_ci		}
55862306a36Sopenharmony_ci#if 0
55962306a36Sopenharmony_ci		if ((i % 100) == 0) {
56062306a36Sopenharmony_ci			acpi_os_printf("%u loops, Thread 0x%x\n",
56162306a36Sopenharmony_ci				       i, acpi_os_get_thread_id());
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		if (return_obj.length) {
56562306a36Sopenharmony_ci			acpi_os_printf
56662306a36Sopenharmony_ci			    ("Evaluation of %s returned object %p Buflen %X\n",
56762306a36Sopenharmony_ci			     info->pathname, return_obj.pointer,
56862306a36Sopenharmony_ci			     (u32)return_obj.length);
56962306a36Sopenharmony_ci			acpi_db_dump_external_object(return_obj.pointer, 1);
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci#endif
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* Signal our completion */
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	allow = 0;
57762306a36Sopenharmony_ci	(void)acpi_os_wait_semaphore(info->thread_complete_gate,
57862306a36Sopenharmony_ci				     1, ACPI_WAIT_FOREVER);
57962306a36Sopenharmony_ci	info->num_completed++;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (info->num_completed == info->num_threads) {
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		/* Do signal for main thread once only */
58462306a36Sopenharmony_ci		allow = 1;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	(void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	if (allow) {
59062306a36Sopenharmony_ci		status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
59162306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
59262306a36Sopenharmony_ci			acpi_os_printf
59362306a36Sopenharmony_ci			    ("Could not signal debugger thread sync semaphore, %s\n",
59462306a36Sopenharmony_ci			     acpi_format_exception(status));
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci/*******************************************************************************
60062306a36Sopenharmony_ci *
60162306a36Sopenharmony_ci * FUNCTION:    acpi_db_single_execution_thread
60262306a36Sopenharmony_ci *
60362306a36Sopenharmony_ci * PARAMETERS:  context                 - Method info struct
60462306a36Sopenharmony_ci *
60562306a36Sopenharmony_ci * RETURN:      None
60662306a36Sopenharmony_ci *
60762306a36Sopenharmony_ci * DESCRIPTION: Create one thread and execute a method
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci ******************************************************************************/
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	struct acpi_db_method_info *info = context;
61462306a36Sopenharmony_ci	acpi_status status;
61562306a36Sopenharmony_ci	struct acpi_buffer return_obj;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	acpi_os_printf("\n");
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	status = acpi_db_execute_method(info, &return_obj);
62062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
62162306a36Sopenharmony_ci		acpi_os_printf("%s During evaluation of %s\n",
62262306a36Sopenharmony_ci			       acpi_format_exception(status), info->pathname);
62362306a36Sopenharmony_ci		return;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* Display a return object, if any */
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (return_obj.length) {
62962306a36Sopenharmony_ci		acpi_os_printf("Evaluation of %s returned object %p, "
63062306a36Sopenharmony_ci			       "external buffer length %X\n",
63162306a36Sopenharmony_ci			       acpi_gbl_db_method_info.pathname,
63262306a36Sopenharmony_ci			       return_obj.pointer, (u32)return_obj.length);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		acpi_db_dump_external_object(return_obj.pointer, 1);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	acpi_os_printf("\nBackground thread completed\n%c ",
63862306a36Sopenharmony_ci		       ACPI_DEBUGGER_COMMAND_PROMPT);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/*******************************************************************************
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci * FUNCTION:    acpi_db_create_execution_thread
64462306a36Sopenharmony_ci *
64562306a36Sopenharmony_ci * PARAMETERS:  method_name_arg         - Control method to execute
64662306a36Sopenharmony_ci *              arguments               - Array of arguments to the method
64762306a36Sopenharmony_ci *              types                   - Corresponding array of object types
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * RETURN:      None
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
65262306a36Sopenharmony_ci *              arguments passed on command line for control methods.
65362306a36Sopenharmony_ci *
65462306a36Sopenharmony_ci ******************************************************************************/
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_civoid
65762306a36Sopenharmony_ciacpi_db_create_execution_thread(char *method_name_arg,
65862306a36Sopenharmony_ci				char **arguments, acpi_object_type *types)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	acpi_status status;
66162306a36Sopenharmony_ci	u32 i;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
66462306a36Sopenharmony_ci	acpi_gbl_db_method_info.name = method_name_arg;
66562306a36Sopenharmony_ci	acpi_gbl_db_method_info.init_args = 1;
66662306a36Sopenharmony_ci	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
66762306a36Sopenharmony_ci	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* Setup method arguments, up to 7 (0-6) */
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) {
67262306a36Sopenharmony_ci		acpi_gbl_db_method_info.arguments[i] = *arguments;
67362306a36Sopenharmony_ci		arguments++;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		acpi_gbl_db_method_info.arg_types[i] = *types;
67662306a36Sopenharmony_ci		types++;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
68062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
68162306a36Sopenharmony_ci		return;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Get the NS node, determines existence also */
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
68762306a36Sopenharmony_ci				 &acpi_gbl_db_method_info.method);
68862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
68962306a36Sopenharmony_ci		acpi_os_printf("%s Could not get handle for %s\n",
69062306a36Sopenharmony_ci			       acpi_format_exception(status),
69162306a36Sopenharmony_ci			       acpi_gbl_db_method_info.pathname);
69262306a36Sopenharmony_ci		return;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
69662306a36Sopenharmony_ci				 acpi_db_single_execution_thread,
69762306a36Sopenharmony_ci				 &acpi_gbl_db_method_info);
69862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
69962306a36Sopenharmony_ci		return;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	acpi_os_printf("\nBackground thread started\n");
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci/*******************************************************************************
70662306a36Sopenharmony_ci *
70762306a36Sopenharmony_ci * FUNCTION:    acpi_db_create_execution_threads
70862306a36Sopenharmony_ci *
70962306a36Sopenharmony_ci * PARAMETERS:  num_threads_arg         - Number of threads to create
71062306a36Sopenharmony_ci *              num_loops_arg           - Loop count for the thread(s)
71162306a36Sopenharmony_ci *              method_name_arg         - Control method to execute
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * RETURN:      None
71462306a36Sopenharmony_ci *
71562306a36Sopenharmony_ci * DESCRIPTION: Create threads to execute method(s)
71662306a36Sopenharmony_ci *
71762306a36Sopenharmony_ci ******************************************************************************/
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_civoid
72062306a36Sopenharmony_ciacpi_db_create_execution_threads(char *num_threads_arg,
72162306a36Sopenharmony_ci				 char *num_loops_arg, char *method_name_arg)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	acpi_status status;
72462306a36Sopenharmony_ci	u32 num_threads;
72562306a36Sopenharmony_ci	u32 num_loops;
72662306a36Sopenharmony_ci	u32 i;
72762306a36Sopenharmony_ci	u32 size;
72862306a36Sopenharmony_ci	acpi_mutex main_thread_gate;
72962306a36Sopenharmony_ci	acpi_mutex thread_complete_gate;
73062306a36Sopenharmony_ci	acpi_mutex info_gate;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/* Get the arguments */
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	num_threads = strtoul(num_threads_arg, NULL, 0);
73562306a36Sopenharmony_ci	num_loops = strtoul(num_loops_arg, NULL, 0);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (!num_threads || !num_loops) {
73862306a36Sopenharmony_ci		acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
73962306a36Sopenharmony_ci			       num_threads, num_loops);
74062306a36Sopenharmony_ci		return;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/*
74462306a36Sopenharmony_ci	 * Create the semaphore for synchronization of
74562306a36Sopenharmony_ci	 * the created threads with the main thread.
74662306a36Sopenharmony_ci	 */
74762306a36Sopenharmony_ci	status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
74862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
74962306a36Sopenharmony_ci		acpi_os_printf("Could not create semaphore for "
75062306a36Sopenharmony_ci			       "synchronization with the main thread, %s\n",
75162306a36Sopenharmony_ci			       acpi_format_exception(status));
75262306a36Sopenharmony_ci		return;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/*
75662306a36Sopenharmony_ci	 * Create the semaphore for synchronization
75762306a36Sopenharmony_ci	 * between the created threads.
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
76062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
76162306a36Sopenharmony_ci		acpi_os_printf("Could not create semaphore for "
76262306a36Sopenharmony_ci			       "synchronization between the created threads, %s\n",
76362306a36Sopenharmony_ci			       acpi_format_exception(status));
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(main_thread_gate);
76662306a36Sopenharmony_ci		return;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	status = acpi_os_create_semaphore(1, 1, &info_gate);
77062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
77162306a36Sopenharmony_ci		acpi_os_printf("Could not create semaphore for "
77262306a36Sopenharmony_ci			       "synchronization of AcpiGbl_DbMethodInfo, %s\n",
77362306a36Sopenharmony_ci			       acpi_format_exception(status));
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(thread_complete_gate);
77662306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(main_thread_gate);
77762306a36Sopenharmony_ci		return;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	/* Array to store IDs of threads */
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	acpi_gbl_db_method_info.num_threads = num_threads;
78562306a36Sopenharmony_ci	size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
78862306a36Sopenharmony_ci	if (acpi_gbl_db_method_info.threads == NULL) {
78962306a36Sopenharmony_ci		acpi_os_printf("No memory for thread IDs array\n");
79062306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(main_thread_gate);
79162306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(thread_complete_gate);
79262306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(info_gate);
79362306a36Sopenharmony_ci		return;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	memset(acpi_gbl_db_method_info.threads, 0, size);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	/* Setup the context to be passed to each thread */
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	acpi_gbl_db_method_info.name = method_name_arg;
80062306a36Sopenharmony_ci	acpi_gbl_db_method_info.flags = 0;
80162306a36Sopenharmony_ci	acpi_gbl_db_method_info.num_loops = num_loops;
80262306a36Sopenharmony_ci	acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
80362306a36Sopenharmony_ci	acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
80462306a36Sopenharmony_ci	acpi_gbl_db_method_info.info_gate = info_gate;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	/* Init arguments to be passed to method */
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	acpi_gbl_db_method_info.init_args = 1;
80962306a36Sopenharmony_ci	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
81062306a36Sopenharmony_ci	acpi_gbl_db_method_info.arguments[0] =
81162306a36Sopenharmony_ci	    acpi_gbl_db_method_info.num_threads_str;
81262306a36Sopenharmony_ci	acpi_gbl_db_method_info.arguments[1] =
81362306a36Sopenharmony_ci	    acpi_gbl_db_method_info.id_of_thread_str;
81462306a36Sopenharmony_ci	acpi_gbl_db_method_info.arguments[2] =
81562306a36Sopenharmony_ci	    acpi_gbl_db_method_info.index_of_thread_str;
81662306a36Sopenharmony_ci	acpi_gbl_db_method_info.arguments[3] = NULL;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
81962306a36Sopenharmony_ci	acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
82062306a36Sopenharmony_ci	acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
82162306a36Sopenharmony_ci	acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	acpi_db_uint32_to_hex_string(num_threads,
82462306a36Sopenharmony_ci				     acpi_gbl_db_method_info.num_threads_str);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
82762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
82862306a36Sopenharmony_ci		goto cleanup_and_exit;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Get the NS node, determines existence also */
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
83462306a36Sopenharmony_ci				 &acpi_gbl_db_method_info.method);
83562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
83662306a36Sopenharmony_ci		acpi_os_printf("%s Could not get handle for %s\n",
83762306a36Sopenharmony_ci			       acpi_format_exception(status),
83862306a36Sopenharmony_ci			       acpi_gbl_db_method_info.pathname);
83962306a36Sopenharmony_ci		goto cleanup_and_exit;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* Create the threads */
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	acpi_os_printf("Creating %X threads to execute %X times each\n",
84562306a36Sopenharmony_ci		       num_threads, num_loops);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	for (i = 0; i < (num_threads); i++) {
84862306a36Sopenharmony_ci		status =
84962306a36Sopenharmony_ci		    acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
85062306a36Sopenharmony_ci				    acpi_db_method_thread,
85162306a36Sopenharmony_ci				    &acpi_gbl_db_method_info);
85262306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
85362306a36Sopenharmony_ci			break;
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	/* Wait for all threads to complete */
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	(void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
86262306a36Sopenharmony_ci	acpi_os_printf("All threads (%X) have completed\n", num_threads);
86362306a36Sopenharmony_ci	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cicleanup_and_exit:
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	/* Cleanup and exit */
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	(void)acpi_os_delete_semaphore(main_thread_gate);
87062306a36Sopenharmony_ci	(void)acpi_os_delete_semaphore(thread_complete_gate);
87162306a36Sopenharmony_ci	(void)acpi_os_delete_semaphore(info_gate);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	acpi_os_free(acpi_gbl_db_method_info.threads);
87462306a36Sopenharmony_ci	acpi_gbl_db_method_info.threads = NULL;
87562306a36Sopenharmony_ci}
876