brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 889d138 Raw
590 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: dbmethod - Debug commands for control methods5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "acdispat.h"11#include "acnamesp.h"12#include "acdebug.h"13#include "acparser.h"14#include "acpredef.h"15 16#define _COMPONENT          ACPI_CA_DEBUGGER17ACPI_MODULE_NAME("dbmethod")18 19/* Local prototypes */20static acpi_status21acpi_db_walk_for_execute(acpi_handle obj_handle,22			 u32 nesting_level, void *context, void **return_value);23 24static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node);25 26/*******************************************************************************27 *28 * FUNCTION:    acpi_db_set_method_breakpoint29 *30 * PARAMETERS:  location            - AML offset of breakpoint31 *              walk_state          - Current walk info32 *              op                  - Current Op (from parse walk)33 *34 * RETURN:      None35 *36 * DESCRIPTION: Set a breakpoint in a control method at the specified37 *              AML offset38 *39 ******************************************************************************/40 41void42acpi_db_set_method_breakpoint(char *location,43			      struct acpi_walk_state *walk_state,44			      union acpi_parse_object *op)45{46	u32 address;47	u32 aml_offset;48 49	if (!op) {50		acpi_os_printf("There is no method currently executing\n");51		return;52	}53 54	/* Get and verify the breakpoint address */55 56	address = strtoul(location, NULL, 16);57	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,58					walk_state->parser_state.aml_start);59	if (address <= aml_offset) {60		acpi_os_printf("Breakpoint %X is beyond current address %X\n",61			       address, aml_offset);62	}63 64	/* Save breakpoint in current walk */65 66	walk_state->user_breakpoint = address;67	acpi_os_printf("Breakpoint set at AML offset %X\n", address);68}69 70/*******************************************************************************71 *72 * FUNCTION:    acpi_db_set_method_call_breakpoint73 *74 * PARAMETERS:  op                  - Current Op (from parse walk)75 *76 * RETURN:      None77 *78 * DESCRIPTION: Set a breakpoint in a control method at the specified79 *              AML offset80 *81 ******************************************************************************/82 83void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)84{85 86	if (!op) {87		acpi_os_printf("There is no method currently executing\n");88		return;89	}90 91	acpi_gbl_step_to_next_call = TRUE;92}93 94/*******************************************************************************95 *96 * FUNCTION:    acpi_db_set_method_data97 *98 * PARAMETERS:  type_arg        - L for local, A for argument99 *              index_arg       - which one100 *              value_arg       - Value to set.101 *102 * RETURN:      None103 *104 * DESCRIPTION: Set a local or argument for the running control method.105 *              NOTE: only object supported is Number.106 *107 ******************************************************************************/108 109void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)110{111	char type;112	u32 index;113	u32 value;114	struct acpi_walk_state *walk_state;115	union acpi_operand_object *obj_desc;116	acpi_status status;117	struct acpi_namespace_node *node;118 119	/* Validate type_arg */120 121	acpi_ut_strupr(type_arg);122	type = type_arg[0];123	if ((type != 'L') && (type != 'A') && (type != 'N')) {124		acpi_os_printf("Invalid SET operand: %s\n", type_arg);125		return;126	}127 128	value = strtoul(value_arg, NULL, 16);129 130	if (type == 'N') {131		node = acpi_db_convert_to_node(index_arg);132		if (!node) {133			return;134		}135 136		if (node->type != ACPI_TYPE_INTEGER) {137			acpi_os_printf("Can only set Integer nodes\n");138			return;139		}140		obj_desc = node->object;141		obj_desc->integer.value = value;142		return;143	}144 145	/* Get the index and value */146 147	index = strtoul(index_arg, NULL, 16);148 149	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);150	if (!walk_state) {151		acpi_os_printf("There is no method currently executing\n");152		return;153	}154 155	/* Create and initialize the new object */156 157	obj_desc = acpi_ut_create_integer_object((u64)value);158	if (!obj_desc) {159		acpi_os_printf("Could not create an internal object\n");160		return;161	}162 163	/* Store the new object into the target */164 165	switch (type) {166	case 'A':167 168		/* Set a method argument */169 170		if (index > ACPI_METHOD_MAX_ARG) {171			acpi_os_printf("Arg%u - Invalid argument name\n",172				       index);173			goto cleanup;174		}175 176		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,177						       index, obj_desc,178						       walk_state);179		if (ACPI_FAILURE(status)) {180			goto cleanup;181		}182 183		obj_desc = walk_state->arguments[index].object;184 185		acpi_os_printf("Arg%u: ", index);186		acpi_db_display_internal_object(obj_desc, walk_state);187		break;188 189	case 'L':190 191		/* Set a method local */192 193		if (index > ACPI_METHOD_MAX_LOCAL) {194			acpi_os_printf195			    ("Local%u - Invalid local variable name\n", index);196			goto cleanup;197		}198 199		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,200						       index, obj_desc,201						       walk_state);202		if (ACPI_FAILURE(status)) {203			goto cleanup;204		}205 206		obj_desc = walk_state->local_variables[index].object;207 208		acpi_os_printf("Local%u: ", index);209		acpi_db_display_internal_object(obj_desc, walk_state);210		break;211 212	default:213 214		break;215	}216 217cleanup:218	acpi_ut_remove_reference(obj_desc);219}220 221#ifdef ACPI_DISASSEMBLER222/*******************************************************************************223 *224 * FUNCTION:    acpi_db_disassemble_aml225 *226 * PARAMETERS:  statements          - Number of statements to disassemble227 *              op                  - Current Op (from parse walk)228 *229 * RETURN:      None230 *231 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number232 *              of statements specified.233 *234 ******************************************************************************/235 236void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)237{238	u32 num_statements = 8;239 240	if (!op) {241		acpi_os_printf("There is no method currently executing\n");242		return;243	}244 245	if (statements) {246		num_statements = strtoul(statements, NULL, 0);247	}248 249	acpi_dm_disassemble(NULL, op, num_statements);250}251 252/*******************************************************************************253 *254 * FUNCTION:    acpi_db_disassemble_method255 *256 * PARAMETERS:  name            - Name of control method257 *258 * RETURN:      None259 *260 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number261 *              of statements specified.262 *263 ******************************************************************************/264 265acpi_status acpi_db_disassemble_method(char *name)266{267	acpi_status status;268	union acpi_parse_object *op;269	struct acpi_walk_state *walk_state;270	union acpi_operand_object *obj_desc;271	struct acpi_namespace_node *method;272 273	method = acpi_db_convert_to_node(name);274	if (!method) {275		return (AE_BAD_PARAMETER);276	}277 278	if (method->type != ACPI_TYPE_METHOD) {279		ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",280			    name, acpi_ut_get_type_name(method->type)));281		return (AE_BAD_PARAMETER);282	}283 284	obj_desc = method->object;285 286	op = acpi_ps_create_scope_op(obj_desc->method.aml_start);287	if (!op) {288		return (AE_NO_MEMORY);289	}290 291	/* Create and initialize a new walk state */292 293	walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);294	if (!walk_state) {295		return (AE_NO_MEMORY);296	}297 298	status = acpi_ds_init_aml_walk(walk_state, op, NULL,299				       obj_desc->method.aml_start,300				       obj_desc->method.aml_length, NULL,301				       ACPI_IMODE_LOAD_PASS1);302	if (ACPI_FAILURE(status)) {303		return (status);304	}305 306	status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);307	if (ACPI_FAILURE(status)) {308		return (status);309	}310 311	walk_state->owner_id = obj_desc->method.owner_id;312 313	/* Push start scope on scope stack and make it current */314 315	status = acpi_ds_scope_stack_push(method, method->type, walk_state);316	if (ACPI_FAILURE(status)) {317		return (status);318	}319 320	/* Parse the entire method AML including deferred operators */321 322	walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;323	walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;324 325	status = acpi_ps_parse_aml(walk_state);326	if (ACPI_FAILURE(status)) {327		return (status);328	}329 330	(void)acpi_dm_parse_deferred_ops(op);331 332	/* Now we can disassemble the method */333 334	acpi_gbl_dm_opt_verbose = FALSE;335	acpi_dm_disassemble(NULL, op, 0);336	acpi_gbl_dm_opt_verbose = TRUE;337 338	acpi_ps_delete_parse_tree(op);339 340	/* Method cleanup */341 342	acpi_ns_delete_namespace_subtree(method);343	acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);344	acpi_ut_release_owner_id(&obj_desc->method.owner_id);345	return (AE_OK);346}347#endif348 349/*******************************************************************************350 *351 * FUNCTION:    acpi_db_evaluate_object352 *353 * PARAMETERS:  node                - Namespace node for the object354 *355 * RETURN:      Status356 *357 * DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger358 *              commands.359 *360 ******************************************************************************/361 362static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node)363{364	char *pathname;365	u32 i;366	struct acpi_device_info *obj_info;367	struct acpi_object_list param_objects;368	union acpi_object params[ACPI_METHOD_NUM_ARGS];369	struct acpi_buffer return_obj;370	acpi_status status;371 372	pathname = acpi_ns_get_external_pathname(node);373	if (!pathname) {374		return (AE_OK);375	}376 377	/* Get the object info for number of method parameters */378 379	status = acpi_get_object_info(node, &obj_info);380	if (ACPI_FAILURE(status)) {381		ACPI_FREE(pathname);382		return (status);383	}384 385	param_objects.pointer = NULL;386	param_objects.count = 0;387 388	if (obj_info->type == ACPI_TYPE_METHOD) {389 390		/* Setup default parameters */391 392		for (i = 0; i < obj_info->param_count; i++) {393			params[i].type = ACPI_TYPE_INTEGER;394			params[i].integer.value = 1;395		}396 397		param_objects.pointer = params;398		param_objects.count = obj_info->param_count;399	}400 401	ACPI_FREE(obj_info);402	return_obj.pointer = NULL;403	return_obj.length = ACPI_ALLOCATE_BUFFER;404 405	/* Do the actual method execution */406 407	acpi_gbl_method_executing = TRUE;408 409	status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);410	acpi_gbl_method_executing = FALSE;411 412	acpi_os_printf("%-32s returned %s\n", pathname,413		       acpi_format_exception(status));414	if (return_obj.length) {415		acpi_os_printf("Evaluation of %s returned object %p, "416			       "external buffer length %X\n",417			       pathname, return_obj.pointer,418			       (u32)return_obj.length);419 420		acpi_db_dump_external_object(return_obj.pointer, 1);421		acpi_os_printf("\n");422	}423 424	ACPI_FREE(pathname);425 426	/* Ignore status from method execution */427 428	return (AE_OK);429 430	/* Update count, check if we have executed enough methods */431 432}433 434/*******************************************************************************435 *436 * FUNCTION:    acpi_db_walk_for_execute437 *438 * PARAMETERS:  Callback from walk_namespace439 *440 * RETURN:      Status441 *442 * DESCRIPTION: Batch execution function. Evaluates all "predefined" objects --443 *              the nameseg begins with an underscore.444 *445 ******************************************************************************/446 447static acpi_status448acpi_db_walk_for_execute(acpi_handle obj_handle,449			 u32 nesting_level, void *context, void **return_value)450{451	struct acpi_namespace_node *node =452	    (struct acpi_namespace_node *)obj_handle;453	struct acpi_db_execute_walk *info =454	    (struct acpi_db_execute_walk *)context;455	acpi_status status;456	const union acpi_predefined_info *predefined;457 458	predefined = acpi_ut_match_predefined_method(node->name.ascii);459	if (!predefined) {460		return (AE_OK);461	}462 463	if (node->type == ACPI_TYPE_LOCAL_SCOPE) {464		return (AE_OK);465	}466 467	acpi_db_evaluate_object(node);468 469	/* Ignore status from object evaluation */470 471	status = AE_OK;472 473	/* Update count, check if we have executed enough methods */474 475	info->count++;476	if (info->count >= info->max_count) {477		status = AE_CTRL_TERMINATE;478	}479 480	return (status);481}482 483/*******************************************************************************484 *485 * FUNCTION:    acpi_db_walk_for_execute_all486 *487 * PARAMETERS:  Callback from walk_namespace488 *489 * RETURN:      Status490 *491 * DESCRIPTION: Batch execution function. Evaluates all objects whose path ends492 *              with the nameseg "Info->NameSeg". Used for the "ALL" command.493 *494 ******************************************************************************/495 496static acpi_status497acpi_db_walk_for_execute_all(acpi_handle obj_handle,498			     u32 nesting_level,499			     void *context, void **return_value)500{501	struct acpi_namespace_node *node =502	    (struct acpi_namespace_node *)obj_handle;503	struct acpi_db_execute_walk *info =504	    (struct acpi_db_execute_walk *)context;505	acpi_status status;506 507	if (!ACPI_COMPARE_NAMESEG(node->name.ascii, info->name_seg)) {508		return (AE_OK);509	}510 511	if (node->type == ACPI_TYPE_LOCAL_SCOPE) {512		return (AE_OK);513	}514 515	/* Now evaluate the input object (node) */516 517	acpi_db_evaluate_object(node);518 519	/* Ignore status from method execution */520 521	status = AE_OK;522 523	/* Update count of executed methods/objects */524 525	info->count++;526	return (status);527}528 529/*******************************************************************************530 *531 * FUNCTION:    acpi_db_evaluate_predefined_names532 *533 * PARAMETERS:  None534 *535 * RETURN:      None536 *537 * DESCRIPTION: Namespace batch execution. Execute predefined names in the538 *              namespace, up to the max count, if specified.539 *540 ******************************************************************************/541 542void acpi_db_evaluate_predefined_names(void)543{544	struct acpi_db_execute_walk info;545 546	info.count = 0;547	info.max_count = ACPI_UINT32_MAX;548 549	/* Search all nodes in namespace */550 551	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,552				  ACPI_UINT32_MAX, acpi_db_walk_for_execute,553				  NULL, (void *)&info, NULL);554 555	acpi_os_printf("Evaluated %u predefined names in the namespace\n",556		       info.count);557}558 559/*******************************************************************************560 *561 * FUNCTION:    acpi_db_evaluate_all562 *563 * PARAMETERS:  none_acpi_gbl_db_method_info564 *565 * RETURN:      None566 *567 * DESCRIPTION: Namespace batch execution. Implements the "ALL" command.568 *              Execute all namepaths whose final nameseg matches the569 *              input nameseg.570 *571 ******************************************************************************/572 573void acpi_db_evaluate_all(char *name_seg)574{575	struct acpi_db_execute_walk info;576 577	info.count = 0;578	info.max_count = ACPI_UINT32_MAX;579	ACPI_COPY_NAMESEG(info.name_seg, name_seg);580	info.name_seg[ACPI_NAMESEG_SIZE] = 0;581 582	/* Search all nodes in namespace */583 584	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,585				  ACPI_UINT32_MAX, acpi_db_walk_for_execute_all,586				  NULL, (void *)&info, NULL);587 588	acpi_os_printf("Evaluated %u names in the namespace\n", info.count);589}590