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