Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux...
[sfrench/cifs-2.6.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 /*******************************************************************************
28  *
29  * FUNCTION:    acpi_db_start_command
30  *
31  * PARAMETERS:  walk_state      - Current walk
32  *              op              - Current executing Op, from AML interpreter
33  *
34  * RETURN:      Status
35  *
36  * DESCRIPTION: Enter debugger command loop
37  *
38  ******************************************************************************/
39
40 static acpi_status
41 acpi_db_start_command(struct acpi_walk_state *walk_state,
42                       union acpi_parse_object *op)
43 {
44         acpi_status status;
45
46         /* TBD: [Investigate] are there namespace locking issues here? */
47
48         /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
49
50         /* Go into the command loop and await next user command */
51
52         acpi_gbl_method_executing = TRUE;
53         status = AE_CTRL_TRUE;
54
55         while (status == AE_CTRL_TRUE) {
56
57                 /* Notify the completion of the command */
58
59                 status = acpi_os_notify_command_complete();
60                 if (ACPI_FAILURE(status)) {
61                         goto error_exit;
62                 }
63
64                 /* Wait the readiness of the command */
65
66                 status = acpi_os_wait_command_ready();
67                 if (ACPI_FAILURE(status)) {
68                         goto error_exit;
69                 }
70
71                 status =
72                     acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
73                                              op);
74         }
75
76         /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
77
78 error_exit:
79         if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
80                 ACPI_EXCEPTION((AE_INFO, status,
81                                 "While parsing/handling command line"));
82         }
83         return (status);
84 }
85
86 /*******************************************************************************
87  *
88  * FUNCTION:    acpi_db_signal_break_point
89  *
90  * PARAMETERS:  walk_state      - Current walk
91  *
92  * RETURN:      Status
93  *
94  * DESCRIPTION: Called for AML_BREAKPOINT_OP
95  *
96  ******************************************************************************/
97
98 void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
99 {
100
101 #ifndef ACPI_APPLICATION
102         if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
103                 return;
104         }
105 #endif
106
107         /*
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.
111          */
112         acpi_gbl_cm_single_step = TRUE;
113         acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
114 }
115
116 /*******************************************************************************
117  *
118  * FUNCTION:    acpi_db_single_step
119  *
120  * PARAMETERS:  walk_state      - Current walk
121  *              op              - Current executing op (from aml interpreter)
122  *              opcode_class    - Class of the current AML Opcode
123  *
124  * RETURN:      Status
125  *
126  * DESCRIPTION: Called just before execution of an AML opcode.
127  *
128  ******************************************************************************/
129
130 acpi_status
131 acpi_db_single_step(struct acpi_walk_state *walk_state,
132                     union acpi_parse_object *op, u32 opcode_class)
133 {
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;
140
141         ACPI_FUNCTION_ENTRY();
142
143 #ifndef ACPI_APPLICATION
144         if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
145                 return (AE_OK);
146         }
147 #endif
148
149         /* Check the abort flag */
150
151         if (acpi_gbl_abort_method) {
152                 acpi_gbl_abort_method = FALSE;
153                 return (AE_ABORT_METHOD);
154         }
155
156         aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
157                                         walk_state->parser_state.aml_start);
158
159         /* Check for single-step breakpoint */
160
161         if (walk_state->method_breakpoint &&
162             (walk_state->method_breakpoint <= aml_offset)) {
163
164                 /* Check if the breakpoint has been reached or passed */
165                 /* Hit the breakpoint, resume single step, reset breakpoint */
166
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;
171         }
172
173         /* Check for user breakpoint (Must be on exact Aml offset) */
174
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;
182         }
183
184         /*
185          * Check if this is an opcode that we are interested in --
186          * namely, opcodes that have arguments
187          */
188         if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
189                 return (AE_OK);
190         }
191
192         switch (opcode_class) {
193         case AML_CLASS_UNKNOWN:
194         case AML_CLASS_ARGUMENT:        /* constants, literals, etc. do nothing */
195
196                 return (AE_OK);
197
198         default:
199
200                 /* All other opcodes -- continue */
201                 break;
202         }
203
204         /*
205          * Under certain debug conditions, display this opcode and its operands
206          */
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");
213                 }
214
215                 /*
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)
219                  */
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;
224
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)) {
231                                 /*
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.
235                                  */
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;
243                                         }
244                                         parent_op = parent_op->common.parent;
245                                 }
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;
259                                         }
260                                         display_op = parent_op;
261                                         parent_op = parent_op->common.parent;
262                                 }
263                         }
264                 }
265
266                 /* Now we can disassemble and display it */
267
268 #ifdef ACPI_DISASSEMBLER
269                 acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
270 #else
271                 /*
272                  * The AML Disassembler is not configured - at least we can
273                  * display the opcode value and name
274                  */
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
278
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");
287                         }
288                 } else if (op->common.aml_opcode == AML_ELSE_OP) {
289                         acpi_os_printf
290                             ("Predicate = [False], ELSE block was executed\n");
291                 }
292
293                 /* Restore everything */
294
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");
300                 }
301                 acpi_dbg_level = original_debug_level;
302         }
303
304         /* If we are not single stepping, just continue executing the method */
305
306         if (!acpi_gbl_cm_single_step) {
307                 return (AE_OK);
308         }
309
310         /*
311          * If we are executing a step-to-call command,
312          * Check if this is a method call.
313          */
314         if (acpi_gbl_step_to_next_call) {
315                 if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
316
317                         /* Not a method call, just keep executing */
318
319                         return (AE_OK);
320                 }
321
322                 /* Found a method call, stop executing */
323
324                 acpi_gbl_step_to_next_call = FALSE;
325         }
326
327         /*
328          * If the next opcode is a method call, we will "step over" it
329          * by default.
330          */
331         if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
332
333                 /* Force no more single stepping while executing called method */
334
335                 acpi_gbl_cm_single_step = FALSE;
336
337                 /*
338                  * Set the breakpoint on/before the call, it will stop execution
339                  * as soon as we return
340                  */
341                 walk_state->method_breakpoint = 1;      /* Must be non-zero! */
342         }
343
344         acpi_ex_exit_interpreter();
345         status = acpi_db_start_command(walk_state, op);
346         acpi_ex_enter_interpreter();
347
348         /* User commands complete, continue execution of the interrupted method */
349
350         return (status);
351 }
352
353 /*******************************************************************************
354  *
355  * FUNCTION:    acpi_initialize_debugger
356  *
357  * PARAMETERS:  None
358  *
359  * RETURN:      Status
360  *
361  * DESCRIPTION: Init and start debugger
362  *
363  ******************************************************************************/
364
365 acpi_status acpi_initialize_debugger(void)
366 {
367         acpi_status status;
368
369         ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
370
371         /* Init globals */
372
373         acpi_gbl_db_buffer = NULL;
374         acpi_gbl_db_filename = NULL;
375         acpi_gbl_db_output_to_file = FALSE;
376
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;
380
381         acpi_gbl_db_opt_no_ini_methods = FALSE;
382
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);
386         }
387         memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
388
389         /* Initial scope is the root */
390
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;
394
395         /* Initialize user commands loop */
396
397         acpi_gbl_db_terminate_loop = FALSE;
398
399         /*
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.
403          */
404         if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
405
406                 /* These were created with one unit, grab it */
407
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);
412                 }
413
414                 /* Create the debug execution thread to execute commands */
415
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);
424                 }
425         } else {
426                 acpi_gbl_db_thread_id = acpi_os_get_thread_id();
427         }
428
429         return_ACPI_STATUS(AE_OK);
430 }
431
432 ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
433
434 /*******************************************************************************
435  *
436  * FUNCTION:    acpi_terminate_debugger
437  *
438  * PARAMETERS:  None
439  *
440  * RETURN:      None
441  *
442  * DESCRIPTION: Stop debugger
443  *
444  ******************************************************************************/
445 void acpi_terminate_debugger(void)
446 {
447
448         /* Terminate the AML Debugger */
449
450         acpi_gbl_db_terminate_loop = TRUE;
451
452         if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
453
454                 /* Wait the AML Debugger threads */
455
456                 while (!acpi_gbl_db_threads_terminated) {
457                         acpi_os_sleep(100);
458                 }
459
460                 acpi_os_terminate_debugger();
461         }
462
463         if (acpi_gbl_db_buffer) {
464                 acpi_os_free(acpi_gbl_db_buffer);
465                 acpi_gbl_db_buffer = NULL;
466         }
467
468         /* Ensure that debug output is now disabled */
469
470         acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
471 }
472
473 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
474
475 /*******************************************************************************
476  *
477  * FUNCTION:    acpi_set_debugger_thread_id
478  *
479  * PARAMETERS:  thread_id       - Debugger thread ID
480  *
481  * RETURN:      None
482  *
483  * DESCRIPTION: Set debugger thread ID
484  *
485  ******************************************************************************/
486 void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
487 {
488         acpi_gbl_db_thread_id = thread_id;
489 }
490
491 ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)