Commit b17629db authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'acpi-debug' into acpica

parents 74bf8efb 59adb398
......@@ -58,14 +58,25 @@ config ACPI_CCA_REQUIRED
bool
config ACPI_DEBUGGER
bool "AML debugger interface (EXPERIMENTAL)"
bool "AML debugger interface"
select ACPI_DEBUG
help
Enable in-kernel debugging of AML facilities: statistics, internal
object dump, single step control method execution.
Enable in-kernel debugging of AML facilities: statistics,
internal object dump, single step control method execution.
This is still under development, currently enabling this only
results in the compilation of the ACPICA debugger files.
if ACPI_DEBUGGER
config ACPI_DEBUGGER_USER
tristate "Userspace debugger accessiblity"
depends on DEBUG_FS
help
Export /sys/kernel/debug/acpi/acpidbg for userspace utilities
to access the debugger functionalities.
endif
config ACPI_SLEEP
bool
depends on SUSPEND || HIBERNATION
......
......@@ -79,6 +79,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
# processor has its own "processor." module_param namespace
processor-y := processor_driver.o
......
This diff is collapsed.
......@@ -80,9 +80,15 @@ struct acpi_db_execute_walk {
/*
* dbxface - external debugger interfaces
*/
acpi_status
acpi_db_single_step(struct acpi_walk_state *walk_state,
union acpi_parse_object *op, u32 op_type);
ACPI_DBR_DEPENDENT_RETURN_OK(acpi_status
acpi_db_single_step(struct acpi_walk_state
*walk_state,
union acpi_parse_object *op,
u32 op_type))
ACPI_DBR_DEPENDENT_RETURN_VOID(void
acpi_db_signal_break_point(struct
acpi_walk_state
*walk_state))
/*
* dbcmds - debug commands and output routines
......@@ -182,11 +188,15 @@ void acpi_db_display_method_info(union acpi_parse_object *op);
void acpi_db_decode_and_display_object(char *target, char *output_type);
void
acpi_db_display_result_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
ACPI_DBR_DEPENDENT_RETURN_VOID(void
acpi_db_display_result_object(union
acpi_operand_object
*obj_desc,
struct
acpi_walk_state
*walk_state))
acpi_status acpi_db_display_all_methods(char *display_count_arg);
acpi_status acpi_db_display_all_methods(char *display_count_arg);
void acpi_db_display_arguments(void);
......@@ -198,9 +208,13 @@ void acpi_db_display_calling_tree(void);
void acpi_db_display_object_type(char *object_arg);
void
acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
ACPI_DBR_DEPENDENT_RETURN_VOID(void
acpi_db_display_argument_object(union
acpi_operand_object
*obj_desc,
struct
acpi_walk_state
*walk_state))
/*
* dbexec - debugger control method execution
......@@ -257,7 +271,7 @@ acpi_db_command_dispatch(char *input_buffer,
void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context);
acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op);
acpi_status acpi_db_user_commands(void);
char *acpi_db_get_next_token(char *string,
char **next, acpi_object_type * return_type);
......
......@@ -326,7 +326,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
#ifdef ACPI_DEBUGGER
ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods);
......@@ -345,7 +344,6 @@ ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
/* These buffers should all be the same size */
ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]);
ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]);
ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]);
......@@ -360,9 +358,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
ACPI_GLOBAL(u32, acpi_gbl_num_objects);
ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready);
ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_complete);
#endif /* ACPI_DEBUGGER */
/*****************************************************************************
......
......@@ -400,17 +400,6 @@
#define ACPI_HW_OPTIONAL_FUNCTION(addr) NULL
#endif
/*
* Some code only gets executed when the debugger is built in.
* Note that this is entirely independent of whether the
* DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not.
*/
#ifdef ACPI_DEBUGGER
#define ACPI_DEBUGGER_EXEC(a) a
#else
#define ACPI_DEBUGGER_EXEC(a)
#endif
/*
* Macros used for ACPICA utilities only
*/
......
......@@ -679,6 +679,12 @@ acpi_db_display_result_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
#ifndef ACPI_APPLICATION
if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
return;
}
#endif
/* Only display if single stepping */
if (!acpi_gbl_cm_single_step) {
......@@ -708,6 +714,12 @@ acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
#ifndef ACPI_APPLICATION
if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
return;
}
#endif
if (!acpi_gbl_cm_single_step) {
return;
}
......
......@@ -53,8 +53,6 @@ static u32 acpi_db_get_line(char *input_buffer);
static u32 acpi_db_match_command(char *user_command);
static void acpi_db_single_thread(void);
static void acpi_db_display_command_info(char *command, u8 display_all);
static void acpi_db_display_help(char *command);
......@@ -1149,55 +1147,16 @@ acpi_db_command_dispatch(char *input_buffer,
void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
{
acpi_status status = AE_OK;
acpi_status Mstatus;
while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) {
acpi_gbl_method_executing = FALSE;
acpi_gbl_step_to_next_call = FALSE;
Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(Mstatus)) {
return;
}
status =
acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL);
acpi_os_release_mutex(acpi_gbl_db_command_complete);
}
(void)acpi_db_user_commands();
acpi_gbl_db_threads_terminated = TRUE;
}
/*******************************************************************************
*
* FUNCTION: acpi_db_single_thread
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Debugger execute thread. Waits for a command line, then
* simply dispatches it.
*
******************************************************************************/
static void acpi_db_single_thread(void)
{
acpi_gbl_method_executing = FALSE;
acpi_gbl_step_to_next_call = FALSE;
(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL);
}
/*******************************************************************************
*
* FUNCTION: acpi_db_user_commands
*
* PARAMETERS: prompt - User prompt (depends on mode)
* op - Current executing parse op
* PARAMETERS: None
*
* RETURN: None
*
......@@ -1206,7 +1165,7 @@ static void acpi_db_single_thread(void)
*
******************************************************************************/
acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
acpi_status acpi_db_user_commands(void)
{
acpi_status status = AE_OK;
......@@ -1216,52 +1175,31 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
while (!acpi_gbl_db_terminate_loop) {
/* Force output to console until a command is entered */
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
/* Wait the readiness of the command */
/* Different prompt if method is executing */
if (!acpi_gbl_method_executing) {
acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
} else {
acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
status = acpi_os_wait_command_ready();
if (ACPI_FAILURE(status)) {
break;
}
/* Get the user input line */
/* Just call to the command line interpreter */
status = acpi_os_get_line(acpi_gbl_db_line_buf,
ACPI_DB_LINE_BUFFER_SIZE, NULL);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"While parsing command line"));
return (status);
}
acpi_gbl_method_executing = FALSE;
acpi_gbl_step_to_next_call = FALSE;
/* Check for single or multithreaded debug */
(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
NULL);
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
/*
* Signal the debug thread that we have a command to execute,
* and wait for the command to complete.
*/
acpi_os_release_mutex(acpi_gbl_db_command_ready);
if (ACPI_FAILURE(status)) {
return (status);
}
/* Notify the completion of the command */
status =
acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
ACPI_WAIT_FOREVER);
status = acpi_os_notify_command_complete();
if (ACPI_FAILURE(status)) {
return (status);
}
} else {
/* Just call to the command line interpreter */
acpi_db_single_thread();
break;
}
}
if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
}
return (status);
}
......@@ -85,46 +85,21 @@ acpi_db_start_command(struct acpi_walk_state *walk_state,
acpi_gbl_method_executing = TRUE;
status = AE_CTRL_TRUE;
while (status == AE_CTRL_TRUE) {
if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) {
/* Handshake with the front-end that gets user command lines */
while (status == AE_CTRL_TRUE) {
acpi_os_release_mutex(acpi_gbl_db_command_complete);
/* Notify the completion of the command */
status =
acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
ACPI_WAIT_FOREVER);
status = acpi_os_notify_command_complete();
if (ACPI_FAILURE(status)) {
return (status);
}
} else {
/* Single threaded, we must get a command line ourselves */
/* Force output to console until a command is entered */
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
/* Different prompt if method is executing */
if (!acpi_gbl_method_executing) {
acpi_os_printf("%1c ",
ACPI_DEBUGGER_COMMAND_PROMPT);
} else {
acpi_os_printf("%1c ",
ACPI_DEBUGGER_EXECUTE_PROMPT);
goto error_exit;
}
/* Get the user input line */
/* Wait the readiness of the command */
status = acpi_os_get_line(acpi_gbl_db_line_buf,
ACPI_DB_LINE_BUFFER_SIZE,
NULL);
status = acpi_os_wait_command_ready();
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"While parsing command line"));
return (status);
}
goto error_exit;
}
status =
......@@ -134,9 +109,44 @@ acpi_db_start_command(struct acpi_walk_state *walk_state,
/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
error_exit:
if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
ACPI_EXCEPTION((AE_INFO, status,
"While parsing/handling command line"));
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_db_signal_break_point
*
* PARAMETERS: walk_state - Current walk
*
* RETURN: Status
*
* DESCRIPTION: Called for AML_BREAK_POINT_OP
*
******************************************************************************/
void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)
{
#ifndef ACPI_APPLICATION
if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
return;
}
#endif
/*
* Set the single-step flag. This will cause the debugger (if present)
* to break to the console within the AML debugger at the start of the
* next AML instruction.
*/
acpi_gbl_cm_single_step = TRUE;
acpi_os_printf("**break** Executed AML BreakPoint opcode\n");
}
/*******************************************************************************
*
* FUNCTION: acpi_db_single_step
......@@ -420,15 +430,7 @@ acpi_status acpi_initialize_debugger(void)
/* These were created with one unit, grab it */
status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
acpi_os_printf("Could not get debugger mutex\n");
return_ACPI_STATUS(status);
}
status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
ACPI_WAIT_FOREVER);
status = acpi_os_initialize_command_signals();
if (ACPI_FAILURE(status)) {
acpi_os_printf("Could not get debugger mutex\n");
return_ACPI_STATUS(status);
......@@ -473,13 +475,14 @@ void acpi_terminate_debugger(void)
acpi_gbl_db_terminate_loop = TRUE;
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
acpi_os_release_mutex(acpi_gbl_db_command_ready);
/* Wait the AML Debugger threads */
while (!acpi_gbl_db_threads_terminated) {
acpi_os_sleep(100);
}
acpi_os_terminate_command_signals();
}
if (acpi_gbl_db_buffer) {
......
......@@ -47,6 +47,7 @@
#include "amlcode.h"
#include "acdispat.h"
#include "acinterp.h"
#include "acdebug.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dscontrol")
......@@ -348,14 +349,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
case AML_BREAK_POINT_OP:
/*
* Set the single-step flag. This will cause the debugger (if present)
* to break to the console within the AML debugger at the start of the
* next AML instruction.
*/
ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
ACPI_DEBUGGER_EXEC(acpi_os_printf
("**break** Executed AML BreakPoint opcode\n"));
acpi_db_signal_break_point(walk_state);
/* Call to the OSL in case OS wants a piece of the action */
......
......@@ -605,8 +605,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
(obj_desc, walk_state));
acpi_db_display_argument_object(obj_desc, walk_state);
} else {
/* Check for null name case */
......@@ -638,10 +638,11 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Argument previously created, already stacked\n"));
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
(walk_state->
operands[walk_state->num_operands -
1], walk_state));
acpi_db_display_argument_object(walk_state->
operands[walk_state->
num_operands -
1],
walk_state);
/*
* Use value that was already previously returned
......@@ -685,8 +686,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
(obj_desc, walk_state));
acpi_db_display_argument_object(obj_desc, walk_state);
}
return_ACPI_STATUS(AE_OK);
......
......@@ -178,8 +178,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
/* Break to debugger to display result */
ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
(local_obj_desc, walk_state));
acpi_db_display_result_object(local_obj_desc, walk_state);
/*
* Delete the predicate result object (we know that
......@@ -386,11 +385,10 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Call debugger for single step support (DEBUG build only) */
ACPI_DEBUGGER_EXEC(status =
acpi_db_single_step(walk_state, op, op_class));
ACPI_DEBUGGER_EXEC(if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);}
) ;
status = acpi_db_single_step(walk_state, op, op_class);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Decode the Opcode Class */
......@@ -728,8 +726,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Break to debugger to display result */
ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
(walk_state->result_obj, walk_state));
acpi_db_display_result_object(walk_state->result_obj,
walk_state);
/*
* Delete the result op if and only if:
......
......@@ -111,17 +111,6 @@ acpi_status acpi_ut_mutex_initialize(void)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
#ifdef ACPI_DEBUGGER
/* Debugger Support */
status = acpi_os_create_mutex(&acpi_gbl_db_command_ready);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status = acpi_os_create_mutex(&acpi_gbl_db_command_complete);
#endif
return_ACPI_STATUS(status);
}
......@@ -162,12 +151,6 @@ void acpi_ut_mutex_terminate(void)
/* Delete the reader/writer lock */
acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock);
#ifdef ACPI_DEBUGGER
acpi_os_delete_mutex(acpi_gbl_db_command_ready);
acpi_os_delete_mutex(acpi_gbl_db_command_complete);
#endif
return_VOID;
}
......
......@@ -1094,6 +1094,7 @@ static int __init acpi_init(void)
acpi_debugfs_init();
acpi_sleep_proc_init();
acpi_wakeup_device_init();
acpi_debugger_init();
return 0;
}
......
......@@ -220,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...)
acpi_os_vprintf(fmt, args);
va_end(args);
}
EXPORT_SYMBOL(acpi_os_printf);
void acpi_os_vprintf(const char *fmt, va_list args)
{
......@@ -234,6 +235,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
printk(KERN_CONT "%s", buffer);
}
#else
if (acpi_debugger_write_log(buffer) < 0)
printk(KERN_CONT "%s", buffer);
#endif
}
......@@ -1101,6 +1103,200 @@ static void acpi_os_execute_deferred(struct work_struct *work)
kfree(dpc);
}
#ifdef CONFIG_ACPI_DEBUGGER
static struct acpi_debugger acpi_debugger;
static bool acpi_debugger_initialized;
int acpi_register_debugger(struct module *owner,
const struct acpi_debugger_ops *ops)
{
int ret = 0;
mutex_lock(&acpi_debugger.lock);
if (acpi_debugger.ops) {
ret = -EBUSY;
goto err_lock;
}
acpi_debugger.owner = owner;
acpi_debugger.ops = ops;
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
EXPORT_SYMBOL(acpi_register_debugger);
void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
{
mutex_lock(&acpi_debugger.lock);
if (ops == acpi_debugger.ops) {
acpi_debugger.ops = NULL;
acpi_debugger.owner = NULL;
}
mutex_unlock(&acpi_debugger.lock);
}
EXPORT_SYMBOL(acpi_unregister_debugger);
int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context)
{
int ret;
int (*func)(acpi_osd_exec_callback, void *);
struct module *owner;
if (!acpi_debugger_initialized)
return -ENODEV;
mutex_lock(&acpi_debugger.lock);
if (!acpi_debugger.ops) {
ret = -ENODEV;
goto err_lock;
}
if (!try_module_get(acpi_debugger.owner)) {
ret = -ENODEV;
goto err_lock;
}
func = acpi_debugger.ops->create_thread;
owner = acpi_debugger.owner;
mutex_unlock(&acpi_debugger.lock);
ret = func(function, context);
mutex_lock(&acpi_debugger.lock);
module_put(owner);
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
ssize_t acpi_debugger_write_log(const char *msg)
{
ssize_t ret;
ssize_t (*func)(const char *);
struct module *owner;
if (!acpi_debugger_initialized)
return -ENODEV;
mutex_lock(&acpi_debugger.lock);
if (!acpi_debugger.ops) {
ret = -ENODEV;
goto err_lock;
}
if (!try_module_get(acpi_debugger.owner)) {
ret = -ENODEV;
goto err_lock;
}
func = acpi_debugger.ops->write_log;
owner = acpi_debugger.owner;
mutex_unlock(&acpi_debugger.lock);
ret = func(msg);
mutex_lock(&acpi_debugger.lock);
module_put(owner);
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length)
{
ssize_t ret;
ssize_t (*func)(char *, size_t);
struct module *owner;
if (!acpi_debugger_initialized)
return -ENODEV;
mutex_lock(&acpi_debugger.lock);
if (!acpi_debugger.ops) {
ret = -ENODEV;
goto err_lock;
}
if (!try_module_get(acpi_debugger.owner)) {
ret = -ENODEV;
goto err_lock;
}
func = acpi_debugger.ops->read_cmd;
owner = acpi_debugger.owner;
mutex_unlock(&acpi_debugger.lock);
ret = func(buffer, buffer_length);
mutex_lock(&acpi_debugger.lock);
module_put(owner);
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
int acpi_debugger_wait_command_ready(void)
{
int ret;
int (*func)(bool, char *, size_t);
struct module *owner;
if (!acpi_debugger_initialized)
return -ENODEV;
mutex_lock(&acpi_debugger.lock);
if (!acpi_debugger.ops) {
ret = -ENODEV;
goto err_lock;
}
if (!try_module_get(acpi_debugger.owner)) {
ret = -ENODEV;
goto err_lock;
}
func = acpi_debugger.ops->wait_command_ready;
owner = acpi_debugger.owner;
mutex_unlock(&acpi_debugger.lock);
ret = func(acpi_gbl_method_executing,
acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE);
mutex_lock(&acpi_debugger.lock);
module_put(owner);
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
int acpi_debugger_notify_command_complete(void)
{
int ret;
int (*func)(void);
struct module *owner;
if (!acpi_debugger_initialized)
return -ENODEV;
mutex_lock(&acpi_debugger.lock);
if (!acpi_debugger.ops) {
ret = -ENODEV;
goto err_lock;
}
if (!try_module_get(acpi_debugger.owner)) {
ret = -ENODEV;
goto err_lock;
}
func = acpi_debugger.ops->notify_command_complete;
owner = acpi_debugger.owner;
mutex_unlock(&acpi_debugger.lock);
ret = func();
mutex_lock(&acpi_debugger.lock);
module_put(owner);
err_lock:
mutex_unlock(&acpi_debugger.lock);
return ret;
}
int __init acpi_debugger_init(void)
{
mutex_init(&acpi_debugger.lock);
acpi_debugger_initialized = true;
return 0;
}
#endif
/*******************************************************************************
*
* FUNCTION: acpi_os_execute
......@@ -1127,6 +1323,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
if (type == OSL_DEBUGGER_MAIN_THREAD) {
ret = acpi_debugger_create_thread(function, context);
if (ret) {
pr_err("Call to kthread_create() failed.\n");
status = AE_ERROR;
}
goto out_thread;
}
/*
* Allocate/initialize DPC structure. Note that this memory will be
* freed by the callee. The kernel handles the work_struct list in a
......@@ -1151,11 +1356,17 @@ acpi_status acpi_os_execute(acpi_execute_type type,
if (type == OSL_NOTIFY_HANDLER) {
queue = kacpi_notify_wq;
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
} else {
} else if (type == OSL_GPE_HANDLER) {
queue = kacpid_wq;
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
} else {
pr_err("Unsupported os_execute type %d.\n", type);
status = AE_ERROR;
}
if (ACPI_FAILURE(status))
goto err_workqueue;
/*
* On some machines, a software-initiated SMI causes corruption unless
* the SMI runs on CPU 0. An SMI can be initiated by any AML, but
......@@ -1164,13 +1375,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
* queueing on CPU 0.
*/
ret = queue_work_on(0, queue, &dpc->work);
if (!ret) {
printk(KERN_ERR PREFIX
"Call to queue_work() failed.\n");
status = AE_ERROR;
kfree(dpc);
}
err_workqueue:
if (ACPI_FAILURE(status))
kfree(dpc);
out_thread:
return status;
}
EXPORT_SYMBOL(acpi_os_execute);
......@@ -1358,10 +1571,39 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
chars = strlen(buffer) - 1;
buffer[chars] = '\0';
}
#else
int ret;
ret = acpi_debugger_read_cmd(buffer, buffer_length);
if (ret < 0)
return AE_ERROR;
if (bytes_read)
*bytes_read = ret;
#endif
return AE_OK;
}
EXPORT_SYMBOL(acpi_os_get_line);
acpi_status acpi_os_wait_command_ready(void)
{
int ret;
ret = acpi_debugger_wait_command_ready();
if (ret < 0)
return AE_ERROR;
return AE_OK;
}
acpi_status acpi_os_notify_command_complete(void)
{
int ret;
ret = acpi_debugger_notify_command_complete();
if (ret < 0)
return AE_ERROR;
return AE_OK;
}
acpi_status acpi_os_signal(u32 function, void *info)
{
......
......@@ -349,12 +349,28 @@ void acpi_os_redirect_output(void *destination);
#endif
/*
* Debug input
* Debug IO
*/
#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line
acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read);
#endif
#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
acpi_status acpi_os_initialize_command_signals(void);
#endif
#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
void acpi_os_terminate_command_signals(void);
#endif
#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
acpi_status acpi_os_wait_command_ready(void);
#endif
#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
acpi_status acpi_os_notify_command_complete(void);
#endif
/*
* Obtain ACPI table(s)
*/
......
......@@ -263,6 +263,15 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_layer, ACPI_TRACE_LAYER_DEFAULT);
ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT);
ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0);
/*
* Debugger command handshake globals. Host OSes need to access these
* variables to implement their own command handshake mechanism.
*/
#ifdef ACPI_DEBUGGER
ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
#endif
/*
* Other miscellaneous globals
*/
......@@ -366,6 +375,29 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running);
#endif /* ACPI_APPLICATION */
/*
* Debugger prototypes
*
* All interfaces used by debugger will be configured
* out of the ACPICA build unless the ACPI_DEBUGGER
* flag is defined.
*/
#ifdef ACPI_DEBUGGER
#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \
ACPI_EXTERNAL_RETURN_OK(prototype)
#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \
ACPI_EXTERNAL_RETURN_VOID(prototype)
#else
#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \
static ACPI_INLINE prototype {return(AE_OK);}
#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \
static ACPI_INLINE prototype {return;}
#endif /* ACPI_DEBUGGER */
/*****************************************************************************
*
* ACPICA public interface prototypes
......@@ -929,6 +961,8 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
void **data,
void (*callback)(void *)))
void acpi_run_debugger(char *batch_buffer);
void acpi_set_debugger_thread_id(acpi_thread_id thread_id);
#endif /* __ACXFACE_H__ */
......@@ -150,6 +150,8 @@
*/
#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable
#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable
#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
/*
* OSL interfaces used by utilities
......
......@@ -129,6 +129,15 @@ static inline u8 acpi_os_readable(void *pointer, acpi_size length)
return TRUE;
}
static inline acpi_status acpi_os_initialize_command_signals(void)
{
return AE_OK;
}
static inline void acpi_os_terminate_command_signals(void)
{
}
/*
* OSL interfaces added by Linux
*/
......
......@@ -37,6 +37,8 @@
#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/dynamic_debug.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
......@@ -119,6 +121,75 @@ typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table);
typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header,
const unsigned long end);
/* Debugger support */
struct acpi_debugger_ops {
int (*create_thread)(acpi_osd_exec_callback function, void *context);
ssize_t (*write_log)(const char *msg);
ssize_t (*read_cmd)(char *buffer, size_t length);
int (*wait_command_ready)(bool single_step, char *buffer, size_t length);
int (*notify_command_complete)(void);
};
struct acpi_debugger {
const struct acpi_debugger_ops *ops;
struct module *owner;
struct mutex lock;
};
#ifdef CONFIG_ACPI_DEBUGGER
int __init acpi_debugger_init(void);
int acpi_register_debugger(struct module *owner,
const struct acpi_debugger_ops *ops);
void acpi_unregister_debugger(const struct acpi_debugger_ops *ops);
int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context);
ssize_t acpi_debugger_write_log(const char *msg);
ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length);
int acpi_debugger_wait_command_ready(void);
int acpi_debugger_notify_command_complete(void);
#else
static inline int acpi_debugger_init(void)
{
return -ENODEV;
}
static inline int acpi_register_debugger(struct module *owner,
const struct acpi_debugger_ops *ops)
{
return -ENODEV;
}
static inline void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
{
}
static inline int acpi_debugger_create_thread(acpi_osd_exec_callback function,
void *context)
{
return -ENODEV;
}
static inline int acpi_debugger_write_log(const char *msg)
{
return -ENODEV;
}
static inline int acpi_debugger_read_cmd(char *buffer, u32 buffer_length)
{
return -ENODEV;
}
static inline int acpi_debugger_wait_command_ready(void)
{
return -ENODEV;
}
static inline int acpi_debugger_notify_command_complete(void)
{
return -ENODEV;
}
#endif
#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
void acpi_initrd_override(void *data, size_t size);
#else
......
......@@ -10,18 +10,18 @@
include ../../scripts/Makefile.include
all: acpidump ec
clean: acpidump_clean ec_clean
install: acpidump_install ec_install
uninstall: acpidump_uninstall ec_uninstall
all: acpidbg acpidump ec
clean: acpidbg_clean acpidump_clean ec_clean
install: acpidbg_install acpidump_install ec_install
uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall
acpidump ec: FORCE
acpidbg acpidump ec: FORCE
$(call descend,tools/$@,all)
acpidump_clean ec_clean:
acpidbg_clean acpidump_clean ec_clean:
$(call descend,tools/$(@:_clean=),clean)
acpidump_install ec_install:
acpidbg_install acpidump_install ec_install:
$(call descend,tools/$(@:_install=),install)
acpidump_uninstall ec_uninstall:
acpidbg_uninstall acpidump_uninstall ec_uninstall:
$(call descend,tools/$(@:_uninstall=),uninstall)
.PHONY: FORCE
# tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile
#
# Copyright (c) 2015, Intel Corporation
# Author: Lv Zheng <lv.zheng@intel.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License.
include ../../Makefile.config
TOOL = acpidbg
vpath %.c \
../../../../../drivers/acpi/acpica\
../../common\
../../os_specific/service_layers\
.
CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
-I.\
-I../../../../../drivers/acpi/acpica\
-I../../../../../include
LDFLAGS += -lpthread
TOOL_OBJS = \
acpidbg.o
include ../../Makefile.rules
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment