linux/drivers/acpi/acpica/dbmethod.c
<<
>>
Prefs
   1/*******************************************************************************
   2 *
   3 * Module Name: dbmethod - Debug commands for control methods
   4 *
   5 ******************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2016, Intel Corp.
   9 * All rights reserved.
  10 *
  11 * Redistribution and use in source and binary forms, with or without
  12 * modification, are permitted provided that the following conditions
  13 * are met:
  14 * 1. Redistributions of source code must retain the above copyright
  15 *    notice, this list of conditions, and the following disclaimer,
  16 *    without modification.
  17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18 *    substantially similar to the "NO WARRANTY" disclaimer below
  19 *    ("Disclaimer") and any redistribution must be conditioned upon
  20 *    including a substantially similar Disclaimer requirement for further
  21 *    binary redistribution.
  22 * 3. Neither the names of the above-listed copyright holders nor the names
  23 *    of any contributors may be used to endorse or promote products derived
  24 *    from this software without specific prior written permission.
  25 *
  26 * Alternatively, this software may be distributed under the terms of the
  27 * GNU General Public License ("GPL") version 2 as published by the Free
  28 * Software Foundation.
  29 *
  30 * NO WARRANTY
  31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41 * POSSIBILITY OF SUCH DAMAGES.
  42 */
  43
  44#include <acpi/acpi.h>
  45#include "accommon.h"
  46#include "acdispat.h"
  47#include "acnamesp.h"
  48#include "acdebug.h"
  49#include "acparser.h"
  50#include "acpredef.h"
  51
  52#define _COMPONENT          ACPI_CA_DEBUGGER
  53ACPI_MODULE_NAME("dbmethod")
  54
  55/* Local prototypes */
  56static acpi_status
  57acpi_db_walk_for_execute(acpi_handle obj_handle,
  58                         u32 nesting_level, void *context, void **return_value);
  59
  60/*******************************************************************************
  61 *
  62 * FUNCTION:    acpi_db_set_method_breakpoint
  63 *
  64 * PARAMETERS:  location            - AML offset of breakpoint
  65 *              walk_state          - Current walk info
  66 *              op                  - Current Op (from parse walk)
  67 *
  68 * RETURN:      None
  69 *
  70 * DESCRIPTION: Set a breakpoint in a control method at the specified
  71 *              AML offset
  72 *
  73 ******************************************************************************/
  74
  75void
  76acpi_db_set_method_breakpoint(char *location,
  77                              struct acpi_walk_state *walk_state,
  78                              union acpi_parse_object *op)
  79{
  80        u32 address;
  81        u32 aml_offset;
  82
  83        if (!op) {
  84                acpi_os_printf("There is no method currently executing\n");
  85                return;
  86        }
  87
  88        /* Get and verify the breakpoint address */
  89
  90        address = strtoul(location, NULL, 16);
  91        aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
  92                                        walk_state->parser_state.aml_start);
  93        if (address <= aml_offset) {
  94                acpi_os_printf("Breakpoint %X is beyond current address %X\n",
  95                               address, aml_offset);
  96        }
  97
  98        /* Save breakpoint in current walk */
  99
 100        walk_state->user_breakpoint = address;
 101        acpi_os_printf("Breakpoint set at AML offset %X\n", address);
 102}
 103
 104/*******************************************************************************
 105 *
 106 * FUNCTION:    acpi_db_set_method_call_breakpoint
 107 *
 108 * PARAMETERS:  op                  - Current Op (from parse walk)
 109 *
 110 * RETURN:      None
 111 *
 112 * DESCRIPTION: Set a breakpoint in a control method at the specified
 113 *              AML offset
 114 *
 115 ******************************************************************************/
 116
 117void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
 118{
 119
 120        if (!op) {
 121                acpi_os_printf("There is no method currently executing\n");
 122                return;
 123        }
 124
 125        acpi_gbl_step_to_next_call = TRUE;
 126}
 127
 128/*******************************************************************************
 129 *
 130 * FUNCTION:    acpi_db_set_method_data
 131 *
 132 * PARAMETERS:  type_arg        - L for local, A for argument
 133 *              index_arg       - which one
 134 *              value_arg       - Value to set.
 135 *
 136 * RETURN:      None
 137 *
 138 * DESCRIPTION: Set a local or argument for the running control method.
 139 *              NOTE: only object supported is Number.
 140 *
 141 ******************************************************************************/
 142
 143void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
 144{
 145        char type;
 146        u32 index;
 147        u32 value;
 148        struct acpi_walk_state *walk_state;
 149        union acpi_operand_object *obj_desc;
 150        acpi_status status;
 151        struct acpi_namespace_node *node;
 152
 153        /* Validate type_arg */
 154
 155        acpi_ut_strupr(type_arg);
 156        type = type_arg[0];
 157        if ((type != 'L') && (type != 'A') && (type != 'N')) {
 158                acpi_os_printf("Invalid SET operand: %s\n", type_arg);
 159                return;
 160        }
 161
 162        value = strtoul(value_arg, NULL, 16);
 163
 164        if (type == 'N') {
 165                node = acpi_db_convert_to_node(index_arg);
 166                if (!node) {
 167                        return;
 168                }
 169
 170                if (node->type != ACPI_TYPE_INTEGER) {
 171                        acpi_os_printf("Can only set Integer nodes\n");
 172                        return;
 173                }
 174                obj_desc = node->object;
 175                obj_desc->integer.value = value;
 176                return;
 177        }
 178
 179        /* Get the index and value */
 180
 181        index = strtoul(index_arg, NULL, 16);
 182
 183        walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
 184        if (!walk_state) {
 185                acpi_os_printf("There is no method currently executing\n");
 186                return;
 187        }
 188
 189        /* Create and initialize the new object */
 190
 191        obj_desc = acpi_ut_create_integer_object((u64)value);
 192        if (!obj_desc) {
 193                acpi_os_printf("Could not create an internal object\n");
 194                return;
 195        }
 196
 197        /* Store the new object into the target */
 198
 199        switch (type) {
 200        case 'A':
 201
 202                /* Set a method argument */
 203
 204                if (index > ACPI_METHOD_MAX_ARG) {
 205                        acpi_os_printf("Arg%u - Invalid argument name\n",
 206                                       index);
 207                        goto cleanup;
 208                }
 209
 210                status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
 211                                                       index, obj_desc,
 212                                                       walk_state);
 213                if (ACPI_FAILURE(status)) {
 214                        goto cleanup;
 215                }
 216
 217                obj_desc = walk_state->arguments[index].object;
 218
 219                acpi_os_printf("Arg%u: ", index);
 220                acpi_db_display_internal_object(obj_desc, walk_state);
 221                break;
 222
 223        case 'L':
 224
 225                /* Set a method local */
 226
 227                if (index > ACPI_METHOD_MAX_LOCAL) {
 228                        acpi_os_printf
 229                            ("Local%u - Invalid local variable name\n", index);
 230                        goto cleanup;
 231                }
 232
 233                status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
 234                                                       index, obj_desc,
 235                                                       walk_state);
 236                if (ACPI_FAILURE(status)) {
 237                        goto cleanup;
 238                }
 239
 240                obj_desc = walk_state->local_variables[index].object;
 241
 242                acpi_os_printf("Local%u: ", index);
 243                acpi_db_display_internal_object(obj_desc, walk_state);
 244                break;
 245
 246        default:
 247
 248                break;
 249        }
 250
 251cleanup:
 252        acpi_ut_remove_reference(obj_desc);
 253}
 254
 255/*******************************************************************************
 256 *
 257 * FUNCTION:    acpi_db_disassemble_aml
 258 *
 259 * PARAMETERS:  statements          - Number of statements to disassemble
 260 *              op                  - Current Op (from parse walk)
 261 *
 262 * RETURN:      None
 263 *
 264 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 265 *              of statements specified.
 266 *
 267 ******************************************************************************/
 268
 269void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
 270{
 271        u32 num_statements = 8;
 272
 273        if (!op) {
 274                acpi_os_printf("There is no method currently executing\n");
 275                return;
 276        }
 277
 278        if (statements) {
 279                num_statements = strtoul(statements, NULL, 0);
 280        }
 281#ifdef ACPI_DISASSEMBLER
 282        acpi_dm_disassemble(NULL, op, num_statements);
 283#endif
 284}
 285
 286/*******************************************************************************
 287 *
 288 * FUNCTION:    acpi_db_disassemble_method
 289 *
 290 * PARAMETERS:  name            - Name of control method
 291 *
 292 * RETURN:      None
 293 *
 294 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 295 *              of statements specified.
 296 *
 297 ******************************************************************************/
 298
 299acpi_status acpi_db_disassemble_method(char *name)
 300{
 301        acpi_status status;
 302        union acpi_parse_object *op;
 303        struct acpi_walk_state *walk_state;
 304        union acpi_operand_object *obj_desc;
 305        struct acpi_namespace_node *method;
 306
 307        method = acpi_db_convert_to_node(name);
 308        if (!method) {
 309                return (AE_BAD_PARAMETER);
 310        }
 311
 312        if (method->type != ACPI_TYPE_METHOD) {
 313                ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
 314                            name, acpi_ut_get_type_name(method->type)));
 315                return (AE_BAD_PARAMETER);
 316        }
 317
 318        obj_desc = method->object;
 319
 320        op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
 321        if (!op) {
 322                return (AE_NO_MEMORY);
 323        }
 324
 325        /* Create and initialize a new walk state */
 326
 327        walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
 328        if (!walk_state) {
 329                return (AE_NO_MEMORY);
 330        }
 331
 332        status = acpi_ds_init_aml_walk(walk_state, op, NULL,
 333                                       obj_desc->method.aml_start,
 334                                       obj_desc->method.aml_length, NULL,
 335                                       ACPI_IMODE_LOAD_PASS1);
 336        if (ACPI_FAILURE(status)) {
 337                return (status);
 338        }
 339
 340        status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
 341        walk_state->owner_id = obj_desc->method.owner_id;
 342
 343        /* Push start scope on scope stack and make it current */
 344
 345        status = acpi_ds_scope_stack_push(method, method->type, walk_state);
 346        if (ACPI_FAILURE(status)) {
 347                return (status);
 348        }
 349
 350        /* Parse the entire method AML including deferred operators */
 351
 352        walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
 353        walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
 354
 355        status = acpi_ps_parse_aml(walk_state);
 356
 357#ifdef ACPI_DISASSEMBLER
 358        (void)acpi_dm_parse_deferred_ops(op);
 359
 360        /* Now we can disassemble the method */
 361
 362        acpi_gbl_dm_opt_verbose = FALSE;
 363        acpi_dm_disassemble(NULL, op, 0);
 364        acpi_gbl_dm_opt_verbose = TRUE;
 365#endif
 366
 367        acpi_ps_delete_parse_tree(op);
 368
 369        /* Method cleanup */
 370
 371        acpi_ns_delete_namespace_subtree(method);
 372        acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
 373        acpi_ut_release_owner_id(&obj_desc->method.owner_id);
 374        return (AE_OK);
 375}
 376
 377/*******************************************************************************
 378 *
 379 * FUNCTION:    acpi_db_walk_for_execute
 380 *
 381 * PARAMETERS:  Callback from walk_namespace
 382 *
 383 * RETURN:      Status
 384 *
 385 * DESCRIPTION: Batch execution module. Currently only executes predefined
 386 *              ACPI names.
 387 *
 388 ******************************************************************************/
 389
 390static acpi_status
 391acpi_db_walk_for_execute(acpi_handle obj_handle,
 392                         u32 nesting_level, void *context, void **return_value)
 393{
 394        struct acpi_namespace_node *node =
 395            (struct acpi_namespace_node *)obj_handle;
 396        struct acpi_db_execute_walk *info =
 397            (struct acpi_db_execute_walk *)context;
 398        struct acpi_buffer return_obj;
 399        acpi_status status;
 400        char *pathname;
 401        u32 i;
 402        struct acpi_device_info *obj_info;
 403        struct acpi_object_list param_objects;
 404        union acpi_object params[ACPI_METHOD_NUM_ARGS];
 405        const union acpi_predefined_info *predefined;
 406
 407        predefined = acpi_ut_match_predefined_method(node->name.ascii);
 408        if (!predefined) {
 409                return (AE_OK);
 410        }
 411
 412        if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
 413                return (AE_OK);
 414        }
 415
 416        pathname = acpi_ns_get_external_pathname(node);
 417        if (!pathname) {
 418                return (AE_OK);
 419        }
 420
 421        /* Get the object info for number of method parameters */
 422
 423        status = acpi_get_object_info(obj_handle, &obj_info);
 424        if (ACPI_FAILURE(status)) {
 425                return (status);
 426        }
 427
 428        param_objects.pointer = NULL;
 429        param_objects.count = 0;
 430
 431        if (obj_info->type == ACPI_TYPE_METHOD) {
 432
 433                /* Setup default parameters */
 434
 435                for (i = 0; i < obj_info->param_count; i++) {
 436                        params[i].type = ACPI_TYPE_INTEGER;
 437                        params[i].integer.value = 1;
 438                }
 439
 440                param_objects.pointer = params;
 441                param_objects.count = obj_info->param_count;
 442        }
 443
 444        ACPI_FREE(obj_info);
 445        return_obj.pointer = NULL;
 446        return_obj.length = ACPI_ALLOCATE_BUFFER;
 447
 448        /* Do the actual method execution */
 449
 450        acpi_gbl_method_executing = TRUE;
 451
 452        status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
 453
 454        acpi_os_printf("%-32s returned %s\n", pathname,
 455                       acpi_format_exception(status));
 456        acpi_gbl_method_executing = FALSE;
 457        ACPI_FREE(pathname);
 458
 459        /* Ignore status from method execution */
 460
 461        status = AE_OK;
 462
 463        /* Update count, check if we have executed enough methods */
 464
 465        info->count++;
 466        if (info->count >= info->max_count) {
 467                status = AE_CTRL_TERMINATE;
 468        }
 469
 470        return (status);
 471}
 472
 473/*******************************************************************************
 474 *
 475 * FUNCTION:    acpi_db_evaluate_predefined_names
 476 *
 477 * PARAMETERS:  None
 478 *
 479 * RETURN:      None
 480 *
 481 * DESCRIPTION: Namespace batch execution. Execute predefined names in the
 482 *              namespace, up to the max count, if specified.
 483 *
 484 ******************************************************************************/
 485
 486void acpi_db_evaluate_predefined_names(void)
 487{
 488        struct acpi_db_execute_walk info;
 489
 490        info.count = 0;
 491        info.max_count = ACPI_UINT32_MAX;
 492
 493        /* Search all nodes in namespace */
 494
 495        (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
 496                                  ACPI_UINT32_MAX, acpi_db_walk_for_execute,
 497                                  NULL, (void *)&info, NULL);
 498
 499        acpi_os_printf("Evaluated %u predefined names in the namespace\n",
 500                       info.count);
 501}
 502