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, ¶m_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