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