Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: dbmethod - Debug commands for control methods
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "acdispat.h"
0011 #include "acnamesp.h"
0012 #include "acdebug.h"
0013 #include "acparser.h"
0014 #include "acpredef.h"
0015 
0016 #define _COMPONENT          ACPI_CA_DEBUGGER
0017 ACPI_MODULE_NAME("dbmethod")
0018 
0019 /* Local prototypes */
0020 static acpi_status
0021 acpi_db_walk_for_execute(acpi_handle obj_handle,
0022              u32 nesting_level, void *context, void **return_value);
0023 
0024 static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node);
0025 
0026 /*******************************************************************************
0027  *
0028  * FUNCTION:    acpi_db_set_method_breakpoint
0029  *
0030  * PARAMETERS:  location            - AML offset of breakpoint
0031  *              walk_state          - Current walk info
0032  *              op                  - Current Op (from parse walk)
0033  *
0034  * RETURN:      None
0035  *
0036  * DESCRIPTION: Set a breakpoint in a control method at the specified
0037  *              AML offset
0038  *
0039  ******************************************************************************/
0040 
0041 void
0042 acpi_db_set_method_breakpoint(char *location,
0043                   struct acpi_walk_state *walk_state,
0044                   union acpi_parse_object *op)
0045 {
0046     u32 address;
0047     u32 aml_offset;
0048 
0049     if (!op) {
0050         acpi_os_printf("There is no method currently executing\n");
0051         return;
0052     }
0053 
0054     /* Get and verify the breakpoint address */
0055 
0056     address = strtoul(location, NULL, 16);
0057     aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
0058                     walk_state->parser_state.aml_start);
0059     if (address <= aml_offset) {
0060         acpi_os_printf("Breakpoint %X is beyond current address %X\n",
0061                    address, aml_offset);
0062     }
0063 
0064     /* Save breakpoint in current walk */
0065 
0066     walk_state->user_breakpoint = address;
0067     acpi_os_printf("Breakpoint set at AML offset %X\n", address);
0068 }
0069 
0070 /*******************************************************************************
0071  *
0072  * FUNCTION:    acpi_db_set_method_call_breakpoint
0073  *
0074  * PARAMETERS:  op                  - Current Op (from parse walk)
0075  *
0076  * RETURN:      None
0077  *
0078  * DESCRIPTION: Set a breakpoint in a control method at the specified
0079  *              AML offset
0080  *
0081  ******************************************************************************/
0082 
0083 void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
0084 {
0085 
0086     if (!op) {
0087         acpi_os_printf("There is no method currently executing\n");
0088         return;
0089     }
0090 
0091     acpi_gbl_step_to_next_call = TRUE;
0092 }
0093 
0094 /*******************************************************************************
0095  *
0096  * FUNCTION:    acpi_db_set_method_data
0097  *
0098  * PARAMETERS:  type_arg        - L for local, A for argument
0099  *              index_arg       - which one
0100  *              value_arg       - Value to set.
0101  *
0102  * RETURN:      None
0103  *
0104  * DESCRIPTION: Set a local or argument for the running control method.
0105  *              NOTE: only object supported is Number.
0106  *
0107  ******************************************************************************/
0108 
0109 void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
0110 {
0111     char type;
0112     u32 index;
0113     u32 value;
0114     struct acpi_walk_state *walk_state;
0115     union acpi_operand_object *obj_desc;
0116     acpi_status status;
0117     struct acpi_namespace_node *node;
0118 
0119     /* Validate type_arg */
0120 
0121     acpi_ut_strupr(type_arg);
0122     type = type_arg[0];
0123     if ((type != 'L') && (type != 'A') && (type != 'N')) {
0124         acpi_os_printf("Invalid SET operand: %s\n", type_arg);
0125         return;
0126     }
0127 
0128     value = strtoul(value_arg, NULL, 16);
0129 
0130     if (type == 'N') {
0131         node = acpi_db_convert_to_node(index_arg);
0132         if (!node) {
0133             return;
0134         }
0135 
0136         if (node->type != ACPI_TYPE_INTEGER) {
0137             acpi_os_printf("Can only set Integer nodes\n");
0138             return;
0139         }
0140         obj_desc = node->object;
0141         obj_desc->integer.value = value;
0142         return;
0143     }
0144 
0145     /* Get the index and value */
0146 
0147     index = strtoul(index_arg, NULL, 16);
0148 
0149     walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
0150     if (!walk_state) {
0151         acpi_os_printf("There is no method currently executing\n");
0152         return;
0153     }
0154 
0155     /* Create and initialize the new object */
0156 
0157     obj_desc = acpi_ut_create_integer_object((u64)value);
0158     if (!obj_desc) {
0159         acpi_os_printf("Could not create an internal object\n");
0160         return;
0161     }
0162 
0163     /* Store the new object into the target */
0164 
0165     switch (type) {
0166     case 'A':
0167 
0168         /* Set a method argument */
0169 
0170         if (index > ACPI_METHOD_MAX_ARG) {
0171             acpi_os_printf("Arg%u - Invalid argument name\n",
0172                        index);
0173             goto cleanup;
0174         }
0175 
0176         status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
0177                                index, obj_desc,
0178                                walk_state);
0179         if (ACPI_FAILURE(status)) {
0180             goto cleanup;
0181         }
0182 
0183         obj_desc = walk_state->arguments[index].object;
0184 
0185         acpi_os_printf("Arg%u: ", index);
0186         acpi_db_display_internal_object(obj_desc, walk_state);
0187         break;
0188 
0189     case 'L':
0190 
0191         /* Set a method local */
0192 
0193         if (index > ACPI_METHOD_MAX_LOCAL) {
0194             acpi_os_printf
0195                 ("Local%u - Invalid local variable name\n", index);
0196             goto cleanup;
0197         }
0198 
0199         status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
0200                                index, obj_desc,
0201                                walk_state);
0202         if (ACPI_FAILURE(status)) {
0203             goto cleanup;
0204         }
0205 
0206         obj_desc = walk_state->local_variables[index].object;
0207 
0208         acpi_os_printf("Local%u: ", index);
0209         acpi_db_display_internal_object(obj_desc, walk_state);
0210         break;
0211 
0212     default:
0213 
0214         break;
0215     }
0216 
0217 cleanup:
0218     acpi_ut_remove_reference(obj_desc);
0219 }
0220 
0221 #ifdef ACPI_DISASSEMBLER
0222 /*******************************************************************************
0223  *
0224  * FUNCTION:    acpi_db_disassemble_aml
0225  *
0226  * PARAMETERS:  statements          - Number of statements to disassemble
0227  *              op                  - Current Op (from parse walk)
0228  *
0229  * RETURN:      None
0230  *
0231  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
0232  *              of statements specified.
0233  *
0234  ******************************************************************************/
0235 
0236 void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
0237 {
0238     u32 num_statements = 8;
0239 
0240     if (!op) {
0241         acpi_os_printf("There is no method currently executing\n");
0242         return;
0243     }
0244 
0245     if (statements) {
0246         num_statements = strtoul(statements, NULL, 0);
0247     }
0248 
0249     acpi_dm_disassemble(NULL, op, num_statements);
0250 }
0251 
0252 /*******************************************************************************
0253  *
0254  * FUNCTION:    acpi_db_disassemble_method
0255  *
0256  * PARAMETERS:  name            - Name of control method
0257  *
0258  * RETURN:      None
0259  *
0260  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
0261  *              of statements specified.
0262  *
0263  ******************************************************************************/
0264 
0265 acpi_status acpi_db_disassemble_method(char *name)
0266 {
0267     acpi_status status;
0268     union acpi_parse_object *op;
0269     struct acpi_walk_state *walk_state;
0270     union acpi_operand_object *obj_desc;
0271     struct acpi_namespace_node *method;
0272 
0273     method = acpi_db_convert_to_node(name);
0274     if (!method) {
0275         return (AE_BAD_PARAMETER);
0276     }
0277 
0278     if (method->type != ACPI_TYPE_METHOD) {
0279         ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
0280                 name, acpi_ut_get_type_name(method->type)));
0281         return (AE_BAD_PARAMETER);
0282     }
0283 
0284     obj_desc = method->object;
0285 
0286     op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
0287     if (!op) {
0288         return (AE_NO_MEMORY);
0289     }
0290 
0291     /* Create and initialize a new walk state */
0292 
0293     walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
0294     if (!walk_state) {
0295         return (AE_NO_MEMORY);
0296     }
0297 
0298     status = acpi_ds_init_aml_walk(walk_state, op, NULL,
0299                        obj_desc->method.aml_start,
0300                        obj_desc->method.aml_length, NULL,
0301                        ACPI_IMODE_LOAD_PASS1);
0302     if (ACPI_FAILURE(status)) {
0303         return (status);
0304     }
0305 
0306     status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
0307     if (ACPI_FAILURE(status)) {
0308         return (status);
0309     }
0310 
0311     walk_state->owner_id = obj_desc->method.owner_id;
0312 
0313     /* Push start scope on scope stack and make it current */
0314 
0315     status = acpi_ds_scope_stack_push(method, method->type, walk_state);
0316     if (ACPI_FAILURE(status)) {
0317         return (status);
0318     }
0319 
0320     /* Parse the entire method AML including deferred operators */
0321 
0322     walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
0323     walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
0324 
0325     status = acpi_ps_parse_aml(walk_state);
0326     if (ACPI_FAILURE(status)) {
0327         return (status);
0328     }
0329 
0330     (void)acpi_dm_parse_deferred_ops(op);
0331 
0332     /* Now we can disassemble the method */
0333 
0334     acpi_gbl_dm_opt_verbose = FALSE;
0335     acpi_dm_disassemble(NULL, op, 0);
0336     acpi_gbl_dm_opt_verbose = TRUE;
0337 
0338     acpi_ps_delete_parse_tree(op);
0339 
0340     /* Method cleanup */
0341 
0342     acpi_ns_delete_namespace_subtree(method);
0343     acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
0344     acpi_ut_release_owner_id(&obj_desc->method.owner_id);
0345     return (AE_OK);
0346 }
0347 #endif
0348 
0349 /*******************************************************************************
0350  *
0351  * FUNCTION:    acpi_db_evaluate_object
0352  *
0353  * PARAMETERS:  node                - Namespace node for the object
0354  *
0355  * RETURN:      Status
0356  *
0357  * DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger
0358  *              commands.
0359  *
0360  ******************************************************************************/
0361 
0362 static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node)
0363 {
0364     char *pathname;
0365     u32 i;
0366     struct acpi_device_info *obj_info;
0367     struct acpi_object_list param_objects;
0368     union acpi_object params[ACPI_METHOD_NUM_ARGS];
0369     struct acpi_buffer return_obj;
0370     acpi_status status;
0371 
0372     pathname = acpi_ns_get_external_pathname(node);
0373     if (!pathname) {
0374         return (AE_OK);
0375     }
0376 
0377     /* Get the object info for number of method parameters */
0378 
0379     status = acpi_get_object_info(node, &obj_info);
0380     if (ACPI_FAILURE(status)) {
0381         ACPI_FREE(pathname);
0382         return (status);
0383     }
0384 
0385     param_objects.pointer = NULL;
0386     param_objects.count = 0;
0387 
0388     if (obj_info->type == ACPI_TYPE_METHOD) {
0389 
0390         /* Setup default parameters */
0391 
0392         for (i = 0; i < obj_info->param_count; i++) {
0393             params[i].type = ACPI_TYPE_INTEGER;
0394             params[i].integer.value = 1;
0395         }
0396 
0397         param_objects.pointer = params;
0398         param_objects.count = obj_info->param_count;
0399     }
0400 
0401     ACPI_FREE(obj_info);
0402     return_obj.pointer = NULL;
0403     return_obj.length = ACPI_ALLOCATE_BUFFER;
0404 
0405     /* Do the actual method execution */
0406 
0407     acpi_gbl_method_executing = TRUE;
0408 
0409     status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
0410     acpi_gbl_method_executing = FALSE;
0411 
0412     acpi_os_printf("%-32s returned %s\n", pathname,
0413                acpi_format_exception(status));
0414     if (return_obj.length) {
0415         acpi_os_printf("Evaluation of %s returned object %p, "
0416                    "external buffer length %X\n",
0417                    pathname, return_obj.pointer,
0418                    (u32)return_obj.length);
0419 
0420         acpi_db_dump_external_object(return_obj.pointer, 1);
0421         acpi_os_printf("\n");
0422     }
0423 
0424     ACPI_FREE(pathname);
0425 
0426     /* Ignore status from method execution */
0427 
0428     return (AE_OK);
0429 
0430     /* Update count, check if we have executed enough methods */
0431 
0432 }
0433 
0434 /*******************************************************************************
0435  *
0436  * FUNCTION:    acpi_db_walk_for_execute
0437  *
0438  * PARAMETERS:  Callback from walk_namespace
0439  *
0440  * RETURN:      Status
0441  *
0442  * DESCRIPTION: Batch execution function. Evaluates all "predefined" objects --
0443  *              the nameseg begins with an underscore.
0444  *
0445  ******************************************************************************/
0446 
0447 static acpi_status
0448 acpi_db_walk_for_execute(acpi_handle obj_handle,
0449              u32 nesting_level, void *context, void **return_value)
0450 {
0451     struct acpi_namespace_node *node =
0452         (struct acpi_namespace_node *)obj_handle;
0453     struct acpi_db_execute_walk *info =
0454         (struct acpi_db_execute_walk *)context;
0455     acpi_status status;
0456     const union acpi_predefined_info *predefined;
0457 
0458     predefined = acpi_ut_match_predefined_method(node->name.ascii);
0459     if (!predefined) {
0460         return (AE_OK);
0461     }
0462 
0463     if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
0464         return (AE_OK);
0465     }
0466 
0467     acpi_db_evaluate_object(node);
0468 
0469     /* Ignore status from object evaluation */
0470 
0471     status = AE_OK;
0472 
0473     /* Update count, check if we have executed enough methods */
0474 
0475     info->count++;
0476     if (info->count >= info->max_count) {
0477         status = AE_CTRL_TERMINATE;
0478     }
0479 
0480     return (status);
0481 }
0482 
0483 /*******************************************************************************
0484  *
0485  * FUNCTION:    acpi_db_walk_for_execute_all
0486  *
0487  * PARAMETERS:  Callback from walk_namespace
0488  *
0489  * RETURN:      Status
0490  *
0491  * DESCRIPTION: Batch execution function. Evaluates all objects whose path ends
0492  *              with the nameseg "Info->NameSeg". Used for the "ALL" command.
0493  *
0494  ******************************************************************************/
0495 
0496 static acpi_status
0497 acpi_db_walk_for_execute_all(acpi_handle obj_handle,
0498                  u32 nesting_level,
0499                  void *context, void **return_value)
0500 {
0501     struct acpi_namespace_node *node =
0502         (struct acpi_namespace_node *)obj_handle;
0503     struct acpi_db_execute_walk *info =
0504         (struct acpi_db_execute_walk *)context;
0505     acpi_status status;
0506 
0507     if (!ACPI_COMPARE_NAMESEG(node->name.ascii, info->name_seg)) {
0508         return (AE_OK);
0509     }
0510 
0511     if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
0512         return (AE_OK);
0513     }
0514 
0515     /* Now evaluate the input object (node) */
0516 
0517     acpi_db_evaluate_object(node);
0518 
0519     /* Ignore status from method execution */
0520 
0521     status = AE_OK;
0522 
0523     /* Update count of executed methods/objects */
0524 
0525     info->count++;
0526     return (status);
0527 }
0528 
0529 /*******************************************************************************
0530  *
0531  * FUNCTION:    acpi_db_evaluate_predefined_names
0532  *
0533  * PARAMETERS:  None
0534  *
0535  * RETURN:      None
0536  *
0537  * DESCRIPTION: Namespace batch execution. Execute predefined names in the
0538  *              namespace, up to the max count, if specified.
0539  *
0540  ******************************************************************************/
0541 
0542 void acpi_db_evaluate_predefined_names(void)
0543 {
0544     struct acpi_db_execute_walk info;
0545 
0546     info.count = 0;
0547     info.max_count = ACPI_UINT32_MAX;
0548 
0549     /* Search all nodes in namespace */
0550 
0551     (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
0552                   ACPI_UINT32_MAX, acpi_db_walk_for_execute,
0553                   NULL, (void *)&info, NULL);
0554 
0555     acpi_os_printf("Evaluated %u predefined names in the namespace\n",
0556                info.count);
0557 }
0558 
0559 /*******************************************************************************
0560  *
0561  * FUNCTION:    acpi_db_evaluate_all
0562  *
0563  * PARAMETERS:  none_acpi_gbl_db_method_info
0564  *
0565  * RETURN:      None
0566  *
0567  * DESCRIPTION: Namespace batch execution. Implements the "ALL" command.
0568  *              Execute all namepaths whose final nameseg matches the
0569  *              input nameseg.
0570  *
0571  ******************************************************************************/
0572 
0573 void acpi_db_evaluate_all(char *name_seg)
0574 {
0575     struct acpi_db_execute_walk info;
0576 
0577     info.count = 0;
0578     info.max_count = ACPI_UINT32_MAX;
0579     ACPI_COPY_NAMESEG(info.name_seg, name_seg);
0580     info.name_seg[ACPI_NAMESEG_SIZE] = 0;
0581 
0582     /* Search all nodes in namespace */
0583 
0584     (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
0585                   ACPI_UINT32_MAX, acpi_db_walk_for_execute_all,
0586                   NULL, (void *)&info, NULL);
0587 
0588     acpi_os_printf("Evaluated %u names in the namespace\n", info.count);
0589 }