Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/acpi/acpica/dbxface.c
26285 views
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
acpi_gbl_db_opt_no_region_support = FALSE;
413
414
acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
415
if (!acpi_gbl_db_buffer) {
416
return_ACPI_STATUS(AE_NO_MEMORY);
417
}
418
memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
419
420
/* Initial scope is the root */
421
422
acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
423
acpi_gbl_db_scope_buf[1] = 0;
424
acpi_gbl_db_scope_node = acpi_gbl_root_node;
425
426
/* Initialize user commands loop */
427
428
acpi_gbl_db_terminate_loop = FALSE;
429
430
/*
431
* If configured for multi-thread support, the debug executor runs in
432
* a separate thread so that the front end can be in another address
433
* space, environment, or even another machine.
434
*/
435
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
436
437
/* These were created with one unit, grab it */
438
439
status = acpi_os_initialize_debugger();
440
if (ACPI_FAILURE(status)) {
441
acpi_os_printf("Could not get debugger mutex\n");
442
return_ACPI_STATUS(status);
443
}
444
445
/* Create the debug execution thread to execute commands */
446
447
acpi_gbl_db_threads_terminated = FALSE;
448
status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
449
acpi_db_execute_thread, NULL);
450
if (ACPI_FAILURE(status)) {
451
ACPI_EXCEPTION((AE_INFO, status,
452
"Could not start debugger thread"));
453
acpi_gbl_db_threads_terminated = TRUE;
454
return_ACPI_STATUS(status);
455
}
456
} else {
457
acpi_gbl_db_thread_id = acpi_os_get_thread_id();
458
}
459
460
return_ACPI_STATUS(AE_OK);
461
}
462
463
ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
464
465
/*******************************************************************************
466
*
467
* FUNCTION: acpi_terminate_debugger
468
*
469
* PARAMETERS: None
470
*
471
* RETURN: None
472
*
473
* DESCRIPTION: Stop debugger
474
*
475
******************************************************************************/
476
void acpi_terminate_debugger(void)
477
{
478
479
/* Terminate the AML Debugger */
480
481
acpi_gbl_db_terminate_loop = TRUE;
482
483
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
484
485
/* Wait the AML Debugger threads */
486
487
while (!acpi_gbl_db_threads_terminated) {
488
acpi_os_sleep(100);
489
}
490
491
acpi_os_terminate_debugger();
492
}
493
494
if (acpi_gbl_db_buffer) {
495
acpi_os_free(acpi_gbl_db_buffer);
496
acpi_gbl_db_buffer = NULL;
497
}
498
499
/* Ensure that debug output is now disabled */
500
501
acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
502
}
503
504
ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
505
506
/*******************************************************************************
507
*
508
* FUNCTION: acpi_set_debugger_thread_id
509
*
510
* PARAMETERS: thread_id - Debugger thread ID
511
*
512
* RETURN: None
513
*
514
* DESCRIPTION: Set debugger thread ID
515
*
516
******************************************************************************/
517
void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
518
{
519
acpi_gbl_db_thread_id = thread_id;
520
}
521
522
ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)
523
524