Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 836d0830 authored by Lv Zheng's avatar Lv Zheng Committed by Rafael J. Wysocki
Browse files

ACPI / debugger: Add module support for ACPI debugger



This patch converts AML debugger into a loadable module.

Note that, it implements driver unloading at the level dependent on the
module reference count. Which means if ACPI debugger is being used by a
userspace program, "rmmod acpi_dbg" should result in failure.

Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 37645d65
Loading
Loading
Loading
Loading
+13 −3
Original line number Original line Diff line number Diff line
@@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED
config ACPI_DEBUGGER
config ACPI_DEBUGGER
	bool "AML debugger interface"
	bool "AML debugger interface"
	select ACPI_DEBUG
	select ACPI_DEBUG
	depends on DEBUG_FS
	help
	help
	  Enable in-kernel debugging of AML facilities: statistics, internal
	  Enable in-kernel debugging of AML facilities: statistics,
	  object dump, single step control method execution.
	  internal object dump, single step control method execution.
	  This is still under development, currently enabling this only
	  This is still under development, currently enabling this only
	  results in the compilation of the ACPICA debugger files.
	  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
config ACPI_SLEEP
	bool
	bool
	depends on SUSPEND || HIBERNATION
	depends on SUSPEND || HIBERNATION
+1 −1
Original line number Original line Diff line number Diff line
@@ -50,7 +50,6 @@ acpi-y += sysfs.o
acpi-y				+= property.o
acpi-y				+= property.o
acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
acpi-y				+= acpi_lpat.o
acpi-y				+= acpi_lpat.o
@@ -80,6 +79,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.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 has its own "processor." module_param namespace
processor-y			:= processor_driver.o
processor-y			:= processor_driver.o
+53 −27
Original line number Original line Diff line number Diff line
@@ -21,7 +21,7 @@
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/debugfs.h>
#include <linux/debugfs.h>
#include <linux/circ_buf.h>
#include <linux/circ_buf.h>
#include <linux/acpi_dbg.h>
#include <linux/acpi.h>
#include "internal.h"
#include "internal.h"


#define ACPI_AML_BUF_ALIGN	(sizeof (acpi_size))
#define ACPI_AML_BUF_ALIGN	(sizeof (acpi_size))
@@ -307,7 +307,7 @@ static int acpi_aml_readb_kern(void)
 * the debugger output and store the output into the debugger interface
 * the debugger output and store the output into the debugger interface
 * buffer. Return the size of stored logs or errno.
 * buffer. Return the size of stored logs or errno.
 */
 */
ssize_t acpi_aml_write_log(const char *msg)
static ssize_t acpi_aml_write_log(const char *msg)
{
{
	int ret = 0;
	int ret = 0;
	int count = 0, size = 0;
	int count = 0, size = 0;
@@ -337,7 +337,6 @@ ssize_t acpi_aml_write_log(const char *msg)
	}
	}
	return size > 0 ? size : ret;
	return size > 0 ? size : ret;
}
}
EXPORT_SYMBOL(acpi_aml_write_log);


/*
/*
 * acpi_aml_read_cmd() - Capture debugger input
 * acpi_aml_read_cmd() - Capture debugger input
@@ -348,7 +347,7 @@ EXPORT_SYMBOL(acpi_aml_write_log);
 * the debugger input commands and store the input commands into the
 * the debugger input commands and store the input commands into the
 * debugger interface buffer. Return the size of stored commands or errno.
 * debugger interface buffer. Return the size of stored commands or errno.
 */
 */
ssize_t acpi_aml_read_cmd(char *msg, size_t count)
static ssize_t acpi_aml_read_cmd(char *msg, size_t count)
{
{
	int ret = 0;
	int ret = 0;
	int size = 0;
	int size = 0;
@@ -390,7 +389,6 @@ ssize_t acpi_aml_read_cmd(char *msg, size_t count)
	}
	}
	return size > 0 ? size : ret;
	return size > 0 ? size : ret;
}
}
EXPORT_SYMBOL(acpi_aml_read_cmd);


static int acpi_aml_thread(void *unsed)
static int acpi_aml_thread(void *unsed)
{
{
@@ -427,7 +425,7 @@ static int acpi_aml_thread(void *unsed)
 * This function should be used to implement acpi_os_execute() which is
 * This function should be used to implement acpi_os_execute() which is
 * used by the ACPICA debugger to create the debugger thread.
 * used by the ACPICA debugger to create the debugger thread.
 */
 */
int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
{
{
	struct task_struct *t;
	struct task_struct *t;


@@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
	mutex_unlock(&acpi_aml_io.lock);
	mutex_unlock(&acpi_aml_io.lock);
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(acpi_aml_create_thread);


int acpi_aml_wait_command_ready(void)
static int acpi_aml_wait_command_ready(bool single_step,
				       char *buffer, size_t length)
{
{
	acpi_status status;
	acpi_status status;


	if (!acpi_gbl_method_executing)
	if (single_step)
		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
	else
		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
	else
		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);


	status = acpi_os_get_line(acpi_gbl_db_line_buf,
	status = acpi_os_get_line(buffer, length, NULL);
				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
	if (ACPI_FAILURE(status))
	if (ACPI_FAILURE(status))
		return -EINVAL;
		return -EINVAL;
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(acpi_aml_wait_command_ready);


int acpi_aml_notify_command_complete(void)
static int acpi_aml_notify_command_complete(void)
{
{
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(acpi_aml_notify_command_complete);


static int acpi_aml_open(struct inode *inode, struct file *file)
static int acpi_aml_open(struct inode *inode, struct file *file)
{
{
@@ -746,10 +741,23 @@ static const struct file_operations acpi_aml_operations = {
	.llseek		= generic_file_llseek,
	.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 __init acpi_aml_init(void)
{
{
	if (!acpi_debugfs_dir)
	int ret = 0;
		return -ENOENT;

	if (!acpi_debugfs_dir) {
		ret = -ENOENT;
		goto err_exit;
	}

	/* Initialize AML IO interface */
	/* Initialize AML IO interface */
	mutex_init(&acpi_aml_io.lock);
	mutex_init(&acpi_aml_io.lock);
	init_waitqueue_head(&acpi_aml_io.wait);
	init_waitqueue_head(&acpi_aml_io.wait);
@@ -759,21 +767,39 @@ int __init acpi_aml_init(void)
					      S_IFREG | S_IRUGO | S_IWUSR,
					      S_IFREG | S_IRUGO | S_IWUSR,
					      acpi_debugfs_dir, NULL,
					      acpi_debugfs_dir, NULL,
					      &acpi_aml_operations);
					      &acpi_aml_operations);
	if (acpi_aml_dentry == NULL)
	if (acpi_aml_dentry == NULL) {
		return -ENODEV;
		ret = -ENODEV;
		goto err_exit;
	}
	ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger);
	if (ret)
		goto err_fs;
	acpi_aml_initialized = true;
	acpi_aml_initialized = true;
	return 0;

err_fs:
	if (ret) {
		debugfs_remove(acpi_aml_dentry);
		acpi_aml_dentry = NULL;
	}
err_exit:
	return ret;
}
}


#if 0
void __exit acpi_aml_exit(void)
void __exit acpi_aml_exit(void)
{
{
	/* TODO: Stop the in kernel debugger */
	if (acpi_aml_initialized) {
	if (acpi_aml_dentry)
		acpi_unregister_debugger(&acpi_aml_debugger);
		if (acpi_aml_dentry) {
			debugfs_remove(acpi_aml_dentry);
			debugfs_remove(acpi_aml_dentry);
			acpi_aml_dentry = NULL;
		}
		acpi_aml_initialized = false;
		acpi_aml_initialized = false;
	}
	}
}


module_init(acpi_aml_init);
module_init(acpi_aml_init);
module_exit(acpi_aml_exit);
module_exit(acpi_aml_exit);
#endif

MODULE_AUTHOR("Lv Zheng");
MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
MODULE_LICENSE("GPL");
+1 −2
Original line number Original line Diff line number Diff line
@@ -37,7 +37,6 @@
#include <acpi/apei.h>
#include <acpi/apei.h>
#include <linux/dmi.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/acpi_dbg.h>


#include "internal.h"
#include "internal.h"


@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
	acpi_debugfs_init();
	acpi_debugfs_init();
	acpi_sleep_proc_init();
	acpi_sleep_proc_init();
	acpi_wakeup_device_init();
	acpi_wakeup_device_init();
	acpi_aml_init();
	acpi_debugger_init();
	return 0;
	return 0;
}
}


+201 −6
Original line number Original line Diff line number Diff line
@@ -40,7 +40,6 @@
#include <linux/list.h>
#include <linux/list.h>
#include <linux/jiffies.h>
#include <linux/jiffies.h>
#include <linux/semaphore.h>
#include <linux/semaphore.h>
#include <linux/acpi_dbg.h>


#include <asm/io.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
@@ -221,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...)
	acpi_os_vprintf(fmt, args);
	acpi_os_vprintf(fmt, args);
	va_end(args);
	va_end(args);
}
}
EXPORT_SYMBOL(acpi_os_printf);


void acpi_os_vprintf(const char *fmt, va_list args)
void acpi_os_vprintf(const char *fmt, va_list args)
{
{
@@ -235,7 +235,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
		printk(KERN_CONT "%s", buffer);
		printk(KERN_CONT "%s", buffer);
	}
	}
#else
#else
	if (acpi_aml_write_log(buffer) < 0)
	if (acpi_debugger_write_log(buffer) < 0)
		printk(KERN_CONT "%s", buffer);
		printk(KERN_CONT "%s", buffer);
#endif
#endif
}
}
@@ -1103,6 +1103,200 @@ static void acpi_os_execute_deferred(struct work_struct *work)
	kfree(dpc);
	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
 * FUNCTION:    acpi_os_execute
@@ -1130,7 +1324,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
			  function, context));
			  function, context));


	if (type == OSL_DEBUGGER_MAIN_THREAD) {
	if (type == OSL_DEBUGGER_MAIN_THREAD) {
		ret = acpi_aml_create_thread(function, context);
		ret = acpi_debugger_create_thread(function, context);
		if (ret) {
		if (ret) {
			pr_err("Call to kthread_create() failed.\n");
			pr_err("Call to kthread_create() failed.\n");
			status = AE_ERROR;
			status = AE_ERROR;
@@ -1380,7 +1574,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
#else
#else
	int ret;
	int ret;


	ret = acpi_aml_read_cmd(buffer, buffer_length);
	ret = acpi_debugger_read_cmd(buffer, buffer_length);
	if (ret < 0)
	if (ret < 0)
		return AE_ERROR;
		return AE_ERROR;
	if (bytes_read)
	if (bytes_read)
@@ -1389,12 +1583,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)


	return AE_OK;
	return AE_OK;
}
}
EXPORT_SYMBOL(acpi_os_get_line);


acpi_status acpi_os_wait_command_ready(void)
acpi_status acpi_os_wait_command_ready(void)
{
{
	int ret;
	int ret;


	ret = acpi_aml_wait_command_ready();
	ret = acpi_debugger_wait_command_ready();
	if (ret < 0)
	if (ret < 0)
		return AE_ERROR;
		return AE_ERROR;
	return AE_OK;
	return AE_OK;
@@ -1404,7 +1599,7 @@ acpi_status acpi_os_notify_command_complete(void)
{
{
	int ret;
	int ret;


	ret = acpi_aml_notify_command_complete();
	ret = acpi_debugger_notify_command_complete();
	if (ret < 0)
	if (ret < 0)
		return AE_ERROR;
		return AE_ERROR;
	return AE_OK;
	return AE_OK;
Loading