linux/drivers/acpi/acpica/dbmethod.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/*******************************************************************************
   3 *
   4 * Module Name: dbmethod - Debug commands for control methods
   5 *
   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_DEBUGGER
  17ACPI_MODULE_NAME("dbmethod")
  18
  19/* Local prototypes */
  20static acpi_status
  21acpi_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_breakpoint
  29 *
  30 * PARAMETERS:  location            - AML offset of breakpoint
  31 *              walk_state          - Current walk info
  32 *              op                  - Current Op (from parse walk)
  33 *
  34 * RETURN:      None
  35 *
  36 * DESCRIPTION: Set a breakpoint in a control method at the specified
  37 *              AML offset
  38 *
  39 ******************************************************************************/
  40
  41void
  42acpi_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_breakpoint
  73 *
  74 * PARAMETERS:  op                  - Current Op (from parse walk)
  75 *
  76 * RETURN:      None
  77 *
  78 * DESCRIPTION: Set a breakpoint in a control method at the specified
  79 *              AML offset
  80 *
  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_data
  97 *
  98 * PARAMETERS:  type_arg        - L for local, A for argument
  99 *              index_arg       - which one
 100 *              value_arg       - Value to set.
 101 *
 102 * RETURN:      None
 103 *
 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_printf
 195                            ("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_DISASSEMBLER
 222/*******************************************************************************
 223 *
 224 * FUNCTION:    acpi_db_disassemble_aml
 225 *
 226 * PARAMETERS:  statements          - Number of statements to disassemble
 227 *              op                  - Current Op (from parse walk)
 228 *
 229 * RETURN:      None
 230 *
 231 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 232 *              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_method
 255 *
 256 * PARAMETERS:  name            - Name of control method
 257 *
 258 * RETURN:      None
 259 *
 260 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 261 *              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#endif
 348
 349/*******************************************************************************
 350 *
 351 * FUNCTION:    acpi_db_evaluate_object
 352 *
 353 * PARAMETERS:  node                - Namespace node for the object
 354 *
 355 * RETURN:      Status
 356 *
 357 * DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger
 358 *              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_execute
 437 *
 438 * PARAMETERS:  Callback from walk_namespace
 439 *
 440 * RETURN:      Status
 441 *
 442 * DESCRIPTION: Batch execution function. Evaluates all "predefined" objects --
 443 *              the nameseg begins with an underscore.
 444 *
 445 ******************************************************************************/
 446
 447static acpi_status
 448acpi_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_all
 486 *
 487 * PARAMETERS:  Callback from walk_namespace
 488 *
 489 * RETURN:      Status
 490 *
 491 * DESCRIPTION: Batch execution function. Evaluates all objects whose path ends
 492 *              with the nameseg "Info->NameSeg". Used for the "ALL" command.
 493 *
 494 ******************************************************************************/
 495
 496static acpi_status
 497acpi_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_names
 532 *
 533 * PARAMETERS:  None
 534 *
 535 * RETURN:      None
 536 *
 537 * DESCRIPTION: Namespace batch execution. Execute predefined names in the
 538 *              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_all
 562 *
 563 * PARAMETERS:  none_acpi_gbl_db_method_info
 564 *
 565 * RETURN:      None
 566 *
 567 * DESCRIPTION: Namespace batch execution. Implements the "ALL" command.
 568 *              Execute all namepaths whose final nameseg matches the
 569 *              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