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
  24/*******************************************************************************
  25 *
  26 * FUNCTION:    acpi_db_set_method_breakpoint
  27 *
  28 * PARAMETERS:  location            - AML offset of breakpoint
  29 *              walk_state          - Current walk info
  30 *              op                  - Current Op (from parse walk)
  31 *
  32 * RETURN:      None
  33 *
  34 * DESCRIPTION: Set a breakpoint in a control method at the specified
  35 *              AML offset
  36 *
  37 ******************************************************************************/
  38
  39void
  40acpi_db_set_method_breakpoint(char *location,
  41                              struct acpi_walk_state *walk_state,
  42                              union acpi_parse_object *op)
  43{
  44        u32 address;
  45        u32 aml_offset;
  46
  47        if (!op) {
  48                acpi_os_printf("There is no method currently executing\n");
  49                return;
  50        }
  51
  52        /* Get and verify the breakpoint address */
  53
  54        address = strtoul(location, NULL, 16);
  55        aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
  56                                        walk_state->parser_state.aml_start);
  57        if (address <= aml_offset) {
  58                acpi_os_printf("Breakpoint %X is beyond current address %X\n",
  59                               address, aml_offset);
  60        }
  61
  62        /* Save breakpoint in current walk */
  63
  64        walk_state->user_breakpoint = address;
  65        acpi_os_printf("Breakpoint set at AML offset %X\n", address);
  66}
  67
  68/*******************************************************************************
  69 *
  70 * FUNCTION:    acpi_db_set_method_call_breakpoint
  71 *
  72 * PARAMETERS:  op                  - Current Op (from parse walk)
  73 *
  74 * RETURN:      None
  75 *
  76 * DESCRIPTION: Set a breakpoint in a control method at the specified
  77 *              AML offset
  78 *
  79 ******************************************************************************/
  80
  81void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
  82{
  83
  84        if (!op) {
  85                acpi_os_printf("There is no method currently executing\n");
  86                return;
  87        }
  88
  89        acpi_gbl_step_to_next_call = TRUE;
  90}
  91
  92/*******************************************************************************
  93 *
  94 * FUNCTION:    acpi_db_set_method_data
  95 *
  96 * PARAMETERS:  type_arg        - L for local, A for argument
  97 *              index_arg       - which one
  98 *              value_arg       - Value to set.
  99 *
 100 * RETURN:      None
 101 *
 102 * DESCRIPTION: Set a local or argument for the running control method.
 103 *              NOTE: only object supported is Number.
 104 *
 105 ******************************************************************************/
 106
 107void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
 108{
 109        char type;
 110        u32 index;
 111        u32 value;
 112        struct acpi_walk_state *walk_state;
 113        union acpi_operand_object *obj_desc;
 114        acpi_status status;
 115        struct acpi_namespace_node *node;
 116
 117        /* Validate type_arg */
 118
 119        acpi_ut_strupr(type_arg);
 120        type = type_arg[0];
 121        if ((type != 'L') && (type != 'A') && (type != 'N')) {
 122                acpi_os_printf("Invalid SET operand: %s\n", type_arg);
 123                return;
 124        }
 125
 126        value = strtoul(value_arg, NULL, 16);
 127
 128        if (type == 'N') {
 129                node = acpi_db_convert_to_node(index_arg);
 130                if (!node) {
 131                        return;
 132                }
 133
 134                if (node->type != ACPI_TYPE_INTEGER) {
 135                        acpi_os_printf("Can only set Integer nodes\n");
 136                        return;
 137                }
 138                obj_desc = node->object;
 139                obj_desc->integer.value = value;
 140                return;
 141        }
 142
 143        /* Get the index and value */
 144
 145        index = strtoul(index_arg, NULL, 16);
 146
 147        walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
 148        if (!walk_state) {
 149                acpi_os_printf("There is no method currently executing\n");
 150                return;
 151        }
 152
 153        /* Create and initialize the new object */
 154
 155        obj_desc = acpi_ut_create_integer_object((u64)value);
 156        if (!obj_desc) {
 157                acpi_os_printf("Could not create an internal object\n");
 158                return;
 159        }
 160
 161        /* Store the new object into the target */
 162
 163        switch (type) {
 164        case 'A':
 165
 166                /* Set a method argument */
 167
 168                if (index > ACPI_METHOD_MAX_ARG) {
 169                        acpi_os_printf("Arg%u - Invalid argument name\n",
 170                                       index);
 171                        goto cleanup;
 172                }
 173
 174                status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
 175                                                       index, obj_desc,
 176                                                       walk_state);
 177                if (ACPI_FAILURE(status)) {
 178                        goto cleanup;
 179                }
 180
 181                obj_desc = walk_state->arguments[index].object;
 182
 183                acpi_os_printf("Arg%u: ", index);
 184                acpi_db_display_internal_object(obj_desc, walk_state);
 185                break;
 186
 187        case 'L':
 188
 189                /* Set a method local */
 190
 191                if (index > ACPI_METHOD_MAX_LOCAL) {
 192                        acpi_os_printf
 193                            ("Local%u - Invalid local variable name\n", index);
 194                        goto cleanup;
 195                }
 196
 197                status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
 198                                                       index, obj_desc,
 199                                                       walk_state);
 200                if (ACPI_FAILURE(status)) {
 201                        goto cleanup;
 202                }
 203
 204                obj_desc = walk_state->local_variables[index].object;
 205
 206                acpi_os_printf("Local%u: ", index);
 207                acpi_db_display_internal_object(obj_desc, walk_state);
 208                break;
 209
 210        default:
 211
 212                break;
 213        }
 214
 215cleanup:
 216        acpi_ut_remove_reference(obj_desc);
 217}
 218
 219#ifdef ACPI_DISASSEMBLER
 220/*******************************************************************************
 221 *
 222 * FUNCTION:    acpi_db_disassemble_aml
 223 *
 224 * PARAMETERS:  statements          - Number of statements to disassemble
 225 *              op                  - Current Op (from parse walk)
 226 *
 227 * RETURN:      None
 228 *
 229 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 230 *              of statements specified.
 231 *
 232 ******************************************************************************/
 233
 234void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
 235{
 236        u32 num_statements = 8;
 237
 238        if (!op) {
 239                acpi_os_printf("There is no method currently executing\n");
 240                return;
 241        }
 242
 243        if (statements) {
 244                num_statements = strtoul(statements, NULL, 0);
 245        }
 246
 247        acpi_dm_disassemble(NULL, op, num_statements);
 248}
 249
 250/*******************************************************************************
 251 *
 252 * FUNCTION:    acpi_db_disassemble_method
 253 *
 254 * PARAMETERS:  name            - Name of control method
 255 *
 256 * RETURN:      None
 257 *
 258 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 259 *              of statements specified.
 260 *
 261 ******************************************************************************/
 262
 263acpi_status acpi_db_disassemble_method(char *name)
 264{
 265        acpi_status status;
 266        union acpi_parse_object *op;
 267        struct acpi_walk_state *walk_state;
 268        union acpi_operand_object *obj_desc;
 269        struct acpi_namespace_node *method;
 270
 271        method = acpi_db_convert_to_node(name);
 272        if (!method) {
 273                return (AE_BAD_PARAMETER);
 274        }
 275
 276        if (method->type != ACPI_TYPE_METHOD) {
 277                ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
 278                            name, acpi_ut_get_type_name(method->type)));
 279                return (AE_BAD_PARAMETER);
 280        }
 281
 282        obj_desc = method->object;
 283
 284        op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
 285        if (!op) {
 286                return (AE_NO_MEMORY);
 287        }
 288
 289        /* Create and initialize a new walk state */
 290
 291        walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
 292        if (!walk_state) {
 293                return (AE_NO_MEMORY);
 294        }
 295
 296        status = acpi_ds_init_aml_walk(walk_state, op, NULL,
 297                                       obj_desc->method.aml_start,
 298                                       obj_desc->method.aml_length, NULL,
 299                                       ACPI_IMODE_LOAD_PASS1);
 300        if (ACPI_FAILURE(status)) {
 301                return (status);
 302        }
 303
 304        status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
 305        walk_state->owner_id = obj_desc->method.owner_id;
 306
 307        /* Push start scope on scope stack and make it current */
 308
 309        status = acpi_ds_scope_stack_push(method, method->type, walk_state);
 310        if (ACPI_FAILURE(status)) {
 311                return (status);
 312        }
 313
 314        /* Parse the entire method AML including deferred operators */
 315
 316        walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
 317        walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
 318
 319        status = acpi_ps_parse_aml(walk_state);
 320        (void)acpi_dm_parse_deferred_ops(op);
 321
 322        /* Now we can disassemble the method */
 323
 324        acpi_gbl_dm_opt_verbose = FALSE;
 325        acpi_dm_disassemble(NULL, op, 0);
 326        acpi_gbl_dm_opt_verbose = TRUE;
 327
 328        acpi_ps_delete_parse_tree(op);
 329
 330        /* Method cleanup */
 331
 332        acpi_ns_delete_namespace_subtree(method);
 333        acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
 334        acpi_ut_release_owner_id(&obj_desc->method.owner_id);
 335        return (AE_OK);
 336}
 337#endif
 338
 339/*******************************************************************************
 340 *
 341 * FUNCTION:    acpi_db_walk_for_execute
 342 *
 343 * PARAMETERS:  Callback from walk_namespace
 344 *
 345 * RETURN:      Status
 346 *
 347 * DESCRIPTION: Batch execution module. Currently only executes predefined
 348 *              ACPI names.
 349 *
 350 ******************************************************************************/
 351
 352static acpi_status
 353acpi_db_walk_for_execute(acpi_handle obj_handle,
 354                         u32 nesting_level, void *context, void **return_value)
 355{
 356        struct acpi_namespace_node *node =
 357            (struct acpi_namespace_node *)obj_handle;
 358        struct acpi_db_execute_walk *info =
 359            (struct acpi_db_execute_walk *)context;
 360        struct acpi_buffer return_obj;
 361        acpi_status status;
 362        char *pathname;
 363        u32 i;
 364        struct acpi_device_info *obj_info;
 365        struct acpi_object_list param_objects;
 366        union acpi_object params[ACPI_METHOD_NUM_ARGS];
 367        const union acpi_predefined_info *predefined;
 368
 369        predefined = acpi_ut_match_predefined_method(node->name.ascii);
 370        if (!predefined) {
 371                return (AE_OK);
 372        }
 373
 374        if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
 375                return (AE_OK);
 376        }
 377
 378        pathname = acpi_ns_get_external_pathname(node);
 379        if (!pathname) {
 380                return (AE_OK);
 381        }
 382
 383        /* Get the object info for number of method parameters */
 384
 385        status = acpi_get_object_info(obj_handle, &obj_info);
 386        if (ACPI_FAILURE(status)) {
 387                ACPI_FREE(pathname);
 388                return (status);
 389        }
 390
 391        param_objects.pointer = NULL;
 392        param_objects.count = 0;
 393
 394        if (obj_info->type == ACPI_TYPE_METHOD) {
 395
 396                /* Setup default parameters */
 397
 398                for (i = 0; i < obj_info->param_count; i++) {
 399                        params[i].type = ACPI_TYPE_INTEGER;
 400                        params[i].integer.value = 1;
 401                }
 402
 403                param_objects.pointer = params;
 404                param_objects.count = obj_info->param_count;
 405        }
 406
 407        ACPI_FREE(obj_info);
 408        return_obj.pointer = NULL;
 409        return_obj.length = ACPI_ALLOCATE_BUFFER;
 410
 411        /* Do the actual method execution */
 412
 413        acpi_gbl_method_executing = TRUE;
 414
 415        status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
 416
 417        acpi_os_printf("%-32s returned %s\n", pathname,
 418                       acpi_format_exception(status));
 419        acpi_gbl_method_executing = FALSE;
 420        ACPI_FREE(pathname);
 421
 422        /* Ignore status from method execution */
 423
 424        status = AE_OK;
 425
 426        /* Update count, check if we have executed enough methods */
 427
 428        info->count++;
 429        if (info->count >= info->max_count) {
 430                status = AE_CTRL_TERMINATE;
 431        }
 432
 433        return (status);
 434}
 435
 436/*******************************************************************************
 437 *
 438 * FUNCTION:    acpi_db_evaluate_predefined_names
 439 *
 440 * PARAMETERS:  None
 441 *
 442 * RETURN:      None
 443 *
 444 * DESCRIPTION: Namespace batch execution. Execute predefined names in the
 445 *              namespace, up to the max count, if specified.
 446 *
 447 ******************************************************************************/
 448
 449void acpi_db_evaluate_predefined_names(void)
 450{
 451        struct acpi_db_execute_walk info;
 452
 453        info.count = 0;
 454        info.max_count = ACPI_UINT32_MAX;
 455
 456        /* Search all nodes in namespace */
 457
 458        (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
 459                                  ACPI_UINT32_MAX, acpi_db_walk_for_execute,
 460                                  NULL, (void *)&info, NULL);
 461
 462        acpi_os_printf("Evaluated %u predefined names in the namespace\n",
 463                       info.count);
 464}
 465