cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dbmethod.c (15023B)


      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}