Linux 4.19.133
[linux/fpc-iii.git] / drivers / acpi / acpica / dbxface.c
blobf2526726daf6cbf7c2c72e7697aaab398ba0beca
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
4 * Module Name: dbxface - AML Debugger external interfaces
6 ******************************************************************************/
8 #include <acpi/acpi.h>
9 #include "accommon.h"
10 #include "amlcode.h"
11 #include "acdebug.h"
12 #include "acinterp.h"
13 #include "acparser.h"
15 #define _COMPONENT ACPI_CA_DEBUGGER
16 ACPI_MODULE_NAME("dbxface")
18 /* Local prototypes */
19 static acpi_status
20 acpi_db_start_command(struct acpi_walk_state *walk_state,
21 union acpi_parse_object *op);
23 #ifdef ACPI_OBSOLETE_FUNCTIONS
24 void acpi_db_method_end(struct acpi_walk_state *walk_state);
25 #endif
27 /*******************************************************************************
29 * FUNCTION: acpi_db_start_command
31 * PARAMETERS: walk_state - Current walk
32 * op - Current executing Op, from AML interpreter
34 * RETURN: Status
36 * DESCRIPTION: Enter debugger command loop
38 ******************************************************************************/
40 static acpi_status
41 acpi_db_start_command(struct acpi_walk_state *walk_state,
42 union acpi_parse_object *op)
44 acpi_status status;
46 /* TBD: [Investigate] are there namespace locking issues here? */
48 /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
50 /* Go into the command loop and await next user command */
52 acpi_gbl_method_executing = TRUE;
53 status = AE_CTRL_TRUE;
55 while (status == AE_CTRL_TRUE) {
57 /* Notify the completion of the command */
59 status = acpi_os_notify_command_complete();
60 if (ACPI_FAILURE(status)) {
61 goto error_exit;
64 /* Wait the readiness of the command */
66 status = acpi_os_wait_command_ready();
67 if (ACPI_FAILURE(status)) {
68 goto error_exit;
71 status =
72 acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
73 op);
76 /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
78 error_exit:
79 if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
80 ACPI_EXCEPTION((AE_INFO, status,
81 "While parsing/handling command line"));
83 return (status);
86 /*******************************************************************************
88 * FUNCTION: acpi_db_signal_break_point
90 * PARAMETERS: walk_state - Current walk
92 * RETURN: Status
94 * DESCRIPTION: Called for AML_BREAKPOINT_OP
96 ******************************************************************************/
98 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
101 #ifndef ACPI_APPLICATION
102 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
103 return;
105 #endif
108 * Set the single-step flag. This will cause the debugger (if present)
109 * to break to the console within the AML debugger at the start of the
110 * next AML instruction.
112 acpi_gbl_cm_single_step = TRUE;
113 acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
116 /*******************************************************************************
118 * FUNCTION: acpi_db_single_step
120 * PARAMETERS: walk_state - Current walk
121 * op - Current executing op (from aml interpreter)
122 * opcode_class - Class of the current AML Opcode
124 * RETURN: Status
126 * DESCRIPTION: Called just before execution of an AML opcode.
128 ******************************************************************************/
130 acpi_status
131 acpi_db_single_step(struct acpi_walk_state *walk_state,
132 union acpi_parse_object *op, u32 opcode_class)
134 union acpi_parse_object *next;
135 acpi_status status = AE_OK;
136 u32 original_debug_level;
137 union acpi_parse_object *display_op;
138 union acpi_parse_object *parent_op;
139 u32 aml_offset;
141 ACPI_FUNCTION_ENTRY();
143 #ifndef ACPI_APPLICATION
144 if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
145 return (AE_OK);
147 #endif
149 /* Check the abort flag */
151 if (acpi_gbl_abort_method) {
152 acpi_gbl_abort_method = FALSE;
153 return (AE_ABORT_METHOD);
156 aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
157 walk_state->parser_state.aml_start);
159 /* Check for single-step breakpoint */
161 if (walk_state->method_breakpoint &&
162 (walk_state->method_breakpoint <= aml_offset)) {
164 /* Check if the breakpoint has been reached or passed */
165 /* Hit the breakpoint, resume single step, reset breakpoint */
167 acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
168 acpi_gbl_cm_single_step = TRUE;
169 acpi_gbl_step_to_next_call = FALSE;
170 walk_state->method_breakpoint = 0;
173 /* Check for user breakpoint (Must be on exact Aml offset) */
175 else if (walk_state->user_breakpoint &&
176 (walk_state->user_breakpoint == aml_offset)) {
177 acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
178 aml_offset);
179 acpi_gbl_cm_single_step = TRUE;
180 acpi_gbl_step_to_next_call = FALSE;
181 walk_state->method_breakpoint = 0;
185 * Check if this is an opcode that we are interested in --
186 * namely, opcodes that have arguments
188 if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
189 return (AE_OK);
192 switch (opcode_class) {
193 case AML_CLASS_UNKNOWN:
194 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */
196 return (AE_OK);
198 default:
200 /* All other opcodes -- continue */
201 break;
205 * Under certain debug conditions, display this opcode and its operands
207 if ((acpi_gbl_db_output_to_file) ||
208 (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
209 if ((acpi_gbl_db_output_to_file) ||
210 (acpi_dbg_level & ACPI_LV_PARSE)) {
211 acpi_os_printf
212 ("\nAML Debug: Next AML Opcode to execute:\n");
216 * Display this op (and only this op - zero out the NEXT field
217 * temporarily, and disable parser trace output for the duration of
218 * the display because we don't want the extraneous debug output)
220 original_debug_level = acpi_dbg_level;
221 acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
222 next = op->common.next;
223 op->common.next = NULL;
225 display_op = op;
226 parent_op = op->common.parent;
227 if (parent_op) {
228 if ((walk_state->control_state) &&
229 (walk_state->control_state->common.state ==
230 ACPI_CONTROL_PREDICATE_EXECUTING)) {
232 * We are executing the predicate of an IF or WHILE statement
233 * Search upwards for the containing IF or WHILE so that the
234 * entire predicate can be displayed.
236 while (parent_op) {
237 if ((parent_op->common.aml_opcode ==
238 AML_IF_OP)
239 || (parent_op->common.aml_opcode ==
240 AML_WHILE_OP)) {
241 display_op = parent_op;
242 break;
244 parent_op = parent_op->common.parent;
246 } else {
247 while (parent_op) {
248 if ((parent_op->common.aml_opcode ==
249 AML_IF_OP)
250 || (parent_op->common.aml_opcode ==
251 AML_ELSE_OP)
252 || (parent_op->common.aml_opcode ==
253 AML_SCOPE_OP)
254 || (parent_op->common.aml_opcode ==
255 AML_METHOD_OP)
256 || (parent_op->common.aml_opcode ==
257 AML_WHILE_OP)) {
258 break;
260 display_op = parent_op;
261 parent_op = parent_op->common.parent;
266 /* Now we can disassemble and display it */
268 #ifdef ACPI_DISASSEMBLER
269 acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
270 #else
272 * The AML Disassembler is not configured - at least we can
273 * display the opcode value and name
275 acpi_os_printf("AML Opcode: %4.4X %s\n", op->common.aml_opcode,
276 acpi_ps_get_opcode_name(op->common.aml_opcode));
277 #endif
279 if ((op->common.aml_opcode == AML_IF_OP) ||
280 (op->common.aml_opcode == AML_WHILE_OP)) {
281 if (walk_state->control_state->common.value) {
282 acpi_os_printf
283 ("Predicate = [True], IF block was executed\n");
284 } else {
285 acpi_os_printf
286 ("Predicate = [False], Skipping IF block\n");
288 } else if (op->common.aml_opcode == AML_ELSE_OP) {
289 acpi_os_printf
290 ("Predicate = [False], ELSE block was executed\n");
293 /* Restore everything */
295 op->common.next = next;
296 acpi_os_printf("\n");
297 if ((acpi_gbl_db_output_to_file) ||
298 (acpi_dbg_level & ACPI_LV_PARSE)) {
299 acpi_os_printf("\n");
301 acpi_dbg_level = original_debug_level;
304 /* If we are not single stepping, just continue executing the method */
306 if (!acpi_gbl_cm_single_step) {
307 return (AE_OK);
311 * If we are executing a step-to-call command,
312 * Check if this is a method call.
314 if (acpi_gbl_step_to_next_call) {
315 if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
317 /* Not a method call, just keep executing */
319 return (AE_OK);
322 /* Found a method call, stop executing */
324 acpi_gbl_step_to_next_call = FALSE;
328 * If the next opcode is a method call, we will "step over" it
329 * by default.
331 if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
333 /* Force no more single stepping while executing called method */
335 acpi_gbl_cm_single_step = FALSE;
338 * Set the breakpoint on/before the call, it will stop execution
339 * as soon as we return
341 walk_state->method_breakpoint = 1; /* Must be non-zero! */
344 acpi_ex_exit_interpreter();
345 status = acpi_db_start_command(walk_state, op);
346 acpi_ex_enter_interpreter();
348 /* User commands complete, continue execution of the interrupted method */
350 return (status);
353 /*******************************************************************************
355 * FUNCTION: acpi_initialize_debugger
357 * PARAMETERS: None
359 * RETURN: Status
361 * DESCRIPTION: Init and start debugger
363 ******************************************************************************/
365 acpi_status acpi_initialize_debugger(void)
367 acpi_status status;
369 ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
371 /* Init globals */
373 acpi_gbl_db_buffer = NULL;
374 acpi_gbl_db_filename = NULL;
375 acpi_gbl_db_output_to_file = FALSE;
377 acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
378 acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
379 acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
381 acpi_gbl_db_opt_no_ini_methods = FALSE;
383 acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
384 if (!acpi_gbl_db_buffer) {
385 return_ACPI_STATUS(AE_NO_MEMORY);
387 memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
389 /* Initial scope is the root */
391 acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
392 acpi_gbl_db_scope_buf[1] = 0;
393 acpi_gbl_db_scope_node = acpi_gbl_root_node;
395 /* Initialize user commands loop */
397 acpi_gbl_db_terminate_loop = FALSE;
400 * If configured for multi-thread support, the debug executor runs in
401 * a separate thread so that the front end can be in another address
402 * space, environment, or even another machine.
404 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
406 /* These were created with one unit, grab it */
408 status = acpi_os_initialize_debugger();
409 if (ACPI_FAILURE(status)) {
410 acpi_os_printf("Could not get debugger mutex\n");
411 return_ACPI_STATUS(status);
414 /* Create the debug execution thread to execute commands */
416 acpi_gbl_db_threads_terminated = FALSE;
417 status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
418 acpi_db_execute_thread, NULL);
419 if (ACPI_FAILURE(status)) {
420 ACPI_EXCEPTION((AE_INFO, status,
421 "Could not start debugger thread"));
422 acpi_gbl_db_threads_terminated = TRUE;
423 return_ACPI_STATUS(status);
425 } else {
426 acpi_gbl_db_thread_id = acpi_os_get_thread_id();
429 return_ACPI_STATUS(AE_OK);
432 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
434 /*******************************************************************************
436 * FUNCTION: acpi_terminate_debugger
438 * PARAMETERS: None
440 * RETURN: None
442 * DESCRIPTION: Stop debugger
444 ******************************************************************************/
445 void acpi_terminate_debugger(void)
448 /* Terminate the AML Debugger */
450 acpi_gbl_db_terminate_loop = TRUE;
452 if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
454 /* Wait the AML Debugger threads */
456 while (!acpi_gbl_db_threads_terminated) {
457 acpi_os_sleep(100);
460 acpi_os_terminate_debugger();
463 if (acpi_gbl_db_buffer) {
464 acpi_os_free(acpi_gbl_db_buffer);
465 acpi_gbl_db_buffer = NULL;
468 /* Ensure that debug output is now disabled */
470 acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
473 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
475 /*******************************************************************************
477 * FUNCTION: acpi_set_debugger_thread_id
479 * PARAMETERS: thread_id - Debugger thread ID
481 * RETURN: None
483 * DESCRIPTION: Set debugger thread ID
485 ******************************************************************************/
486 void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
488 acpi_gbl_db_thread_id = thread_id;
491 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)