Loading drivers/acpi/Kconfig +14 −3 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/acpi/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/acpi/acpi_dbg.c 0 → 100644 +804 −0 Original line number Diff line number Diff line /* * ACPI AML interfacing support * * Copyright (C) 2015, Intel Corporation * Authors: 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 version 2 as * published by the Free Software Foundation. */ /* #define DEBUG */ #define pr_fmt(fmt) "ACPI : AML: " fmt #include <linux/kernel.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/poll.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/proc_fs.h> #include <linux/debugfs.h> #include <linux/circ_buf.h> #include <linux/acpi.h> #include "internal.h" #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) #define ACPI_AML_BUF_SIZE PAGE_SIZE #define circ_count(circ) \ (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_count_to_end(circ) \ (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_space(circ) \ (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_space_to_end(circ) \ (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define ACPI_AML_OPENED 0x0001 #define ACPI_AML_CLOSED 0x0002 #define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */ #define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */ #define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */ #define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */ #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER) #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN) #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN) #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED) struct acpi_aml_io { wait_queue_head_t wait; unsigned long flags; unsigned long users; struct mutex lock; struct task_struct *thread; char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); struct circ_buf out_crc; char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); struct circ_buf in_crc; acpi_osd_exec_callback function; void *context; unsigned long usages; }; static struct acpi_aml_io acpi_aml_io; static bool acpi_aml_initialized; static struct file *acpi_aml_active_reader; static struct dentry *acpi_aml_dentry; static inline bool __acpi_aml_running(void) { return acpi_aml_io.thread ? true : false; } static inline bool __acpi_aml_access_ok(unsigned long flag) { /* * The debugger interface is in opened state (OPENED && !CLOSED), * then it is allowed to access the debugger buffers from either * user space or the kernel space. * In addition, for the kernel space, only the debugger thread * (thread ID matched) is allowed to access. */ if (!(acpi_aml_io.flags & ACPI_AML_OPENED) || (acpi_aml_io.flags & ACPI_AML_CLOSED) || !__acpi_aml_running()) return false; if ((flag & ACPI_AML_KERN) && current != acpi_aml_io.thread) return false; return true; } static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag) { /* * Another read is not in progress and there is data in buffer * available for read. */ if (!(acpi_aml_io.flags & flag) && circ_count(circ)) return true; return false; } static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag) { /* * Another write is not in progress and there is buffer space * available for write. */ if (!(acpi_aml_io.flags & flag) && circ_space(circ)) return true; return false; } static inline bool __acpi_aml_busy(void) { if (acpi_aml_io.flags & ACPI_AML_BUSY) return true; return false; } static inline bool __acpi_aml_opened(void) { if (acpi_aml_io.flags & ACPI_AML_OPEN) return true; return false; } static inline bool __acpi_aml_used(void) { return acpi_aml_io.usages ? true : false; } static inline bool acpi_aml_running(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_running(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_busy(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_busy(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_used(void) { bool ret; /* * The usage count is prepared to avoid race conditions between the * starts and the stops of the debugger thread. */ mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_used(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_kern_readable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) || __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_kern_writable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) || __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_user_readable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) || __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_user_writable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) || __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER); mutex_unlock(&acpi_aml_io.lock); return ret; } static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag) { int ret = 0; mutex_lock(&acpi_aml_io.lock); if (!__acpi_aml_access_ok(flag)) { ret = -EFAULT; goto out; } if (!__acpi_aml_writable(circ, flag)) { ret = -EAGAIN; goto out; } acpi_aml_io.flags |= flag; out: mutex_unlock(&acpi_aml_io.lock); return ret; } static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag) { int ret = 0; mutex_lock(&acpi_aml_io.lock); if (!__acpi_aml_access_ok(flag)) { ret = -EFAULT; goto out; } if (!__acpi_aml_readable(circ, flag)) { ret = -EAGAIN; goto out; } acpi_aml_io.flags |= flag; out: mutex_unlock(&acpi_aml_io.lock); return ret; } static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup) { mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags &= ~flag; if (wakeup) wake_up_interruptible(&acpi_aml_io.wait); mutex_unlock(&acpi_aml_io.lock); } static int acpi_aml_write_kern(const char *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.out_crc; int n; char *p; ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN); if (IS_ERR_VALUE(ret)) return ret; /* sync tail before inserting logs */ smp_mb(); p = &crc->buf[crc->head]; n = min(len, circ_space_to_end(crc)); memcpy(p, buf, n); /* sync head after inserting logs */ smp_wmb(); crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true); return n; } static int acpi_aml_readb_kern(void) { int ret; struct circ_buf *crc = &acpi_aml_io.in_crc; char *p; ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN); if (IS_ERR_VALUE(ret)) return ret; /* sync head before removing cmds */ smp_rmb(); p = &crc->buf[crc->tail]; ret = (int)*p; /* sync tail before inserting cmds */ smp_mb(); crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true); return ret; } /* * acpi_aml_write_log() - Capture debugger output * @msg: the debugger output * * This function should be used to implement acpi_os_printf() to filter out * the debugger output and store the output into the debugger interface * buffer. Return the size of stored logs or errno. */ static ssize_t acpi_aml_write_log(const char *msg) { int ret = 0; int count = 0, size = 0; if (!acpi_aml_initialized) return -ENODEV; if (msg) count = strlen(msg); while (count > 0) { again: ret = acpi_aml_write_kern(msg + size, count); if (ret == -EAGAIN) { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_kern_writable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; break; } if (IS_ERR_VALUE(ret)) break; size += ret; count -= ret; } return size > 0 ? size : ret; } /* * acpi_aml_read_cmd() - Capture debugger input * @msg: the debugger input * @size: the size of the debugger input * * This function should be used to implement acpi_os_get_line() to capture * the debugger input commands and store the input commands into the * debugger interface buffer. Return the size of stored commands or errno. */ static ssize_t acpi_aml_read_cmd(char *msg, size_t count) { int ret = 0; int size = 0; /* * This is ensured by the running fact of the debugger thread * unless a bug is introduced. */ BUG_ON(!acpi_aml_initialized); while (count > 0) { again: /* * Check each input byte to find the end of the command. */ ret = acpi_aml_readb_kern(); if (ret == -EAGAIN) { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_kern_readable()); /* * We need to retry when the condition becomes * true. */ if (ret == 0) goto again; } if (IS_ERR_VALUE(ret)) break; *(msg + size) = (char)ret; size++; count--; if (ret == '\n') { /* * acpi_os_get_line() requires a zero terminated command * string. */ *(msg + size - 1) = '\0'; break; } } return size > 0 ? size : ret; } static int acpi_aml_thread(void *unsed) { acpi_osd_exec_callback function = NULL; void *context; mutex_lock(&acpi_aml_io.lock); if (acpi_aml_io.function) { acpi_aml_io.usages++; function = acpi_aml_io.function; context = acpi_aml_io.context; } mutex_unlock(&acpi_aml_io.lock); if (function) function(context); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.usages--; if (!__acpi_aml_used()) { acpi_aml_io.thread = NULL; wake_up(&acpi_aml_io.wait); } mutex_unlock(&acpi_aml_io.lock); return 0; } /* * acpi_aml_create_thread() - Create AML debugger thread * @function: the debugger thread callback * @context: the context to be passed to the debugger thread * * This function should be used to implement acpi_os_execute() which is * used by the ACPICA debugger to create the debugger thread. */ static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) { struct task_struct *t; mutex_lock(&acpi_aml_io.lock); acpi_aml_io.function = function; acpi_aml_io.context = context; mutex_unlock(&acpi_aml_io.lock); t = kthread_create(acpi_aml_thread, NULL, "aml"); if (IS_ERR(t)) { pr_err("Failed to create AML debugger thread.\n"); return PTR_ERR(t); } mutex_lock(&acpi_aml_io.lock); acpi_aml_io.thread = t; acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t); wake_up_process(t); mutex_unlock(&acpi_aml_io.lock); return 0; } static int acpi_aml_wait_command_ready(bool single_step, char *buffer, size_t length) { acpi_status status; if (single_step) acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); else acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); status = acpi_os_get_line(buffer, length, NULL); if (ACPI_FAILURE(status)) return -EINVAL; return 0; } static int acpi_aml_notify_command_complete(void) { return 0; } static int acpi_aml_open(struct inode *inode, struct file *file) { int ret = 0; acpi_status status; mutex_lock(&acpi_aml_io.lock); /* * The debugger interface is being closed, no new user is allowed * during this period. */ if (acpi_aml_io.flags & ACPI_AML_CLOSED) { ret = -EBUSY; goto err_lock; } if ((file->f_flags & O_ACCMODE) != O_WRONLY) { /* * Only one reader is allowed to initiate the debugger * thread. */ if (acpi_aml_active_reader) { ret = -EBUSY; goto err_lock; } else { pr_debug("Opening debugger reader.\n"); acpi_aml_active_reader = file; } } else { /* * No writer is allowed unless the debugger thread is * ready. */ if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) { ret = -ENODEV; goto err_lock; } } if (acpi_aml_active_reader == file) { pr_debug("Opening debugger interface.\n"); mutex_unlock(&acpi_aml_io.lock); pr_debug("Initializing debugger thread.\n"); status = acpi_initialize_debugger(); if (ACPI_FAILURE(status)) { pr_err("Failed to initialize debugger.\n"); ret = -EINVAL; goto err_exit; } pr_debug("Debugger thread initialized.\n"); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags |= ACPI_AML_OPENED; acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; pr_debug("Debugger interface opened.\n"); } acpi_aml_io.users++; err_lock: if (IS_ERR_VALUE(ret)) { if (acpi_aml_active_reader == file) acpi_aml_active_reader = NULL; } mutex_unlock(&acpi_aml_io.lock); err_exit: return ret; } static int acpi_aml_release(struct inode *inode, struct file *file) { mutex_lock(&acpi_aml_io.lock); acpi_aml_io.users--; if (file == acpi_aml_active_reader) { pr_debug("Closing debugger reader.\n"); acpi_aml_active_reader = NULL; pr_debug("Closing debugger interface.\n"); acpi_aml_io.flags |= ACPI_AML_CLOSED; /* * Wake up all user space/kernel space blocked * readers/writers. */ wake_up_interruptible(&acpi_aml_io.wait); mutex_unlock(&acpi_aml_io.lock); /* * Wait all user space/kernel space readers/writers to * stop so that ACPICA command loop of the debugger thread * should fail all its command line reads after this point. */ wait_event(acpi_aml_io.wait, !acpi_aml_busy()); /* * Then we try to terminate the debugger thread if it is * not terminated. */ pr_debug("Terminating debugger thread.\n"); acpi_terminate_debugger(); wait_event(acpi_aml_io.wait, !acpi_aml_used()); pr_debug("Debugger thread terminated.\n"); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags &= ~ACPI_AML_OPENED; } if (acpi_aml_io.users == 0) { pr_debug("Debugger interface closed.\n"); acpi_aml_io.flags &= ~ACPI_AML_CLOSED; } mutex_unlock(&acpi_aml_io.lock); return 0; } static int acpi_aml_read_user(char __user *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.out_crc; int n; char *p; ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); if (IS_ERR_VALUE(ret)) return ret; /* sync head before removing logs */ smp_rmb(); p = &crc->buf[crc->tail]; n = min(len, circ_count_to_end(crc)); if (copy_to_user(buf, p, n)) { ret = -EFAULT; goto out; } /* sync tail after removing logs */ smp_mb(); crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret)); return ret; } static ssize_t acpi_aml_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret = 0; int size = 0; if (!count) return 0; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; while (count > 0) { again: ret = acpi_aml_read_user(buf + size, count); if (ret == -EAGAIN) { if (file->f_flags & O_NONBLOCK) break; else { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_user_readable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; } } if (IS_ERR_VALUE(ret)) { if (!acpi_aml_running()) ret = 0; break; } if (ret) { size += ret; count -= ret; *ppos += ret; break; } } return size > 0 ? size : ret; } static int acpi_aml_write_user(const char __user *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.in_crc; int n; char *p; ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); if (IS_ERR_VALUE(ret)) return ret; /* sync tail before inserting cmds */ smp_mb(); p = &crc->buf[crc->head]; n = min(len, circ_space_to_end(crc)); if (copy_from_user(p, buf, n)) { ret = -EFAULT; goto out; } /* sync head after inserting cmds */ smp_wmb(); crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret)); return n; } static ssize_t acpi_aml_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret = 0; int size = 0; if (!count) return 0; if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; while (count > 0) { again: ret = acpi_aml_write_user(buf + size, count); if (ret == -EAGAIN) { if (file->f_flags & O_NONBLOCK) break; else { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_user_writable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; } } if (IS_ERR_VALUE(ret)) { if (!acpi_aml_running()) ret = 0; break; } if (ret) { size += ret; count -= ret; *ppos += ret; } } return size > 0 ? size : ret; } static unsigned int acpi_aml_poll(struct file *file, poll_table *wait) { int masks = 0; poll_wait(file, &acpi_aml_io.wait, wait); if (acpi_aml_user_readable()) masks |= POLLIN | POLLRDNORM; if (acpi_aml_user_writable()) masks |= POLLOUT | POLLWRNORM; return masks; } static const struct file_operations acpi_aml_operations = { .read = acpi_aml_read, .write = acpi_aml_write, .poll = acpi_aml_poll, .open = acpi_aml_open, .release = acpi_aml_release, .llseek = generic_file_llseek, }; static const struct acpi_debugger_ops acpi_aml_debugger = { .create_thread = acpi_aml_create_thread, .read_cmd = acpi_aml_read_cmd, .write_log = acpi_aml_write_log, .wait_command_ready = acpi_aml_wait_command_ready, .notify_command_complete = acpi_aml_notify_command_complete, }; int __init acpi_aml_init(void) { int ret = 0; if (!acpi_debugfs_dir) { ret = -ENOENT; goto err_exit; } /* Initialize AML IO interface */ mutex_init(&acpi_aml_io.lock); init_waitqueue_head(&acpi_aml_io.wait); acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; acpi_aml_dentry = debugfs_create_file("acpidbg", S_IFREG | S_IRUGO | S_IWUSR, acpi_debugfs_dir, NULL, &acpi_aml_operations); if (acpi_aml_dentry == NULL) { ret = -ENODEV; goto err_exit; } ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); if (ret) goto err_fs; acpi_aml_initialized = true; err_fs: if (ret) { debugfs_remove(acpi_aml_dentry); acpi_aml_dentry = NULL; } err_exit: return ret; } void __exit acpi_aml_exit(void) { if (acpi_aml_initialized) { acpi_unregister_debugger(&acpi_aml_debugger); if (acpi_aml_dentry) { debugfs_remove(acpi_aml_dentry); acpi_aml_dentry = NULL; } acpi_aml_initialized = false; } } module_init(acpi_aml_init); module_exit(acpi_aml_exit); MODULE_AUTHOR("Lv Zheng"); MODULE_DESCRIPTION("ACPI debugger userspace IO driver"); MODULE_LICENSE("GPL"); drivers/acpi/acpica/acdebug.h +25 −11 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -182,9 +188,13 @@ 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); Loading @@ -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 Loading Loading @@ -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); Loading drivers/acpi/acpica/acglobal.h +0 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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]); Loading @@ -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 */ /***************************************************************************** Loading Loading
drivers/acpi/Kconfig +14 −3 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/acpi/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/acpi/acpi_dbg.c 0 → 100644 +804 −0 Original line number Diff line number Diff line /* * ACPI AML interfacing support * * Copyright (C) 2015, Intel Corporation * Authors: 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 version 2 as * published by the Free Software Foundation. */ /* #define DEBUG */ #define pr_fmt(fmt) "ACPI : AML: " fmt #include <linux/kernel.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/poll.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/proc_fs.h> #include <linux/debugfs.h> #include <linux/circ_buf.h> #include <linux/acpi.h> #include "internal.h" #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) #define ACPI_AML_BUF_SIZE PAGE_SIZE #define circ_count(circ) \ (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_count_to_end(circ) \ (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_space(circ) \ (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define circ_space_to_end(circ) \ (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) #define ACPI_AML_OPENED 0x0001 #define ACPI_AML_CLOSED 0x0002 #define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */ #define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */ #define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */ #define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */ #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER) #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN) #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN) #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED) struct acpi_aml_io { wait_queue_head_t wait; unsigned long flags; unsigned long users; struct mutex lock; struct task_struct *thread; char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); struct circ_buf out_crc; char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); struct circ_buf in_crc; acpi_osd_exec_callback function; void *context; unsigned long usages; }; static struct acpi_aml_io acpi_aml_io; static bool acpi_aml_initialized; static struct file *acpi_aml_active_reader; static struct dentry *acpi_aml_dentry; static inline bool __acpi_aml_running(void) { return acpi_aml_io.thread ? true : false; } static inline bool __acpi_aml_access_ok(unsigned long flag) { /* * The debugger interface is in opened state (OPENED && !CLOSED), * then it is allowed to access the debugger buffers from either * user space or the kernel space. * In addition, for the kernel space, only the debugger thread * (thread ID matched) is allowed to access. */ if (!(acpi_aml_io.flags & ACPI_AML_OPENED) || (acpi_aml_io.flags & ACPI_AML_CLOSED) || !__acpi_aml_running()) return false; if ((flag & ACPI_AML_KERN) && current != acpi_aml_io.thread) return false; return true; } static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag) { /* * Another read is not in progress and there is data in buffer * available for read. */ if (!(acpi_aml_io.flags & flag) && circ_count(circ)) return true; return false; } static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag) { /* * Another write is not in progress and there is buffer space * available for write. */ if (!(acpi_aml_io.flags & flag) && circ_space(circ)) return true; return false; } static inline bool __acpi_aml_busy(void) { if (acpi_aml_io.flags & ACPI_AML_BUSY) return true; return false; } static inline bool __acpi_aml_opened(void) { if (acpi_aml_io.flags & ACPI_AML_OPEN) return true; return false; } static inline bool __acpi_aml_used(void) { return acpi_aml_io.usages ? true : false; } static inline bool acpi_aml_running(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_running(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_busy(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_busy(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_used(void) { bool ret; /* * The usage count is prepared to avoid race conditions between the * starts and the stops of the debugger thread. */ mutex_lock(&acpi_aml_io.lock); ret = __acpi_aml_used(); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_kern_readable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) || __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_kern_writable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) || __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_user_readable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) || __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER); mutex_unlock(&acpi_aml_io.lock); return ret; } static bool acpi_aml_user_writable(void) { bool ret; mutex_lock(&acpi_aml_io.lock); ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) || __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER); mutex_unlock(&acpi_aml_io.lock); return ret; } static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag) { int ret = 0; mutex_lock(&acpi_aml_io.lock); if (!__acpi_aml_access_ok(flag)) { ret = -EFAULT; goto out; } if (!__acpi_aml_writable(circ, flag)) { ret = -EAGAIN; goto out; } acpi_aml_io.flags |= flag; out: mutex_unlock(&acpi_aml_io.lock); return ret; } static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag) { int ret = 0; mutex_lock(&acpi_aml_io.lock); if (!__acpi_aml_access_ok(flag)) { ret = -EFAULT; goto out; } if (!__acpi_aml_readable(circ, flag)) { ret = -EAGAIN; goto out; } acpi_aml_io.flags |= flag; out: mutex_unlock(&acpi_aml_io.lock); return ret; } static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup) { mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags &= ~flag; if (wakeup) wake_up_interruptible(&acpi_aml_io.wait); mutex_unlock(&acpi_aml_io.lock); } static int acpi_aml_write_kern(const char *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.out_crc; int n; char *p; ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN); if (IS_ERR_VALUE(ret)) return ret; /* sync tail before inserting logs */ smp_mb(); p = &crc->buf[crc->head]; n = min(len, circ_space_to_end(crc)); memcpy(p, buf, n); /* sync head after inserting logs */ smp_wmb(); crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true); return n; } static int acpi_aml_readb_kern(void) { int ret; struct circ_buf *crc = &acpi_aml_io.in_crc; char *p; ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN); if (IS_ERR_VALUE(ret)) return ret; /* sync head before removing cmds */ smp_rmb(); p = &crc->buf[crc->tail]; ret = (int)*p; /* sync tail before inserting cmds */ smp_mb(); crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true); return ret; } /* * acpi_aml_write_log() - Capture debugger output * @msg: the debugger output * * This function should be used to implement acpi_os_printf() to filter out * the debugger output and store the output into the debugger interface * buffer. Return the size of stored logs or errno. */ static ssize_t acpi_aml_write_log(const char *msg) { int ret = 0; int count = 0, size = 0; if (!acpi_aml_initialized) return -ENODEV; if (msg) count = strlen(msg); while (count > 0) { again: ret = acpi_aml_write_kern(msg + size, count); if (ret == -EAGAIN) { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_kern_writable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; break; } if (IS_ERR_VALUE(ret)) break; size += ret; count -= ret; } return size > 0 ? size : ret; } /* * acpi_aml_read_cmd() - Capture debugger input * @msg: the debugger input * @size: the size of the debugger input * * This function should be used to implement acpi_os_get_line() to capture * the debugger input commands and store the input commands into the * debugger interface buffer. Return the size of stored commands or errno. */ static ssize_t acpi_aml_read_cmd(char *msg, size_t count) { int ret = 0; int size = 0; /* * This is ensured by the running fact of the debugger thread * unless a bug is introduced. */ BUG_ON(!acpi_aml_initialized); while (count > 0) { again: /* * Check each input byte to find the end of the command. */ ret = acpi_aml_readb_kern(); if (ret == -EAGAIN) { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_kern_readable()); /* * We need to retry when the condition becomes * true. */ if (ret == 0) goto again; } if (IS_ERR_VALUE(ret)) break; *(msg + size) = (char)ret; size++; count--; if (ret == '\n') { /* * acpi_os_get_line() requires a zero terminated command * string. */ *(msg + size - 1) = '\0'; break; } } return size > 0 ? size : ret; } static int acpi_aml_thread(void *unsed) { acpi_osd_exec_callback function = NULL; void *context; mutex_lock(&acpi_aml_io.lock); if (acpi_aml_io.function) { acpi_aml_io.usages++; function = acpi_aml_io.function; context = acpi_aml_io.context; } mutex_unlock(&acpi_aml_io.lock); if (function) function(context); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.usages--; if (!__acpi_aml_used()) { acpi_aml_io.thread = NULL; wake_up(&acpi_aml_io.wait); } mutex_unlock(&acpi_aml_io.lock); return 0; } /* * acpi_aml_create_thread() - Create AML debugger thread * @function: the debugger thread callback * @context: the context to be passed to the debugger thread * * This function should be used to implement acpi_os_execute() which is * used by the ACPICA debugger to create the debugger thread. */ static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) { struct task_struct *t; mutex_lock(&acpi_aml_io.lock); acpi_aml_io.function = function; acpi_aml_io.context = context; mutex_unlock(&acpi_aml_io.lock); t = kthread_create(acpi_aml_thread, NULL, "aml"); if (IS_ERR(t)) { pr_err("Failed to create AML debugger thread.\n"); return PTR_ERR(t); } mutex_lock(&acpi_aml_io.lock); acpi_aml_io.thread = t; acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t); wake_up_process(t); mutex_unlock(&acpi_aml_io.lock); return 0; } static int acpi_aml_wait_command_ready(bool single_step, char *buffer, size_t length) { acpi_status status; if (single_step) acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); else acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); status = acpi_os_get_line(buffer, length, NULL); if (ACPI_FAILURE(status)) return -EINVAL; return 0; } static int acpi_aml_notify_command_complete(void) { return 0; } static int acpi_aml_open(struct inode *inode, struct file *file) { int ret = 0; acpi_status status; mutex_lock(&acpi_aml_io.lock); /* * The debugger interface is being closed, no new user is allowed * during this period. */ if (acpi_aml_io.flags & ACPI_AML_CLOSED) { ret = -EBUSY; goto err_lock; } if ((file->f_flags & O_ACCMODE) != O_WRONLY) { /* * Only one reader is allowed to initiate the debugger * thread. */ if (acpi_aml_active_reader) { ret = -EBUSY; goto err_lock; } else { pr_debug("Opening debugger reader.\n"); acpi_aml_active_reader = file; } } else { /* * No writer is allowed unless the debugger thread is * ready. */ if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) { ret = -ENODEV; goto err_lock; } } if (acpi_aml_active_reader == file) { pr_debug("Opening debugger interface.\n"); mutex_unlock(&acpi_aml_io.lock); pr_debug("Initializing debugger thread.\n"); status = acpi_initialize_debugger(); if (ACPI_FAILURE(status)) { pr_err("Failed to initialize debugger.\n"); ret = -EINVAL; goto err_exit; } pr_debug("Debugger thread initialized.\n"); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags |= ACPI_AML_OPENED; acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; pr_debug("Debugger interface opened.\n"); } acpi_aml_io.users++; err_lock: if (IS_ERR_VALUE(ret)) { if (acpi_aml_active_reader == file) acpi_aml_active_reader = NULL; } mutex_unlock(&acpi_aml_io.lock); err_exit: return ret; } static int acpi_aml_release(struct inode *inode, struct file *file) { mutex_lock(&acpi_aml_io.lock); acpi_aml_io.users--; if (file == acpi_aml_active_reader) { pr_debug("Closing debugger reader.\n"); acpi_aml_active_reader = NULL; pr_debug("Closing debugger interface.\n"); acpi_aml_io.flags |= ACPI_AML_CLOSED; /* * Wake up all user space/kernel space blocked * readers/writers. */ wake_up_interruptible(&acpi_aml_io.wait); mutex_unlock(&acpi_aml_io.lock); /* * Wait all user space/kernel space readers/writers to * stop so that ACPICA command loop of the debugger thread * should fail all its command line reads after this point. */ wait_event(acpi_aml_io.wait, !acpi_aml_busy()); /* * Then we try to terminate the debugger thread if it is * not terminated. */ pr_debug("Terminating debugger thread.\n"); acpi_terminate_debugger(); wait_event(acpi_aml_io.wait, !acpi_aml_used()); pr_debug("Debugger thread terminated.\n"); mutex_lock(&acpi_aml_io.lock); acpi_aml_io.flags &= ~ACPI_AML_OPENED; } if (acpi_aml_io.users == 0) { pr_debug("Debugger interface closed.\n"); acpi_aml_io.flags &= ~ACPI_AML_CLOSED; } mutex_unlock(&acpi_aml_io.lock); return 0; } static int acpi_aml_read_user(char __user *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.out_crc; int n; char *p; ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); if (IS_ERR_VALUE(ret)) return ret; /* sync head before removing logs */ smp_rmb(); p = &crc->buf[crc->tail]; n = min(len, circ_count_to_end(crc)); if (copy_to_user(buf, p, n)) { ret = -EFAULT; goto out; } /* sync tail after removing logs */ smp_mb(); crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret)); return ret; } static ssize_t acpi_aml_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret = 0; int size = 0; if (!count) return 0; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; while (count > 0) { again: ret = acpi_aml_read_user(buf + size, count); if (ret == -EAGAIN) { if (file->f_flags & O_NONBLOCK) break; else { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_user_readable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; } } if (IS_ERR_VALUE(ret)) { if (!acpi_aml_running()) ret = 0; break; } if (ret) { size += ret; count -= ret; *ppos += ret; break; } } return size > 0 ? size : ret; } static int acpi_aml_write_user(const char __user *buf, int len) { int ret; struct circ_buf *crc = &acpi_aml_io.in_crc; int n; char *p; ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); if (IS_ERR_VALUE(ret)) return ret; /* sync tail before inserting cmds */ smp_mb(); p = &crc->buf[crc->head]; n = min(len, circ_space_to_end(crc)); if (copy_from_user(p, buf, n)) { ret = -EFAULT; goto out; } /* sync head after inserting cmds */ smp_wmb(); crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret)); return n; } static ssize_t acpi_aml_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret = 0; int size = 0; if (!count) return 0; if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; while (count > 0) { again: ret = acpi_aml_write_user(buf + size, count); if (ret == -EAGAIN) { if (file->f_flags & O_NONBLOCK) break; else { ret = wait_event_interruptible(acpi_aml_io.wait, acpi_aml_user_writable()); /* * We need to retry when the condition * becomes true. */ if (ret == 0) goto again; } } if (IS_ERR_VALUE(ret)) { if (!acpi_aml_running()) ret = 0; break; } if (ret) { size += ret; count -= ret; *ppos += ret; } } return size > 0 ? size : ret; } static unsigned int acpi_aml_poll(struct file *file, poll_table *wait) { int masks = 0; poll_wait(file, &acpi_aml_io.wait, wait); if (acpi_aml_user_readable()) masks |= POLLIN | POLLRDNORM; if (acpi_aml_user_writable()) masks |= POLLOUT | POLLWRNORM; return masks; } static const struct file_operations acpi_aml_operations = { .read = acpi_aml_read, .write = acpi_aml_write, .poll = acpi_aml_poll, .open = acpi_aml_open, .release = acpi_aml_release, .llseek = generic_file_llseek, }; static const struct acpi_debugger_ops acpi_aml_debugger = { .create_thread = acpi_aml_create_thread, .read_cmd = acpi_aml_read_cmd, .write_log = acpi_aml_write_log, .wait_command_ready = acpi_aml_wait_command_ready, .notify_command_complete = acpi_aml_notify_command_complete, }; int __init acpi_aml_init(void) { int ret = 0; if (!acpi_debugfs_dir) { ret = -ENOENT; goto err_exit; } /* Initialize AML IO interface */ mutex_init(&acpi_aml_io.lock); init_waitqueue_head(&acpi_aml_io.wait); acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; acpi_aml_dentry = debugfs_create_file("acpidbg", S_IFREG | S_IRUGO | S_IWUSR, acpi_debugfs_dir, NULL, &acpi_aml_operations); if (acpi_aml_dentry == NULL) { ret = -ENODEV; goto err_exit; } ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); if (ret) goto err_fs; acpi_aml_initialized = true; err_fs: if (ret) { debugfs_remove(acpi_aml_dentry); acpi_aml_dentry = NULL; } err_exit: return ret; } void __exit acpi_aml_exit(void) { if (acpi_aml_initialized) { acpi_unregister_debugger(&acpi_aml_debugger); if (acpi_aml_dentry) { debugfs_remove(acpi_aml_dentry); acpi_aml_dentry = NULL; } acpi_aml_initialized = false; } } module_init(acpi_aml_init); module_exit(acpi_aml_exit); MODULE_AUTHOR("Lv Zheng"); MODULE_DESCRIPTION("ACPI debugger userspace IO driver"); MODULE_LICENSE("GPL");
drivers/acpi/acpica/acdebug.h +25 −11 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -182,9 +188,13 @@ 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); Loading @@ -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 Loading Loading @@ -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); Loading
drivers/acpi/acpica/acglobal.h +0 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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]); Loading @@ -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 */ /***************************************************************************** Loading