xref: /openbmc/linux/drivers/acpi/acpica/dbxface.c (revision fca3aa16)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
3  *
4  * Module Name: dbxface - AML Debugger external interfaces
5  *
6  ******************************************************************************/
7 
8 #include <acpi/acpi.h>
9 #include "accommon.h"
10 #include "amlcode.h"
11 #include "acdebug.h"
12 #include "acinterp.h"
13 
14 #define _COMPONENT          ACPI_CA_DEBUGGER
15 ACPI_MODULE_NAME("dbxface")
16 
17 /* Local prototypes */
18 static acpi_status
19 acpi_db_start_command(struct acpi_walk_state *walk_state,
20 		      union acpi_parse_object *op);
21 
22 #ifdef ACPI_OBSOLETE_FUNCTIONS
23 void acpi_db_method_end(struct acpi_walk_state *walk_state);
24 #endif
25 
26 /*******************************************************************************
27  *
28  * FUNCTION:    acpi_db_start_command
29  *
30  * PARAMETERS:  walk_state      - Current walk
31  *              op              - Current executing Op, from AML interpreter
32  *
33  * RETURN:      Status
34  *
35  * DESCRIPTION: Enter debugger command loop
36  *
37  ******************************************************************************/
38 
39 static acpi_status
40 acpi_db_start_command(struct acpi_walk_state *walk_state,
41 		      union acpi_parse_object *op)
42 {
43 	acpi_status status;
44 
45 	/* TBD: [Investigate] are there namespace locking issues here? */
46 
47 	/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
48 
49 	/* Go into the command loop and await next user command */
50 
51 	acpi_gbl_method_executing = TRUE;
52 	status = AE_CTRL_TRUE;
53 
54 	while (status == AE_CTRL_TRUE) {
55 
56 		/* Notify the completion of the command */
57 
58 		status = acpi_os_notify_command_complete();
59 		if (ACPI_FAILURE(status)) {
60 			goto error_exit;
61 		}
62 
63 		/* Wait the readiness of the command */
64 
65 		status = acpi_os_wait_command_ready();
66 		if (ACPI_FAILURE(status)) {
67 			goto error_exit;
68 		}
69 
70 		status =
71 		    acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
72 					     op);
73 	}
74 
75 	/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
76 
77 error_exit:
78 	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
79 		ACPI_EXCEPTION((AE_INFO, status,
80 				"While parsing/handling command line"));
81 	}
82 	return (status);
83 }
84 
85 /*******************************************************************************
86  *
87  * FUNCTION:    acpi_db_signal_break_point
88  *
89  * PARAMETERS:  walk_state      - Current walk
90  *
91  * RETURN:      Status
92  *
93  * DESCRIPTION: Called for AML_BREAKPOINT_OP
94  *
95  ******************************************************************************/
96 
97 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
98 {
99 
100 #ifndef ACPI_APPLICATION
101 	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
102 		return;
103 	}
104 #endif
105 
106 	/*
107 	 * Set the single-step flag. This will cause the debugger (if present)
108 	 * to break to the console within the AML debugger at the start of the
109 	 * next AML instruction.
110 	 */
111 	acpi_gbl_cm_single_step = TRUE;
112 	acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
113 }
114 
115 /*******************************************************************************
116  *
117  * FUNCTION:    acpi_db_single_step
118  *
119  * PARAMETERS:  walk_state      - Current walk
120  *              op              - Current executing op (from aml interpreter)
121  *              opcode_class    - Class of the current AML Opcode
122  *
123  * RETURN:      Status
124  *
125  * DESCRIPTION: Called just before execution of an AML opcode.
126  *
127  ******************************************************************************/
128 
129 acpi_status
130 acpi_db_single_step(struct acpi_walk_state *walk_state,
131 		    union acpi_parse_object *op, u32 opcode_class)
132 {
133 	union acpi_parse_object *next;
134 	acpi_status status = AE_OK;
135 	u32 original_debug_level;
136 	union acpi_parse_object *display_op;
137 	union acpi_parse_object *parent_op;
138 	u32 aml_offset;
139 
140 	ACPI_FUNCTION_ENTRY();
141 
142 #ifndef ACPI_APPLICATION
143 	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
144 		return (AE_OK);
145 	}
146 #endif
147 
148 	/* Check the abort flag */
149 
150 	if (acpi_gbl_abort_method) {
151 		acpi_gbl_abort_method = FALSE;
152 		return (AE_ABORT_METHOD);
153 	}
154 
155 	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
156 					walk_state->parser_state.aml_start);
157 
158 	/* Check for single-step breakpoint */
159 
160 	if (walk_state->method_breakpoint &&
161 	    (walk_state->method_breakpoint <= aml_offset)) {
162 
163 		/* Check if the breakpoint has been reached or passed */
164 		/* Hit the breakpoint, resume single step, reset breakpoint */
165 
166 		acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
167 		acpi_gbl_cm_single_step = TRUE;
168 		acpi_gbl_step_to_next_call = FALSE;
169 		walk_state->method_breakpoint = 0;
170 	}
171 
172 	/* Check for user breakpoint (Must be on exact Aml offset) */
173 
174 	else if (walk_state->user_breakpoint &&
175 		 (walk_state->user_breakpoint == aml_offset)) {
176 		acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
177 			       aml_offset);
178 		acpi_gbl_cm_single_step = TRUE;
179 		acpi_gbl_step_to_next_call = FALSE;
180 		walk_state->method_breakpoint = 0;
181 	}
182 
183 	/*
184 	 * Check if this is an opcode that we are interested in --
185 	 * namely, opcodes that have arguments
186 	 */
187 	if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
188 		return (AE_OK);
189 	}
190 
191 	switch (opcode_class) {
192 	case AML_CLASS_UNKNOWN:
193 	case AML_CLASS_ARGUMENT:	/* constants, literals, etc. do nothing */
194 
195 		return (AE_OK);
196 
197 	default:
198 
199 		/* All other opcodes -- continue */
200 		break;
201 	}
202 
203 	/*
204 	 * Under certain debug conditions, display this opcode and its operands
205 	 */
206 	if ((acpi_gbl_db_output_to_file) ||
207 	    (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
208 		if ((acpi_gbl_db_output_to_file) ||
209 		    (acpi_dbg_level & ACPI_LV_PARSE)) {
210 			acpi_os_printf
211 			    ("\nAML Debug: Next AML Opcode to execute:\n");
212 		}
213 
214 		/*
215 		 * Display this op (and only this op - zero out the NEXT field
216 		 * temporarily, and disable parser trace output for the duration of
217 		 * the display because we don't want the extraneous debug output)
218 		 */
219 		original_debug_level = acpi_dbg_level;
220 		acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
221 		next = op->common.next;
222 		op->common.next = NULL;
223 
224 		display_op = op;
225 		parent_op = op->common.parent;
226 		if (parent_op) {
227 			if ((walk_state->control_state) &&
228 			    (walk_state->control_state->common.state ==
229 			     ACPI_CONTROL_PREDICATE_EXECUTING)) {
230 				/*
231 				 * We are executing the predicate of an IF or WHILE statement
232 				 * Search upwards for the containing IF or WHILE so that the
233 				 * entire predicate can be displayed.
234 				 */
235 				while (parent_op) {
236 					if ((parent_op->common.aml_opcode ==
237 					     AML_IF_OP)
238 					    || (parent_op->common.aml_opcode ==
239 						AML_WHILE_OP)) {
240 						display_op = parent_op;
241 						break;
242 					}
243 					parent_op = parent_op->common.parent;
244 				}
245 			} else {
246 				while (parent_op) {
247 					if ((parent_op->common.aml_opcode ==
248 					     AML_IF_OP)
249 					    || (parent_op->common.aml_opcode ==
250 						AML_ELSE_OP)
251 					    || (parent_op->common.aml_opcode ==
252 						AML_SCOPE_OP)
253 					    || (parent_op->common.aml_opcode ==
254 						AML_METHOD_OP)
255 					    || (parent_op->common.aml_opcode ==
256 						AML_WHILE_OP)) {
257 						break;
258 					}
259 					display_op = parent_op;
260 					parent_op = parent_op->common.parent;
261 				}
262 			}
263 		}
264 
265 		/* Now we can display it */
266 
267 #ifdef ACPI_DISASSEMBLER
268 		acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
269 #endif
270 
271 		if ((op->common.aml_opcode == AML_IF_OP) ||
272 		    (op->common.aml_opcode == AML_WHILE_OP)) {
273 			if (walk_state->control_state->common.value) {
274 				acpi_os_printf
275 				    ("Predicate = [True], IF block was executed\n");
276 			} else {
277 				acpi_os_printf
278 				    ("Predicate = [False], Skipping IF block\n");
279 			}
280 		} else if (op->common.aml_opcode == AML_ELSE_OP) {
281 			acpi_os_printf
282 			    ("Predicate = [False], ELSE block was executed\n");
283 		}
284 
285 		/* Restore everything */
286 
287 		op->common.next = next;
288 		acpi_os_printf("\n");
289 		if ((acpi_gbl_db_output_to_file) ||
290 		    (acpi_dbg_level & ACPI_LV_PARSE)) {
291 			acpi_os_printf("\n");
292 		}
293 		acpi_dbg_level = original_debug_level;
294 	}
295 
296 	/* If we are not single stepping, just continue executing the method */
297 
298 	if (!acpi_gbl_cm_single_step) {
299 		return (AE_OK);
300 	}
301 
302 	/*
303 	 * If we are executing a step-to-call command,
304 	 * Check if this is a method call.
305 	 */
306 	if (acpi_gbl_step_to_next_call) {
307 		if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
308 
309 			/* Not a method call, just keep executing */
310 
311 			return (AE_OK);
312 		}
313 
314 		/* Found a method call, stop executing */
315 
316 		acpi_gbl_step_to_next_call = FALSE;
317 	}
318 
319 	/*
320 	 * If the next opcode is a method call, we will "step over" it
321 	 * by default.
322 	 */
323 	if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
324 
325 		/* Force no more single stepping while executing called method */
326 
327 		acpi_gbl_cm_single_step = FALSE;
328 
329 		/*
330 		 * Set the breakpoint on/before the call, it will stop execution
331 		 * as soon as we return
332 		 */
333 		walk_state->method_breakpoint = 1;	/* Must be non-zero! */
334 	}
335 
336 	acpi_ex_exit_interpreter();
337 	status = acpi_db_start_command(walk_state, op);
338 	acpi_ex_enter_interpreter();
339 
340 	/* User commands complete, continue execution of the interrupted method */
341 
342 	return (status);
343 }
344 
345 /*******************************************************************************
346  *
347  * FUNCTION:    acpi_initialize_debugger
348  *
349  * PARAMETERS:  None
350  *
351  * RETURN:      Status
352  *
353  * DESCRIPTION: Init and start debugger
354  *
355  ******************************************************************************/
356 
357 acpi_status acpi_initialize_debugger(void)
358 {
359 	acpi_status status;
360 
361 	ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
362 
363 	/* Init globals */
364 
365 	acpi_gbl_db_buffer = NULL;
366 	acpi_gbl_db_filename = NULL;
367 	acpi_gbl_db_output_to_file = FALSE;
368 
369 	acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
370 	acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
371 	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
372 
373 	acpi_gbl_db_opt_no_ini_methods = FALSE;
374 
375 	acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
376 	if (!acpi_gbl_db_buffer) {
377 		return_ACPI_STATUS(AE_NO_MEMORY);
378 	}
379 	memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
380 
381 	/* Initial scope is the root */
382 
383 	acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
384 	acpi_gbl_db_scope_buf[1] = 0;
385 	acpi_gbl_db_scope_node = acpi_gbl_root_node;
386 
387 	/* Initialize user commands loop */
388 
389 	acpi_gbl_db_terminate_loop = FALSE;
390 
391 	/*
392 	 * If configured for multi-thread support, the debug executor runs in
393 	 * a separate thread so that the front end can be in another address
394 	 * space, environment, or even another machine.
395 	 */
396 	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
397 
398 		/* These were created with one unit, grab it */
399 
400 		status = acpi_os_initialize_debugger();
401 		if (ACPI_FAILURE(status)) {
402 			acpi_os_printf("Could not get debugger mutex\n");
403 			return_ACPI_STATUS(status);
404 		}
405 
406 		/* Create the debug execution thread to execute commands */
407 
408 		acpi_gbl_db_threads_terminated = FALSE;
409 		status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
410 					 acpi_db_execute_thread, NULL);
411 		if (ACPI_FAILURE(status)) {
412 			ACPI_EXCEPTION((AE_INFO, status,
413 					"Could not start debugger thread"));
414 			acpi_gbl_db_threads_terminated = TRUE;
415 			return_ACPI_STATUS(status);
416 		}
417 	} else {
418 		acpi_gbl_db_thread_id = acpi_os_get_thread_id();
419 	}
420 
421 	return_ACPI_STATUS(AE_OK);
422 }
423 
424 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
425 
426 /*******************************************************************************
427  *
428  * FUNCTION:    acpi_terminate_debugger
429  *
430  * PARAMETERS:  None
431  *
432  * RETURN:      None
433  *
434  * DESCRIPTION: Stop debugger
435  *
436  ******************************************************************************/
437 void acpi_terminate_debugger(void)
438 {
439 
440 	/* Terminate the AML Debugger */
441 
442 	acpi_gbl_db_terminate_loop = TRUE;
443 
444 	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
445 
446 		/* Wait the AML Debugger threads */
447 
448 		while (!acpi_gbl_db_threads_terminated) {
449 			acpi_os_sleep(100);
450 		}
451 
452 		acpi_os_terminate_debugger();
453 	}
454 
455 	if (acpi_gbl_db_buffer) {
456 		acpi_os_free(acpi_gbl_db_buffer);
457 		acpi_gbl_db_buffer = NULL;
458 	}
459 
460 	/* Ensure that debug output is now disabled */
461 
462 	acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
463 }
464 
465 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
466 
467 /*******************************************************************************
468  *
469  * FUNCTION:    acpi_set_debugger_thread_id
470  *
471  * PARAMETERS:  thread_id       - Debugger thread ID
472  *
473  * RETURN:      None
474  *
475  * DESCRIPTION: Set debugger thread ID
476  *
477  ******************************************************************************/
478 void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
479 {
480 	acpi_gbl_db_thread_id = thread_id;
481 }
482 
483 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)
484