All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/14] ACPICA: 20150930 Release
       [not found] <8c1016ca8a570ba7c7a1c9f0f88d73cd83cea490>
@ 2015-10-19  2:24   ` Lv Zheng
  2015-11-06  6:46   ` Lv Zheng
  1 sibling, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The 20150930 ACPICA kernel-resident subsystem updates are linuxized based
on the linux-pm/linux-next branch.

The patchset has passed the following build/boot tests.
Build tests are performed as follows:
1. i386 + allyes
2. i386 + allno
3. i386 + default + ACPI_DEBUGGER=y
4. i386 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
5. i386 + default + ACPI_DEBUG=n + ACPI=y
6. i386 + default + ACPI=n
7. x86_64 + allyes
8. x86_64 + allno
9. x86_64 + default + ACPI_DEBUGGER=y
10.x86_64 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
11.x86_64 + default + ACPI_DEBUG=n + ACPI=y
12.x86_64 + default + ACPI=n
Boot tests are performed as follows:
1. i386 + default + ACPI_DEBUGGER=y
2. x86_64 + default + ACPI_DEBUGGER=y
Where:
1. i386: machine named as "Dell Inspiron Mini 1010"
2. x86_64: machine named as "HP Compaq 8200 Elite SFF PC"
3. default: kernel configuration with following items enabled:
   All hardware drivers related to the machines of i386/x86_64
   All "drivers/acpi" configurations
   All "drivers/platform" drivers
   All other drivers that link the APIs provided by ACPICA subsystem

The divergences checking result:
Before applying (20150818 Release):
  517 lines
After applying (20150930 Release):
  517 lines

Note there are still 2 ACPICA debugger patches not released during this
release cycle, so the debugger IO driver is not released in this cycle. In
this series the ACPICA debugger core is compile time enabled as all ACPICA
debugger files can be built with ACPI_DEBUGGER=y, but not runtime enabled
as there is no invocations calling ACPICA debugger APIs and its required
OSls are just stubs. The embedded debugger invocation acpi_db_single_step()
is also stubbed via debugger thread ID support.

Bob Moore (8):
  ACPICA: Remove unnecessary conditional compilation.
  ACPICA: iASL: Add symbolic operator support for Index() operator.
  ACPICA: Update exception code for "file not found" error
  ACPICA: Debugger: Update mutexes used for multithreaded debugger
  ACPICA: Update NFIT table to rename a flags field
  ACPICA: Improve typechecking, both compile-time and runtime
  ACPICA: iASL: General cleanup of the file suffix #defines
  ACPICA: Update version to 20150930

Lv Zheng (6):
  ACPICA: Linuxize: Export debugger files to Linux
  ACPICA: Debugger: Fix "quit/exit" command by cleaning up user
    commands termination logic
  ACPICA: Debugger: Fix "terminate" command by cleaning up subsystem
    shutdown logic
  ACPICA: Debugger: Add thread ID support so that single step mode can
    only apply to the debugger thread
  ACPI: Enable build of AML interpreter debugger
  ACPICA: Debugger: Fix dead lock issue ocurred in single stepping mode

 drivers/acpi/Kconfig                      |    9 +
 drivers/acpi/acpica/Makefile              |   18 +-
 drivers/acpi/acpica/acapps.h              |    2 +-
 drivers/acpi/acpica/acdebug.h             |    6 +
 drivers/acpi/acpica/acglobal.h            |    7 +-
 drivers/acpi/acpica/acinterp.h            |    2 -
 drivers/acpi/acpica/aclocal.h             |   22 +-
 drivers/acpi/acpica/acnamesp.h            |    4 -
 drivers/acpi/acpica/acopcode.h            |    4 +-
 drivers/acpi/acpica/acparser.h            |    4 -
 drivers/acpi/acpica/acutils.h             |    2 -
 drivers/acpi/acpica/amlcode.h             |   11 +-
 drivers/acpi/acpica/dbcmds.c              | 1187 +++++++++++++++++++++++++++
 drivers/acpi/acpica/dbconvert.c           |  484 +++++++++++
 drivers/acpi/acpica/dbdisply.c            | 1108 +++++++++++++++++++++++++
 drivers/acpi/acpica/dbexec.c              |  764 +++++++++++++++++
 drivers/acpi/acpica/dbfileio.c            |  256 ++++++
 drivers/acpi/acpica/dbhistry.c            |  239 ++++++
 drivers/acpi/acpica/dbinput.c             | 1267 +++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbmethod.c            |  369 +++++++++
 drivers/acpi/acpica/dbnames.c             |  947 +++++++++++++++++++++
 drivers/acpi/acpica/dbobject.c            |  533 ++++++++++++
 drivers/acpi/acpica/dbstats.c             |  546 +++++++++++++
 drivers/acpi/acpica/dbtest.c              | 1057 ++++++++++++++++++++++++
 drivers/acpi/acpica/dbutils.c             |  457 +++++++++++
 drivers/acpi/acpica/dbxface.c             |  513 ++++++++++++
 drivers/acpi/acpica/evxface.c             |    2 +-
 drivers/acpi/acpica/exconvrt.c            |    1 +
 drivers/acpi/acpica/exresolv.c            |    1 -
 drivers/acpi/acpica/exresop.c             |    2 +
 drivers/acpi/acpica/exstore.c             |  120 ++-
 drivers/acpi/acpica/exstoren.c            |    5 +-
 drivers/acpi/acpica/nsdump.c              |    6 -
 drivers/acpi/acpica/nspredef.c            |    2 +-
 drivers/acpi/acpica/pstree.c              |    2 -
 drivers/acpi/acpica/psutils.c             |    2 -
 drivers/acpi/acpica/rsdump.c              |    3 -
 drivers/acpi/acpica/rsutils.c             |    2 -
 drivers/acpi/acpica/rsxface.c             |    4 +-
 drivers/acpi/acpica/utdecode.c            |   21 +-
 drivers/acpi/acpica/utfileio.c            |    6 +
 drivers/acpi/acpica/utinit.c              |   15 +-
 drivers/acpi/acpica/utmutex.c             |   21 +
 drivers/acpi/acpica/utxface.c             |   19 +-
 drivers/acpi/nfit.c                       |    6 +-
 drivers/acpi/nfit.h                       |    2 +-
 drivers/acpi/osl.c                        |   11 +-
 include/acpi/acexcep.h                    |    7 +-
 include/acpi/acpiosxf.h                   |    3 +-
 include/acpi/acpixf.h                     |   14 +-
 include/acpi/actbl1.h                     |    2 +-
 include/acpi/platform/acenv.h             |    8 +-
 include/acpi/platform/aclinux.h           |    7 +-
 include/acpi/platform/aclinuxex.h         |    5 +
 tools/power/acpi/tools/acpidump/apfiles.c |    2 +-
 55 files changed, 9982 insertions(+), 137 deletions(-)
 create mode 100644 drivers/acpi/acpica/dbcmds.c
 create mode 100644 drivers/acpi/acpica/dbconvert.c
 create mode 100644 drivers/acpi/acpica/dbdisply.c
 create mode 100644 drivers/acpi/acpica/dbexec.c
 create mode 100644 drivers/acpi/acpica/dbfileio.c
 create mode 100644 drivers/acpi/acpica/dbhistry.c
 create mode 100644 drivers/acpi/acpica/dbinput.c
 create mode 100644 drivers/acpi/acpica/dbmethod.c
 create mode 100644 drivers/acpi/acpica/dbnames.c
 create mode 100644 drivers/acpi/acpica/dbobject.c
 create mode 100644 drivers/acpi/acpica/dbstats.c
 create mode 100644 drivers/acpi/acpica/dbtest.c
 create mode 100644 drivers/acpi/acpica/dbutils.c
 create mode 100644 drivers/acpi/acpica/dbxface.c

-- 
1.7.10

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v2 00/14] ACPICA: 20150930 Release
@ 2015-10-19  2:24   ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The 20150930 ACPICA kernel-resident subsystem updates are linuxized based
on the linux-pm/linux-next branch.

The patchset has passed the following build/boot tests.
Build tests are performed as follows:
1. i386 + allyes
2. i386 + allno
3. i386 + default + ACPI_DEBUGGER=y
4. i386 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
5. i386 + default + ACPI_DEBUG=n + ACPI=y
6. i386 + default + ACPI=n
7. x86_64 + allyes
8. x86_64 + allno
9. x86_64 + default + ACPI_DEBUGGER=y
10.x86_64 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
11.x86_64 + default + ACPI_DEBUG=n + ACPI=y
12.x86_64 + default + ACPI=n
Boot tests are performed as follows:
1. i386 + default + ACPI_DEBUGGER=y
2. x86_64 + default + ACPI_DEBUGGER=y
Where:
1. i386: machine named as "Dell Inspiron Mini 1010"
2. x86_64: machine named as "HP Compaq 8200 Elite SFF PC"
3. default: kernel configuration with following items enabled:
   All hardware drivers related to the machines of i386/x86_64
   All "drivers/acpi" configurations
   All "drivers/platform" drivers
   All other drivers that link the APIs provided by ACPICA subsystem

The divergences checking result:
Before applying (20150818 Release):
  517 lines
After applying (20150930 Release):
  517 lines

Note there are still 2 ACPICA debugger patches not released during this
release cycle, so the debugger IO driver is not released in this cycle. In
this series the ACPICA debugger core is compile time enabled as all ACPICA
debugger files can be built with ACPI_DEBUGGER=y, but not runtime enabled
as there is no invocations calling ACPICA debugger APIs and its required
OSls are just stubs. The embedded debugger invocation acpi_db_single_step()
is also stubbed via debugger thread ID support.

Bob Moore (8):
  ACPICA: Remove unnecessary conditional compilation.
  ACPICA: iASL: Add symbolic operator support for Index() operator.
  ACPICA: Update exception code for "file not found" error
  ACPICA: Debugger: Update mutexes used for multithreaded debugger
  ACPICA: Update NFIT table to rename a flags field
  ACPICA: Improve typechecking, both compile-time and runtime
  ACPICA: iASL: General cleanup of the file suffix #defines
  ACPICA: Update version to 20150930

Lv Zheng (6):
  ACPICA: Linuxize: Export debugger files to Linux
  ACPICA: Debugger: Fix "quit/exit" command by cleaning up user
    commands termination logic
  ACPICA: Debugger: Fix "terminate" command by cleaning up subsystem
    shutdown logic
  ACPICA: Debugger: Add thread ID support so that single step mode can
    only apply to the debugger thread
  ACPI: Enable build of AML interpreter debugger
  ACPICA: Debugger: Fix dead lock issue ocurred in single stepping mode

 drivers/acpi/Kconfig                      |    9 +
 drivers/acpi/acpica/Makefile              |   18 +-
 drivers/acpi/acpica/acapps.h              |    2 +-
 drivers/acpi/acpica/acdebug.h             |    6 +
 drivers/acpi/acpica/acglobal.h            |    7 +-
 drivers/acpi/acpica/acinterp.h            |    2 -
 drivers/acpi/acpica/aclocal.h             |   22 +-
 drivers/acpi/acpica/acnamesp.h            |    4 -
 drivers/acpi/acpica/acopcode.h            |    4 +-
 drivers/acpi/acpica/acparser.h            |    4 -
 drivers/acpi/acpica/acutils.h             |    2 -
 drivers/acpi/acpica/amlcode.h             |   11 +-
 drivers/acpi/acpica/dbcmds.c              | 1187 +++++++++++++++++++++++++++
 drivers/acpi/acpica/dbconvert.c           |  484 +++++++++++
 drivers/acpi/acpica/dbdisply.c            | 1108 +++++++++++++++++++++++++
 drivers/acpi/acpica/dbexec.c              |  764 +++++++++++++++++
 drivers/acpi/acpica/dbfileio.c            |  256 ++++++
 drivers/acpi/acpica/dbhistry.c            |  239 ++++++
 drivers/acpi/acpica/dbinput.c             | 1267 +++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbmethod.c            |  369 +++++++++
 drivers/acpi/acpica/dbnames.c             |  947 +++++++++++++++++++++
 drivers/acpi/acpica/dbobject.c            |  533 ++++++++++++
 drivers/acpi/acpica/dbstats.c             |  546 +++++++++++++
 drivers/acpi/acpica/dbtest.c              | 1057 ++++++++++++++++++++++++
 drivers/acpi/acpica/dbutils.c             |  457 +++++++++++
 drivers/acpi/acpica/dbxface.c             |  513 ++++++++++++
 drivers/acpi/acpica/evxface.c             |    2 +-
 drivers/acpi/acpica/exconvrt.c            |    1 +
 drivers/acpi/acpica/exresolv.c            |    1 -
 drivers/acpi/acpica/exresop.c             |    2 +
 drivers/acpi/acpica/exstore.c             |  120 ++-
 drivers/acpi/acpica/exstoren.c            |    5 +-
 drivers/acpi/acpica/nsdump.c              |    6 -
 drivers/acpi/acpica/nspredef.c            |    2 +-
 drivers/acpi/acpica/pstree.c              |    2 -
 drivers/acpi/acpica/psutils.c             |    2 -
 drivers/acpi/acpica/rsdump.c              |    3 -
 drivers/acpi/acpica/rsutils.c             |    2 -
 drivers/acpi/acpica/rsxface.c             |    4 +-
 drivers/acpi/acpica/utdecode.c            |   21 +-
 drivers/acpi/acpica/utfileio.c            |    6 +
 drivers/acpi/acpica/utinit.c              |   15 +-
 drivers/acpi/acpica/utmutex.c             |   21 +
 drivers/acpi/acpica/utxface.c             |   19 +-
 drivers/acpi/nfit.c                       |    6 +-
 drivers/acpi/nfit.h                       |    2 +-
 drivers/acpi/osl.c                        |   11 +-
 include/acpi/acexcep.h                    |    7 +-
 include/acpi/acpiosxf.h                   |    3 +-
 include/acpi/acpixf.h                     |   14 +-
 include/acpi/actbl1.h                     |    2 +-
 include/acpi/platform/acenv.h             |    8 +-
 include/acpi/platform/aclinux.h           |    7 +-
 include/acpi/platform/aclinuxex.h         |    5 +
 tools/power/acpi/tools/acpidump/apfiles.c |    2 +-
 55 files changed, 9982 insertions(+), 137 deletions(-)
 create mode 100644 drivers/acpi/acpica/dbcmds.c
 create mode 100644 drivers/acpi/acpica/dbconvert.c
 create mode 100644 drivers/acpi/acpica/dbdisply.c
 create mode 100644 drivers/acpi/acpica/dbexec.c
 create mode 100644 drivers/acpi/acpica/dbfileio.c
 create mode 100644 drivers/acpi/acpica/dbhistry.c
 create mode 100644 drivers/acpi/acpica/dbinput.c
 create mode 100644 drivers/acpi/acpica/dbmethod.c
 create mode 100644 drivers/acpi/acpica/dbnames.c
 create mode 100644 drivers/acpi/acpica/dbobject.c
 create mode 100644 drivers/acpi/acpica/dbstats.c
 create mode 100644 drivers/acpi/acpica/dbtest.c
 create mode 100644 drivers/acpi/acpica/dbutils.c
 create mode 100644 drivers/acpi/acpica/dbxface.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v2 01/14] ACPICA: Remove unnecessary conditional compilation.
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit eea1f0e561893b6d6417913b2d224082fe3a0a5e

Remove use of ACPI_DEBUGGER and ACPI_DISASSEMBLER where these
defines are used around entire modules.

Note: This type of code also causes problems with IDEs.

Link: https://github.com/acpica/acpica/commit/eea1f0e5
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/Makefile  |    2 +-
 drivers/acpi/acpica/acdebug.h |    6 ++++++
 drivers/acpi/acpica/rsdump.c  |    3 ---
 include/acpi/platform/acenv.h |    2 +-
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index fedcc16..ac78d76 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -123,7 +123,6 @@ acpi-y +=		\
 	rsaddr.o	\
 	rscalc.o	\
 	rscreate.o	\
-	rsdump.o	\
 	rsdumpinfo.o	\
 	rsinfo.o	\
 	rsio.o		\
@@ -179,6 +178,7 @@ acpi-y +=		\
 	utxfmutex.o
 
 acpi-$(ACPI_FUTURE_USAGE) +=	\
+	rsdump.o		\
 	utcache.o		\
 	utfileio.o		\
 	utprint.o		\
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index eb2e926..c928ba4 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -44,6 +44,12 @@
 #ifndef __ACDEBUG_H__
 #define __ACDEBUG_H__
 
+/* The debugger is used in conjunction with the disassembler most of time */
+
+#ifdef ACPI_DISASSEMBLER
+#include "acdisasm.h"
+#endif
+
 #define ACPI_DEBUG_BUFFER_SIZE  0x4000	/* 16K buffer for return objects */
 
 struct acpi_db_command_info {
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index c428bb3..2a09288 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -51,7 +51,6 @@ ACPI_MODULE_NAME("rsdump")
 /*
  * All functions in this module are used by the AML Debugger only
  */
-#if defined(ACPI_DEBUGGER)
 /* Local prototypes */
 static void acpi_rs_out_string(char *title, char *value);
 
@@ -565,5 +564,3 @@ static void acpi_rs_dump_word_list(u16 length, u16 *data)
 		acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]);
 	}
 }
-
-#endif
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index ec00e2b..15ef08c 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -142,7 +142,7 @@
 
 #ifdef ACPI_LIBRARY
 #define ACPI_USE_LOCAL_CACHE
-#define ACPI_FUTURE_USAGE
+#define ACPI_FULL_DEBUG
 #endif
 
 /* Common for all ACPICA applications */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 01/14] ACPICA: Remove unnecessary conditional compilation.
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit eea1f0e561893b6d6417913b2d224082fe3a0a5e

Remove use of ACPI_DEBUGGER and ACPI_DISASSEMBLER where these
defines are used around entire modules.

Note: This type of code also causes problems with IDEs.

Link: https://github.com/acpica/acpica/commit/eea1f0e5
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/Makefile  |    2 +-
 drivers/acpi/acpica/acdebug.h |    6 ++++++
 drivers/acpi/acpica/rsdump.c  |    3 ---
 include/acpi/platform/acenv.h |    2 +-
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index fedcc16..ac78d76 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -123,7 +123,6 @@ acpi-y +=		\
 	rsaddr.o	\
 	rscalc.o	\
 	rscreate.o	\
-	rsdump.o	\
 	rsdumpinfo.o	\
 	rsinfo.o	\
 	rsio.o		\
@@ -179,6 +178,7 @@ acpi-y +=		\
 	utxfmutex.o
 
 acpi-$(ACPI_FUTURE_USAGE) +=	\
+	rsdump.o		\
 	utcache.o		\
 	utfileio.o		\
 	utprint.o		\
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index eb2e926..c928ba4 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -44,6 +44,12 @@
 #ifndef __ACDEBUG_H__
 #define __ACDEBUG_H__
 
+/* The debugger is used in conjunction with the disassembler most of time */
+
+#ifdef ACPI_DISASSEMBLER
+#include "acdisasm.h"
+#endif
+
 #define ACPI_DEBUG_BUFFER_SIZE  0x4000	/* 16K buffer for return objects */
 
 struct acpi_db_command_info {
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index c428bb3..2a09288 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -51,7 +51,6 @@ ACPI_MODULE_NAME("rsdump")
 /*
  * All functions in this module are used by the AML Debugger only
  */
-#if defined(ACPI_DEBUGGER)
 /* Local prototypes */
 static void acpi_rs_out_string(char *title, char *value);
 
@@ -565,5 +564,3 @@ static void acpi_rs_dump_word_list(u16 length, u16 *data)
 		acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]);
 	}
 }
-
-#endif
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index ec00e2b..15ef08c 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -142,7 +142,7 @@
 
 #ifdef ACPI_LIBRARY
 #define ACPI_USE_LOCAL_CACHE
-#define ACPI_FUTURE_USAGE
+#define ACPI_FULL_DEBUG
 #endif
 
 /* Common for all ACPICA applications */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 02/14] ACPICA: iASL: Add symbolic operator support for Index() operator.
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit fbe67c46830f10c839941f8512cac5bddcb86bd3

Index (XXXX, 2) is now supported by XXXX [2]

This patch doesn't affect Linux kernel.

Link: https://github.com/acpica/acpica/commit/fbe67c46
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 6f70826..8a66fef 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -848,7 +848,7 @@ struct acpi_parse_state {
 #define ACPI_PARSEOP_PARAMLIST          0x02
 #define ACPI_PARSEOP_EMPTY_TERMLIST     0x04
 #define ACPI_PARSEOP_PREDEF_CHECKED     0x08
-#define ACPI_PARSEOP_SPECIAL            0x10
+#define ACPI_PARSEOP_CLOSING_PAREN      0x10
 #define ACPI_PARSEOP_COMPOUND           0x20
 #define ACPI_PARSEOP_ASSIGNMENT         0x40
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 02/14] ACPICA: iASL: Add symbolic operator support for Index() operator.
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit fbe67c46830f10c839941f8512cac5bddcb86bd3

Index (XXXX, 2) is now supported by XXXX [2]

This patch doesn't affect Linux kernel.

Link: https://github.com/acpica/acpica/commit/fbe67c46
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 6f70826..8a66fef 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -848,7 +848,7 @@ struct acpi_parse_state {
 #define ACPI_PARSEOP_PARAMLIST          0x02
 #define ACPI_PARSEOP_EMPTY_TERMLIST     0x04
 #define ACPI_PARSEOP_PREDEF_CHECKED     0x08
-#define ACPI_PARSEOP_SPECIAL            0x10
+#define ACPI_PARSEOP_CLOSING_PAREN      0x10
 #define ACPI_PARSEOP_COMPOUND           0x20
 #define ACPI_PARSEOP_ASSIGNMENT         0x40
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 03/14] ACPICA: Update exception code for "file not found" error
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit ac1564c26d239348ef13455f61d5616f3961ff43

Used by the ACPICA applications.

This patch is a bit broken due to non-portable <errno.h> inclusion as on
some platforms, there is no such a header file for their lib-c exports.
Fortunately, Linux doesn't compile utfileio.c for either the kernel
space ACPICA core (drivers/acpi/acpica) or the userspace ACPICA tools
(tools/power/acpi) for now, so it's safe to leave this patch as it is.

Link: https://github.com/acpica/acpica/commit/ac1564c2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/utfileio.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c
index 75a94f5..d435b7b 100644
--- a/drivers/acpi/acpica/utfileio.c
+++ b/drivers/acpi/acpica/utfileio.c
@@ -45,6 +45,7 @@
 #include "accommon.h"
 #include "actables.h"
 #include "acapps.h"
+#include "errno.h"
 
 #ifdef ACPI_ASL_COMPILER
 #include "aslcompiler.h"
@@ -301,6 +302,11 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
 	file = fopen(filename, "rb");
 	if (!file) {
 		perror("Could not open input file");
+
+		if (errno == ENOENT) {
+			return (AE_NOT_EXIST);
+		}
+
 		return (status);
 	}
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 03/14] ACPICA: Update exception code for "file not found" error
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit ac1564c26d239348ef13455f61d5616f3961ff43

Used by the ACPICA applications.

This patch is a bit broken due to non-portable <errno.h> inclusion as on
some platforms, there is no such a header file for their lib-c exports.
Fortunately, Linux doesn't compile utfileio.c for either the kernel
space ACPICA core (drivers/acpi/acpica) or the userspace ACPICA tools
(tools/power/acpi) for now, so it's safe to leave this patch as it is.

Link: https://github.com/acpica/acpica/commit/ac1564c2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/utfileio.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c
index 75a94f5..d435b7b 100644
--- a/drivers/acpi/acpica/utfileio.c
+++ b/drivers/acpi/acpica/utfileio.c
@@ -45,6 +45,7 @@
 #include "accommon.h"
 #include "actables.h"
 #include "acapps.h"
+#include "errno.h"
 
 #ifdef ACPI_ASL_COMPILER
 #include "aslcompiler.h"
@@ -301,6 +302,11 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
 	file = fopen(filename, "rb");
 	if (!file) {
 		perror("Could not open input file");
+
+		if (errno == ENOENT) {
+			return (AE_NOT_EXIST);
+		}
+
 		return (status);
 	}
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 04/14] ACPICA: Debugger: Update mutexes used for multithreaded debugger
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 6b2701f619040e803313363f516b200e362a9100

Make these mutex objects independent of the deadlock detection mechanism.
This mechanism caused failures with the multithread debugger.

This patch doesn't affect Linux kernel as debugger is currently not fully
functioning in the Linux kernel. And the further debugger cleanups will
take care of handling debugger command signalling correctly instead of
using such kind of mutexes. So it is safe to leave this patch as it is.

Link: https://github.com/acpica/acpica/commit/6b2701f6
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    3 +++
 drivers/acpi/acpica/aclocal.h  |    4 +---
 drivers/acpi/acpica/utdecode.c |    2 --
 drivers/acpi/acpica/utmutex.c  |   21 +++++++++++++++++++++
 include/acpi/platform/acenv.h  |    6 +++---
 5 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 09f37b5..593de41 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -357,6 +357,9 @@ 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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 8a66fef..918f70d 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -83,10 +83,8 @@ union acpi_parse_object;
 #define ACPI_MTX_EVENTS                 3	/* Data for ACPI events */
 #define ACPI_MTX_CACHES                 4	/* Internal caches, general purposes */
 #define ACPI_MTX_MEMORY                 5	/* Debug memory tracking lists */
-#define ACPI_MTX_DEBUG_CMD_COMPLETE     6	/* AML debugger */
-#define ACPI_MTX_DEBUG_CMD_READY        7	/* AML debugger */
 
-#define ACPI_MAX_MUTEX                  7
+#define ACPI_MAX_MUTEX                  5
 #define ACPI_NUM_MUTEX                  ACPI_MAX_MUTEX+1
 
 /* Lock structure for reader/writer interfaces */
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index 988e23b..d452a78 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -407,8 +407,6 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
 	"ACPI_MTX_Events",
 	"ACPI_MTX_Caches",
 	"ACPI_MTX_Memory",
-	"ACPI_MTX_CommandComplete",
-	"ACPI_MTX_CommandReady"
 };
 
 char *acpi_ut_get_mutex_name(u32 mutex_id)
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 37b8b58..ce406e3 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -108,6 +108,21 @@ acpi_status acpi_ut_mutex_initialize(void)
 	/* Create the reader/writer lock for namespace access */
 
 	status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
+	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);
 }
 
@@ -147,6 +162,12 @@ 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;
 }
 
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 15ef08c..056f245 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -304,11 +304,11 @@
  * multi-threaded if ACPI_APPLICATION is not set.
  */
 #ifndef DEBUGGER_THREADING
-#ifdef ACPI_APPLICATION
-#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
+#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP)
+#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
 
 #else
-#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
+#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
 #endif
 #endif				/* !DEBUGGER_THREADING */
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 04/14] ACPICA: Debugger: Update mutexes used for multithreaded debugger
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 6b2701f619040e803313363f516b200e362a9100

Make these mutex objects independent of the deadlock detection mechanism.
This mechanism caused failures with the multithread debugger.

This patch doesn't affect Linux kernel as debugger is currently not fully
functioning in the Linux kernel. And the further debugger cleanups will
take care of handling debugger command signalling correctly instead of
using such kind of mutexes. So it is safe to leave this patch as it is.

Link: https://github.com/acpica/acpica/commit/6b2701f6
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    3 +++
 drivers/acpi/acpica/aclocal.h  |    4 +---
 drivers/acpi/acpica/utdecode.c |    2 --
 drivers/acpi/acpica/utmutex.c  |   21 +++++++++++++++++++++
 include/acpi/platform/acenv.h  |    6 +++---
 5 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 09f37b5..593de41 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -357,6 +357,9 @@ 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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 8a66fef..918f70d 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -83,10 +83,8 @@ union acpi_parse_object;
 #define ACPI_MTX_EVENTS                 3	/* Data for ACPI events */
 #define ACPI_MTX_CACHES                 4	/* Internal caches, general purposes */
 #define ACPI_MTX_MEMORY                 5	/* Debug memory tracking lists */
-#define ACPI_MTX_DEBUG_CMD_COMPLETE     6	/* AML debugger */
-#define ACPI_MTX_DEBUG_CMD_READY        7	/* AML debugger */
 
-#define ACPI_MAX_MUTEX                  7
+#define ACPI_MAX_MUTEX                  5
 #define ACPI_NUM_MUTEX                  ACPI_MAX_MUTEX+1
 
 /* Lock structure for reader/writer interfaces */
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index 988e23b..d452a78 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -407,8 +407,6 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
 	"ACPI_MTX_Events",
 	"ACPI_MTX_Caches",
 	"ACPI_MTX_Memory",
-	"ACPI_MTX_CommandComplete",
-	"ACPI_MTX_CommandReady"
 };
 
 char *acpi_ut_get_mutex_name(u32 mutex_id)
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 37b8b58..ce406e3 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -108,6 +108,21 @@ acpi_status acpi_ut_mutex_initialize(void)
 	/* Create the reader/writer lock for namespace access */
 
 	status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
+	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);
 }
 
@@ -147,6 +162,12 @@ 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;
 }
 
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 15ef08c..056f245 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -304,11 +304,11 @@
  * multi-threaded if ACPI_APPLICATION is not set.
  */
 #ifndef DEBUGGER_THREADING
-#ifdef ACPI_APPLICATION
-#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
+#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP)
+#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
 
 #else
-#define DEBUGGER_THREADING          DEBUGGER_MULTI_THREADED
+#define DEBUGGER_THREADING          DEBUGGER_SINGLE_THREADED
 #endif
 #endif				/* !DEBUGGER_THREADING */
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 05/14] ACPICA: Update NFIT table to rename a flags field
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 534deab97fb416a13bfede15c538e2c9eac9384a

Updated one of the memory subtable flags to clarify.

Link: https://github.com/acpica/acpica/commit/534deab9
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/nfit.c   |    6 +++---
 drivers/acpi/nfit.h   |    2 +-
 include/acpi/actbl1.h |    2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index c1b8d03..bc18aa2 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -706,7 +706,7 @@ static ssize_t flags_show(struct device *dev,
 		flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
 		flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
 		flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
-		flags & ACPI_NFIT_MEM_ARMED ? "not_armed " : "",
+		flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
 		flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
 }
 static DEVICE_ATTR_RO(flags);
@@ -815,7 +815,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 			flags |= NDD_ALIASING;
 
 		mem_flags = __to_nfit_memdev(nfit_mem)->flags;
-		if (mem_flags & ACPI_NFIT_MEM_ARMED)
+		if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
 			flags |= NDD_UNARMED;
 
 		rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
@@ -839,7 +839,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 		  mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
 		  mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
 		  mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
-		  mem_flags & ACPI_NFIT_MEM_ARMED ? " not_armed" : "");
+		  mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
 
 	}
 
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index 7e74015..329a1eb 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -24,7 +24,7 @@
 #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
 #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
 		| ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
-		| ACPI_NFIT_MEM_ARMED)
+		| ACPI_NFIT_MEM_NOT_ARMED)
 
 enum nfit_uuids {
 	NFIT_SPA_VOLATILE,
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index fcd5709..1bb979e 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -1012,7 +1012,7 @@ struct acpi_nfit_memory_map {
 #define ACPI_NFIT_MEM_SAVE_FAILED       (1)	/* 00: Last SAVE to Memory Device failed */
 #define ACPI_NFIT_MEM_RESTORE_FAILED    (1<<1)	/* 01: Last RESTORE from Memory Device failed */
 #define ACPI_NFIT_MEM_FLUSH_FAILED      (1<<2)	/* 02: Platform flush failed */
-#define ACPI_NFIT_MEM_ARMED             (1<<3)	/* 03: Memory Device observed to be not armed */
+#define ACPI_NFIT_MEM_NOT_ARMED         (1<<3)	/* 03: Memory Device is not armed */
 #define ACPI_NFIT_MEM_HEALTH_OBSERVED   (1<<4)	/* 04: Memory Device observed SMART/health events */
 #define ACPI_NFIT_MEM_HEALTH_ENABLED    (1<<5)	/* 05: SMART/health events enabled */
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 05/14] ACPICA: Update NFIT table to rename a flags field
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 534deab97fb416a13bfede15c538e2c9eac9384a

Updated one of the memory subtable flags to clarify.

Link: https://github.com/acpica/acpica/commit/534deab9
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/nfit.c   |    6 +++---
 drivers/acpi/nfit.h   |    2 +-
 include/acpi/actbl1.h |    2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index c1b8d03..bc18aa2 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -706,7 +706,7 @@ static ssize_t flags_show(struct device *dev,
 		flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
 		flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
 		flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
-		flags & ACPI_NFIT_MEM_ARMED ? "not_armed " : "",
+		flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "",
 		flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "");
 }
 static DEVICE_ATTR_RO(flags);
@@ -815,7 +815,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 			flags |= NDD_ALIASING;
 
 		mem_flags = __to_nfit_memdev(nfit_mem)->flags;
-		if (mem_flags & ACPI_NFIT_MEM_ARMED)
+		if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED)
 			flags |= NDD_UNARMED;
 
 		rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle);
@@ -839,7 +839,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
 		  mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
 		  mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
 		  mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "",
-		  mem_flags & ACPI_NFIT_MEM_ARMED ? " not_armed" : "");
+		  mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "");
 
 	}
 
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index 7e74015..329a1eb 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -24,7 +24,7 @@
 #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
 #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
 		| ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
-		| ACPI_NFIT_MEM_ARMED)
+		| ACPI_NFIT_MEM_NOT_ARMED)
 
 enum nfit_uuids {
 	NFIT_SPA_VOLATILE,
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index fcd5709..1bb979e 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -1012,7 +1012,7 @@ struct acpi_nfit_memory_map {
 #define ACPI_NFIT_MEM_SAVE_FAILED       (1)	/* 00: Last SAVE to Memory Device failed */
 #define ACPI_NFIT_MEM_RESTORE_FAILED    (1<<1)	/* 01: Last RESTORE from Memory Device failed */
 #define ACPI_NFIT_MEM_FLUSH_FAILED      (1<<2)	/* 02: Platform flush failed */
-#define ACPI_NFIT_MEM_ARMED             (1<<3)	/* 03: Memory Device observed to be not armed */
+#define ACPI_NFIT_MEM_NOT_ARMED         (1<<3)	/* 03: Memory Device is not armed */
 #define ACPI_NFIT_MEM_HEALTH_OBSERVED   (1<<4)	/* 04: Memory Device observed SMART/health events */
 #define ACPI_NFIT_MEM_HEALTH_ENABLED    (1<<5)	/* 05: SMART/health events enabled */
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 06/14] ACPICA: Improve typechecking, both compile-time and runtime
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:24     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 8d0f96e2a11a4ceabb2cae4b41e0ce1f4d3786b9

Adds much stricter typechecking in the iASL compiler, and
also adds some additional checking in the interpreter.

Link: https://github.com/acpica/acpica/commit/8d0f96e2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h  |    8 ++-
 drivers/acpi/acpica/acopcode.h |    4 +-
 drivers/acpi/acpica/amlcode.h  |   11 ++--
 drivers/acpi/acpica/exconvrt.c |    1 +
 drivers/acpi/acpica/exresolv.c |    1 -
 drivers/acpi/acpica/exresop.c  |    2 +
 drivers/acpi/acpica/exstore.c  |  120 ++++++++++++++++++++++++++++++----------
 drivers/acpi/acpica/exstoren.c |    5 +-
 drivers/acpi/acpica/nspredef.c |    2 +-
 drivers/acpi/acpica/utdecode.c |   19 ++++++-
 include/acpi/acexcep.h         |    7 ++-
 11 files changed, 134 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 918f70d..4e41b43 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -285,13 +285,17 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
 #define ACPI_BTYPE_BUFFER_FIELD         0x00002000
 #define ACPI_BTYPE_DDB_HANDLE           0x00004000
 #define ACPI_BTYPE_DEBUG_OBJECT         0x00008000
-#define ACPI_BTYPE_REFERENCE            0x00010000
+#define ACPI_BTYPE_REFERENCE_OBJECT     0x00010000	/* From Index(), ref_of(), etc (type6_opcodes) */
 #define ACPI_BTYPE_RESOURCE             0x00020000
+#define ACPI_BTYPE_NAMED_REFERENCE      0x00040000	/* Generic unresolved Name or Namepath */
 
 #define ACPI_BTYPE_COMPUTE_DATA         (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER)
 
 #define ACPI_BTYPE_DATA                 (ACPI_BTYPE_COMPUTE_DATA  | ACPI_BTYPE_PACKAGE)
-#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE)
+
+	/* Used by Copy, de_ref_of, Store, Printf, Fprintf */
+
+#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE)
 #define ACPI_BTYPE_DEVICE_OBJECTS       (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR)
 #define ACPI_BTYPE_OBJECTS_AND_REFS     0x0001FFFF	/* ARG or LOCAL */
 #define ACPI_BTYPE_ALL_OBJECTS          0x0000FFFF
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index fd85ad0..f9acf92 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -211,7 +211,7 @@
 #define ARGI_ARG4                       ARG_NONE
 #define ARGI_ARG5                       ARG_NONE
 #define ARGI_ARG6                       ARG_NONE
-#define ARGI_BANK_FIELD_OP              ARGI_INVALID_OPCODE
+#define ARGI_BANK_FIELD_OP              ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_BIT_AND_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NAND_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NOR_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
@@ -307,7 +307,7 @@
 #define ARGI_SLEEP_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STALL_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STATICSTRING_OP            ARGI_INVALID_OPCODE
-#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET)
 #define ARGI_STRING_OP                  ARGI_INVALID_OPCODE
 #define ARGI_SUBTRACT_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_THERMAL_ZONE_OP            ARGI_INVALID_OPCODE
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index be9fd00..883f20c 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -277,14 +277,15 @@
 #define ARGI_TARGETREF              0x0F	/* Target, subject to implicit conversion */
 #define ARGI_FIXED_TARGET           0x10	/* Target, no implicit conversion */
 #define ARGI_SIMPLE_TARGET          0x11	/* Name, Local, Arg -- no implicit conversion */
+#define ARGI_STORE_TARGET           0x12	/* Target for store is TARGETREF + package objects */
 
 /* Multiple/complex types */
 
-#define ARGI_DATAOBJECT             0x12	/* Buffer, String, package or reference to a node - Used only by size_of operator */
-#define ARGI_COMPLEXOBJ             0x13	/* Buffer, String, or package (Used by INDEX op only) */
-#define ARGI_REF_OR_STRING          0x14	/* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_BUFFER       0x15	/* Used by LOAD op only */
-#define ARGI_DATAREFOBJ             0x16
+#define ARGI_DATAOBJECT             0x13	/* Buffer, String, package or reference to a node - Used only by size_of operator */
+#define ARGI_COMPLEXOBJ             0x14	/* Buffer, String, or package (Used by INDEX op only) */
+#define ARGI_REF_OR_STRING          0x15	/* Reference or String (Used by DEREFOF op only) */
+#define ARGI_REGION_OR_BUFFER       0x16	/* Used by LOAD op only */
+#define ARGI_DATAREFOBJ             0x17
 
 /* Note: types above can expand to 0x1F maximum */
 
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 075d654..1e4c5b6 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -618,6 +618,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
 		break;
 
 	case ARGI_TARGETREF:
+	case ARGI_STORE_TARGET:
 
 		switch (destination_type) {
 		case ACPI_TYPE_INTEGER:
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 7b10912..a1afe1a 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -209,7 +209,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
 					 * (i.e., dereference the package index)
 					 * Delete the ref object, increment the returned object
 					 */
-					acpi_ut_remove_reference(stack_desc);
 					acpi_ut_add_reference(obj_desc);
 					*stack_ptr = obj_desc;
 				} else {
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index d2964af..424442d 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -307,6 +307,8 @@ acpi_ex_resolve_operands(u16 opcode,
 		case ARGI_TARGETREF:	/* Allows implicit conversion rules before store */
 		case ARGI_FIXED_TARGET:	/* No implicit conversion before store to target */
 		case ARGI_SIMPLE_TARGET:	/* Name, Local, or arg - no implicit conversion  */
+		case ARGI_STORE_TARGET:
+
 			/*
 			 * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
 			 * A Namespace Node is OK as-is
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index a7eee24..c076e91 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -137,7 +137,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
 		/* Destination is not a Reference object */
 
 		ACPI_ERROR((AE_INFO,
-			    "Target is not a Reference or Constant object - %s [%p]",
+			    "Target is not a Reference or Constant object - [%s] %p",
 			    acpi_ut_get_object_type_name(dest_desc),
 			    dest_desc));
 
@@ -189,7 +189,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
 		 * displayed and otherwise has no effect -- see ACPI Specification
 		 */
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "**** Write to Debug Object: Object %p %s ****:\n\n",
+				  "**** Write to Debug Object: Object %p [%s] ****:\n\n",
 				  source_desc,
 				  acpi_ut_get_object_type_name(source_desc)));
 
@@ -341,7 +341,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
 			/* All other types are invalid */
 
 			ACPI_ERROR((AE_INFO,
-				    "Source must be Integer/Buffer/String type, not %s",
+				    "Source must be type [Integer/Buffer/String], found [%s]",
 				    acpi_ut_get_object_type_name(source_desc)));
 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 		}
@@ -352,8 +352,9 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
 		break;
 
 	default:
-		ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField"));
-		status = AE_AML_OPERAND_TYPE;
+		ACPI_ERROR((AE_INFO,
+			    "Target is not of type [Package/BufferField]"));
+		status = AE_AML_TARGET_TYPE;
 		break;
 	}
 
@@ -373,20 +374,20 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
  *
  * DESCRIPTION: Store the object to the named object.
  *
- *              The Assignment of an object to a named object is handled here
- *              The value passed in will replace the current value (if any)
- *              with the input value.
+ * The assignment of an object to a named object is handled here.
+ * The value passed in will replace the current value (if any)
+ * with the input value.
  *
- *              When storing into an object the data is converted to the
- *              target object type then stored in the object. This means
- *              that the target object type (for an initialized target) will
- *              not be changed by a store operation. A copy_object can change
- *              the target type, however.
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation. A copy_object can change
+ * the target type, however.
  *
- *              The implicit_conversion flag is set to NO/FALSE only when
- *              storing to an arg_x -- as per the rules of the ACPI spec.
+ * The implicit_conversion flag is set to NO/FALSE only when
+ * storing to an arg_x -- as per the rules of the ACPI spec.
  *
- *              Assumes parameters are already validated.
+ * Assumes parameters are already validated.
  *
  ******************************************************************************/
 
@@ -408,11 +409,75 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 	target_type = acpi_ns_get_type(node);
 	target_desc = acpi_ns_get_attached_object(node);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n",
 			  source_desc,
 			  acpi_ut_get_object_type_name(source_desc), node,
 			  acpi_ut_get_type_name(target_type)));
 
+	/* Only limited target types possible for everything except copy_object */
+
+	if (walk_state->opcode != AML_COPY_OP) {
+		/*
+		 * Only copy_object allows all object types to be overwritten. For
+		 * target_ref(s), there are restrictions on the object types that
+		 * are allowed.
+		 *
+		 * Allowable operations/typing for Store:
+		 *
+		 * 1) Simple Store
+		 *      Integer     --> Integer (Named/Local/Arg)
+		 *      String      --> String  (Named/Local/Arg)
+		 *      Buffer      --> Buffer  (Named/Local/Arg)
+		 *      Package     --> Package (Named/Local/Arg)
+		 *
+		 * 2) Store with implicit conversion
+		 *      Integer     --> String or Buffer  (Named)
+		 *      String      --> Integer or Buffer (Named)
+		 *      Buffer      --> Integer or String (Named)
+		 */
+		switch (target_type) {
+		case ACPI_TYPE_PACKAGE:
+			/*
+			 * Here, can only store a package to an existing package.
+			 * Storing a package to a Local/Arg is OK, and handled
+			 * elsewhere.
+			 */
+			if (walk_state->opcode == AML_STORE_OP) {
+				if (source_desc->common.type !=
+				    ACPI_TYPE_PACKAGE) {
+					ACPI_ERROR((AE_INFO,
+						    "Cannot assign type [%s] to [Package] "
+						    "(source must be type Pkg)",
+						    acpi_ut_get_object_type_name
+						    (source_desc)));
+
+					return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+				}
+				break;
+			}
+
+			/* Fallthrough */
+
+		case ACPI_TYPE_DEVICE:
+		case ACPI_TYPE_EVENT:
+		case ACPI_TYPE_MUTEX:
+		case ACPI_TYPE_REGION:
+		case ACPI_TYPE_POWER:
+		case ACPI_TYPE_PROCESSOR:
+		case ACPI_TYPE_THERMAL:
+
+			ACPI_ERROR((AE_INFO,
+				    "Target must be [Buffer/Integer/String/Reference], found [%s] (%4.4s)",
+				    acpi_ut_get_type_name(node->type),
+				    node->name.ascii));
+
+			return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+
+		default:
+			break;
+		}
+	}
+
 	/*
 	 * Resolve the source object to an actual value
 	 * (If it is a reference object)
@@ -425,13 +490,13 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 	/* Do the actual store operation */
 
 	switch (target_type) {
-	case ACPI_TYPE_INTEGER:
-	case ACPI_TYPE_STRING:
-	case ACPI_TYPE_BUFFER:
 		/*
 		 * The simple data types all support implicit source operand
 		 * conversion before the store.
 		 */
+	case ACPI_TYPE_INTEGER:
+	case ACPI_TYPE_STRING:
+	case ACPI_TYPE_BUFFER:
 
 		if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
 			/*
@@ -467,7 +532,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 						       new_desc->common.type);
 
 			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-					  "Store %s into %s via Convert/Attach\n",
+					  "Store type [%s] into [%s] via Convert/Attach\n",
 					  acpi_ut_get_object_type_name
 					  (source_desc),
 					  acpi_ut_get_object_type_name
@@ -491,15 +556,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 
 	default:
 		/*
-		 * No conversions for all other types. Directly store a copy of
-		 * the source object. This is the ACPI spec-defined behavior for
-		 * the copy_object operator.
+		 * copy_object operator: No conversions for all other types.
+		 * Instead, directly store a copy of the source object.
 		 *
-		 * NOTE: For the Store operator, this is a departure from the
-		 * ACPI spec, which states "If conversion is impossible, abort
-		 * the running control method". Instead, this code implements
-		 * "If conversion is impossible, treat the Store operation as
-		 * a CopyObject".
+		 * This is the ACPI spec-defined behavior for the copy_object
+		 * operator. (Note, for this default case, all normal
+		 * Store/Target operations exited above with an error).
 		 */
 		status = acpi_ex_store_direct_to_node(source_desc, node,
 						      walk_state);
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 3101607..d1841de 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -122,9 +122,10 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
 			/* Conversion successful but still not a valid type */
 
 			ACPI_ERROR((AE_INFO,
-				    "Cannot assign type %s to %s (must be type Int/Str/Buf)",
+				    "Cannot assign type [%s] to [%s] (must be type Int/Str/Buf)",
 				    acpi_ut_get_object_type_name(source_desc),
 				    acpi_ut_get_type_name(target_type)));
+
 			status = AE_AML_OPERAND_TYPE;
 		}
 		break;
@@ -275,7 +276,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
 		/*
 		 * All other types come here.
 		 */
-		ACPI_WARNING((AE_INFO, "Store into type %s not implemented",
+		ACPI_WARNING((AE_INFO, "Store into type [%s] not implemented",
 			      acpi_ut_get_object_type_name(dest_desc)));
 
 		status = AE_NOT_IMPLEMENTED;
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 0eb5431..0c20980 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -226,7 +226,7 @@ acpi_ns_check_object_type(struct acpi_evaluate_info *info,
 {
 	union acpi_operand_object *return_object = *return_object_ptr;
 	acpi_status status = AE_OK;
-	char type_buffer[48];	/* Room for 5 types */
+	char type_buffer[96];	/* Room for 10 types */
 
 	/* A Namespace node should not get here, but make sure */
 
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index d452a78..ecaaaff 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -232,12 +232,27 @@ char *acpi_ut_get_type_name(acpi_object_type type)
 
 char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
 {
+	ACPI_FUNCTION_TRACE(ut_get_object_type_name);
 
 	if (!obj_desc) {
-		return ("[NULL Object Descriptor]");
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
+		return_PTR("[NULL Object Descriptor]");
 	}
 
-	return (acpi_ut_get_type_name(obj_desc->common.type));
+	/* These descriptor types share a common area */
+
+	if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) &&
+	    (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_NAMED)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+				  "Invalid object descriptor type: 0x%2.2X [%s] (%p)\n",
+				  ACPI_GET_DESCRIPTOR_TYPE(obj_desc),
+				  acpi_ut_get_descriptor_name(obj_desc),
+				  obj_desc));
+
+		return_PTR("Invalid object");
+	}
+
+	return_PTR(acpi_ut_get_type_name(obj_desc->common.type));
 }
 
 /*******************************************************************************
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 9f20eb4a..204f581 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -193,8 +193,9 @@ struct acpi_exception_info {
 #define AE_AML_ILLEGAL_ADDRESS          EXCEP_AML (0x0020)
 #define AE_AML_INFINITE_LOOP            EXCEP_AML (0x0021)
 #define AE_AML_UNINITIALIZED_NODE       EXCEP_AML (0x0022)
+#define AE_AML_TARGET_TYPE              EXCEP_AML (0x0023)
 
-#define AE_CODE_AML_MAX                 0x0022
+#define AE_CODE_AML_MAX                 0x0023
 
 /*
  * Internal exceptions used for control
@@ -358,7 +359,9 @@ static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = {
 	EXCEP_TXT("AE_AML_INFINITE_LOOP",
 		  "An apparent infinite AML While loop, method was aborted"),
 	EXCEP_TXT("AE_AML_UNINITIALIZED_NODE",
-		  "A namespace node is uninitialized or unresolved")
+		  "A namespace node is uninitialized or unresolved"),
+	EXCEP_TXT("AE_AML_TARGET_TYPE",
+		  "A target operand of an incorrect type was encountered")
 };
 
 static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 06/14] ACPICA: Improve typechecking, both compile-time and runtime
@ 2015-10-19  2:24     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit 8d0f96e2a11a4ceabb2cae4b41e0ce1f4d3786b9

Adds much stricter typechecking in the iASL compiler, and
also adds some additional checking in the interpreter.

Link: https://github.com/acpica/acpica/commit/8d0f96e2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h  |    8 ++-
 drivers/acpi/acpica/acopcode.h |    4 +-
 drivers/acpi/acpica/amlcode.h  |   11 ++--
 drivers/acpi/acpica/exconvrt.c |    1 +
 drivers/acpi/acpica/exresolv.c |    1 -
 drivers/acpi/acpica/exresop.c  |    2 +
 drivers/acpi/acpica/exstore.c  |  120 ++++++++++++++++++++++++++++++----------
 drivers/acpi/acpica/exstoren.c |    5 +-
 drivers/acpi/acpica/nspredef.c |    2 +-
 drivers/acpi/acpica/utdecode.c |   19 ++++++-
 include/acpi/acexcep.h         |    7 ++-
 11 files changed, 134 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 918f70d..4e41b43 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -285,13 +285,17 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
 #define ACPI_BTYPE_BUFFER_FIELD         0x00002000
 #define ACPI_BTYPE_DDB_HANDLE           0x00004000
 #define ACPI_BTYPE_DEBUG_OBJECT         0x00008000
-#define ACPI_BTYPE_REFERENCE            0x00010000
+#define ACPI_BTYPE_REFERENCE_OBJECT     0x00010000	/* From Index(), ref_of(), etc (type6_opcodes) */
 #define ACPI_BTYPE_RESOURCE             0x00020000
+#define ACPI_BTYPE_NAMED_REFERENCE      0x00040000	/* Generic unresolved Name or Namepath */
 
 #define ACPI_BTYPE_COMPUTE_DATA         (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER)
 
 #define ACPI_BTYPE_DATA                 (ACPI_BTYPE_COMPUTE_DATA  | ACPI_BTYPE_PACKAGE)
-#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE)
+
+	/* Used by Copy, de_ref_of, Store, Printf, Fprintf */
+
+#define ACPI_BTYPE_DATA_REFERENCE       (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE_OBJECT | ACPI_BTYPE_DDB_HANDLE)
 #define ACPI_BTYPE_DEVICE_OBJECTS       (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR)
 #define ACPI_BTYPE_OBJECTS_AND_REFS     0x0001FFFF	/* ARG or LOCAL */
 #define ACPI_BTYPE_ALL_OBJECTS          0x0000FFFF
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index fd85ad0..f9acf92 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -211,7 +211,7 @@
 #define ARGI_ARG4                       ARG_NONE
 #define ARGI_ARG5                       ARG_NONE
 #define ARGI_ARG6                       ARG_NONE
-#define ARGI_BANK_FIELD_OP              ARGI_INVALID_OPCODE
+#define ARGI_BANK_FIELD_OP              ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_BIT_AND_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NAND_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BIT_NOR_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
@@ -307,7 +307,7 @@
 #define ARGI_SLEEP_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STALL_OP                   ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_STATICSTRING_OP            ARGI_INVALID_OPCODE
-#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STORE_OP                   ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_STORE_TARGET)
 #define ARGI_STRING_OP                  ARGI_INVALID_OPCODE
 #define ARGI_SUBTRACT_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_THERMAL_ZONE_OP            ARGI_INVALID_OPCODE
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index be9fd00..883f20c 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -277,14 +277,15 @@
 #define ARGI_TARGETREF              0x0F	/* Target, subject to implicit conversion */
 #define ARGI_FIXED_TARGET           0x10	/* Target, no implicit conversion */
 #define ARGI_SIMPLE_TARGET          0x11	/* Name, Local, Arg -- no implicit conversion */
+#define ARGI_STORE_TARGET           0x12	/* Target for store is TARGETREF + package objects */
 
 /* Multiple/complex types */
 
-#define ARGI_DATAOBJECT             0x12	/* Buffer, String, package or reference to a node - Used only by size_of operator */
-#define ARGI_COMPLEXOBJ             0x13	/* Buffer, String, or package (Used by INDEX op only) */
-#define ARGI_REF_OR_STRING          0x14	/* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_BUFFER       0x15	/* Used by LOAD op only */
-#define ARGI_DATAREFOBJ             0x16
+#define ARGI_DATAOBJECT             0x13	/* Buffer, String, package or reference to a node - Used only by size_of operator */
+#define ARGI_COMPLEXOBJ             0x14	/* Buffer, String, or package (Used by INDEX op only) */
+#define ARGI_REF_OR_STRING          0x15	/* Reference or String (Used by DEREFOF op only) */
+#define ARGI_REGION_OR_BUFFER       0x16	/* Used by LOAD op only */
+#define ARGI_DATAREFOBJ             0x17
 
 /* Note: types above can expand to 0x1F maximum */
 
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 075d654..1e4c5b6 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -618,6 +618,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
 		break;
 
 	case ARGI_TARGETREF:
+	case ARGI_STORE_TARGET:
 
 		switch (destination_type) {
 		case ACPI_TYPE_INTEGER:
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 7b10912..a1afe1a 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -209,7 +209,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
 					 * (i.e., dereference the package index)
 					 * Delete the ref object, increment the returned object
 					 */
-					acpi_ut_remove_reference(stack_desc);
 					acpi_ut_add_reference(obj_desc);
 					*stack_ptr = obj_desc;
 				} else {
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index d2964af..424442d 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -307,6 +307,8 @@ acpi_ex_resolve_operands(u16 opcode,
 		case ARGI_TARGETREF:	/* Allows implicit conversion rules before store */
 		case ARGI_FIXED_TARGET:	/* No implicit conversion before store to target */
 		case ARGI_SIMPLE_TARGET:	/* Name, Local, or arg - no implicit conversion  */
+		case ARGI_STORE_TARGET:
+
 			/*
 			 * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
 			 * A Namespace Node is OK as-is
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index a7eee24..c076e91 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -137,7 +137,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
 		/* Destination is not a Reference object */
 
 		ACPI_ERROR((AE_INFO,
-			    "Target is not a Reference or Constant object - %s [%p]",
+			    "Target is not a Reference or Constant object - [%s] %p",
 			    acpi_ut_get_object_type_name(dest_desc),
 			    dest_desc));
 
@@ -189,7 +189,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
 		 * displayed and otherwise has no effect -- see ACPI Specification
 		 */
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "**** Write to Debug Object: Object %p %s ****:\n\n",
+				  "**** Write to Debug Object: Object %p [%s] ****:\n\n",
 				  source_desc,
 				  acpi_ut_get_object_type_name(source_desc)));
 
@@ -341,7 +341,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
 			/* All other types are invalid */
 
 			ACPI_ERROR((AE_INFO,
-				    "Source must be Integer/Buffer/String type, not %s",
+				    "Source must be type [Integer/Buffer/String], found [%s]",
 				    acpi_ut_get_object_type_name(source_desc)));
 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 		}
@@ -352,8 +352,9 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
 		break;
 
 	default:
-		ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField"));
-		status = AE_AML_OPERAND_TYPE;
+		ACPI_ERROR((AE_INFO,
+			    "Target is not of type [Package/BufferField]"));
+		status = AE_AML_TARGET_TYPE;
 		break;
 	}
 
@@ -373,20 +374,20 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
  *
  * DESCRIPTION: Store the object to the named object.
  *
- *              The Assignment of an object to a named object is handled here
- *              The value passed in will replace the current value (if any)
- *              with the input value.
+ * The assignment of an object to a named object is handled here.
+ * The value passed in will replace the current value (if any)
+ * with the input value.
  *
- *              When storing into an object the data is converted to the
- *              target object type then stored in the object. This means
- *              that the target object type (for an initialized target) will
- *              not be changed by a store operation. A copy_object can change
- *              the target type, however.
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation. A copy_object can change
+ * the target type, however.
  *
- *              The implicit_conversion flag is set to NO/FALSE only when
- *              storing to an arg_x -- as per the rules of the ACPI spec.
+ * The implicit_conversion flag is set to NO/FALSE only when
+ * storing to an arg_x -- as per the rules of the ACPI spec.
  *
- *              Assumes parameters are already validated.
+ * Assumes parameters are already validated.
  *
  ******************************************************************************/
 
@@ -408,11 +409,75 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 	target_type = acpi_ns_get_type(node);
 	target_desc = acpi_ns_get_attached_object(node);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n",
 			  source_desc,
 			  acpi_ut_get_object_type_name(source_desc), node,
 			  acpi_ut_get_type_name(target_type)));
 
+	/* Only limited target types possible for everything except copy_object */
+
+	if (walk_state->opcode != AML_COPY_OP) {
+		/*
+		 * Only copy_object allows all object types to be overwritten. For
+		 * target_ref(s), there are restrictions on the object types that
+		 * are allowed.
+		 *
+		 * Allowable operations/typing for Store:
+		 *
+		 * 1) Simple Store
+		 *      Integer     --> Integer (Named/Local/Arg)
+		 *      String      --> String  (Named/Local/Arg)
+		 *      Buffer      --> Buffer  (Named/Local/Arg)
+		 *      Package     --> Package (Named/Local/Arg)
+		 *
+		 * 2) Store with implicit conversion
+		 *      Integer     --> String or Buffer  (Named)
+		 *      String      --> Integer or Buffer (Named)
+		 *      Buffer      --> Integer or String (Named)
+		 */
+		switch (target_type) {
+		case ACPI_TYPE_PACKAGE:
+			/*
+			 * Here, can only store a package to an existing package.
+			 * Storing a package to a Local/Arg is OK, and handled
+			 * elsewhere.
+			 */
+			if (walk_state->opcode == AML_STORE_OP) {
+				if (source_desc->common.type !=
+				    ACPI_TYPE_PACKAGE) {
+					ACPI_ERROR((AE_INFO,
+						    "Cannot assign type [%s] to [Package] "
+						    "(source must be type Pkg)",
+						    acpi_ut_get_object_type_name
+						    (source_desc)));
+
+					return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+				}
+				break;
+			}
+
+			/* Fallthrough */
+
+		case ACPI_TYPE_DEVICE:
+		case ACPI_TYPE_EVENT:
+		case ACPI_TYPE_MUTEX:
+		case ACPI_TYPE_REGION:
+		case ACPI_TYPE_POWER:
+		case ACPI_TYPE_PROCESSOR:
+		case ACPI_TYPE_THERMAL:
+
+			ACPI_ERROR((AE_INFO,
+				    "Target must be [Buffer/Integer/String/Reference], found [%s] (%4.4s)",
+				    acpi_ut_get_type_name(node->type),
+				    node->name.ascii));
+
+			return_ACPI_STATUS(AE_AML_TARGET_TYPE);
+
+		default:
+			break;
+		}
+	}
+
 	/*
 	 * Resolve the source object to an actual value
 	 * (If it is a reference object)
@@ -425,13 +490,13 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 	/* Do the actual store operation */
 
 	switch (target_type) {
-	case ACPI_TYPE_INTEGER:
-	case ACPI_TYPE_STRING:
-	case ACPI_TYPE_BUFFER:
 		/*
 		 * The simple data types all support implicit source operand
 		 * conversion before the store.
 		 */
+	case ACPI_TYPE_INTEGER:
+	case ACPI_TYPE_STRING:
+	case ACPI_TYPE_BUFFER:
 
 		if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
 			/*
@@ -467,7 +532,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 						       new_desc->common.type);
 
 			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-					  "Store %s into %s via Convert/Attach\n",
+					  "Store type [%s] into [%s] via Convert/Attach\n",
 					  acpi_ut_get_object_type_name
 					  (source_desc),
 					  acpi_ut_get_object_type_name
@@ -491,15 +556,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
 
 	default:
 		/*
-		 * No conversions for all other types. Directly store a copy of
-		 * the source object. This is the ACPI spec-defined behavior for
-		 * the copy_object operator.
+		 * copy_object operator: No conversions for all other types.
+		 * Instead, directly store a copy of the source object.
 		 *
-		 * NOTE: For the Store operator, this is a departure from the
-		 * ACPI spec, which states "If conversion is impossible, abort
-		 * the running control method". Instead, this code implements
-		 * "If conversion is impossible, treat the Store operation as
-		 * a CopyObject".
+		 * This is the ACPI spec-defined behavior for the copy_object
+		 * operator. (Note, for this default case, all normal
+		 * Store/Target operations exited above with an error).
 		 */
 		status = acpi_ex_store_direct_to_node(source_desc, node,
 						      walk_state);
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 3101607..d1841de 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -122,9 +122,10 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
 			/* Conversion successful but still not a valid type */
 
 			ACPI_ERROR((AE_INFO,
-				    "Cannot assign type %s to %s (must be type Int/Str/Buf)",
+				    "Cannot assign type [%s] to [%s] (must be type Int/Str/Buf)",
 				    acpi_ut_get_object_type_name(source_desc),
 				    acpi_ut_get_type_name(target_type)));
+
 			status = AE_AML_OPERAND_TYPE;
 		}
 		break;
@@ -275,7 +276,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
 		/*
 		 * All other types come here.
 		 */
-		ACPI_WARNING((AE_INFO, "Store into type %s not implemented",
+		ACPI_WARNING((AE_INFO, "Store into type [%s] not implemented",
 			      acpi_ut_get_object_type_name(dest_desc)));
 
 		status = AE_NOT_IMPLEMENTED;
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 0eb5431..0c20980 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -226,7 +226,7 @@ acpi_ns_check_object_type(struct acpi_evaluate_info *info,
 {
 	union acpi_operand_object *return_object = *return_object_ptr;
 	acpi_status status = AE_OK;
-	char type_buffer[48];	/* Room for 5 types */
+	char type_buffer[96];	/* Room for 10 types */
 
 	/* A Namespace node should not get here, but make sure */
 
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index d452a78..ecaaaff 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -232,12 +232,27 @@ char *acpi_ut_get_type_name(acpi_object_type type)
 
 char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
 {
+	ACPI_FUNCTION_TRACE(ut_get_object_type_name);
 
 	if (!obj_desc) {
-		return ("[NULL Object Descriptor]");
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
+		return_PTR("[NULL Object Descriptor]");
 	}
 
-	return (acpi_ut_get_type_name(obj_desc->common.type));
+	/* These descriptor types share a common area */
+
+	if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) &&
+	    (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_NAMED)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+				  "Invalid object descriptor type: 0x%2.2X [%s] (%p)\n",
+				  ACPI_GET_DESCRIPTOR_TYPE(obj_desc),
+				  acpi_ut_get_descriptor_name(obj_desc),
+				  obj_desc));
+
+		return_PTR("Invalid object");
+	}
+
+	return_PTR(acpi_ut_get_type_name(obj_desc->common.type));
 }
 
 /*******************************************************************************
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 9f20eb4a..204f581 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -193,8 +193,9 @@ struct acpi_exception_info {
 #define AE_AML_ILLEGAL_ADDRESS          EXCEP_AML (0x0020)
 #define AE_AML_INFINITE_LOOP            EXCEP_AML (0x0021)
 #define AE_AML_UNINITIALIZED_NODE       EXCEP_AML (0x0022)
+#define AE_AML_TARGET_TYPE              EXCEP_AML (0x0023)
 
-#define AE_CODE_AML_MAX                 0x0022
+#define AE_CODE_AML_MAX                 0x0023
 
 /*
  * Internal exceptions used for control
@@ -358,7 +359,9 @@ static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = {
 	EXCEP_TXT("AE_AML_INFINITE_LOOP",
 		  "An apparent infinite AML While loop, method was aborted"),
 	EXCEP_TXT("AE_AML_UNINITIALIZED_NODE",
-		  "A namespace node is uninitialized or unresolved")
+		  "A namespace node is uninitialized or unresolved"),
+	EXCEP_TXT("AE_AML_TARGET_TYPE",
+		  "A target operand of an incorrect type was encountered")
 };
 
 static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 07/14] ACPICA: iASL: General cleanup of the file suffix #defines
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit bed456ed2976bdaafdef406b982fdf6c539befc0

Removed some extraneous defines, reordered others.

Link: https://github.com/acpica/acpica/commit/bed456ed
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acapps.h              |    2 +-
 tools/power/acpi/tools/acpidump/apfiles.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
index e9f0833..e4cc48f 100644
--- a/drivers/acpi/acpica/acapps.h
+++ b/drivers/acpi/acpica/acapps.h
@@ -88,7 +88,7 @@
 	acpi_os_printf (" %-18s%s\n", name, description);
 
 #define FILE_SUFFIX_DISASSEMBLY     "dsl"
-#define ACPI_TABLE_FILE_SUFFIX      ".dat"
+#define FILE_SUFFIX_BINARY_TABLE    ".dat"	/* Needs the dot */
 
 /*
  * getopt
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
index a37f970..a1c62de 100644
--- a/tools/power/acpi/tools/acpidump/apfiles.c
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -150,7 +150,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
 		strcat(filename, instance_str);
 	}
 
-	strcat(filename, ACPI_TABLE_FILE_SUFFIX);
+	strcat(filename, FILE_SUFFIX_BINARY_TABLE);
 
 	if (gbl_verbose_mode) {
 		acpi_log_error
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 07/14] ACPICA: iASL: General cleanup of the file suffix #defines
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit bed456ed2976bdaafdef406b982fdf6c539befc0

Removed some extraneous defines, reordered others.

Link: https://github.com/acpica/acpica/commit/bed456ed
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acapps.h              |    2 +-
 tools/power/acpi/tools/acpidump/apfiles.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
index e9f0833..e4cc48f 100644
--- a/drivers/acpi/acpica/acapps.h
+++ b/drivers/acpi/acpica/acapps.h
@@ -88,7 +88,7 @@
 	acpi_os_printf (" %-18s%s\n", name, description);
 
 #define FILE_SUFFIX_DISASSEMBLY     "dsl"
-#define ACPI_TABLE_FILE_SUFFIX      ".dat"
+#define FILE_SUFFIX_BINARY_TABLE    ".dat"	/* Needs the dot */
 
 /*
  * getopt
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
index a37f970..a1c62de 100644
--- a/tools/power/acpi/tools/acpidump/apfiles.c
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -150,7 +150,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance)
 		strcat(filename, instance_str);
 	}
 
-	strcat(filename, ACPI_TABLE_FILE_SUFFIX);
+	strcat(filename, FILE_SUFFIX_BINARY_TABLE);
 
 	if (gbl_verbose_mode) {
 		acpi_log_error
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 08/14] ACPICA: Linuxize: Export debugger files to Linux
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit bc2d3daa4bd429611451f28800def9fea55e63de

This patch exports debugger files to Linux.

Link: https://github.com/acpica/acpica/commit/bc2d3daa
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbcmds.c    | 1187 ++++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbconvert.c |  484 +++++++++++++++
 drivers/acpi/acpica/dbdisply.c  | 1108 ++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbexec.c    |  753 +++++++++++++++++++++++
 drivers/acpi/acpica/dbfileio.c  |  256 ++++++++
 drivers/acpi/acpica/dbhistry.c  |  239 ++++++++
 drivers/acpi/acpica/dbinput.c   | 1274 +++++++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbmethod.c  |  369 ++++++++++++
 drivers/acpi/acpica/dbnames.c   |  947 +++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbobject.c  |  533 ++++++++++++++++
 drivers/acpi/acpica/dbstats.c   |  546 +++++++++++++++++
 drivers/acpi/acpica/dbtest.c    | 1057 ++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbutils.c   |  457 ++++++++++++++
 drivers/acpi/acpica/dbxface.c   |  467 ++++++++++++++
 14 files changed, 9677 insertions(+)
 create mode 100644 drivers/acpi/acpica/dbcmds.c
 create mode 100644 drivers/acpi/acpica/dbconvert.c
 create mode 100644 drivers/acpi/acpica/dbdisply.c
 create mode 100644 drivers/acpi/acpica/dbexec.c
 create mode 100644 drivers/acpi/acpica/dbfileio.c
 create mode 100644 drivers/acpi/acpica/dbhistry.c
 create mode 100644 drivers/acpi/acpica/dbinput.c
 create mode 100644 drivers/acpi/acpica/dbmethod.c
 create mode 100644 drivers/acpi/acpica/dbnames.c
 create mode 100644 drivers/acpi/acpica/dbobject.c
 create mode 100644 drivers/acpi/acpica/dbstats.c
 create mode 100644 drivers/acpi/acpica/dbtest.c
 create mode 100644 drivers/acpi/acpica/dbutils.c
 create mode 100644 drivers/acpi/acpica/dbxface.c

diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c
new file mode 100644
index 0000000..30414b3
--- /dev/null
+++ b/drivers/acpi/acpica/dbcmds.c
@@ -0,0 +1,1187 @@
+/*******************************************************************************
+ *
+ * Module Name: dbcmds - Miscellaneous debug commands and output routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acresrc.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbcmds")
+
+/* Local prototypes */
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+			      acpi_rsdesc_size aml1_buffer_length,
+			      u8 *aml2_buffer,
+			      acpi_rsdesc_size aml2_buffer_length);
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name);
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context);
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+			 u32 nesting_level, void *context, void **return_value);
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state);
+
+static char *acpi_db_trace_method_name = NULL;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_node
+ *
+ * PARAMETERS:  in_string           - String to convert
+ *
+ * RETURN:      Pointer to a NS node
+ *
+ * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or
+ *              alphanumeric strings.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string)
+{
+	struct acpi_namespace_node *node;
+	acpi_size address;
+
+	if ((*in_string >= 0x30) && (*in_string <= 0x39)) {
+
+		/* Numeric argument, convert */
+
+		address = strtoul(in_string, NULL, 16);
+		node = ACPI_TO_POINTER(address);
+		if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+			acpi_os_printf("Address %p is invalid", node);
+			return (NULL);
+		}
+
+		/* Make sure pointer is valid NS node */
+
+		if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+			acpi_os_printf
+			    ("Address %p is not a valid namespace node [%s]\n",
+			     node, acpi_ut_get_descriptor_name(node));
+			return (NULL);
+		}
+	} else {
+		/*
+		 * Alpha argument: The parameter is a name string that must be
+		 * resolved to a Namespace object.
+		 */
+		node = acpi_db_local_ns_lookup(in_string);
+		if (!node) {
+			acpi_os_printf
+			    ("Could not find [%s] in namespace, defaulting to root node\n",
+			     in_string);
+			node = acpi_gbl_root_node;
+		}
+	}
+
+	return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_sleep
+ *
+ * PARAMETERS:  object_arg          - Desired sleep state (0-5). NULL means
+ *                                    invoke all possible sleep states.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simulate sleep/wake sequences
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_sleep(char *object_arg)
+{
+	u8 sleep_state;
+	u32 i;
+
+	ACPI_FUNCTION_TRACE(acpi_db_sleep);
+
+	/* Null input (no arguments) means to invoke all sleep states */
+
+	if (!object_arg) {
+		acpi_os_printf("Invoking all possible sleep states, 0-%d\n",
+			       ACPI_S_STATES_MAX);
+
+		for (i = 0; i <= ACPI_S_STATES_MAX; i++) {
+			acpi_db_do_one_sleep_state((u8)i);
+		}
+
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* Convert argument to binary and invoke the sleep state */
+
+	sleep_state = (u8)strtoul(object_arg, NULL, 0);
+	acpi_db_do_one_sleep_state(sleep_state);
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_do_one_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Desired sleep state (0-5)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate a sleep/wake sequence
+ *
+ ******************************************************************************/
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state)
+{
+	acpi_status status;
+	u8 sleep_type_a;
+	u8 sleep_type_b;
+
+	/* Validate parameter */
+
+	if (sleep_state > ACPI_S_STATES_MAX) {
+		acpi_os_printf("Sleep state %d out of range (%d max)\n",
+			       sleep_state, ACPI_S_STATES_MAX);
+		return;
+	}
+
+	acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n",
+		       sleep_state, acpi_gbl_sleep_state_names[sleep_state]);
+
+	/* Get the values for the sleep type registers (for display only) */
+
+	status =
+	    acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not evaluate [%s] method, %s\n",
+			       acpi_gbl_sleep_state_names[sleep_state],
+			       acpi_format_exception(status));
+		return;
+	}
+
+	acpi_os_printf
+	    ("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n",
+	     sleep_state, sleep_type_a, sleep_type_b);
+
+	/* Invoke the various sleep/wake interfaces */
+
+	acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_enter_sleep_state_prep(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state);
+	status = acpi_enter_sleep_state(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_leave_sleep_state_prep(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_leave_sleep_state(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	return;
+
+error_exit:
+	ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d",
+			sleep_state));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locks
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about internal mutexes.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locks(void)
+{
+	u32 i;
+
+	for (i = 0; i < ACPI_MAX_MUTEX; i++) {
+		acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i),
+			       acpi_gbl_mutex_info[i].thread_id ==
+			       ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked");
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_table_info
+ *
+ * PARAMETERS:  table_arg           - Name of table to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about loaded tables. Current
+ *              implementation displays all loaded tables.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_table_info(char *table_arg)
+{
+	u32 i;
+	struct acpi_table_desc *table_desc;
+	acpi_status status;
+
+	/* Header */
+
+	acpi_os_printf("Idx ID  Status Type                    "
+		       "TableHeader (Sig, Address, Length, Misc)\n");
+
+	/* Walk the entire root table list */
+
+	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+		table_desc = &acpi_gbl_root_table_list.tables[i];
+
+		/* Index and Table ID */
+
+		acpi_os_printf("%3u %.2u ", i, table_desc->owner_id);
+
+		/* Decode the table flags */
+
+		if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) {
+			acpi_os_printf("NotLoaded ");
+		} else {
+			acpi_os_printf(" Loaded ");
+		}
+
+		switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+		case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+			acpi_os_printf("External/virtual ");
+			break;
+
+		case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+			acpi_os_printf("Internal/physical ");
+			break;
+
+		case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+
+			acpi_os_printf("Internal/virtual ");
+			break;
+
+		default:
+
+			acpi_os_printf("INVALID TYPE    ");
+			break;
+		}
+
+		/* Make sure that the table is mapped */
+
+		status = acpi_tb_validate_table(table_desc);
+		if (ACPI_FAILURE(status)) {
+			return;
+		}
+
+		/* Dump the table header */
+
+		if (table_desc->pointer) {
+			acpi_tb_print_table_header(table_desc->address,
+						   table_desc->pointer);
+		} else {
+			/* If the pointer is null, the table has been unloaded */
+
+			ACPI_INFO((AE_INFO, "%4.4s - Table has been unloaded",
+				   table_desc->signature.ascii));
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_unload_acpi_table
+ *
+ * PARAMETERS:  object_name         - Namespace pathname for an object that
+ *                                    is owned by the table to be unloaded
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned
+ *              by the table.
+ *
+ ******************************************************************************/
+
+void acpi_db_unload_acpi_table(char *object_name)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	/* Translate name to an Named object */
+
+	node = acpi_db_convert_to_node(object_name);
+	if (!node) {
+		return;
+	}
+
+	status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node));
+	if (ACPI_SUCCESS(status)) {
+		acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n",
+			       object_name, node);
+	} else {
+		acpi_os_printf("%s, while unloading parent table of [%s]\n",
+			       acpi_format_exception(status), object_name);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_send_notify
+ *
+ * PARAMETERS:  name                - Name of ACPI object where to send notify
+ *              value               - Value of the notify to send.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Send an ACPI notification. The value specified is sent to the
+ *              named object as an ACPI notify.
+ *
+ ******************************************************************************/
+
+void acpi_db_send_notify(char *name, u32 value)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	/* Translate name to an Named object */
+
+	node = acpi_db_convert_to_node(name);
+	if (!node) {
+		return;
+	}
+
+	/* Dispatch the notify if legal */
+
+	if (acpi_ev_is_notify_object(node)) {
+		status = acpi_ev_queue_notify_request(node, value);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not queue notify\n");
+		}
+	} else {
+		acpi_os_printf("Named object [%4.4s] Type %s, "
+			       "must be Device/Thermal/Processor type\n",
+			       acpi_ut_get_node_name(node),
+			       acpi_ut_get_type_name(node->type));
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_interfaces
+ *
+ * PARAMETERS:  action_arg          - Null, "install", or "remove"
+ *              interface_name_arg  - Name for install/remove options
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display or modify the global _OSI interface list
+ *
+ ******************************************************************************/
+
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg)
+{
+	struct acpi_interface_info *next_interface;
+	char *sub_string;
+	acpi_status status;
+
+	/* If no arguments, just display current interface list */
+
+	if (!action_arg) {
+		(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex,
+					    ACPI_WAIT_FOREVER);
+
+		next_interface = acpi_gbl_supported_interfaces;
+		while (next_interface) {
+			if (!(next_interface->flags & ACPI_OSI_INVALID)) {
+				acpi_os_printf("%s\n", next_interface->name);
+			}
+
+			next_interface = next_interface->next;
+		}
+
+		acpi_os_release_mutex(acpi_gbl_osi_mutex);
+		return;
+	}
+
+	/* If action_arg exists, so must interface_name_arg */
+
+	if (!interface_name_arg) {
+		acpi_os_printf("Missing Interface Name argument\n");
+		return;
+	}
+
+	/* Uppercase the action for match below */
+
+	acpi_ut_strupr(action_arg);
+
+	/* install - install an interface */
+
+	sub_string = strstr("INSTALL", action_arg);
+	if (sub_string) {
+		status = acpi_install_interface(interface_name_arg);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("%s, while installing \"%s\"\n",
+				       acpi_format_exception(status),
+				       interface_name_arg);
+		}
+		return;
+	}
+
+	/* remove - remove an interface */
+
+	sub_string = strstr("REMOVE", action_arg);
+	if (sub_string) {
+		status = acpi_remove_interface(interface_name_arg);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("%s, while removing \"%s\"\n",
+				       acpi_format_exception(status),
+				       interface_name_arg);
+		}
+		return;
+	}
+
+	/* Invalid action_arg */
+
+	acpi_os_printf("Invalid action argument: %s\n", action_arg);
+	return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_template
+ *
+ * PARAMETERS:  buffer_arg          - Buffer name or address
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump a buffer that contains a resource template
+ *
+ ******************************************************************************/
+
+void acpi_db_display_template(char *buffer_arg)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+	struct acpi_buffer return_buffer;
+
+	/* Translate buffer_arg to an Named object */
+
+	node = acpi_db_convert_to_node(buffer_arg);
+	if (!node || (node == acpi_gbl_root_node)) {
+		acpi_os_printf("Invalid argument: %s\n", buffer_arg);
+		return;
+	}
+
+	/* We must have a buffer object */
+
+	if (node->type != ACPI_TYPE_BUFFER) {
+		acpi_os_printf
+		    ("Not a Buffer object, cannot be a template: %s\n",
+		     buffer_arg);
+		return;
+	}
+
+	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+	return_buffer.pointer = acpi_gbl_db_buffer;
+
+	/* Attempt to convert the raw buffer to a resource list */
+
+	status = acpi_rs_create_resource_list(node->object, &return_buffer);
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf
+		    ("Could not convert Buffer to a resource list: %s, %s\n",
+		     buffer_arg, acpi_format_exception(status));
+		goto dump_buffer;
+	}
+
+	/* Now we can dump the resource list */
+
+	acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+						 return_buffer.pointer));
+
+dump_buffer:
+	acpi_os_printf("\nRaw data buffer:\n");
+	acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer,
+				  node->object->buffer.length,
+				  DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_compare_aml_resources
+ *
+ * PARAMETERS:  aml1_buffer         - Contains first resource list
+ *              aml1_buffer_length  - Length of first resource list
+ *              aml2_buffer         - Contains second resource list
+ *              aml2_buffer_length  - Length of second resource list
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in
+ *              order to isolate a miscompare to an individual resource)
+ *
+ ******************************************************************************/
+
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+			      acpi_rsdesc_size aml1_buffer_length,
+			      u8 *aml2_buffer,
+			      acpi_rsdesc_size aml2_buffer_length)
+{
+	u8 *aml1;
+	u8 *aml2;
+	u8 *aml1_end;
+	u8 *aml2_end;
+	acpi_rsdesc_size aml1_length;
+	acpi_rsdesc_size aml2_length;
+	acpi_rsdesc_size offset = 0;
+	u8 resource_type;
+	u32 count = 0;
+	u32 i;
+
+	/* Compare overall buffer sizes (may be different due to size rounding) */
+
+	if (aml1_buffer_length != aml2_buffer_length) {
+		acpi_os_printf("**** Buffer length mismatch in converted "
+			       "AML: Original %X, New %X ****\n",
+			       aml1_buffer_length, aml2_buffer_length);
+	}
+
+	aml1 = aml1_buffer;
+	aml2 = aml2_buffer;
+	aml1_end = aml1_buffer + aml1_buffer_length;
+	aml2_end = aml2_buffer + aml2_buffer_length;
+
+	/* Walk the descriptor lists, comparing each descriptor */
+
+	while ((aml1 < aml1_end) && (aml2 < aml2_end)) {
+
+		/* Get the lengths of each descriptor */
+
+		aml1_length = acpi_ut_get_descriptor_length(aml1);
+		aml2_length = acpi_ut_get_descriptor_length(aml2);
+		resource_type = acpi_ut_get_resource_type(aml1);
+
+		/* Check for descriptor length match */
+
+		if (aml1_length != aml2_length) {
+			acpi_os_printf
+			    ("**** Length mismatch in descriptor [%.2X] type %2.2X, "
+			     "Offset %8.8X Len1 %X, Len2 %X ****\n", count,
+			     resource_type, offset, aml1_length, aml2_length);
+		}
+
+		/* Check for descriptor byte match */
+
+		else if (memcmp(aml1, aml2, aml1_length)) {
+			acpi_os_printf
+			    ("**** Data mismatch in descriptor [%.2X] type %2.2X, "
+			     "Offset %8.8X ****\n", count, resource_type,
+			     offset);
+
+			for (i = 0; i < aml1_length; i++) {
+				if (aml1[i] != aml2[i]) {
+					acpi_os_printf
+					    ("Mismatch at byte offset %.2X: is %2.2X, "
+					     "should be %2.2X\n", i, aml2[i],
+					     aml1[i]);
+				}
+			}
+		}
+
+		/* Exit on end_tag descriptor */
+
+		if (resource_type == ACPI_RESOURCE_NAME_END_TAG) {
+			return;
+		}
+
+		/* Point to next descriptor in each buffer */
+
+		count++;
+		offset += aml1_length;
+		aml1 += aml1_length;
+		aml2 += aml2_length;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_test_resource_conversion
+ *
+ * PARAMETERS:  node                - Parent device node
+ *              name                - resource method name (_CRS)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Compare the original AML with a conversion of the AML to
+ *              internal resource list, then back to AML.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name)
+{
+	acpi_status status;
+	struct acpi_buffer return_buffer;
+	struct acpi_buffer resource_buffer;
+	struct acpi_buffer new_aml;
+	union acpi_object *original_aml;
+
+	acpi_os_printf("Resource Conversion Comparison:\n");
+
+	new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+	/* Get the original _CRS AML resource template */
+
+	status = acpi_evaluate_object(node, name, NULL, &return_buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not obtain %s: %s\n",
+			       name, acpi_format_exception(status));
+		return (status);
+	}
+
+	/* Get the AML resource template, converted to internal resource structs */
+
+	status = acpi_get_current_resources(node, &resource_buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+			       acpi_format_exception(status));
+		goto exit1;
+	}
+
+	/* Convert internal resource list to external AML resource template */
+
+	status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n",
+			       acpi_format_exception(status));
+		goto exit2;
+	}
+
+	/* Compare original AML to the newly created AML resource list */
+
+	original_aml = return_buffer.pointer;
+
+	acpi_dm_compare_aml_resources(original_aml->buffer.pointer,
+				      (acpi_rsdesc_size) original_aml->buffer.
+				      length, new_aml.pointer,
+				      (acpi_rsdesc_size) new_aml.length);
+
+	/* Cleanup and exit */
+
+	ACPI_FREE(new_aml.pointer);
+exit2:
+	ACPI_FREE(resource_buffer.pointer);
+exit1:
+	ACPI_FREE(return_buffer.pointer);
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_resource_callback
+ *
+ * PARAMETERS:  acpi_walk_resource_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simple callback to exercise acpi_walk_resources and
+ *              acpi_walk_resource_buffer.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context)
+{
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_device_resources
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+			 u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	struct acpi_namespace_node *prt_node = NULL;
+	struct acpi_namespace_node *crs_node = NULL;
+	struct acpi_namespace_node *prs_node = NULL;
+	struct acpi_namespace_node *aei_node = NULL;
+	char *parent_path;
+	struct acpi_buffer return_buffer;
+	acpi_status status;
+
+	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	parent_path = acpi_ns_get_external_pathname(node);
+	if (!parent_path) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Get handles to the resource methods for this device */
+
+	(void)acpi_get_handle(node, METHOD_NAME__PRT,
+			      ACPI_CAST_PTR(acpi_handle, &prt_node));
+	(void)acpi_get_handle(node, METHOD_NAME__CRS,
+			      ACPI_CAST_PTR(acpi_handle, &crs_node));
+	(void)acpi_get_handle(node, METHOD_NAME__PRS,
+			      ACPI_CAST_PTR(acpi_handle, &prs_node));
+	(void)acpi_get_handle(node, METHOD_NAME__AEI,
+			      ACPI_CAST_PTR(acpi_handle, &aei_node));
+
+	if (!prt_node && !crs_node && !prs_node && !aei_node) {
+		goto cleanup;	/* Nothing to do */
+	}
+
+	acpi_os_printf("\nDevice: %s\n", parent_path);
+
+	/* Prepare for a return object of arbitrary size */
+
+	return_buffer.pointer = acpi_gbl_db_buffer;
+	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+	/* _PRT */
+
+	if (prt_node) {
+		acpi_os_printf("Evaluating _PRT\n");
+
+		status =
+		    acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _PRT: %s\n",
+				       acpi_format_exception(status));
+			goto get_crs;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_irq_routing_table(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("GetIrqRoutingTable failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_crs;
+		}
+
+		acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer));
+	}
+
+	/* _CRS */
+
+get_crs:
+	if (crs_node) {
+		acpi_os_printf("Evaluating _CRS\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _CRS: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* This code exercises the acpi_walk_resources interface */
+
+		status = acpi_walk_resources(node, METHOD_NAME__CRS,
+					     acpi_db_resource_callback, NULL);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiWalkResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* Get the _CRS resource list (test ALLOCATE buffer) */
+
+		return_buffer.pointer = NULL;
+		return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+		status = acpi_get_current_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* This code exercises the acpi_walk_resource_buffer interface */
+
+		status = acpi_walk_resource_buffer(&return_buffer,
+						   acpi_db_resource_callback,
+						   NULL);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n",
+				       acpi_format_exception(status));
+			goto end_crs;
+		}
+
+		/* Dump the _CRS resource list */
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+							 return_buffer.
+							 pointer));
+
+		/*
+		 * Perform comparison of original AML to newly created AML. This
+		 * tests both the AML->Resource conversion and the Resource->AML
+		 * conversion.
+		 */
+		(void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS);
+
+		/* Execute _SRS with the resource list */
+
+		acpi_os_printf("Evaluating _SRS\n");
+
+		status = acpi_set_current_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiSetCurrentResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto end_crs;
+		}
+
+end_crs:
+		ACPI_FREE(return_buffer.pointer);
+	}
+
+	/* _PRS */
+
+get_prs:
+	if (prs_node) {
+		acpi_os_printf("Evaluating _PRS\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _PRS: %s\n",
+				       acpi_format_exception(status));
+			goto get_aei;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_possible_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetPossibleResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_aei;
+		}
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR
+					   (struct acpi_resource,
+					    acpi_gbl_db_buffer));
+	}
+
+	/* _AEI */
+
+get_aei:
+	if (aei_node) {
+		acpi_os_printf("Evaluating _AEI\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _AEI: %s\n",
+				       acpi_format_exception(status));
+			goto cleanup;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_event_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetEventResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto cleanup;
+		}
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR
+					   (struct acpi_resource,
+					    acpi_gbl_db_buffer));
+	}
+
+cleanup:
+	ACPI_FREE(parent_path);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_resources
+ *
+ * PARAMETERS:  object_arg          - String object name or object pointer.
+ *                                    NULL or "*" means "display resources for
+ *                                    all devices"
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the resource objects associated with a device.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_resources(char *object_arg)
+{
+	struct acpi_namespace_node *node;
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+	/* Asterisk means "display resources for all devices" */
+
+	if (!object_arg || (!strcmp(object_arg, "*"))) {
+		(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_device_resources, NULL, NULL,
+					  NULL);
+	} else {
+		/* Convert string to object pointer */
+
+		node = acpi_db_convert_to_node(object_arg);
+		if (node) {
+			if (node->type != ACPI_TYPE_DEVICE) {
+				acpi_os_printf
+				    ("%4.4s: Name is not a device object (%s)\n",
+				     node->name.ascii,
+				     acpi_ut_get_type_name(node->type));
+			} else {
+				(void)acpi_db_device_resources(node, 0, NULL,
+							       NULL);
+			}
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_gpe
+ *
+ * PARAMETERS:  gpe_arg             - Raw GPE number, ascii string
+ *              block_arg           - GPE block number, ascii string
+ *                                    0 or 1 for FADT GPE blocks
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate firing of a GPE
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
+{
+	u32 block_number = 0;
+	u32 gpe_number;
+	struct acpi_gpe_event_info *gpe_event_info;
+
+	gpe_number = strtoul(gpe_arg, NULL, 0);
+
+	/*
+	 * If no block arg, or block arg == 0 or 1, use the FADT-defined
+	 * GPE blocks.
+	 */
+	if (block_arg) {
+		block_number = strtoul(block_arg, NULL, 0);
+		if (block_number == 1) {
+			block_number = 0;
+		}
+	}
+
+	gpe_event_info =
+	    acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
+				       gpe_number);
+	if (!gpe_event_info) {
+		acpi_os_printf("Invalid GPE\n");
+		return;
+	}
+
+	(void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_sci
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch.
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_sci(void)
+{
+	acpi_ev_sci_dispatch();
+}
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_trace
+ *
+ * PARAMETERS:  enable_arg          - ENABLE/AML to enable tracer
+ *                                    DISABLE to disable tracer
+ *              method_arg          - Method to trace
+ *              once_arg            - Whether trace once
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Control method tracing facility
+ *
+ ******************************************************************************/
+
+void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg)
+{
+	u32 debug_level = 0;
+	u32 debug_layer = 0;
+	u32 flags = 0;
+
+	if (enable_arg) {
+		acpi_ut_strupr(enable_arg);
+	}
+
+	if (once_arg) {
+		acpi_ut_strupr(once_arg);
+	}
+
+	if (method_arg) {
+		if (acpi_db_trace_method_name) {
+			ACPI_FREE(acpi_db_trace_method_name);
+			acpi_db_trace_method_name = NULL;
+		}
+
+		acpi_db_trace_method_name =
+		    ACPI_ALLOCATE(strlen(method_arg) + 1);
+		if (!acpi_db_trace_method_name) {
+			acpi_os_printf("Failed to allocate method name (%s)\n",
+				       method_arg);
+			return;
+		}
+
+		strcpy(acpi_db_trace_method_name, method_arg);
+	}
+
+	if (!strcmp(enable_arg, "ENABLE") ||
+	    !strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) {
+		if (!strcmp(enable_arg, "ENABLE")) {
+
+			/* Inherit current console settings */
+
+			debug_level = acpi_gbl_db_console_debug_level;
+			debug_layer = acpi_dbg_layer;
+		} else {
+			/* Restrict console output to trace points only */
+
+			debug_level = ACPI_LV_TRACE_POINT;
+			debug_layer = ACPI_EXECUTER;
+		}
+
+		flags = ACPI_TRACE_ENABLED;
+
+		if (!strcmp(enable_arg, "OPCODE")) {
+			flags |= ACPI_TRACE_OPCODE;
+		}
+
+		if (once_arg && !strcmp(once_arg, "ONCE")) {
+			flags |= ACPI_TRACE_ONESHOT;
+		}
+	}
+
+	(void)acpi_debug_trace(acpi_db_trace_method_name,
+			       debug_level, debug_layer, flags);
+}
diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
new file mode 100644
index 0000000..a71632c
--- /dev/null
+++ b/drivers/acpi/acpica/dbconvert.c
@@ -0,0 +1,484 @@
+/*******************************************************************************
+ *
+ * Module Name: dbconvert - debugger miscellaneous conversion routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbconvert")
+
+#define DB_DEFAULT_PKG_ELEMENTS     33
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_char_to_value
+ *
+ * PARAMETERS:  hex_char            - Ascii Hex digit, 0-9|a-f|A-F
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16).
+ *
+ ******************************************************************************/
+acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value)
+{
+	u8 value;
+
+	/* Digit must be ascii [0-9a-fA-F] */
+
+	if (!isxdigit(hex_char)) {
+		return (AE_BAD_HEX_CONSTANT);
+	}
+
+	if (hex_char <= 0x39) {
+		value = (u8)(hex_char - 0x30);
+	} else {
+		value = (u8)(toupper(hex_char) - 0x37);
+	}
+
+	*return_value = value;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_byte_to_binary
+ *
+ * PARAMETERS:  hex_byte            - Double hex digit (0x00 - 0xFF) in format:
+ *                                    hi_byte then lo_byte.
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255).
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_hex_byte_to_binary(char *hex_byte, u8 *return_value)
+{
+	u8 local0;
+	u8 local1;
+	acpi_status status;
+
+	/* High byte */
+
+	status = acpi_db_hex_char_to_value(hex_byte[0], &local0);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Low byte */
+
+	status = acpi_db_hex_char_to_value(hex_byte[1], &local1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	*return_value = (u8)((local0 << 4) | local1);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_buffer
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the buffer object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a buffer object. String is treated a list
+ *              of buffer elements, each separated by a space or comma.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_convert_to_buffer(char *string, union acpi_object *object)
+{
+	u32 i;
+	u32 j;
+	u32 length;
+	u8 *buffer;
+	acpi_status status;
+
+	/* Generate the final buffer length */
+
+	for (i = 0, length = 0; string[i];) {
+		i += 2;
+		length++;
+
+		while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+			i++;
+		}
+	}
+
+	buffer = ACPI_ALLOCATE(length);
+	if (!buffer) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Convert the command line bytes to the buffer */
+
+	for (i = 0, j = 0; string[i];) {
+		status = acpi_db_hex_byte_to_binary(&string[i], &buffer[j]);
+		if (ACPI_FAILURE(status)) {
+			ACPI_FREE(buffer);
+			return (status);
+		}
+
+		j++;
+		i += 2;
+		while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+			i++;
+		}
+	}
+
+	object->type = ACPI_TYPE_BUFFER;
+	object->buffer.pointer = buffer;
+	object->buffer.length = length;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_package
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the package object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a package object. Handles nested packages
+ *              via recursion with acpi_db_convert_to_object.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_convert_to_package(char *string, union acpi_object * object)
+{
+	char *this;
+	char *next;
+	u32 i;
+	acpi_object_type type;
+	union acpi_object *elements;
+	acpi_status status;
+
+	elements =
+	    ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
+				 sizeof(union acpi_object));
+
+	this = string;
+	for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
+		this = acpi_db_get_next_token(this, &next, &type);
+		if (!this) {
+			break;
+		}
+
+		/* Recursive call to convert each package element */
+
+		status = acpi_db_convert_to_object(type, this, &elements[i]);
+		if (ACPI_FAILURE(status)) {
+			acpi_db_delete_objects(i + 1, elements);
+			ACPI_FREE(elements);
+			return (status);
+		}
+
+		this = next;
+	}
+
+	object->type = ACPI_TYPE_PACKAGE;
+	object->package.count = i;
+	object->package.elements = elements;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_object
+ *
+ * PARAMETERS:  type                - Object type as determined by parser
+ *              string              - Input string to be converted
+ *              object              - Where the new object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a typed and tokenized string to an union acpi_object. Typing:
+ *              1) String objects were surrounded by quotes.
+ *              2) Buffer objects were surrounded by parentheses.
+ *              3) Package objects were surrounded by brackets "[]".
+ *              4) All standalone tokens are treated as integers.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_convert_to_object(acpi_object_type type,
+			  char *string, union acpi_object * object)
+{
+	acpi_status status = AE_OK;
+
+	switch (type) {
+	case ACPI_TYPE_STRING:
+
+		object->type = ACPI_TYPE_STRING;
+		object->string.pointer = string;
+		object->string.length = (u32)strlen(string);
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		status = acpi_db_convert_to_buffer(string, object);
+		break;
+
+	case ACPI_TYPE_PACKAGE:
+
+		status = acpi_db_convert_to_package(string, object);
+		break;
+
+	default:
+
+		object->type = ACPI_TYPE_INTEGER;
+		status = acpi_ut_strtoul64(string, 16, &object->integer.value);
+		break;
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_encode_pld_buffer
+ *
+ * PARAMETERS:  pld_info            - _PLD buffer struct (Using local struct)
+ *
+ * RETURN:      Encode _PLD buffer suitable for return value from _PLD
+ *
+ * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros
+ *
+ ******************************************************************************/
+
+u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info)
+{
+	u32 *buffer;
+	u32 dword;
+
+	buffer = ACPI_ALLOCATE_ZEROED(ACPI_PLD_BUFFER_SIZE);
+	if (!buffer) {
+		return (NULL);
+	}
+
+	/* First 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_REVISION(&dword, pld_info->revision);
+	ACPI_PLD_SET_IGNORE_COLOR(&dword, pld_info->ignore_color);
+	ACPI_PLD_SET_RED(&dword, pld_info->red);
+	ACPI_PLD_SET_GREEN(&dword, pld_info->green);
+	ACPI_PLD_SET_BLUE(&dword, pld_info->blue);
+	ACPI_MOVE_32_TO_32(&buffer[0], &dword);
+
+	/* Second 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_WIDTH(&dword, pld_info->width);
+	ACPI_PLD_SET_HEIGHT(&dword, pld_info->height);
+	ACPI_MOVE_32_TO_32(&buffer[1], &dword);
+
+	/* Third 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_USER_VISIBLE(&dword, pld_info->user_visible);
+	ACPI_PLD_SET_DOCK(&dword, pld_info->dock);
+	ACPI_PLD_SET_LID(&dword, pld_info->lid);
+	ACPI_PLD_SET_PANEL(&dword, pld_info->panel);
+	ACPI_PLD_SET_VERTICAL(&dword, pld_info->vertical_position);
+	ACPI_PLD_SET_HORIZONTAL(&dword, pld_info->horizontal_position);
+	ACPI_PLD_SET_SHAPE(&dword, pld_info->shape);
+	ACPI_PLD_SET_ORIENTATION(&dword, pld_info->group_orientation);
+	ACPI_PLD_SET_TOKEN(&dword, pld_info->group_token);
+	ACPI_PLD_SET_POSITION(&dword, pld_info->group_position);
+	ACPI_PLD_SET_BAY(&dword, pld_info->bay);
+	ACPI_MOVE_32_TO_32(&buffer[2], &dword);
+
+	/* Fourth 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_EJECTABLE(&dword, pld_info->ejectable);
+	ACPI_PLD_SET_OSPM_EJECT(&dword, pld_info->ospm_eject_required);
+	ACPI_PLD_SET_CABINET(&dword, pld_info->cabinet_number);
+	ACPI_PLD_SET_CARD_CAGE(&dword, pld_info->card_cage_number);
+	ACPI_PLD_SET_REFERENCE(&dword, pld_info->reference);
+	ACPI_PLD_SET_ROTATION(&dword, pld_info->rotation);
+	ACPI_PLD_SET_ORDER(&dword, pld_info->order);
+	ACPI_MOVE_32_TO_32(&buffer[3], &dword);
+
+	if (pld_info->revision >= 2) {
+
+		/* Fifth 32 bits */
+
+		dword = 0;
+		ACPI_PLD_SET_VERT_OFFSET(&dword, pld_info->vertical_offset);
+		ACPI_PLD_SET_HORIZ_OFFSET(&dword, pld_info->horizontal_offset);
+		ACPI_MOVE_32_TO_32(&buffer[4], &dword);
+	}
+
+	return (ACPI_CAST_PTR(u8, buffer));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_pld_buffer
+ *
+ * PARAMETERS:  obj_desc            - Object returned from _PLD method
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Dumps formatted contents of a _PLD return buffer.
+ *
+ ******************************************************************************/
+
+#define ACPI_PLD_OUTPUT     "%20s : %-6X\n"
+
+void acpi_db_dump_pld_buffer(union acpi_object *obj_desc)
+{
+	union acpi_object *buffer_desc;
+	struct acpi_pld_info *pld_info;
+	u8 *new_buffer;
+	acpi_status status;
+
+	/* Object must be of type Package with at least one Buffer element */
+
+	if (obj_desc->type != ACPI_TYPE_PACKAGE) {
+		return;
+	}
+
+	buffer_desc = &obj_desc->package.elements[0];
+	if (buffer_desc->type != ACPI_TYPE_BUFFER) {
+		return;
+	}
+
+	/* Convert _PLD buffer to local _PLD struct */
+
+	status = acpi_decode_pld_buffer(buffer_desc->buffer.pointer,
+					buffer_desc->buffer.length, &pld_info);
+	if (ACPI_FAILURE(status)) {
+		return;
+	}
+
+	/* Encode local _PLD struct back to a _PLD buffer */
+
+	new_buffer = acpi_db_encode_pld_buffer(pld_info);
+	if (!new_buffer) {
+		return;
+	}
+
+	/* The two bit-packed buffers should match */
+
+	if (memcmp(new_buffer, buffer_desc->buffer.pointer,
+		   buffer_desc->buffer.length)) {
+		acpi_os_printf
+		    ("Converted _PLD buffer does not compare. New:\n");
+
+		acpi_ut_dump_buffer(new_buffer,
+				    buffer_desc->buffer.length, DB_BYTE_DISPLAY,
+				    0);
+	}
+
+	/* First 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Revision", pld_info->revision);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_IgnoreColor",
+		       pld_info->ignore_color);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Red", pld_info->red);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Green", pld_info->green);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Blue", pld_info->blue);
+
+	/* Second 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Width", pld_info->width);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Height", pld_info->height);
+
+	/* Third 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_UserVisible",
+		       pld_info->user_visible);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Dock", pld_info->dock);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Lid", pld_info->lid);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Panel", pld_info->panel);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalPosition",
+		       pld_info->vertical_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalPosition",
+		       pld_info->horizontal_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Shape", pld_info->shape);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupOrientation",
+		       pld_info->group_orientation);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupToken",
+		       pld_info->group_token);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupPosition",
+		       pld_info->group_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Bay", pld_info->bay);
+
+	/* Fourth 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Ejectable", pld_info->ejectable);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_EjectRequired",
+		       pld_info->ospm_eject_required);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CabinetNumber",
+		       pld_info->cabinet_number);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CardCageNumber",
+		       pld_info->card_cage_number);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Reference", pld_info->reference);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Rotation", pld_info->rotation);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Order", pld_info->order);
+
+	/* Fifth 32-bit dword */
+
+	if (buffer_desc->buffer.length > 16) {
+		acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalOffset",
+			       pld_info->vertical_offset);
+		acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalOffset",
+			       pld_info->horizontal_offset);
+	}
+
+	ACPI_FREE(pld_info);
+	ACPI_FREE(new_buffer);
+}
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
new file mode 100644
index 0000000..672977e
--- /dev/null
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -0,0 +1,1108 @@
+/*******************************************************************************
+ *
+ * Module Name: dbdisply - debug display commands
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbdisply")
+
+/* Local prototypes */
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op);
+
+static void *acpi_db_get_pointer(void *target);
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+/*
+ * System handler information.
+ * Used for Handlers command, in acpi_db_display_handlers.
+ */
+#define ACPI_PREDEFINED_PREFIX          "%25s (%.2X) : "
+#define ACPI_HANDLER_NAME_STRING               "%30s : "
+#define ACPI_HANDLER_PRESENT_STRING                    "%-9s (%p)\n"
+#define ACPI_HANDLER_PRESENT_STRING2                   "%-9s (%p)"
+#define ACPI_HANDLER_NOT_PRESENT_STRING                "%-9s\n"
+
+/* All predefined Address Space IDs */
+
+static acpi_adr_space_type acpi_gbl_space_id_list[] = {
+	ACPI_ADR_SPACE_SYSTEM_MEMORY,
+	ACPI_ADR_SPACE_SYSTEM_IO,
+	ACPI_ADR_SPACE_PCI_CONFIG,
+	ACPI_ADR_SPACE_EC,
+	ACPI_ADR_SPACE_SMBUS,
+	ACPI_ADR_SPACE_CMOS,
+	ACPI_ADR_SPACE_PCI_BAR_TARGET,
+	ACPI_ADR_SPACE_IPMI,
+	ACPI_ADR_SPACE_GPIO,
+	ACPI_ADR_SPACE_GSBUS,
+	ACPI_ADR_SPACE_DATA_TABLE,
+	ACPI_ADR_SPACE_FIXED_HARDWARE
+};
+
+/* Global handler information */
+
+typedef struct acpi_handler_info {
+	void *handler;
+	char *name;
+
+} acpi_handler_info;
+
+static struct acpi_handler_info acpi_gbl_handler_list[] = {
+	{&acpi_gbl_global_notify[0].handler, "System Notifications"},
+	{&acpi_gbl_global_notify[1].handler, "Device Notifications"},
+	{&acpi_gbl_table_handler, "ACPI Table Events"},
+	{&acpi_gbl_exception_handler, "Control Method Exceptions"},
+	{&acpi_gbl_interface_handler, "OSI Invocations"}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_pointer
+ *
+ * PARAMETERS:  target          - Pointer to string to be converted
+ *
+ * RETURN:      Converted pointer
+ *
+ * DESCRIPTION: Convert an ascii pointer value to a real value
+ *
+ ******************************************************************************/
+
+static void *acpi_db_get_pointer(void *target)
+{
+	void *obj_ptr;
+	acpi_size address;
+
+	address = strtoul(target, NULL, 16);
+	obj_ptr = ACPI_TO_POINTER(address);
+	return (obj_ptr);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_parser_descriptor
+ *
+ * PARAMETERS:  op              - A parser Op descriptor
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted parser object
+ *
+ ******************************************************************************/
+
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op)
+{
+	const struct acpi_opcode_info *info;
+
+	info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+
+	acpi_os_printf("Parser Op Descriptor:\n");
+	acpi_os_printf("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode);
+
+	ACPI_DEBUG_ONLY_MEMBERS(acpi_os_printf("%20.20s : %s\n", "Opcode Name",
+					       info->name));
+
+	acpi_os_printf("%20.20s : %p\n", "Value/ArgList", op->common.value.arg);
+	acpi_os_printf("%20.20s : %p\n", "Parent", op->common.parent);
+	acpi_os_printf("%20.20s : %p\n", "NextOp", op->common.next);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_and_display_object
+ *
+ * PARAMETERS:  target          - String with object to be displayed. Names
+ *                                and hex pointers are supported.
+ *              output_type     - Byte, Word, Dword, or Qword (B|W|D|Q)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted ACPI object
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_and_display_object(char *target, char *output_type)
+{
+	void *obj_ptr;
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	u32 display = DB_BYTE_DISPLAY;
+	char buffer[80];
+	struct acpi_buffer ret_buf;
+	acpi_status status;
+	u32 size;
+
+	if (!target) {
+		return;
+	}
+
+	/* Decode the output type */
+
+	if (output_type) {
+		acpi_ut_strupr(output_type);
+		if (output_type[0] == 'W') {
+			display = DB_WORD_DISPLAY;
+		} else if (output_type[0] == 'D') {
+			display = DB_DWORD_DISPLAY;
+		} else if (output_type[0] == 'Q') {
+			display = DB_QWORD_DISPLAY;
+		}
+	}
+
+	ret_buf.length = sizeof(buffer);
+	ret_buf.pointer = buffer;
+
+	/* Differentiate between a number and a name */
+
+	if ((target[0] >= 0x30) && (target[0] <= 0x39)) {
+		obj_ptr = acpi_db_get_pointer(target);
+		if (!acpi_os_readable(obj_ptr, 16)) {
+			acpi_os_printf
+			    ("Address %p is invalid in this address space\n",
+			     obj_ptr);
+			return;
+		}
+
+		/* Decode the object type */
+
+		switch (ACPI_GET_DESCRIPTOR_TYPE(obj_ptr)) {
+		case ACPI_DESC_TYPE_NAMED:
+
+			/* This is a namespace Node */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(struct acpi_namespace_node))) {
+				acpi_os_printf
+				    ("Cannot read entire Named object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			node = obj_ptr;
+			goto dump_node;
+
+		case ACPI_DESC_TYPE_OPERAND:
+
+			/* This is a ACPI OPERAND OBJECT */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(union acpi_operand_object))) {
+				acpi_os_printf
+				    ("Cannot read entire ACPI object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			acpi_ut_debug_dump_buffer(obj_ptr,
+						  sizeof(union
+							 acpi_operand_object),
+						  display, ACPI_UINT32_MAX);
+			acpi_ex_dump_object_descriptor(obj_ptr, 1);
+			break;
+
+		case ACPI_DESC_TYPE_PARSER:
+
+			/* This is a Parser Op object */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(union acpi_parse_object))) {
+				acpi_os_printf
+				    ("Cannot read entire Parser object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			acpi_ut_debug_dump_buffer(obj_ptr,
+						  sizeof(union
+							 acpi_parse_object),
+						  display, ACPI_UINT32_MAX);
+			acpi_db_dump_parser_descriptor((union acpi_parse_object
+							*)obj_ptr);
+			break;
+
+		default:
+
+			/* Is not a recognizeable object */
+
+			acpi_os_printf
+			    ("Not a known ACPI internal object, descriptor type %2.2X\n",
+			     ACPI_GET_DESCRIPTOR_TYPE(obj_ptr));
+
+			size = 16;
+			if (acpi_os_readable(obj_ptr, 64)) {
+				size = 64;
+			}
+
+			/* Just dump some memory */
+
+			acpi_ut_debug_dump_buffer(obj_ptr, size, display,
+						  ACPI_UINT32_MAX);
+			break;
+		}
+
+		return;
+	}
+
+	/* The parameter is a name string that must be resolved to a Named obj */
+
+	node = acpi_db_local_ns_lookup(target);
+	if (!node) {
+		return;
+	}
+
+dump_node:
+	/* Now dump the NS node */
+
+	status = acpi_get_name(node, ACPI_FULL_PATHNAME_NO_TRAILING, &ret_buf);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not convert name to pathname\n");
+	}
+
+	else {
+		acpi_os_printf("Object (%p) Pathname: %s\n",
+			       node, (char *)ret_buf.pointer);
+	}
+
+	if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+		acpi_os_printf("Invalid Named object at address %p\n", node);
+		return;
+	}
+
+	acpi_ut_debug_dump_buffer((void *)node,
+				  sizeof(struct acpi_namespace_node), display,
+				  ACPI_UINT32_MAX);
+	acpi_ex_dump_namespace_node(node, 1);
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
+		acpi_os_printf("\nAttached Object (%p):\n", obj_desc);
+		if (!acpi_os_readable
+		    (obj_desc, sizeof(union acpi_operand_object))) {
+			acpi_os_printf
+			    ("Invalid internal ACPI Object at address %p\n",
+			     obj_desc);
+			return;
+		}
+
+		acpi_ut_debug_dump_buffer((void *)obj_desc,
+					  sizeof(union acpi_operand_object),
+					  display, ACPI_UINT32_MAX);
+		acpi_ex_dump_object_descriptor(obj_desc, 1);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_method_info
+ *
+ * PARAMETERS:  start_op        - Root of the control method parse tree
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the current method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_method_info(union acpi_parse_object *start_op)
+{
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	union acpi_parse_object *root_op;
+	union acpi_parse_object *op;
+	const struct acpi_opcode_info *op_info;
+	u32 num_ops = 0;
+	u32 num_operands = 0;
+	u32 num_operators = 0;
+	u32 num_remaining_ops = 0;
+	u32 num_remaining_operands = 0;
+	u32 num_remaining_operators = 0;
+	u8 count_remaining = FALSE;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	acpi_os_printf("Currently executing control method is [%4.4s]\n",
+		       acpi_ut_get_node_name(node));
+	acpi_os_printf("%X Arguments, SyncLevel = %X\n",
+		       (u32)obj_desc->method.param_count,
+		       (u32)obj_desc->method.sync_level);
+
+	root_op = start_op;
+	while (root_op->common.parent) {
+		root_op = root_op->common.parent;
+	}
+
+	op = root_op;
+
+	while (op) {
+		if (op == start_op) {
+			count_remaining = TRUE;
+		}
+
+		num_ops++;
+		if (count_remaining) {
+			num_remaining_ops++;
+		}
+
+		/* Decode the opcode */
+
+		op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+		switch (op_info->class) {
+		case AML_CLASS_ARGUMENT:
+
+			if (count_remaining) {
+				num_remaining_operands++;
+			}
+
+			num_operands++;
+			break;
+
+		case AML_CLASS_UNKNOWN:
+
+			/* Bad opcode or ASCII character */
+
+			continue;
+
+		default:
+
+			if (count_remaining) {
+				num_remaining_operators++;
+			}
+
+			num_operators++;
+			break;
+		}
+
+		op = acpi_ps_get_depth_next(start_op, op);
+	}
+
+	acpi_os_printf
+	    ("Method contains:       %X AML Opcodes - %X Operators, %X Operands\n",
+	     num_ops, num_operators, num_operands);
+
+	acpi_os_printf
+	    ("Remaining to execute:  %X AML Opcodes - %X Operators, %X Operands\n",
+	     num_remaining_ops, num_remaining_operators,
+	     num_remaining_operands);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locals
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locals(void)
+{
+	struct acpi_walk_state *walk_state;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_db_decode_locals(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_arguments
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_arguments(void)
+{
+	struct acpi_walk_state *walk_state;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_db_decode_arguments(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_results
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current contents of a method result stack
+ *
+ ******************************************************************************/
+
+void acpi_db_display_results(void)
+{
+	u32 i;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	u32 result_count = 0;
+	struct acpi_namespace_node *node;
+	union acpi_generic_state *frame;
+	u32 index;		/* Index onto current frame */
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	if (walk_state->results) {
+		result_count = walk_state->result_count;
+	}
+
+	acpi_os_printf("Method [%4.4s] has %X stacked result objects\n",
+		       acpi_ut_get_node_name(node), result_count);
+
+	/* From the top element of result stack */
+
+	frame = walk_state->results;
+	index = (result_count - 1) % ACPI_RESULTS_FRAME_OBJ_NUM;
+
+	for (i = 0; i < result_count; i++) {
+		obj_desc = frame->results.obj_desc[index];
+		acpi_os_printf("Result%u: ", i);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+
+		if (index == 0) {
+			frame = frame->results.next;
+			index = ACPI_RESULTS_FRAME_OBJ_NUM;
+		}
+
+		index--;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_calling_tree
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current calling tree of nested control methods
+ *
+ ******************************************************************************/
+
+void acpi_db_display_calling_tree(void)
+{
+	struct acpi_walk_state *walk_state;
+	struct acpi_namespace_node *node;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	node = walk_state->method_node;
+	acpi_os_printf("Current Control Method Call Tree\n");
+
+	while (walk_state) {
+		node = walk_state->method_node;
+		acpi_os_printf("  [%4.4s]\n", acpi_ut_get_node_name(node));
+
+		walk_state = walk_state->next;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_object_type
+ *
+ * PARAMETERS:  name            - User entered NS node handle or name
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display type of an arbitrary NS node
+ *
+ ******************************************************************************/
+
+void acpi_db_display_object_type(char *name)
+{
+	struct acpi_namespace_node *node;
+	struct acpi_device_info *info;
+	acpi_status status;
+	u32 i;
+
+	node = acpi_db_convert_to_node(name);
+	if (!node) {
+		return;
+	}
+
+	status = acpi_get_object_info(ACPI_CAST_PTR(acpi_handle, node), &info);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not get object info, %s\n",
+			       acpi_format_exception(status));
+		return;
+	}
+
+	if (info->valid & ACPI_VALID_ADR) {
+		acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n",
+			       ACPI_FORMAT_UINT64(info->address),
+			       info->current_status, info->flags);
+	}
+	if (info->valid & ACPI_VALID_SXDS) {
+		acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n",
+			       info->highest_dstates[0],
+			       info->highest_dstates[1],
+			       info->highest_dstates[2],
+			       info->highest_dstates[3]);
+	}
+	if (info->valid & ACPI_VALID_SXWS) {
+		acpi_os_printf
+		    ("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n",
+		     info->lowest_dstates[0], info->lowest_dstates[1],
+		     info->lowest_dstates[2], info->lowest_dstates[3],
+		     info->lowest_dstates[4]);
+	}
+
+	if (info->valid & ACPI_VALID_HID) {
+		acpi_os_printf("HID: %s\n", info->hardware_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_UID) {
+		acpi_os_printf("UID: %s\n", info->unique_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_SUB) {
+		acpi_os_printf("SUB: %s\n", info->subsystem_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_CID) {
+		for (i = 0; i < info->compatible_id_list.count; i++) {
+			acpi_os_printf("CID %u: %s\n", i,
+				       info->compatible_id_list.ids[i].string);
+		}
+	}
+
+	ACPI_FREE(info);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_result_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ * Note: Curently only displays the result object if we are single stepping.
+ * However, this output may be useful in other contexts and could be enabled
+ * to do so if needed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_result_object(union acpi_operand_object *obj_desc,
+			      struct acpi_walk_state *walk_state)
+{
+
+	/* Only display if single stepping */
+
+	if (!acpi_gbl_cm_single_step) {
+		return;
+	}
+
+	acpi_os_printf("ResultObj: ");
+	acpi_db_display_internal_object(obj_desc, walk_state);
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_argument_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
+				struct acpi_walk_state *walk_state)
+{
+
+	if (!acpi_gbl_cm_single_step) {
+		return;
+	}
+
+	acpi_os_printf("ArgObj:  ");
+	acpi_db_display_internal_object(obj_desc, walk_state);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the current GPE structures
+ *
+ ******************************************************************************/
+
+void acpi_db_display_gpes(void)
+{
+	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_event_info *gpe_event_info;
+	struct acpi_gpe_register_info *gpe_register_info;
+	char *gpe_type;
+	struct acpi_gpe_notify_info *notify;
+	u32 gpe_index;
+	u32 block = 0;
+	u32 i;
+	u32 j;
+	u32 count;
+	char buffer[80];
+	struct acpi_buffer ret_buf;
+	acpi_status status;
+
+	ret_buf.length = sizeof(buffer);
+	ret_buf.pointer = buffer;
+
+	block = 0;
+
+	/* Walk the GPE lists */
+
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			status = acpi_get_name(gpe_block->node,
+					       ACPI_FULL_PATHNAME_NO_TRAILING,
+					       &ret_buf);
+			if (ACPI_FAILURE(status)) {
+				acpi_os_printf
+				    ("Could not convert name to pathname\n");
+			}
+
+			if (gpe_block->node == acpi_gbl_fadt_gpe_device) {
+				gpe_type = "FADT-defined GPE block";
+			} else {
+				gpe_type = "GPE Block Device";
+			}
+
+			acpi_os_printf
+			    ("\nBlock %u - Info %p  DeviceNode %p [%s] - %s\n",
+			     block, gpe_block, gpe_block->node, buffer,
+			     gpe_type);
+
+			acpi_os_printf("    Registers:    %u (%u GPEs)\n",
+				       gpe_block->register_count,
+				       gpe_block->gpe_count);
+
+			acpi_os_printf
+			    ("    GPE range:    0x%X to 0x%X on interrupt %u\n",
+			     gpe_block->block_base_number,
+			     gpe_block->block_base_number +
+			     (gpe_block->gpe_count - 1),
+			     gpe_xrupt_info->interrupt_number);
+
+			acpi_os_printf
+			    ("    RegisterInfo: %p  Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+			     gpe_block->register_info,
+			     ACPI_FORMAT_UINT64(gpe_block->register_info->
+						status_address.address),
+			     ACPI_FORMAT_UINT64(gpe_block->register_info->
+						enable_address.address));
+
+			acpi_os_printf("  EventInfo:    %p\n",
+				       gpe_block->event_info);
+
+			/* Examine each GPE Register within the block */
+
+			for (i = 0; i < gpe_block->register_count; i++) {
+				gpe_register_info =
+				    &gpe_block->register_info[i];
+
+				acpi_os_printf("    Reg %u: (GPE %.2X-%.2X)  "
+					       "RunEnable %2.2X WakeEnable %2.2X"
+					       " Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+					       i,
+					       gpe_register_info->
+					       base_gpe_number,
+					       gpe_register_info->
+					       base_gpe_number +
+					       (ACPI_GPE_REGISTER_WIDTH - 1),
+					       gpe_register_info->
+					       enable_for_run,
+					       gpe_register_info->
+					       enable_for_wake,
+					       ACPI_FORMAT_UINT64
+					       (gpe_register_info->
+						status_address.address),
+					       ACPI_FORMAT_UINT64
+					       (gpe_register_info->
+						enable_address.address));
+
+				/* Now look at the individual GPEs in this byte register */
+
+				for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+					gpe_index =
+					    (i * ACPI_GPE_REGISTER_WIDTH) + j;
+					gpe_event_info =
+					    &gpe_block->event_info[gpe_index];
+
+					if (ACPI_GPE_DISPATCH_TYPE
+					    (gpe_event_info->flags) ==
+					    ACPI_GPE_DISPATCH_NONE) {
+
+						/* This GPE is not used (no method or handler), ignore it */
+
+						continue;
+					}
+
+					acpi_os_printf
+					    ("        GPE %.2X: %p  RunRefs %2.2X Flags %2.2X (",
+					     gpe_block->block_base_number +
+					     gpe_index, gpe_event_info,
+					     gpe_event_info->runtime_count,
+					     gpe_event_info->flags);
+
+					/* Decode the flags byte */
+
+					if (gpe_event_info->
+					    flags & ACPI_GPE_LEVEL_TRIGGERED) {
+						acpi_os_printf("Level, ");
+					} else {
+						acpi_os_printf("Edge, ");
+					}
+
+					if (gpe_event_info->
+					    flags & ACPI_GPE_CAN_WAKE) {
+						acpi_os_printf("CanWake, ");
+					} else {
+						acpi_os_printf("RunOnly, ");
+					}
+
+					switch (ACPI_GPE_DISPATCH_TYPE
+						(gpe_event_info->flags)) {
+					case ACPI_GPE_DISPATCH_NONE:
+
+						acpi_os_printf("NotUsed");
+						break;
+
+					case ACPI_GPE_DISPATCH_METHOD:
+
+						acpi_os_printf("Method");
+						break;
+
+					case ACPI_GPE_DISPATCH_HANDLER:
+
+						acpi_os_printf("Handler");
+						break;
+
+					case ACPI_GPE_DISPATCH_NOTIFY:
+
+						count = 0;
+						notify =
+						    gpe_event_info->dispatch.
+						    notify_list;
+						while (notify) {
+							count++;
+							notify = notify->next;
+						}
+
+						acpi_os_printf
+						    ("Implicit Notify on %u devices",
+						     count);
+						break;
+
+					case ACPI_GPE_DISPATCH_RAW_HANDLER:
+
+						acpi_os_printf("RawHandler");
+						break;
+
+					default:
+
+						acpi_os_printf("UNKNOWN: %X",
+							       ACPI_GPE_DISPATCH_TYPE
+							       (gpe_event_info->
+								flags));
+						break;
+					}
+
+					acpi_os_printf(")\n");
+				}
+			}
+
+			block++;
+			gpe_block = gpe_block->next;
+		}
+
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+}
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_handlers
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the currently installed global handlers
+ *
+ ******************************************************************************/
+
+void acpi_db_display_handlers(void)
+{
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+	acpi_adr_space_type space_id;
+	u32 i;
+
+	/* Operation region handlers */
+
+	acpi_os_printf("\nOperation Region Handlers at the namespace root:\n");
+
+	obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node);
+	if (obj_desc) {
+		for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) {
+			space_id = acpi_gbl_space_id_list[i];
+			handler_obj = obj_desc->device.handler;
+
+			acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+				       acpi_ut_get_region_name((u8)space_id),
+				       space_id);
+
+			while (handler_obj) {
+				if (acpi_gbl_space_id_list[i] ==
+				    handler_obj->address_space.space_id) {
+					acpi_os_printf
+					    (ACPI_HANDLER_PRESENT_STRING,
+					     (handler_obj->address_space.
+					      handler_flags &
+					      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+					     ? "Default" : "User",
+					     handler_obj->address_space.
+					     handler);
+
+					goto found_handler;
+				}
+
+				handler_obj = handler_obj->address_space.next;
+			}
+
+			/* There is no handler for this space_id */
+
+			acpi_os_printf("None\n");
+
+found_handler:		;
+		}
+
+		/* Find all handlers for user-defined space_IDs */
+
+		handler_obj = obj_desc->device.handler;
+		while (handler_obj) {
+			if (handler_obj->address_space.space_id >=
+			    ACPI_USER_REGION_BEGIN) {
+				acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+					       "User-defined ID",
+					       handler_obj->address_space.
+					       space_id);
+				acpi_os_printf(ACPI_HANDLER_PRESENT_STRING,
+					       (handler_obj->address_space.
+						handler_flags &
+						ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+					       ? "Default" : "User",
+					       handler_obj->address_space.
+					       handler);
+			}
+
+			handler_obj = handler_obj->address_space.next;
+		}
+	}
+#if (!ACPI_REDUCED_HARDWARE)
+
+	/* Fixed event handlers */
+
+	acpi_os_printf("\nFixed Event Handlers:\n");
+
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+		acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+			       acpi_ut_get_event_name(i), i);
+		if (acpi_gbl_fixed_event_handlers[i].handler) {
+			acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+				       acpi_gbl_fixed_event_handlers[i].
+				       handler);
+		} else {
+			acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+		}
+	}
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+	/* Miscellaneous global handlers */
+
+	acpi_os_printf("\nMiscellaneous Global Handlers:\n");
+
+	for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_handler_list); i++) {
+		acpi_os_printf(ACPI_HANDLER_NAME_STRING,
+			       acpi_gbl_handler_list[i].name);
+
+		if (acpi_gbl_handler_list[i].handler) {
+			acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+				       acpi_gbl_handler_list[i].handler);
+		} else {
+			acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+		}
+	}
+
+	/* Other handlers that are installed throughout the namespace */
+
+	acpi_os_printf("\nOperation Region Handlers for specific devices:\n");
+
+	(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_display_non_root_handlers, NULL, NULL,
+				  NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_non_root_handlers
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display information about all handlers installed for a
+ *              device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+	char *pathname;
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* Display all handlers associated with this device */
+
+	handler_obj = obj_desc->device.handler;
+	while (handler_obj) {
+		acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+			       acpi_ut_get_region_name((u8)handler_obj->
+						       address_space.space_id),
+			       handler_obj->address_space.space_id);
+
+		acpi_os_printf(ACPI_HANDLER_PRESENT_STRING2,
+			       (handler_obj->address_space.handler_flags &
+				ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default"
+			       : "User", handler_obj->address_space.handler);
+
+		acpi_os_printf(" Device Name: %s (%p)\n", pathname, node);
+
+		handler_obj = handler_obj->address_space.next;
+	}
+
+	ACPI_FREE(pathname);
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
new file mode 100644
index 0000000..8eef298
--- /dev/null
+++ b/drivers/acpi/acpica/dbexec.c
@@ -0,0 +1,753 @@
+/*******************************************************************************
+ *
+ * Module Name: dbexec - debugger control method execution
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbexec")
+
+static struct acpi_db_method_info acpi_gbl_db_method_info;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+		       struct acpi_buffer *return_obj);
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
+
+static u32 acpi_db_get_outstanding_allocations(void);
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_delete_objects
+ *
+ * PARAMETERS:  count               - Count of objects in the list
+ *              objects             - Array of ACPI_OBJECTs to be deleted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
+ *              packages via recursion.
+ *
+ ******************************************************************************/
+
+void acpi_db_delete_objects(u32 count, union acpi_object *objects)
+{
+	u32 i;
+
+	for (i = 0; i < count; i++) {
+		switch (objects[i].type) {
+		case ACPI_TYPE_BUFFER:
+
+			ACPI_FREE(objects[i].buffer.pointer);
+			break;
+
+		case ACPI_TYPE_PACKAGE:
+
+			/* Recursive call to delete package elements */
+
+			acpi_db_delete_objects(objects[i].package.count,
+					       objects[i].package.elements);
+
+			/* Free the elements array */
+
+			ACPI_FREE(objects[i].package.elements);
+			break;
+
+		default:
+
+			break;
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_method
+ *
+ * PARAMETERS:  info            - Valid info segment
+ *              return_obj      - Where to put return object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+		       struct acpi_buffer *return_obj)
+{
+	acpi_status status;
+	struct acpi_object_list param_objects;
+	union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
+	u32 i;
+
+	ACPI_FUNCTION_TRACE(db_execute_method);
+
+	if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
+		acpi_os_printf("Warning: debug output is not enabled!\n");
+	}
+
+	param_objects.count = 0;
+	param_objects.pointer = NULL;
+
+	/* Pass through any command-line arguments */
+
+	if (info->args && info->args[0]) {
+
+		/* Get arguments passed on the command line */
+
+		for (i = 0; (info->args[i] && *(info->args[i])); i++) {
+
+			/* Convert input string (token) to an actual union acpi_object */
+
+			status = acpi_db_convert_to_object(info->types[i],
+							   info->args[i],
+							   &params[i]);
+			if (ACPI_FAILURE(status)) {
+				ACPI_EXCEPTION((AE_INFO, status,
+						"While parsing method arguments"));
+				goto cleanup;
+			}
+		}
+
+		param_objects.count = i;
+		param_objects.pointer = params;
+	}
+
+	/* Prepare for a return object of arbitrary size */
+
+	return_obj->pointer = acpi_gbl_db_buffer;
+	return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
+
+	/* Do the actual method execution */
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(NULL, info->pathname,
+				      &param_objects, return_obj);
+
+	acpi_gbl_cm_single_step = FALSE;
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"while executing %s from debugger",
+				info->pathname));
+
+		if (status == AE_BUFFER_OVERFLOW) {
+			ACPI_ERROR((AE_INFO,
+				    "Possible overflow of internal debugger "
+				    "buffer (size 0x%X needed 0x%X)",
+				    ACPI_DEBUG_BUFFER_SIZE,
+				    (u32)return_obj->length));
+		}
+	}
+
+cleanup:
+	acpi_db_delete_objects(param_objects.count, params);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_setup
+ *
+ * PARAMETERS:  info            - Valid method info
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Setup info segment prior to method execution
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_NAME(db_execute_setup);
+
+	/* Catenate the current scope to the supplied name */
+
+	info->pathname[0] = 0;
+	if ((info->name[0] != '\\') && (info->name[0] != '/')) {
+		if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+					acpi_gbl_db_scope_buf)) {
+			status = AE_BUFFER_OVERFLOW;
+			goto error_exit;
+		}
+	}
+
+	if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+				info->name)) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	acpi_db_prep_namestring(info->pathname);
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("Evaluating %s\n", info->pathname);
+
+	if (info->flags & EX_SINGLE_STEP) {
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	}
+
+	else {
+		/* No single step, allow redirection to a file */
+
+		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	}
+
+	return (AE_OK);
+
+error_exit:
+
+	ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
+	return (status);
+}
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
+{
+
+	return (cache->total_allocated - cache->total_freed -
+		cache->current_depth);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_outstanding_allocations
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Current global allocation count minus cache entries
+ *
+ * DESCRIPTION: Determine the current number of "outstanding" allocations --
+ *              those allocations that have not been freed and also are not
+ *              in one of the various object caches.
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_outstanding_allocations(void)
+{
+	u32 outstanding = 0;
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+	outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
+#endif
+
+	return (outstanding);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execution_walk
+ *
+ * PARAMETERS:  WALK_CALLBACK
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value)
+{
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	struct acpi_buffer return_obj;
+	acpi_status status;
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc->method.param_count) {
+		return (AE_OK);
+	}
+
+	return_obj.pointer = NULL;
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	acpi_ns_print_node_pathname(node, "Evaluating");
+
+	/* Do the actual method execution */
+
+	acpi_os_printf("\n");
+	acpi_gbl_method_executing = TRUE;
+
+	status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
+
+	acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
+		       acpi_ut_get_node_name(node),
+		       acpi_format_exception(status));
+
+	acpi_gbl_method_executing = FALSE;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute
+ *
+ * PARAMETERS:  name                - Name of method to execute
+ *              args                - Parameters to the method
+ *              Types               -
+ *              flags               - single step/no single step
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
+{
+	acpi_status status;
+	struct acpi_buffer return_obj;
+	char *name_string;
+
+#ifdef ACPI_DEBUG_OUTPUT
+	u32 previous_allocations;
+	u32 allocations;
+
+	/* Memory allocation tracking */
+
+	previous_allocations = acpi_db_get_outstanding_allocations();
+#endif
+
+	if (*name == '*') {
+		(void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_execution_walk, NULL, NULL,
+					  NULL);
+		return;
+	} else {
+		name_string = ACPI_ALLOCATE(strlen(name) + 1);
+		if (!name_string) {
+			return;
+		}
+
+		memset(&acpi_gbl_db_method_info, 0,
+		       sizeof(struct acpi_db_method_info));
+
+		strcpy(name_string, name);
+		acpi_ut_strupr(name_string);
+		acpi_gbl_db_method_info.name = name_string;
+		acpi_gbl_db_method_info.args = args;
+		acpi_gbl_db_method_info.types = types;
+		acpi_gbl_db_method_info.flags = flags;
+
+		return_obj.pointer = NULL;
+		return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+		status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+		if (ACPI_FAILURE(status)) {
+			ACPI_FREE(name_string);
+			return;
+		}
+
+		/* Get the NS node, determines existence also */
+
+		status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+					 &acpi_gbl_db_method_info.method);
+		if (ACPI_SUCCESS(status)) {
+			status =
+			    acpi_db_execute_method(&acpi_gbl_db_method_info,
+						   &return_obj);
+		}
+		ACPI_FREE(name_string);
+	}
+
+	/*
+	 * Allow any handlers in separate threads to complete.
+	 * (Such as Notify handlers invoked from AML executed above).
+	 */
+	acpi_os_sleep((u64)10);
+
+#ifdef ACPI_DEBUG_OUTPUT
+
+	/* Memory allocation tracking */
+
+	allocations =
+	    acpi_db_get_outstanding_allocations() - previous_allocations;
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+
+	if (allocations > 0) {
+		acpi_os_printf
+		    ("0x%X Outstanding allocations after evaluation of %s\n",
+		     allocations, acpi_gbl_db_method_info.pathname);
+	}
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Evaluation of %s failed with status %s\n",
+			       acpi_gbl_db_method_info.pathname,
+			       acpi_format_exception(status));
+	} else {
+		/* Display a return object, if any */
+
+		if (return_obj.length) {
+			acpi_os_printf("Evaluation of %s returned object %p, "
+				       "external buffer length %X\n",
+				       acpi_gbl_db_method_info.pathname,
+				       return_obj.pointer,
+				       (u32)return_obj.length);
+
+			acpi_db_dump_external_object(return_obj.pointer, 1);
+
+			/* Dump a _PLD buffer if present */
+
+			if (ACPI_COMPARE_NAME
+			    ((ACPI_CAST_PTR
+			      (struct acpi_namespace_node,
+			       acpi_gbl_db_method_info.method)->name.ascii),
+			     METHOD_NAME__PLD)) {
+				acpi_db_dump_pld_buffer(return_obj.pointer);
+			}
+		} else {
+			acpi_os_printf
+			    ("No object was returned from evaluation of %s\n",
+			     acpi_gbl_db_method_info.pathname);
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_method_thread
+ *
+ * PARAMETERS:  context             - Execution info segment
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
+{
+	acpi_status status;
+	struct acpi_db_method_info *info = context;
+	struct acpi_db_method_info local_info;
+	u32 i;
+	u8 allow;
+	struct acpi_buffer return_obj;
+
+	/*
+	 * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
+	 * Prevent acpi_gbl_db_method_info from being modified by multiple threads
+	 * concurrently.
+	 *
+	 * Note: The arguments we are passing are used by the ASL test suite
+	 * (aslts). Do not change them without updating the tests.
+	 */
+	(void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
+
+	if (info->init_args) {
+		acpi_db_uint32_to_hex_string(info->num_created,
+					     info->index_of_thread_str);
+		acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
+					     info->id_of_thread_str);
+	}
+
+	if (info->threads && (info->num_created < info->num_threads)) {
+		info->threads[info->num_created++] = acpi_os_get_thread_id();
+	}
+
+	local_info = *info;
+	local_info.args = local_info.arguments;
+	local_info.arguments[0] = local_info.num_threads_str;
+	local_info.arguments[1] = local_info.id_of_thread_str;
+	local_info.arguments[2] = local_info.index_of_thread_str;
+	local_info.arguments[3] = NULL;
+
+	local_info.types = local_info.arg_types;
+
+	(void)acpi_os_signal_semaphore(info->info_gate, 1);
+
+	for (i = 0; i < info->num_loops; i++) {
+		status = acpi_db_execute_method(&local_info, &return_obj);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s During evaluation of %s at iteration %X\n",
+			     acpi_format_exception(status), info->pathname, i);
+			if (status == AE_ABORT_METHOD) {
+				break;
+			}
+		}
+#if 0
+		if ((i % 100) == 0) {
+			acpi_os_printf("%u loops, Thread 0x%x\n",
+				       i, acpi_os_get_thread_id());
+		}
+
+		if (return_obj.length) {
+			acpi_os_printf
+			    ("Evaluation of %s returned object %p Buflen %X\n",
+			     info->pathname, return_obj.pointer,
+			     (u32)return_obj.length);
+			acpi_db_dump_external_object(return_obj.pointer, 1);
+		}
+#endif
+	}
+
+	/* Signal our completion */
+
+	allow = 0;
+	(void)acpi_os_wait_semaphore(info->thread_complete_gate,
+				     1, ACPI_WAIT_FOREVER);
+	info->num_completed++;
+
+	if (info->num_completed == info->num_threads) {
+
+		/* Do signal for main thread once only */
+		allow = 1;
+	}
+
+	(void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
+
+	if (allow) {
+		status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not signal debugger thread sync semaphore, %s\n",
+			     acpi_format_exception(status));
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_create_execution_threads
+ *
+ * PARAMETERS:  num_threads_arg         - Number of threads to create
+ *              num_loops_arg           - Loop count for the thread(s)
+ *              method_name_arg         - Control method to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Create threads to execute method(s)
+ *
+ ******************************************************************************/
+
+void
+acpi_db_create_execution_threads(char *num_threads_arg,
+				 char *num_loops_arg, char *method_name_arg)
+{
+	acpi_status status;
+	u32 num_threads;
+	u32 num_loops;
+	u32 i;
+	u32 size;
+	acpi_mutex main_thread_gate;
+	acpi_mutex thread_complete_gate;
+	acpi_mutex info_gate;
+
+	/* Get the arguments */
+
+	num_threads = strtoul(num_threads_arg, NULL, 0);
+	num_loops = strtoul(num_loops_arg, NULL, 0);
+
+	if (!num_threads || !num_loops) {
+		acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
+			       num_threads, num_loops);
+		return;
+	}
+
+	/*
+	 * Create the semaphore for synchronization of
+	 * the created threads with the main thread.
+	 */
+	status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization with the main thread, %s\n",
+			       acpi_format_exception(status));
+		return;
+	}
+
+	/*
+	 * Create the semaphore for synchronization
+	 * between the created threads.
+	 */
+	status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization between the created threads, %s\n",
+			       acpi_format_exception(status));
+
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		return;
+	}
+
+	status = acpi_os_create_semaphore(1, 1, &info_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization of AcpiGbl_DbMethodInfo, %s\n",
+			       acpi_format_exception(status));
+
+		(void)acpi_os_delete_semaphore(thread_complete_gate);
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		return;
+	}
+
+	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
+
+	/* Array to store IDs of threads */
+
+	acpi_gbl_db_method_info.num_threads = num_threads;
+	size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
+
+	acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
+	if (acpi_gbl_db_method_info.threads == NULL) {
+		acpi_os_printf("No memory for thread IDs array\n");
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		(void)acpi_os_delete_semaphore(thread_complete_gate);
+		(void)acpi_os_delete_semaphore(info_gate);
+		return;
+	}
+	memset(acpi_gbl_db_method_info.threads, 0, size);
+
+	/* Setup the context to be passed to each thread */
+
+	acpi_gbl_db_method_info.name = method_name_arg;
+	acpi_gbl_db_method_info.flags = 0;
+	acpi_gbl_db_method_info.num_loops = num_loops;
+	acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
+	acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
+	acpi_gbl_db_method_info.info_gate = info_gate;
+
+	/* Init arguments to be passed to method */
+
+	acpi_gbl_db_method_info.init_args = 1;
+	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
+	acpi_gbl_db_method_info.arguments[0] =
+	    acpi_gbl_db_method_info.num_threads_str;
+	acpi_gbl_db_method_info.arguments[1] =
+	    acpi_gbl_db_method_info.id_of_thread_str;
+	acpi_gbl_db_method_info.arguments[2] =
+	    acpi_gbl_db_method_info.index_of_thread_str;
+	acpi_gbl_db_method_info.arguments[3] = NULL;
+
+	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
+	acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
+	acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
+	acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
+
+	acpi_db_uint32_to_hex_string(num_threads,
+				     acpi_gbl_db_method_info.num_threads_str);
+
+	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+	if (ACPI_FAILURE(status)) {
+		goto cleanup_and_exit;
+	}
+
+	/* Get the NS node, determines existence also */
+
+	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+				 &acpi_gbl_db_method_info.method);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("%s Could not get handle for %s\n",
+			       acpi_format_exception(status),
+			       acpi_gbl_db_method_info.pathname);
+		goto cleanup_and_exit;
+	}
+
+	/* Create the threads */
+
+	acpi_os_printf("Creating %X threads to execute %X times each\n",
+		       num_threads, num_loops);
+
+	for (i = 0; i < (num_threads); i++) {
+		status =
+		    acpi_os_execute(OSL_DEBUGGER_THREAD, acpi_db_method_thread,
+				    &acpi_gbl_db_method_info);
+		if (ACPI_FAILURE(status)) {
+			break;
+		}
+	}
+
+	/* Wait for all threads to complete */
+
+	(void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("All threads (%X) have completed\n", num_threads);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+
+cleanup_and_exit:
+
+	/* Cleanup and exit */
+
+	(void)acpi_os_delete_semaphore(main_thread_gate);
+	(void)acpi_os_delete_semaphore(thread_complete_gate);
+	(void)acpi_os_delete_semaphore(info_gate);
+
+	acpi_os_free(acpi_gbl_db_method_info.threads);
+	acpi_gbl_db_method_info.threads = NULL;
+}
diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c
new file mode 100644
index 0000000..d0e6b20
--- /dev/null
+++ b/drivers/acpi/acpica/dbfileio.c
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ *
+ * Module Name: dbfileio - Debugger file I/O commands. These can't usually
+ *              be used when running the debugger in Ring 0 (Kernel mode)
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbfileio")
+
+#ifdef ACPI_DEBUGGER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_close_debug_file
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: If open, close the current debug output file
+ *
+ ******************************************************************************/
+void acpi_db_close_debug_file(void)
+{
+
+#ifdef ACPI_APPLICATION
+
+	if (acpi_gbl_debug_file) {
+		fclose(acpi_gbl_debug_file);
+		acpi_gbl_debug_file = NULL;
+		acpi_gbl_db_output_to_file = FALSE;
+		acpi_os_printf("Debug output file %s closed\n",
+			       acpi_gbl_db_debug_filename);
+	}
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_open_debug_file
+ *
+ * PARAMETERS:  name                - Filename to open
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Open a file where debug output will be directed.
+ *
+ ******************************************************************************/
+
+void acpi_db_open_debug_file(char *name)
+{
+
+#ifdef ACPI_APPLICATION
+
+	acpi_db_close_debug_file();
+	acpi_gbl_debug_file = fopen(name, "w+");
+	if (!acpi_gbl_debug_file) {
+		acpi_os_printf("Could not open debug file %s\n", name);
+		return;
+	}
+
+	acpi_os_printf("Debug output file %s opened\n", name);
+	strncpy(acpi_gbl_db_debug_filename, name,
+		sizeof(acpi_gbl_db_debug_filename));
+	acpi_gbl_db_output_to_file = TRUE;
+
+#endif
+}
+#endif
+
+#ifdef ACPI_APPLICATION
+#include "acapps.h"
+
+/*******************************************************************************
+ *
+ * FUNCTION:    ae_local_load_table
+ *
+ * PARAMETERS:  table           - pointer to a buffer containing the entire
+ *                                table to be loaded
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to load a table from the caller's
+ *              buffer. The buffer must contain an entire ACPI Table including
+ *              a valid header. The header fields will be verified, and if it
+ *              is determined that the table is invalid, the call will fail.
+ *
+ ******************************************************************************/
+
+static acpi_status ae_local_load_table(struct acpi_table_header *table)
+{
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE(ae_local_load_table);
+
+#if 0
+/*    struct acpi_table_desc          table_info; */
+
+	if (!table) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	table_info.pointer = table;
+	status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Install the new table into the local data structures */
+
+	status = acpi_tb_init_table_descriptor(&table_info);
+	if (ACPI_FAILURE(status)) {
+		if (status == AE_ALREADY_EXISTS) {
+
+			/* Table already exists, no error */
+
+			status = AE_OK;
+		}
+
+		/* Free table allocated by acpi_tb_get_table */
+
+		acpi_tb_delete_single_table(&table_info);
+		return_ACPI_STATUS(status);
+	}
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+	status =
+	    acpi_ns_load_table(table_info.installed_desc, acpi_gbl_root_node);
+	if (ACPI_FAILURE(status)) {
+
+		/* Uninstall table and free the buffer */
+
+		acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_DSDT);
+		return_ACPI_STATUS(status);
+	}
+#endif
+#endif
+
+	return_ACPI_STATUS(status);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_table_from_file
+ *
+ * PARAMETERS:  filename        - File where table is located
+ *              return_table    - Where a pointer to the table is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load an ACPI table from a file
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_get_table_from_file(char *filename,
+			    struct acpi_table_header **return_table,
+			    u8 must_be_aml_file)
+{
+#ifdef ACPI_APPLICATION
+	acpi_status status;
+	struct acpi_table_header *table;
+	u8 is_aml_table = TRUE;
+
+	status = acpi_ut_read_table_from_file(filename, &table);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	if (must_be_aml_file) {
+		is_aml_table = acpi_ut_is_aml_table(table);
+		if (!is_aml_table) {
+			ACPI_EXCEPTION((AE_INFO, AE_OK,
+					"Input for -e is not an AML table: "
+					"\"%4.4s\" (must be DSDT/SSDT)",
+					table->signature));
+			return (AE_TYPE);
+		}
+	}
+
+	if (is_aml_table) {
+
+		/* Attempt to recognize and install the table */
+
+		status = ae_local_load_table(table);
+		if (ACPI_FAILURE(status)) {
+			if (status == AE_ALREADY_EXISTS) {
+				acpi_os_printf
+				    ("Table %4.4s is already installed\n",
+				     table->signature);
+			} else {
+				acpi_os_printf("Could not install table, %s\n",
+					       acpi_format_exception(status));
+			}
+
+			return (status);
+		}
+
+		acpi_tb_print_table_header(0, table);
+
+		fprintf(stderr,
+			"Acpi table [%4.4s] successfully installed and loaded\n",
+			table->signature);
+	}
+
+	acpi_gbl_acpi_hardware_present = FALSE;
+	if (return_table) {
+		*return_table = table;
+	}
+
+#endif				/* ACPI_APPLICATION */
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c
new file mode 100644
index 0000000..9c66a9e
--- /dev/null
+++ b/drivers/acpi/acpica/dbhistry.c
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * Module Name: dbhistry - debugger HISTORY command
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbhistry")
+
+#define HI_NO_HISTORY       0
+#define HI_RECORD_HISTORY   1
+#define HISTORY_SIZE        40
+typedef struct history_info {
+	char *command;
+	u32 cmd_num;
+
+} HISTORY_INFO;
+
+static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
+static u16 acpi_gbl_lo_history = 0;
+static u16 acpi_gbl_num_history = 0;
+static u16 acpi_gbl_next_history_index = 0;
+u32 acpi_gbl_next_cmd_num = 1;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_add_to_history
+ *
+ * PARAMETERS:  command_line    - Command to add
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add a command line to the history buffer.
+ *
+ ******************************************************************************/
+
+void acpi_db_add_to_history(char *command_line)
+{
+	u16 cmd_len;
+	u16 buffer_len;
+
+	/* Put command into the next available slot */
+
+	cmd_len = (u16)strlen(command_line);
+	if (!cmd_len) {
+		return;
+	}
+
+	if (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command !=
+	    NULL) {
+		buffer_len =
+		    (u16)
+		    strlen(acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+			   command);
+
+		if (cmd_len > buffer_len) {
+			acpi_os_free(acpi_gbl_history_buffer
+				     [acpi_gbl_next_history_index].command);
+			acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+			    command = acpi_os_allocate(cmd_len + 1);
+		}
+	} else {
+		acpi_gbl_history_buffer[acpi_gbl_next_history_index].command =
+		    acpi_os_allocate(cmd_len + 1);
+	}
+
+	strcpy(acpi_gbl_history_buffer[acpi_gbl_next_history_index].command,
+	       command_line);
+
+	acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num =
+	    acpi_gbl_next_cmd_num;
+
+	/* Adjust indexes */
+
+	if ((acpi_gbl_num_history == HISTORY_SIZE) &&
+	    (acpi_gbl_next_history_index == acpi_gbl_lo_history)) {
+		acpi_gbl_lo_history++;
+		if (acpi_gbl_lo_history >= HISTORY_SIZE) {
+			acpi_gbl_lo_history = 0;
+		}
+	}
+
+	acpi_gbl_next_history_index++;
+	if (acpi_gbl_next_history_index >= HISTORY_SIZE) {
+		acpi_gbl_next_history_index = 0;
+	}
+
+	acpi_gbl_next_cmd_num++;
+	if (acpi_gbl_num_history < HISTORY_SIZE) {
+		acpi_gbl_num_history++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_history
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the contents of the history buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_display_history(void)
+{
+	u32 i;
+	u16 history_index;
+
+	history_index = acpi_gbl_lo_history;
+
+	/* Dump entire history buffer */
+
+	for (i = 0; i < acpi_gbl_num_history; i++) {
+		if (acpi_gbl_history_buffer[history_index].command) {
+			acpi_os_printf("%3ld %s\n",
+				       acpi_gbl_history_buffer[history_index].
+				       cmd_num,
+				       acpi_gbl_history_buffer[history_index].
+				       command);
+		}
+
+		history_index++;
+		if (history_index >= HISTORY_SIZE) {
+			history_index = 0;
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_from_history
+ *
+ * PARAMETERS:  command_num_arg         - String containing the number of the
+ *                                        command to be retrieved
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_from_history(char *command_num_arg)
+{
+	u32 cmd_num;
+
+	if (command_num_arg == NULL) {
+		cmd_num = acpi_gbl_next_cmd_num - 1;
+	}
+
+	else {
+		cmd_num = strtoul(command_num_arg, NULL, 0);
+	}
+
+	return (acpi_db_get_history_by_index(cmd_num));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_history_by_index
+ *
+ * PARAMETERS:  cmd_num             - Index of the desired history entry.
+ *                                    Values are 0...(acpi_gbl_next_cmd_num - 1)
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_history_by_index(u32 cmd_num)
+{
+	u32 i;
+	u16 history_index;
+
+	/* Search history buffer */
+
+	history_index = acpi_gbl_lo_history;
+	for (i = 0; i < acpi_gbl_num_history; i++) {
+		if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) {
+
+			/* Found the command, return it */
+
+			return (acpi_gbl_history_buffer[history_index].command);
+		}
+
+		/* History buffer is circular */
+
+		history_index++;
+		if (history_index >= HISTORY_SIZE) {
+			history_index = 0;
+		}
+	}
+
+	acpi_os_printf("Invalid history number: %u\n", history_index);
+	return (NULL);
+}
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
new file mode 100644
index 0000000..7f1b6ec
--- /dev/null
+++ b/drivers/acpi/acpica/dbinput.c
@@ -0,0 +1,1274 @@
+/*******************************************************************************
+ *
+ * Module Name: dbinput - user front-end to the AML debugger
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbinput")
+
+/* Local prototypes */
+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);
+
+static u8
+acpi_db_match_command_help(char *command,
+			   const struct acpi_db_command_help *help);
+
+/*
+ * Top-level debugger commands.
+ *
+ * This list of commands must match the string table below it
+ */
+enum acpi_ex_debugger_commands {
+	CMD_NOT_FOUND = 0,
+	CMD_NULL,
+	CMD_ALLOCATIONS,
+	CMD_ARGS,
+	CMD_ARGUMENTS,
+	CMD_BREAKPOINT,
+	CMD_BUSINFO,
+	CMD_CALL,
+	CMD_DEBUG,
+	CMD_DISASSEMBLE,
+	CMD_DISASM,
+	CMD_DUMP,
+	CMD_EVALUATE,
+	CMD_EXECUTE,
+	CMD_EXIT,
+	CMD_FIND,
+	CMD_GO,
+	CMD_HANDLERS,
+	CMD_HELP,
+	CMD_HELP2,
+	CMD_HISTORY,
+	CMD_HISTORY_EXE,
+	CMD_HISTORY_LAST,
+	CMD_INFORMATION,
+	CMD_INTEGRITY,
+	CMD_INTO,
+	CMD_LEVEL,
+	CMD_LIST,
+	CMD_LOCALS,
+	CMD_LOCKS,
+	CMD_METHODS,
+	CMD_NAMESPACE,
+	CMD_NOTIFY,
+	CMD_OBJECTS,
+	CMD_OSI,
+	CMD_OWNER,
+	CMD_PATHS,
+	CMD_PREDEFINED,
+	CMD_PREFIX,
+	CMD_QUIT,
+	CMD_REFERENCES,
+	CMD_RESOURCES,
+	CMD_RESULTS,
+	CMD_SET,
+	CMD_STATS,
+	CMD_STOP,
+	CMD_TABLES,
+	CMD_TEMPLATE,
+	CMD_TRACE,
+	CMD_TREE,
+	CMD_TYPE,
+#ifdef ACPI_APPLICATION
+	CMD_ENABLEACPI,
+	CMD_EVENT,
+	CMD_GPE,
+	CMD_GPES,
+	CMD_SCI,
+	CMD_SLEEP,
+
+	CMD_CLOSE,
+	CMD_LOAD,
+	CMD_OPEN,
+	CMD_UNLOAD,
+
+	CMD_TERMINATE,
+	CMD_THREADS,
+
+	CMD_TEST,
+#endif
+};
+
+#define CMD_FIRST_VALID     2
+
+/* Second parameter is the required argument count */
+
+static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
+	{"<NOT FOUND>", 0},
+	{"<NULL>", 0},
+	{"ALLOCATIONS", 0},
+	{"ARGS", 0},
+	{"ARGUMENTS", 0},
+	{"BREAKPOINT", 1},
+	{"BUSINFO", 0},
+	{"CALL", 0},
+	{"DEBUG", 1},
+	{"DISASSEMBLE", 1},
+	{"DISASM", 1},
+	{"DUMP", 1},
+	{"EVALUATE", 1},
+	{"EXECUTE", 1},
+	{"EXIT", 0},
+	{"FIND", 1},
+	{"GO", 0},
+	{"HANDLERS", 0},
+	{"HELP", 0},
+	{"?", 0},
+	{"HISTORY", 0},
+	{"!", 1},
+	{"!!", 0},
+	{"INFORMATION", 0},
+	{"INTEGRITY", 0},
+	{"INTO", 0},
+	{"LEVEL", 0},
+	{"LIST", 0},
+	{"LOCALS", 0},
+	{"LOCKS", 0},
+	{"METHODS", 0},
+	{"NAMESPACE", 0},
+	{"NOTIFY", 2},
+	{"OBJECTS", 0},
+	{"OSI", 0},
+	{"OWNER", 1},
+	{"PATHS", 0},
+	{"PREDEFINED", 0},
+	{"PREFIX", 0},
+	{"QUIT", 0},
+	{"REFERENCES", 1},
+	{"RESOURCES", 0},
+	{"RESULTS", 0},
+	{"SET", 3},
+	{"STATS", 1},
+	{"STOP", 0},
+	{"TABLES", 0},
+	{"TEMPLATE", 1},
+	{"TRACE", 1},
+	{"TREE", 0},
+	{"TYPE", 1},
+#ifdef ACPI_APPLICATION
+	{"ENABLEACPI", 0},
+	{"EVENT", 1},
+	{"GPE", 1},
+	{"GPES", 0},
+	{"SCI", 0},
+	{"SLEEP", 0},
+
+	{"CLOSE", 0},
+	{"LOAD", 1},
+	{"OPEN", 1},
+	{"UNLOAD", 1},
+
+	{"TERMINATE", 0},
+	{"THREADS", 3},
+
+	{"TEST", 1},
+#endif
+	{NULL, 0}
+};
+
+/*
+ * Help for all debugger commands. First argument is the number of lines
+ * of help to output for the command.
+ */
+static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
+	{0, "\nGeneral-Purpose Commands:", "\n"},
+	{1, "  Allocations", "Display list of current memory allocations\n"},
+	{2, "  Dump <Address>|<Namepath>", "\n"},
+	{0, "       [Byte|Word|Dword|Qword]",
+	 "Display ACPI objects or memory\n"},
+	{1, "  Handlers", "Info about global handlers\n"},
+	{1, "  Help [Command]", "This help screen or individual command\n"},
+	{1, "  History", "Display command history buffer\n"},
+	{1, "  Level <DebugLevel>] [console]",
+	 "Get/Set debug level for file or console\n"},
+	{1, "  Locks", "Current status of internal mutexes\n"},
+	{1, "  Osi [Install|Remove <name>]",
+	 "Display or modify global _OSI list\n"},
+	{1, "  Quit or Exit", "Exit this command\n"},
+	{8, "  Stats <SubCommand>",
+	 "Display namespace and memory statistics\n"},
+	{1, "     Allocations", "Display list of current memory allocations\n"},
+	{1, "     Memory", "Dump internal memory lists\n"},
+	{1, "     Misc", "Namespace search and mutex stats\n"},
+	{1, "     Objects", "Summary of namespace objects\n"},
+	{1, "     Sizes", "Sizes for each of the internal objects\n"},
+	{1, "     Stack", "Display CPU stack usage\n"},
+	{1, "     Tables", "Info about current ACPI table(s)\n"},
+	{1, "  Tables", "Display info about loaded ACPI tables\n"},
+	{1, "  ! <CommandNumber>", "Execute command from history buffer\n"},
+	{1, "  !!", "Execute last command again\n"},
+
+	{0, "\nNamespace Access Commands:", "\n"},
+	{1, "  Businfo", "Display system bus info\n"},
+	{1, "  Disassemble <Method>", "Disassemble a control method\n"},
+	{1, "  Find <AcpiName> (? is wildcard)",
+	 "Find ACPI name(s) with wildcards\n"},
+	{1, "  Integrity", "Validate namespace integrity\n"},
+	{1, "  Methods", "Display list of loaded control methods\n"},
+	{1, "  Namespace [Object] [Depth]",
+	 "Display loaded namespace tree/subtree\n"},
+	{1, "  Notify <Object> <Value>", "Send a notification on Object\n"},
+	{1, "  Objects [ObjectType]",
+	 "Display summary of all objects or just given type\n"},
+	{1, "  Owner <OwnerId> [Depth]",
+	 "Display loaded namespace by object owner\n"},
+	{1, "  Paths", "Display full pathnames of namespace objects\n"},
+	{1, "  Predefined", "Check all predefined names\n"},
+	{1, "  Prefix [<Namepath>]", "Set or Get current execution prefix\n"},
+	{1, "  References <Addr>", "Find all references to object at addr\n"},
+	{1, "  Resources [DeviceName]",
+	 "Display Device resources (no arg = all devices)\n"},
+	{1, "  Set N <NamedObject> <Value>", "Set value for named integer\n"},
+	{1, "  Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"},
+	{1, "  Type <Object>", "Display object type\n"},
+
+	{0, "\nControl Method Execution Commands:", "\n"},
+	{1, "  Arguments (or Args)", "Display method arguments\n"},
+	{1, "  Breakpoint <AmlOffset>", "Set an AML execution breakpoint\n"},
+	{1, "  Call", "Run to next control method invocation\n"},
+	{1, "  Debug <Namepath> [Arguments]", "Single Step a control method\n"},
+	{6, "  Evaluate", "Synonym for Execute\n"},
+	{5, "  Execute <Namepath> [Arguments]", "Execute control method\n"},
+	{1, "     Hex Integer", "Integer method argument\n"},
+	{1, "     \"Ascii String\"", "String method argument\n"},
+	{1, "     (Hex Byte List)", "Buffer method argument\n"},
+	{1, "     [Package Element List]", "Package method argument\n"},
+	{1, "  Go", "Allow method to run to completion\n"},
+	{1, "  Information", "Display info about the current method\n"},
+	{1, "  Into", "Step into (not over) a method call\n"},
+	{1, "  List [# of Aml Opcodes]", "Display method ASL statements\n"},
+	{1, "  Locals", "Display method local variables\n"},
+	{1, "  Results", "Display method result stack\n"},
+	{1, "  Set <A|L> <#> <Value>", "Set method data (Arguments/Locals)\n"},
+	{1, "  Stop", "Terminate control method\n"},
+	{5, "  Trace <State> [<Namepath>] [Once]",
+	 "Trace control method execution\n"},
+	{1, "     Enable", "Enable all messages\n"},
+	{1, "     Disable", "Disable tracing\n"},
+	{1, "     Method", "Enable method execution messages\n"},
+	{1, "     Opcode", "Enable opcode execution messages\n"},
+	{1, "  Tree", "Display control method calling tree\n"},
+	{1, "  <Enter>", "Single step next AML opcode (over calls)\n"},
+
+#ifdef ACPI_APPLICATION
+	{0, "\nHardware Simulation Commands:", "\n"},
+	{1, "  EnableAcpi", "Enable ACPI (hardware) mode\n"},
+	{1, "  Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"},
+	{1, "  Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"},
+	{1, "  Gpes", "Display info on all GPE devices\n"},
+	{1, "  Sci", "Generate an SCI\n"},
+	{1, "  Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"},
+
+	{0, "\nFile I/O Commands:", "\n"},
+	{1, "  Close", "Close debug output file\n"},
+	{1, "  Load <Input Filename>", "Load ACPI table from a file\n"},
+	{1, "  Open <Output Filename>", "Open a file for debug output\n"},
+	{1, "  Unload <Namepath>",
+	 "Unload an ACPI table via namespace object\n"},
+
+	{0, "\nUser Space Commands:", "\n"},
+	{1, "  Terminate", "Delete namespace and all internal objects\n"},
+	{1, "  Thread <Threads><Loops><NamePath>",
+	 "Spawn threads to execute method(s)\n"},
+
+	{0, "\nDebug Test Commands:", "\n"},
+	{3, "  Test <TestName>", "Invoke a debug test\n"},
+	{1, "     Objects", "Read/write/compare all namespace data objects\n"},
+	{1, "     Predefined",
+	 "Execute all ACPI predefined names (_STA, etc.)\n"},
+#endif
+	{0, NULL, NULL}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command_help
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              help                - Help table entry to attempt match
+ *
+ * RETURN:      TRUE if command matched, FALSE otherwise
+ *
+ * DESCRIPTION: Attempt to match a command in the help table in order to
+ *              print help information for a single command.
+ *
+ ******************************************************************************/
+
+static u8
+acpi_db_match_command_help(char *command,
+			   const struct acpi_db_command_help *help)
+{
+	char *invocation = help->invocation;
+	u32 line_count;
+
+	/* Valid commands in the help table begin with a couple of spaces */
+
+	if (*invocation != ' ') {
+		return (FALSE);
+	}
+
+	while (*invocation == ' ') {
+		invocation++;
+	}
+
+	/* Match command name (full command or substring) */
+
+	while ((*command) && (*invocation) && (*invocation != ' ')) {
+		if (tolower((int)*command) != tolower((int)*invocation)) {
+			return (FALSE);
+		}
+
+		invocation++;
+		command++;
+	}
+
+	/* Print the appropriate number of help lines */
+
+	line_count = help->line_count;
+	while (line_count) {
+		acpi_os_printf("%-38s : %s", help->invocation,
+			       help->description);
+		help++;
+		line_count--;
+	}
+
+	return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_command_info
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              display_all         - Display all matching commands, or just
+ *                                    the first one (substring match)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help information for a Debugger command.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_command_info(char *command, u8 display_all)
+{
+	const struct acpi_db_command_help *next;
+	u8 matched;
+
+	next = acpi_gbl_db_command_help;
+	while (next->invocation) {
+		matched = acpi_db_match_command_help(command, next);
+		if (!display_all && matched) {
+			return;
+		}
+
+		next++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_help
+ *
+ * PARAMETERS:  command             - Optional command string to display help.
+ *                                    if not specified, all debugger command
+ *                                    help strings are displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help for a single debugger command, or all of them.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_help(char *command)
+{
+	const struct acpi_db_command_help *next = acpi_gbl_db_command_help;
+
+	if (!command) {
+
+		/* No argument to help, display help for all commands */
+
+		while (next->invocation) {
+			acpi_os_printf("%-38s%s", next->invocation,
+				       next->description);
+			next++;
+		}
+	} else {
+		/* Display help for all commands that match the subtring */
+
+		acpi_db_display_command_info(command, TRUE);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_next_token
+ *
+ * PARAMETERS:  string          - Command buffer
+ *              next            - Return value, end of next token
+ *
+ * RETURN:      Pointer to the start of the next token.
+ *
+ * DESCRIPTION: Command line parsing. Get the next token on the command line
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_next_token(char *string,
+			     char **next, acpi_object_type * return_type)
+{
+	char *start;
+	u32 depth;
+	acpi_object_type type = ACPI_TYPE_INTEGER;
+
+	/* At end of buffer? */
+
+	if (!string || !(*string)) {
+		return (NULL);
+	}
+
+	/* Remove any spaces at the beginning */
+
+	if (*string == ' ') {
+		while (*string && (*string == ' ')) {
+			string++;
+		}
+
+		if (!(*string)) {
+			return (NULL);
+		}
+	}
+
+	switch (*string) {
+	case '"':
+
+		/* This is a quoted string, scan until closing quote */
+
+		string++;
+		start = string;
+		type = ACPI_TYPE_STRING;
+
+		/* Find end of string */
+
+		while (*string && (*string != '"')) {
+			string++;
+		}
+		break;
+
+	case '(':
+
+		/* This is the start of a buffer, scan until closing paren */
+
+		string++;
+		start = string;
+		type = ACPI_TYPE_BUFFER;
+
+		/* Find end of buffer */
+
+		while (*string && (*string != ')')) {
+			string++;
+		}
+		break;
+
+	case '[':
+
+		/* This is the start of a package, scan until closing bracket */
+
+		string++;
+		depth = 1;
+		start = string;
+		type = ACPI_TYPE_PACKAGE;
+
+		/* Find end of package (closing bracket) */
+
+		while (*string) {
+
+			/* Handle String package elements */
+
+			if (*string == '"') {
+				/* Find end of string */
+
+				string++;
+				while (*string && (*string != '"')) {
+					string++;
+				}
+				if (!(*string)) {
+					break;
+				}
+			} else if (*string == '[') {
+				depth++;	/* A nested package declaration */
+			} else if (*string == ']') {
+				depth--;
+				if (depth == 0) {	/* Found final package closing bracket */
+					break;
+				}
+			}
+
+			string++;
+		}
+		break;
+
+	default:
+
+		start = string;
+
+		/* Find end of token */
+
+		while (*string && (*string != ' ')) {
+			string++;
+		}
+		break;
+	}
+
+	if (!(*string)) {
+		*next = NULL;
+	} else {
+		*string = 0;
+		*next = string + 1;
+	}
+
+	*return_type = type;
+	return (start);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_line
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *
+ * RETURN:      Count of arguments to the command
+ *
+ * DESCRIPTION: Get the next command line from the user. Gets entire line
+ *              up to the next newline
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_line(char *input_buffer)
+{
+	u32 i;
+	u32 count;
+	char *next;
+	char *this;
+
+	if (acpi_ut_safe_strcpy
+	    (acpi_gbl_db_parsed_buf, sizeof(acpi_gbl_db_parsed_buf),
+	     input_buffer)) {
+		acpi_os_printf
+		    ("Buffer overflow while parsing input line (max %u characters)\n",
+		     sizeof(acpi_gbl_db_parsed_buf));
+		return (0);
+	}
+
+	this = acpi_gbl_db_parsed_buf;
+	for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) {
+		acpi_gbl_db_args[i] = acpi_db_get_next_token(this, &next,
+							     &acpi_gbl_db_arg_types
+							     [i]);
+		if (!acpi_gbl_db_args[i]) {
+			break;
+		}
+
+		this = next;
+	}
+
+	/* Uppercase the actual command */
+
+	if (acpi_gbl_db_args[0]) {
+		acpi_ut_strupr(acpi_gbl_db_args[0]);
+	}
+
+	count = i;
+	if (count) {
+		count--;	/* Number of args only */
+	}
+
+	return (count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command
+ *
+ * PARAMETERS:  user_command            - User command line
+ *
+ * RETURN:      Index into command array, -1 if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_match_command(char *user_command)
+{
+	u32 i;
+
+	if (!user_command || user_command[0] == 0) {
+		return (CMD_NULL);
+	}
+
+	for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) {
+		if (strstr(acpi_gbl_db_commands[i].name, user_command) ==
+		    acpi_gbl_db_commands[i].name) {
+			return (i);
+		}
+	}
+
+	/* Command not recognized */
+
+	return (CMD_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_command_dispatch
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *              walk_state          - Current walk
+ *              op                  - Current (executing) parse op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Command dispatcher.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_command_dispatch(char *input_buffer,
+			 struct acpi_walk_state * walk_state,
+			 union acpi_parse_object * op)
+{
+	u32 temp;
+	u32 command_index;
+	u32 param_count;
+	char *command_line;
+	acpi_status status = AE_CTRL_TRUE;
+
+	/* If acpi_terminate has been called, terminate this thread */
+
+	if (acpi_gbl_db_terminate_threads) {
+		return (AE_CTRL_TERMINATE);
+	}
+
+	/* Find command and add to the history buffer */
+
+	param_count = acpi_db_get_line(input_buffer);
+	command_index = acpi_db_match_command(acpi_gbl_db_args[0]);
+	temp = 0;
+
+	/*
+	 * We don't want to add the !! command to the history buffer. It
+	 * would cause an infinite loop because it would always be the
+	 * previous command.
+	 */
+	if (command_index != CMD_HISTORY_LAST) {
+		acpi_db_add_to_history(input_buffer);
+	}
+
+	/* Verify that we have the minimum number of params */
+
+	if (param_count < acpi_gbl_db_commands[command_index].min_args) {
+		acpi_os_printf
+		    ("%u parameters entered, [%s] requires %u parameters\n",
+		     param_count, acpi_gbl_db_commands[command_index].name,
+		     acpi_gbl_db_commands[command_index].min_args);
+
+		acpi_db_display_command_info(acpi_gbl_db_commands
+					     [command_index].name, FALSE);
+		return (AE_CTRL_TRUE);
+	}
+
+	/* Decode and dispatch the command */
+
+	switch (command_index) {
+	case CMD_NULL:
+
+		if (op) {
+			return (AE_OK);
+		}
+		break;
+
+	case CMD_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_ut_dump_allocations((u32)-1, NULL);
+#endif
+		break;
+
+	case CMD_ARGS:
+	case CMD_ARGUMENTS:
+
+		acpi_db_display_arguments();
+		break;
+
+	case CMD_BREAKPOINT:
+
+		acpi_db_set_method_breakpoint(acpi_gbl_db_args[1], walk_state,
+					      op);
+		break;
+
+	case CMD_BUSINFO:
+
+		acpi_db_get_bus_info();
+		break;
+
+	case CMD_CALL:
+
+		acpi_db_set_method_call_breakpoint(op);
+		status = AE_OK;
+		break;
+
+	case CMD_DEBUG:
+
+		acpi_db_execute(acpi_gbl_db_args[1],
+				&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+				EX_SINGLE_STEP);
+		break;
+
+	case CMD_DISASSEMBLE:
+	case CMD_DISASM:
+
+		(void)acpi_db_disassemble_method(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_DUMP:
+
+		acpi_db_decode_and_display_object(acpi_gbl_db_args[1],
+						  acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_EVALUATE:
+	case CMD_EXECUTE:
+
+		acpi_db_execute(acpi_gbl_db_args[1],
+				&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+				EX_NO_SINGLE_STEP);
+		break;
+
+	case CMD_FIND:
+
+		status = acpi_db_find_name_in_namespace(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_GO:
+
+		acpi_gbl_cm_single_step = FALSE;
+		return (AE_OK);
+
+	case CMD_HANDLERS:
+
+		acpi_db_display_handlers();
+		break;
+
+	case CMD_HELP:
+	case CMD_HELP2:
+
+		acpi_db_display_help(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_HISTORY:
+
+		acpi_db_display_history();
+		break;
+
+	case CMD_HISTORY_EXE:	/* ! command */
+
+		command_line = acpi_db_get_from_history(acpi_gbl_db_args[1]);
+		if (!command_line) {
+			return (AE_CTRL_TRUE);
+		}
+
+		status = acpi_db_command_dispatch(command_line, walk_state, op);
+		return (status);
+
+	case CMD_HISTORY_LAST:	/* !! command */
+
+		command_line = acpi_db_get_from_history(NULL);
+		if (!command_line) {
+			return (AE_CTRL_TRUE);
+		}
+
+		status = acpi_db_command_dispatch(command_line, walk_state, op);
+		return (status);
+
+	case CMD_INFORMATION:
+
+		acpi_db_display_method_info(op);
+		break;
+
+	case CMD_INTEGRITY:
+
+		acpi_db_check_integrity();
+		break;
+
+	case CMD_INTO:
+
+		if (op) {
+			acpi_gbl_cm_single_step = TRUE;
+			return (AE_OK);
+		}
+		break;
+
+	case CMD_LEVEL:
+
+		if (param_count == 0) {
+			acpi_os_printf
+			    ("Current debug level for file output is:    %8.8lX\n",
+			     acpi_gbl_db_debug_level);
+			acpi_os_printf
+			    ("Current debug level for console output is: %8.8lX\n",
+			     acpi_gbl_db_console_debug_level);
+		} else if (param_count == 2) {
+			temp = acpi_gbl_db_console_debug_level;
+			acpi_gbl_db_console_debug_level =
+			    strtoul(acpi_gbl_db_args[1], NULL, 16);
+			acpi_os_printf
+			    ("Debug Level for console output was %8.8lX, now %8.8lX\n",
+			     temp, acpi_gbl_db_console_debug_level);
+		} else {
+			temp = acpi_gbl_db_debug_level;
+			acpi_gbl_db_debug_level =
+			    strtoul(acpi_gbl_db_args[1], NULL, 16);
+			acpi_os_printf
+			    ("Debug Level for file output was %8.8lX, now %8.8lX\n",
+			     temp, acpi_gbl_db_debug_level);
+		}
+		break;
+
+	case CMD_LIST:
+
+		acpi_db_disassemble_aml(acpi_gbl_db_args[1], op);
+		break;
+
+	case CMD_LOCKS:
+
+		acpi_db_display_locks();
+		break;
+
+	case CMD_LOCALS:
+
+		acpi_db_display_locals();
+		break;
+
+	case CMD_METHODS:
+
+		status = acpi_db_display_objects("METHOD", acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_NAMESPACE:
+
+		acpi_db_dump_namespace(acpi_gbl_db_args[1],
+				       acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_NOTIFY:
+
+		temp = strtoul(acpi_gbl_db_args[2], NULL, 0);
+		acpi_db_send_notify(acpi_gbl_db_args[1], temp);
+		break;
+
+	case CMD_OBJECTS:
+
+		acpi_ut_strupr(acpi_gbl_db_args[1]);
+		status =
+		    acpi_db_display_objects(acpi_gbl_db_args[1],
+					    acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_OSI:
+
+		acpi_db_display_interfaces(acpi_gbl_db_args[1],
+					   acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_OWNER:
+
+		acpi_db_dump_namespace_by_owner(acpi_gbl_db_args[1],
+						acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_PATHS:
+
+		acpi_db_dump_namespace_paths();
+		break;
+
+	case CMD_PREFIX:
+
+		acpi_db_set_scope(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_REFERENCES:
+
+		acpi_db_find_references(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_RESOURCES:
+
+		acpi_db_display_resources(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_RESULTS:
+
+		acpi_db_display_results();
+		break;
+
+	case CMD_SET:
+
+		acpi_db_set_method_data(acpi_gbl_db_args[1],
+					acpi_gbl_db_args[2],
+					acpi_gbl_db_args[3]);
+		break;
+
+	case CMD_STATS:
+
+		status = acpi_db_display_statistics(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_STOP:
+
+		return (AE_NOT_IMPLEMENTED);
+
+	case CMD_TABLES:
+
+		acpi_db_display_table_info(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_TEMPLATE:
+
+		acpi_db_display_template(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_TRACE:
+
+		acpi_db_trace(acpi_gbl_db_args[1], acpi_gbl_db_args[2],
+			      acpi_gbl_db_args[3]);
+		break;
+
+	case CMD_TREE:
+
+		acpi_db_display_calling_tree();
+		break;
+
+	case CMD_TYPE:
+
+		acpi_db_display_object_type(acpi_gbl_db_args[1]);
+		break;
+
+#ifdef ACPI_APPLICATION
+
+		/* Hardware simulation commands. */
+
+	case CMD_ENABLEACPI:
+#if (!ACPI_REDUCED_HARDWARE)
+
+		status = acpi_enable();
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiEnable failed (Status=%X)\n",
+				       status);
+			return (status);
+		}
+#endif				/* !ACPI_REDUCED_HARDWARE */
+		break;
+
+	case CMD_EVENT:
+
+		acpi_os_printf("Event command not implemented\n");
+		break;
+
+	case CMD_GPE:
+
+		acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_GPES:
+
+		acpi_db_display_gpes();
+		break;
+
+	case CMD_SCI:
+
+		acpi_db_generate_sci();
+		break;
+
+	case CMD_SLEEP:
+
+		status = acpi_db_sleep(acpi_gbl_db_args[1]);
+		break;
+
+		/* File I/O commands. */
+
+	case CMD_CLOSE:
+
+		acpi_db_close_debug_file();
+		break;
+
+	case CMD_LOAD:
+
+		status =
+		    acpi_db_get_table_from_file(acpi_gbl_db_args[1], NULL,
+						FALSE);
+		break;
+
+	case CMD_OPEN:
+
+		acpi_db_open_debug_file(acpi_gbl_db_args[1]);
+		break;
+
+		/* User space commands. */
+
+	case CMD_TERMINATE:
+
+		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+		acpi_ut_subsystem_shutdown();
+
+		/*
+		 * TBD: [Restructure] Need some way to re-initialize without
+		 * re-creating the semaphores!
+		 */
+
+		/*  acpi_initialize (NULL); */
+		break;
+
+	case CMD_THREADS:
+
+		acpi_db_create_execution_threads(acpi_gbl_db_args[1],
+						 acpi_gbl_db_args[2],
+						 acpi_gbl_db_args[3]);
+		break;
+
+		/* Debug test commands. */
+
+	case CMD_PREDEFINED:
+
+		acpi_db_check_predefined_names();
+		break;
+
+	case CMD_TEST:
+
+		acpi_db_execute_test(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_UNLOAD:
+
+		acpi_db_unload_acpi_table(acpi_gbl_db_args[1]);
+		break;
+#endif
+
+	case CMD_EXIT:
+	case CMD_QUIT:
+
+		if (op) {
+			acpi_os_printf("Method execution terminated\n");
+			return (AE_CTRL_TERMINATE);
+		}
+
+		if (!acpi_gbl_db_output_to_file) {
+			acpi_dbg_level = ACPI_DEBUG_DEFAULT;
+		}
+#ifdef ACPI_APPLICATION
+		acpi_db_close_debug_file();
+#endif
+		acpi_gbl_db_terminate_threads = TRUE;
+		return (AE_CTRL_TERMINATE);
+
+	case CMD_NOT_FOUND:
+	default:
+
+		acpi_os_printf("%s: unknown command\n", acpi_gbl_db_args[0]);
+		return (AE_CTRL_TRUE);
+	}
+
+	if (ACPI_SUCCESS(status)) {
+		status = AE_CTRL_TRUE;
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_thread
+ *
+ * PARAMETERS:  context         - Not used
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+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_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);
+	}
+}
+
+/*******************************************************************************
+ *
+ * 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
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Command line execution for the AML debugger. Commands are
+ *              matched and dispatched here.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
+{
+	acpi_status status = AE_OK;
+
+	acpi_os_printf("\n");
+
+	/* TBD: [Restructure] Need a separate command line buffer for step mode */
+
+	while (!acpi_gbl_db_terminate_threads) {
+
+		/* 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);
+		}
+
+		/* Get the user input line */
+
+		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);
+		}
+
+		/* Check for single or multithreaded debug */
+
+		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);
+			}
+
+			status =
+			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
+						  ACPI_WAIT_FOREVER);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+		} else {
+			/* Just call to the command line interpreter */
+
+			acpi_db_single_thread();
+		}
+	}
+
+	/* Shut down the debugger */
+
+	acpi_terminate_debugger();
+
+	/*
+	 * Only this thread (the original thread) should actually terminate the
+	 * subsystem, because all the semaphores are deleted during termination
+	 */
+	status = acpi_terminate();
+	return (status);
+}
diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c
new file mode 100644
index 0000000..01e5a71
--- /dev/null
+++ b/drivers/acpi/acpica/dbmethod.c
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ *
+ * Module Name: dbmethod - Debug commands for control methods
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acparser.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbmethod")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_breakpoint
+ *
+ * PARAMETERS:  location            - AML offset of breakpoint
+ *              walk_state          - Current walk info
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+void
+acpi_db_set_method_breakpoint(char *location,
+			      struct acpi_walk_state *walk_state,
+			      union acpi_parse_object *op)
+{
+	u32 address;
+	u32 aml_offset;
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	/* Get and verify the breakpoint address */
+
+	address = strtoul(location, NULL, 16);
+	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+					walk_state->parser_state.aml_start);
+	if (address <= aml_offset) {
+		acpi_os_printf("Breakpoint %X is beyond current address %X\n",
+			       address, aml_offset);
+	}
+
+	/* Save breakpoint in current walk */
+
+	walk_state->user_breakpoint = address;
+	acpi_os_printf("Breakpoint set at AML offset %X\n", address);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_call_breakpoint
+ *
+ * PARAMETERS:  op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
+{
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_gbl_step_to_next_call = TRUE;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_data
+ *
+ * PARAMETERS:  type_arg        - L for local, A for argument
+ *              index_arg       - which one
+ *              value_arg       - Value to set.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a local or argument for the running control method.
+ *              NOTE: only object supported is Number.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
+{
+	char type;
+	u32 index;
+	u32 value;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	acpi_status status;
+	struct acpi_namespace_node *node;
+
+	/* Validate type_arg */
+
+	acpi_ut_strupr(type_arg);
+	type = type_arg[0];
+	if ((type != 'L') && (type != 'A') && (type != 'N')) {
+		acpi_os_printf("Invalid SET operand: %s\n", type_arg);
+		return;
+	}
+
+	value = strtoul(value_arg, NULL, 16);
+
+	if (type == 'N') {
+		node = acpi_db_convert_to_node(index_arg);
+		if (!node) {
+			return;
+		}
+
+		if (node->type != ACPI_TYPE_INTEGER) {
+			acpi_os_printf("Can only set Integer nodes\n");
+			return;
+		}
+		obj_desc = node->object;
+		obj_desc->integer.value = value;
+		return;
+	}
+
+	/* Get the index and value */
+
+	index = strtoul(index_arg, NULL, 16);
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	/* Create and initialize the new object */
+
+	obj_desc = acpi_ut_create_integer_object((u64)value);
+	if (!obj_desc) {
+		acpi_os_printf("Could not create an internal object\n");
+		return;
+	}
+
+	/* Store the new object into the target */
+
+	switch (type) {
+	case 'A':
+
+		/* Set a method argument */
+
+		if (index > ACPI_METHOD_MAX_ARG) {
+			acpi_os_printf("Arg%u - Invalid argument name\n",
+				       index);
+			goto cleanup;
+		}
+
+		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
+						       index, obj_desc,
+						       walk_state);
+		if (ACPI_FAILURE(status)) {
+			goto cleanup;
+		}
+
+		obj_desc = walk_state->arguments[index].object;
+
+		acpi_os_printf("Arg%u: ", index);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+		break;
+
+	case 'L':
+
+		/* Set a method local */
+
+		if (index > ACPI_METHOD_MAX_LOCAL) {
+			acpi_os_printf
+			    ("Local%u - Invalid local variable name\n", index);
+			goto cleanup;
+		}
+
+		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
+						       index, obj_desc,
+						       walk_state);
+		if (ACPI_FAILURE(status)) {
+			goto cleanup;
+		}
+
+		obj_desc = walk_state->local_variables[index].object;
+
+		acpi_os_printf("Local%u: ", index);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+		break;
+
+	default:
+
+		break;
+	}
+
+cleanup:
+	acpi_ut_remove_reference(obj_desc);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_aml
+ *
+ * PARAMETERS:  statements          - Number of statements to disassemble
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
+{
+	u32 num_statements = 8;
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	if (statements) {
+		num_statements = strtoul(statements, NULL, 0);
+	}
+#ifdef ACPI_DISASSEMBLER
+	acpi_dm_disassemble(NULL, op, num_statements);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_method
+ *
+ * PARAMETERS:  name            - Name of control method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_disassemble_method(char *name)
+{
+	acpi_status status;
+	union acpi_parse_object *op;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *method;
+
+	method = acpi_db_convert_to_node(name);
+	if (!method) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	if (method->type != ACPI_TYPE_METHOD) {
+		ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
+			    name, acpi_ut_get_type_name(method->type)));
+		return (AE_BAD_PARAMETER);
+	}
+
+	obj_desc = method->object;
+
+	op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
+	if (!op) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Create and initialize a new walk state */
+
+	walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
+	if (!walk_state) {
+		return (AE_NO_MEMORY);
+	}
+
+	status = acpi_ds_init_aml_walk(walk_state, op, NULL,
+				       obj_desc->method.aml_start,
+				       obj_desc->method.aml_length, NULL,
+				       ACPI_IMODE_LOAD_PASS1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+	walk_state->owner_id = obj_desc->method.owner_id;
+
+	/* Push start scope on scope stack and make it current */
+
+	status = acpi_ds_scope_stack_push(method, method->type, walk_state);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Parse the entire method AML including deferred operators */
+
+	walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
+	walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
+
+	status = acpi_ps_parse_aml(walk_state);
+
+#ifdef ACPI_DISASSEMBLER
+	(void)acpi_dm_parse_deferred_ops(op);
+
+	/* Now we can disassemble the method */
+
+	acpi_gbl_dm_opt_verbose = FALSE;
+	acpi_dm_disassemble(NULL, op, 0);
+	acpi_gbl_dm_opt_verbose = TRUE;
+#endif
+
+	acpi_ps_delete_parse_tree(op);
+
+	/* Method cleanup */
+
+	acpi_ns_delete_namespace_subtree(method);
+	acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
+	acpi_ut_release_owner_id(&obj_desc->method.owner_id);
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c
new file mode 100644
index 0000000..04ff1eb
--- /dev/null
+++ b/drivers/acpi/acpica/dbnames.c
@@ -0,0 +1,947 @@
+/*******************************************************************************
+ *
+ * Module Name: dbnames - Debugger commands for the acpi namespace
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbnames")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+			       u32 nesting_level,
+			       void *context, void **return_value);
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+		 u32 nesting_level, void *context, void **return_value);
+
+/*
+ * Arguments for the Objects command
+ * These object types map directly to the ACPI_TYPES
+ */
+static struct acpi_db_argument_info acpi_db_object_types[] = {
+	{"ANY"},
+	{"INTEGERS"},
+	{"STRINGS"},
+	{"BUFFERS"},
+	{"PACKAGES"},
+	{"FIELDS"},
+	{"DEVICES"},
+	{"EVENTS"},
+	{"METHODS"},
+	{"MUTEXES"},
+	{"REGIONS"},
+	{"POWERRESOURCES"},
+	{"PROCESSORS"},
+	{"THERMALZONES"},
+	{"BUFFERFIELDS"},
+	{"DDBHANDLES"},
+	{"DEBUG"},
+	{"REGIONFIELDS"},
+	{"BANKFIELDS"},
+	{"INDEXFIELDS"},
+	{"REFERENCES"},
+	{"ALIASES"},
+	{"METHODALIASES"},
+	{"NOTIFY"},
+	{"ADDRESSHANDLER"},
+	{"RESOURCE"},
+	{"RESOURCEFIELD"},
+	{"SCOPES"},
+	{NULL}			/* Must be null terminated */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_scope
+ *
+ * PARAMETERS:  name                - New scope path
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Set the "current scope" as maintained by this utility.
+ *              The scope is used as a prefix to ACPI paths.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_scope(char *name)
+{
+	acpi_status status;
+	struct acpi_namespace_node *node;
+
+	if (!name || name[0] == 0) {
+		acpi_os_printf("Current scope: %s\n", acpi_gbl_db_scope_buf);
+		return;
+	}
+
+	acpi_db_prep_namestring(name);
+
+	if (ACPI_IS_ROOT_PREFIX(name[0])) {
+
+		/* Validate new scope from the root */
+
+		status = acpi_ns_get_node(acpi_gbl_root_node, name,
+					  ACPI_NS_NO_UPSEARCH, &node);
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
+		}
+
+		acpi_gbl_db_scope_buf[0] = 0;
+	} else {
+		/* Validate new scope relative to old scope */
+
+		status = acpi_ns_get_node(acpi_gbl_db_scope_node, name,
+					  ACPI_NS_NO_UPSEARCH, &node);
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
+		}
+	}
+
+	/* Build the final pathname */
+
+	if (acpi_ut_safe_strcat
+	    (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), name)) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	if (acpi_ut_safe_strcat
+	    (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), "\\")) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	acpi_gbl_db_scope_node = node;
+	acpi_os_printf("New scope: %s\n", acpi_gbl_db_scope_buf);
+	return;
+
+error_exit:
+
+	acpi_os_printf("Could not attach scope: %s, %s\n",
+		       name, acpi_format_exception(status));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace
+ *
+ * PARAMETERS:  start_arg       - Node to begin namespace dump
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed
+ *              with type and other information.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace(char *start_arg, char *depth_arg)
+{
+	acpi_handle subtree_entry = acpi_gbl_root_node;
+	u32 max_depth = ACPI_UINT32_MAX;
+
+	/* No argument given, just start at the root and dump entire namespace */
+
+	if (start_arg) {
+		subtree_entry = acpi_db_convert_to_node(start_arg);
+		if (!subtree_entry) {
+			return;
+		}
+
+		/* Now we can check for the depth argument */
+
+		if (depth_arg) {
+			max_depth = strtoul(depth_arg, NULL, 0);
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n",
+		       ((struct acpi_namespace_node *)subtree_entry)->name.
+		       ascii, subtree_entry);
+
+	/* Display the subtree */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+			     ACPI_OWNER_ID_MAX, subtree_entry);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_paths
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace with full object pathnames and object
+ *              type information. Alternative to "namespace" command.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_paths(void)
+{
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace (from root):\n");
+
+	/* Display the entire namespace */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY,
+				  ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX,
+				  acpi_gbl_root_node);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_by_owner
+ *
+ * PARAMETERS:  owner_arg       - Owner ID whose nodes will be displayed
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump elements of the namespace that are owned by the owner_id.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg)
+{
+	acpi_handle subtree_entry = acpi_gbl_root_node;
+	u32 max_depth = ACPI_UINT32_MAX;
+	acpi_owner_id owner_id;
+
+	owner_id = (acpi_owner_id) strtoul(owner_arg, NULL, 0);
+
+	/* Now we can check for the depth argument */
+
+	if (depth_arg) {
+		max_depth = strtoul(depth_arg, NULL, 0);
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace by owner %X:\n", owner_id);
+
+	/* Display the subtree */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+			     owner_id, subtree_entry);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_and_match_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Find a particular name/names within the namespace. Wildcards
+ *              are supported -- '?' matches any character.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	acpi_status status;
+	char *requested_name = (char *)context;
+	u32 i;
+	struct acpi_buffer buffer;
+	struct acpi_walk_info info;
+
+	/* Check for a name match */
+
+	for (i = 0; i < 4; i++) {
+
+		/* Wildcard support */
+
+		if ((requested_name[i] != '?') &&
+		    (requested_name[i] != ((struct acpi_namespace_node *)
+					   obj_handle)->name.ascii[i])) {
+
+			/* No match, just exit */
+
+			return (AE_OK);
+		}
+	}
+
+	/* Get the full pathname to this object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+	} else {
+		info.owner_id = ACPI_OWNER_ID_MAX;
+		info.debug_level = ACPI_UINT32_MAX;
+		info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+		acpi_os_printf("%32s", (char *)buffer.pointer);
+		(void)acpi_ns_dump_one_object(obj_handle, nesting_level, &info,
+					      NULL);
+		ACPI_FREE(buffer.pointer);
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_name_in_namespace
+ *
+ * PARAMETERS:  name_arg        - The 4-character ACPI name to find.
+ *                                wildcards are supported.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search the namespace for a given name (with wildcards)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_find_name_in_namespace(char *name_arg)
+{
+	char acpi_name[5] = "____";
+	char *acpi_name_ptr = acpi_name;
+
+	if (strlen(name_arg) > ACPI_NAME_SIZE) {
+		acpi_os_printf("Name must be no longer than 4 characters\n");
+		return (AE_OK);
+	}
+
+	/* Pad out name with underscores as necessary to create a 4-char name */
+
+	acpi_ut_strupr(name_arg);
+	while (*name_arg) {
+		*acpi_name_ptr = *name_arg;
+		acpi_name_ptr++;
+		name_arg++;
+	}
+
+	/* Walk the namespace from the root */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_walk_and_match_name,
+				  NULL, acpi_name, NULL);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_predefined_names
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Detect and display predefined ACPI names (names that start with
+ *              an underscore)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	u32 *count = (u32 *)context;
+	const union acpi_predefined_info *predefined;
+	const union acpi_predefined_info *package = NULL;
+	char *pathname;
+	char string_buffer[48];
+
+	predefined = acpi_ut_match_predefined_method(node->name.ascii);
+	if (!predefined) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* If method returns a package, the info is in the next table entry */
+
+	if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
+		package = predefined + 1;
+	}
+
+	acpi_ut_get_expected_return_types(string_buffer,
+					  predefined->info.expected_btypes);
+
+	acpi_os_printf("%-32s Arguments %X, Return Types: %s", pathname,
+		       METHOD_GET_ARG_COUNT(predefined->info.argument_list),
+		       string_buffer);
+
+	if (package) {
+		acpi_os_printf(" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)",
+			       package->ret_info.type,
+			       package->ret_info.object_type1,
+			       package->ret_info.count1);
+	}
+
+	acpi_os_printf("\n");
+
+	/* Check that the declared argument count matches the ACPI spec */
+
+	acpi_ns_check_acpi_compliance(pathname, node, predefined);
+
+	ACPI_FREE(pathname);
+	(*count)++;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_predefined_names
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Validate all predefined names in the namespace
+ *
+ ******************************************************************************/
+
+void acpi_db_check_predefined_names(void)
+{
+	u32 count = 0;
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_walk_for_predefined_names, NULL,
+				  (void *)&count, NULL);
+
+	acpi_os_printf("Found %u predefined names in the namespace\n", count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_object_counts
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+			       u32 nesting_level,
+			       void *context, void **return_value)
+{
+	struct acpi_object_info *info = (struct acpi_object_info *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+
+	if (node->type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_os_printf("[%4.4s]: Unknown object type %X\n",
+			       node->name.ascii, node->type);
+	} else {
+		info->types[node->type]++;
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_specific_objects
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_walk_info *info = (struct acpi_walk_info *)context;
+	struct acpi_buffer buffer;
+	acpi_status status;
+
+	info->count++;
+
+	/* Get and display the full pathname to this object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+		return (AE_OK);
+	}
+
+	acpi_os_printf("%32s", (char *)buffer.pointer);
+	ACPI_FREE(buffer.pointer);
+
+	/* Dump short info about the object */
+
+	(void)acpi_ns_dump_one_object(obj_handle, nesting_level, info, NULL);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_objects
+ *
+ * PARAMETERS:  obj_type_arg        - Type of object to display
+ *              display_count_arg   - Max depth to display
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display objects in the namespace of the requested type
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg)
+{
+	struct acpi_walk_info info;
+	acpi_object_type type;
+	struct acpi_object_info *object_info;
+	u32 i;
+	u32 total_objects = 0;
+
+	/* No argument means display summary/count of all object types */
+
+	if (!obj_type_arg) {
+		object_info =
+		    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info));
+
+		/* Walk the namespace from the root */
+
+		(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_walk_for_object_counts, NULL,
+					  (void *)object_info, NULL);
+
+		acpi_os_printf("\nSummary of namespace objects:\n\n");
+
+		for (i = 0; i < ACPI_TOTAL_TYPES; i++) {
+			acpi_os_printf("%8u %s\n", object_info->types[i],
+				       acpi_ut_get_type_name(i));
+
+			total_objects += object_info->types[i];
+		}
+
+		acpi_os_printf("\n%8u Total namespace objects\n\n",
+			       total_objects);
+
+		ACPI_FREE(object_info);
+		return (AE_OK);
+	}
+
+	/* Get the object type */
+
+	type = acpi_db_match_argument(obj_type_arg, acpi_db_object_types);
+	if (type == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return (AE_OK);
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf
+	    ("Objects of type [%s] defined in the current ACPI Namespace:\n",
+	     acpi_ut_get_type_name(type));
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+
+	info.count = 0;
+	info.owner_id = ACPI_OWNER_ID_MAX;
+	info.debug_level = ACPI_UINT32_MAX;
+	info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+	/* Walk the namespace from the root */
+
+	(void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+				  acpi_db_walk_for_specific_objects, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf
+	    ("\nFound %u objects of type [%s] in the current ACPI Namespace\n",
+	     info.count, acpi_ut_get_type_name(type));
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_integrity_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Examine one NS node for valid values.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_integrity_info *info =
+	    (struct acpi_integrity_info *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	union acpi_operand_object *object;
+	u8 alias = TRUE;
+
+	info->nodes++;
+
+	/* Verify the NS node, and dereference aliases */
+
+	while (alias) {
+		if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+			acpi_os_printf
+			    ("Invalid Descriptor Type for Node %p [%s] - "
+			     "is %2.2X should be %2.2X\n", node,
+			     acpi_ut_get_descriptor_name(node),
+			     ACPI_GET_DESCRIPTOR_TYPE(node),
+			     ACPI_DESC_TYPE_NAMED);
+			return (AE_OK);
+		}
+
+		if ((node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+		    (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+			node = (struct acpi_namespace_node *)node->object;
+		} else {
+			alias = FALSE;
+		}
+	}
+
+	if (node->type > ACPI_TYPE_LOCAL_MAX) {
+		acpi_os_printf("Invalid Object Type for Node %p, Type = %X\n",
+			       node, node->type);
+		return (AE_OK);
+	}
+
+	if (!acpi_ut_valid_acpi_name(node->name.ascii)) {
+		acpi_os_printf("Invalid AcpiName for Node %p\n", node);
+		return (AE_OK);
+	}
+
+	object = acpi_ns_get_attached_object(node);
+	if (object) {
+		info->objects++;
+		if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
+			acpi_os_printf
+			    ("Invalid Descriptor Type for Object %p [%s]\n",
+			     object, acpi_ut_get_descriptor_name(object));
+		}
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_integrity
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check entire namespace for data structure integrity
+ *
+ ******************************************************************************/
+
+void acpi_db_check_integrity(void)
+{
+	struct acpi_integrity_info info = { 0, 0 };
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_integrity_walk, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf("Verified %u namespace nodes with %u Objects\n",
+		       info.nodes, info.objects);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_references
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check if this namespace object refers to the target object
+ *              that is passed in as the context value.
+ *
+ * Note: Currently doesn't check subobjects within the Node's object
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	union acpi_operand_object *obj_desc =
+	    (union acpi_operand_object *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+
+	/* Check for match against the namespace node itself */
+
+	if (node == (void *)obj_desc) {
+		acpi_os_printf("Object is a Node [%4.4s]\n",
+			       acpi_ut_get_node_name(node));
+	}
+
+	/* Check for match against the object attached to the node */
+
+	if (acpi_ns_get_attached_object(node) == obj_desc) {
+		acpi_os_printf("Reference at Node->Object %p [%4.4s]\n",
+			       node, acpi_ut_get_node_name(node));
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_references
+ *
+ * PARAMETERS:  object_arg      - String with hex value of the object
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search namespace for all references to the input object
+ *
+ ******************************************************************************/
+
+void acpi_db_find_references(char *object_arg)
+{
+	union acpi_operand_object *obj_desc;
+	acpi_size address;
+
+	/* Convert string to object pointer */
+
+	address = strtoul(object_arg, NULL, 16);
+	obj_desc = ACPI_TO_POINTER(address);
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_walk_for_references,
+				  NULL, (void *)obj_desc, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_bus_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display info about device objects that have a corresponding
+ *              _PRT method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+		 u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	acpi_status status;
+	struct acpi_buffer buffer;
+	struct acpi_namespace_node *temp_node;
+	struct acpi_device_info *info;
+	u32 i;
+
+	if ((node->type != ACPI_TYPE_DEVICE) &&
+	    (node->type != ACPI_TYPE_PROCESSOR)) {
+		return (AE_OK);
+	}
+
+	/* Exit if there is no _PRT under this device */
+
+	status = acpi_get_handle(node, METHOD_NAME__PRT,
+				 ACPI_CAST_PTR(acpi_handle, &temp_node));
+	if (ACPI_FAILURE(status)) {
+		return (AE_OK);
+	}
+
+	/* Get the full path to this device object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+		return (AE_OK);
+	}
+
+	status = acpi_get_object_info(obj_handle, &info);
+	if (ACPI_FAILURE(status)) {
+		return (AE_OK);
+	}
+
+	/* Display the full path */
+
+	acpi_os_printf("%-32s Type %X", (char *)buffer.pointer, node->type);
+	ACPI_FREE(buffer.pointer);
+
+	if (info->flags & ACPI_PCI_ROOT_BRIDGE) {
+		acpi_os_printf(" - Is PCI Root Bridge");
+	}
+	acpi_os_printf("\n");
+
+	/* _PRT info */
+
+	acpi_os_printf("_PRT: %p\n", temp_node);
+
+	/* Dump _ADR, _HID, _UID, _CID */
+
+	if (info->valid & ACPI_VALID_ADR) {
+		acpi_os_printf("_ADR: %8.8X%8.8X\n",
+			       ACPI_FORMAT_UINT64(info->address));
+	} else {
+		acpi_os_printf("_ADR: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_HID) {
+		acpi_os_printf("_HID: %s\n", info->hardware_id.string);
+	} else {
+		acpi_os_printf("_HID: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_UID) {
+		acpi_os_printf("_UID: %s\n", info->unique_id.string);
+	} else {
+		acpi_os_printf("_UID: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_CID) {
+		for (i = 0; i < info->compatible_id_list.count; i++) {
+			acpi_os_printf("_CID: %s\n",
+				       info->compatible_id_list.ids[i].string);
+		}
+	} else {
+		acpi_os_printf("_CID: <Not Present>\n");
+	}
+
+	ACPI_FREE(info);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_bus_info
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display info about system busses.
+ *
+ ******************************************************************************/
+
+void acpi_db_get_bus_info(void)
+{
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_bus_walk, NULL, NULL,
+				  NULL);
+}
diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c
new file mode 100644
index 0000000..116f6db8
--- /dev/null
+++ b/drivers/acpi/acpica/dbobject.c
@@ -0,0 +1,533 @@
+/*******************************************************************************
+ *
+ * Module Name: dbobject - ACPI object decode and display
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbobject")
+
+/* Local prototypes */
+static void acpi_db_decode_node(struct acpi_namespace_node *node);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_method_info
+ *
+ * PARAMETERS:  status          - Method execution status
+ *              walk_state      - Current state of the parse tree walk
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Called when a method has been aborted because of an error.
+ *              Dumps the method execution stack, and the method locals/args,
+ *              and disassembles the AML opcode that failed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state)
+{
+	struct acpi_thread_state *thread;
+
+	/* Ignore control codes, they are not errors */
+
+	if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) {
+		return;
+	}
+
+	/* We may be executing a deferred opcode */
+
+	if (walk_state->deferred_node) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/*
+	 * If there is no Thread, we are not actually executing a method.
+	 * This can happen when the iASL compiler calls the interpreter
+	 * to perform constant folding.
+	 */
+	thread = walk_state->thread;
+	if (!thread) {
+		return;
+	}
+
+	/* Display the method locals and arguments */
+
+	acpi_os_printf("\n");
+	acpi_db_decode_locals(walk_state);
+	acpi_os_printf("\n");
+	acpi_db_decode_arguments(walk_state);
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers.
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		acpi_os_printf(" Uninitialized");
+		return;
+	}
+
+	if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+		acpi_os_printf(" %p [%s]", obj_desc,
+			       acpi_ut_get_descriptor_name(obj_desc));
+		return;
+	}
+
+	acpi_os_printf(" %s", acpi_ut_get_object_type_name(obj_desc));
+
+	switch (obj_desc->common.type) {
+	case ACPI_TYPE_INTEGER:
+
+		acpi_os_printf(" %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(obj_desc->integer.value));
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		acpi_os_printf("(%u) \"%.24s",
+			       obj_desc->string.length,
+			       obj_desc->string.pointer);
+
+		if (obj_desc->string.length > 24) {
+			acpi_os_printf("...");
+		} else {
+			acpi_os_printf("\"");
+		}
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		acpi_os_printf("(%u)", obj_desc->buffer.length);
+		for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) {
+			acpi_os_printf(" %2.2X", obj_desc->buffer.pointer[i]);
+		}
+		break;
+
+	default:
+
+		acpi_os_printf(" %p", obj_desc);
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_node
+ *
+ * PARAMETERS:  node        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of a namespace node
+ *
+ ******************************************************************************/
+
+static void acpi_db_decode_node(struct acpi_namespace_node *node)
+{
+
+	acpi_os_printf("<Node>          Name %4.4s",
+		       acpi_ut_get_node_name(node));
+
+	if (node->flags & ANOBJ_METHOD_ARG) {
+		acpi_os_printf(" [Method Arg]");
+	}
+	if (node->flags & ANOBJ_METHOD_LOCAL) {
+		acpi_os_printf(" [Method Local]");
+	}
+
+	switch (node->type) {
+
+		/* These types have no attached object */
+
+	case ACPI_TYPE_DEVICE:
+
+		acpi_os_printf(" Device");
+		break;
+
+	case ACPI_TYPE_THERMAL:
+
+		acpi_os_printf(" Thermal Zone");
+		break;
+
+	default:
+
+		acpi_db_decode_internal_object(acpi_ns_get_attached_object
+					       (node));
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_internal_object(union acpi_operand_object *obj_desc,
+				struct acpi_walk_state *walk_state)
+{
+	u8 type;
+
+	acpi_os_printf("%p ", obj_desc);
+
+	if (!obj_desc) {
+		acpi_os_printf("<Null Object>\n");
+		return;
+	}
+
+	/* Decode the object type */
+
+	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
+	case ACPI_DESC_TYPE_PARSER:
+
+		acpi_os_printf("<Parser> ");
+		break;
+
+	case ACPI_DESC_TYPE_NAMED:
+
+		acpi_db_decode_node((struct acpi_namespace_node *)obj_desc);
+		break;
+
+	case ACPI_DESC_TYPE_OPERAND:
+
+		type = obj_desc->common.type;
+		if (type > ACPI_TYPE_LOCAL_MAX) {
+			acpi_os_printf(" Type %X [Invalid Type]", (u32)type);
+			return;
+		}
+
+		/* Decode the ACPI object type */
+
+		switch (obj_desc->common.type) {
+		case ACPI_TYPE_LOCAL_REFERENCE:
+
+			acpi_os_printf("[%s] ",
+				       acpi_ut_get_reference_name(obj_desc));
+
+			/* Decode the refererence */
+
+			switch (obj_desc->reference.class) {
+			case ACPI_REFCLASS_LOCAL:
+
+				acpi_os_printf("%X ",
+					       obj_desc->reference.value);
+				if (walk_state) {
+					obj_desc = walk_state->local_variables
+					    [obj_desc->reference.value].object;
+					acpi_os_printf("%p", obj_desc);
+					acpi_db_decode_internal_object
+					    (obj_desc);
+				}
+				break;
+
+			case ACPI_REFCLASS_ARG:
+
+				acpi_os_printf("%X ",
+					       obj_desc->reference.value);
+				if (walk_state) {
+					obj_desc = walk_state->arguments
+					    [obj_desc->reference.value].object;
+					acpi_os_printf("%p", obj_desc);
+					acpi_db_decode_internal_object
+					    (obj_desc);
+				}
+				break;
+
+			case ACPI_REFCLASS_INDEX:
+
+				switch (obj_desc->reference.target_type) {
+				case ACPI_TYPE_BUFFER_FIELD:
+
+					acpi_os_printf("%p",
+						       obj_desc->reference.
+						       object);
+					acpi_db_decode_internal_object
+					    (obj_desc->reference.object);
+					break;
+
+				case ACPI_TYPE_PACKAGE:
+
+					acpi_os_printf("%p",
+						       obj_desc->reference.
+						       where);
+					if (!obj_desc->reference.where) {
+						acpi_os_printf
+						    (" Uninitialized WHERE pointer");
+					} else {
+						acpi_db_decode_internal_object(*
+									       (obj_desc->
+										reference.
+										where));
+					}
+					break;
+
+				default:
+
+					acpi_os_printf
+					    ("Unknown index target type");
+					break;
+				}
+				break;
+
+			case ACPI_REFCLASS_REFOF:
+
+				if (!obj_desc->reference.object) {
+					acpi_os_printf
+					    ("Uninitialized reference subobject pointer");
+					break;
+				}
+
+				/* Reference can be to a Node or an Operand object */
+
+				switch (ACPI_GET_DESCRIPTOR_TYPE
+					(obj_desc->reference.object)) {
+				case ACPI_DESC_TYPE_NAMED:
+
+					acpi_db_decode_node(obj_desc->reference.
+							    object);
+					break;
+
+				case ACPI_DESC_TYPE_OPERAND:
+
+					acpi_db_decode_internal_object
+					    (obj_desc->reference.object);
+					break;
+
+				default:
+					break;
+				}
+				break;
+
+			case ACPI_REFCLASS_NAME:
+
+				acpi_db_decode_node(obj_desc->reference.node);
+				break;
+
+			case ACPI_REFCLASS_DEBUG:
+			case ACPI_REFCLASS_TABLE:
+
+				acpi_os_printf("\n");
+				break;
+
+			default:	/* Unknown reference class */
+
+				acpi_os_printf("%2.2X\n",
+					       obj_desc->reference.class);
+				break;
+			}
+			break;
+
+		default:
+
+			acpi_os_printf("<Obj>          ");
+			acpi_db_decode_internal_object(obj_desc);
+			break;
+		}
+		break;
+
+	default:
+
+		acpi_os_printf("<Not a valid ACPI Object Descriptor> [%s]",
+			       acpi_ut_get_descriptor_name(obj_desc));
+		break;
+	}
+
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_locals
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_locals(struct acpi_walk_state *walk_state)
+{
+	u32 i;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	u8 display_locals = FALSE;
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	if (!node) {
+		acpi_os_printf
+		    ("No method node (Executing subtree for buffer or opregion)\n");
+		return;
+	}
+
+	if (node->type != ACPI_TYPE_METHOD) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/* Are any locals actually set? */
+
+	for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+		obj_desc = walk_state->local_variables[i].object;
+		if (obj_desc) {
+			display_locals = TRUE;
+			break;
+		}
+	}
+
+	/* If any are set, only display the ones that are set */
+
+	if (display_locals) {
+		acpi_os_printf
+		    ("\nInitialized Local Variables for method [%4.4s]:\n",
+		     acpi_ut_get_node_name(node));
+
+		for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+			obj_desc = walk_state->local_variables[i].object;
+			if (obj_desc) {
+				acpi_os_printf("  Local%X: ", i);
+				acpi_db_display_internal_object(obj_desc,
+								walk_state);
+			}
+		}
+	} else {
+		acpi_os_printf
+		    ("No Local Variables are initialized for method [%4.4s]\n",
+		     acpi_ut_get_node_name(node));
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_arguments
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_arguments(struct acpi_walk_state *walk_state)
+{
+	u32 i;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	u8 display_args = FALSE;
+
+	node = walk_state->method_node;
+	obj_desc = walk_state->method_desc;
+
+	if (!node) {
+		acpi_os_printf
+		    ("No method node (Executing subtree for buffer or opregion)\n");
+		return;
+	}
+
+	if (node->type != ACPI_TYPE_METHOD) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/* Are any arguments actually set? */
+
+	for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+		obj_desc = walk_state->arguments[i].object;
+		if (obj_desc) {
+			display_args = TRUE;
+			break;
+		}
+	}
+
+	/* If any are set, only display the ones that are set */
+
+	if (display_args) {
+		acpi_os_printf("Initialized Arguments for Method [%4.4s]:  "
+			       "(%X arguments defined for method invocation)\n",
+			       acpi_ut_get_node_name(node),
+			       obj_desc->method.param_count);
+
+		for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+			obj_desc = walk_state->arguments[i].object;
+			if (obj_desc) {
+				acpi_os_printf("  Arg%u:   ", i);
+				acpi_db_display_internal_object(obj_desc,
+								walk_state);
+			}
+		}
+	} else {
+		acpi_os_printf
+		    ("No Arguments are initialized for method [%4.4s]\n",
+		     acpi_ut_get_node_name(node));
+	}
+}
diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c
new file mode 100644
index 0000000..4ba0a20
--- /dev/null
+++ b/drivers/acpi/acpica/dbstats.c
@@ -0,0 +1,546 @@
+/*******************************************************************************
+ *
+ * Module Name: dbstats - Generation and display of ACPI table statistics
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbstats")
+
+/* Local prototypes */
+static void acpi_db_count_namespace_objects(void);
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc);
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+static void acpi_db_list_info(struct acpi_memory_list *list);
+#endif
+
+/*
+ * Statistics subcommands
+ */
+static struct acpi_db_argument_info acpi_db_stat_types[] = {
+	{"ALLOCATIONS"},
+	{"OBJECTS"},
+	{"MEMORY"},
+	{"MISC"},
+	{"TABLES"},
+	{"SIZES"},
+	{"STACK"},
+	{NULL}			/* Must be null terminated */
+};
+
+#define CMD_STAT_ALLOCATIONS     0
+#define CMD_STAT_OBJECTS         1
+#define CMD_STAT_MEMORY          2
+#define CMD_STAT_MISC            3
+#define CMD_STAT_TABLES          4
+#define CMD_STAT_SIZES           5
+#define CMD_STAT_STACK           6
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_list_info
+ *
+ * PARAMETERS:  list            - Memory list/cache to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the input memory list or cache.
+ *
+ ******************************************************************************/
+
+static void acpi_db_list_info(struct acpi_memory_list *list)
+{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	u32 outstanding;
+#endif
+
+	acpi_os_printf("\n%s\n", list->list_name);
+
+	/* max_depth > 0 indicates a cache object */
+
+	if (list->max_depth > 0) {
+		acpi_os_printf
+		    ("    Cache: [Depth    MaxD Avail  Size]                "
+		     "%8.2X %8.2X %8.2X %8.2X\n", list->current_depth,
+		     list->max_depth, list->max_depth - list->current_depth,
+		     (list->current_depth * list->object_size));
+	}
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	if (list->max_depth > 0) {
+		acpi_os_printf
+		    ("    Cache: [Requests Hits Misses ObjSize]             "
+		     "%8.2X %8.2X %8.2X %8.2X\n", list->requests, list->hits,
+		     list->requests - list->hits, list->object_size);
+	}
+
+	outstanding = acpi_db_get_cache_info(list);
+
+	if (list->object_size) {
+		acpi_os_printf
+		    ("    Mem:   [Alloc    Free Max    CurSize Outstanding] "
+		     "%8.2X %8.2X %8.2X %8.2X %8.2X\n", list->total_allocated,
+		     list->total_freed, list->max_occupied,
+		     outstanding * list->object_size, outstanding);
+	} else {
+		acpi_os_printf
+		    ("    Mem:   [Alloc Free Max CurSize Outstanding Total] "
+		     "%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n",
+		     list->total_allocated, list->total_freed,
+		     list->max_occupied, list->current_total_size, outstanding,
+		     list->total_size);
+	}
+#endif
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_enumerate_object
+ *
+ * PARAMETERS:  obj_desc            - Object to be counted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add this object to the global counts, by object type.
+ *              Limited recursion handles subobjects and packages, and this
+ *              is probably acceptable within the AML debugger only.
+ *
+ ******************************************************************************/
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		return;
+	}
+
+	/* Enumerate this object first */
+
+	acpi_gbl_num_objects++;
+
+	if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_gbl_obj_type_count_misc++;
+	} else {
+		acpi_gbl_obj_type_count[obj_desc->common.type]++;
+	}
+
+	/* Count the sub-objects */
+
+	switch (obj_desc->common.type) {
+	case ACPI_TYPE_PACKAGE:
+
+		for (i = 0; i < obj_desc->package.count; i++) {
+			acpi_db_enumerate_object(obj_desc->package.elements[i]);
+		}
+		break;
+
+	case ACPI_TYPE_DEVICE:
+
+		acpi_db_enumerate_object(obj_desc->device.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->device.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->device.handler);
+		break;
+
+	case ACPI_TYPE_BUFFER_FIELD:
+
+		if (acpi_ns_get_secondary_object(obj_desc)) {
+			acpi_gbl_obj_type_count[ACPI_TYPE_BUFFER_FIELD]++;
+		}
+		break;
+
+	case ACPI_TYPE_REGION:
+
+		acpi_gbl_obj_type_count[ACPI_TYPE_LOCAL_REGION_FIELD]++;
+		acpi_db_enumerate_object(obj_desc->region.handler);
+		break;
+
+	case ACPI_TYPE_POWER:
+
+		acpi_db_enumerate_object(obj_desc->power_resource.
+					 notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->power_resource.
+					 notify_list[1]);
+		break;
+
+	case ACPI_TYPE_PROCESSOR:
+
+		acpi_db_enumerate_object(obj_desc->processor.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->processor.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->processor.handler);
+		break;
+
+	case ACPI_TYPE_THERMAL:
+
+		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->thermal_zone.handler);
+		break;
+
+	default:
+
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_classify_one_object
+ *
+ * PARAMETERS:  Callback for walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
+ *              the parent namespace node.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	u32 type;
+
+	acpi_gbl_num_nodes++;
+
+	node = (struct acpi_namespace_node *)obj_handle;
+	obj_desc = acpi_ns_get_attached_object(node);
+
+	acpi_db_enumerate_object(obj_desc);
+
+	type = node->type;
+	if (type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_gbl_node_type_count_misc++;
+	} else {
+		acpi_gbl_node_type_count[type]++;
+	}
+
+	return (AE_OK);
+
+#ifdef ACPI_FUTURE_IMPLEMENTATION
+
+	/* TBD: These need to be counted during the initial parsing phase */
+
+	if (acpi_ps_is_named_op(op->opcode)) {
+		num_nodes++;
+	}
+
+	if (is_method) {
+		num_method_elements++;
+	}
+
+	num_grammar_elements++;
+	op = acpi_ps_get_depth_next(root, op);
+
+	size_of_parse_tree = (num_grammar_elements - num_method_elements) *
+	    (u32)sizeof(union acpi_parse_object);
+	size_of_method_trees =
+	    num_method_elements * (u32)sizeof(union acpi_parse_object);
+	size_of_node_entries =
+	    num_nodes * (u32)sizeof(struct acpi_namespace_node);
+	size_of_acpi_objects =
+	    num_nodes * (u32)sizeof(union acpi_operand_object);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_count_namespace_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Count and classify the entire namespace, including all
+ *              namespace nodes and attached objects.
+ *
+ ******************************************************************************/
+
+static void acpi_db_count_namespace_objects(void)
+{
+	u32 i;
+
+	acpi_gbl_num_nodes = 0;
+	acpi_gbl_num_objects = 0;
+
+	acpi_gbl_obj_type_count_misc = 0;
+	for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX - 1); i++) {
+		acpi_gbl_obj_type_count[i] = 0;
+		acpi_gbl_node_type_count[i] = 0;
+	}
+
+	(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, FALSE,
+				     acpi_db_classify_one_object, NULL, NULL,
+				     NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_statistics
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display various statistics
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_statistics(char *type_arg)
+{
+	u32 i;
+	u32 temp;
+
+	acpi_ut_strupr(type_arg);
+	temp = acpi_db_match_argument(type_arg, acpi_db_stat_types);
+	if (temp == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return (AE_OK);
+	}
+
+	switch (temp) {
+	case CMD_STAT_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_ut_dump_allocation_info();
+#endif
+		break;
+
+	case CMD_STAT_TABLES:
+
+		acpi_os_printf("ACPI Table Information (not implemented):\n\n");
+		break;
+
+	case CMD_STAT_OBJECTS:
+
+		acpi_db_count_namespace_objects();
+
+		acpi_os_printf
+		    ("\nObjects defined in the current namespace:\n\n");
+
+		acpi_os_printf("%16.16s %10.10s %10.10s\n",
+			       "ACPI_TYPE", "NODES", "OBJECTS");
+
+		for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) {
+			acpi_os_printf("%16.16s % 10ld% 10ld\n",
+				       acpi_ut_get_type_name(i),
+				       acpi_gbl_node_type_count[i],
+				       acpi_gbl_obj_type_count[i]);
+		}
+		acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
+			       acpi_gbl_node_type_count_misc,
+			       acpi_gbl_obj_type_count_misc);
+
+		acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:",
+			       acpi_gbl_num_nodes, acpi_gbl_num_objects);
+		break;
+
+	case CMD_STAT_MEMORY:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_os_printf
+		    ("\n----Object Statistics (all in hex)---------\n");
+
+		acpi_db_list_info(acpi_gbl_global_list);
+		acpi_db_list_info(acpi_gbl_ns_node_list);
+#endif
+
+#ifdef ACPI_USE_LOCAL_CACHE
+		acpi_os_printf
+		    ("\n----Cache Statistics (all in hex)---------\n");
+		acpi_db_list_info(acpi_gbl_operand_cache);
+		acpi_db_list_info(acpi_gbl_ps_node_cache);
+		acpi_db_list_info(acpi_gbl_ps_node_ext_cache);
+		acpi_db_list_info(acpi_gbl_state_cache);
+#endif
+
+		break;
+
+	case CMD_STAT_MISC:
+
+		acpi_os_printf("\nMiscellaneous Statistics:\n\n");
+		acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n",
+			       acpi_gbl_ps_find_count);
+		acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n",
+			       acpi_gbl_ns_lookup_count);
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("Mutex usage:\n\n");
+		for (i = 0; i < ACPI_NUM_MUTEX; i++) {
+			acpi_os_printf("%-28s:     % 7ld\n",
+				       acpi_ut_get_mutex_name(i),
+				       acpi_gbl_mutex_info[i].use_count);
+		}
+		break;
+
+	case CMD_STAT_SIZES:
+
+		acpi_os_printf("\nInternal object sizes:\n\n");
+
+		acpi_os_printf("Common         %3d\n",
+			       sizeof(struct acpi_object_common));
+		acpi_os_printf("Number         %3d\n",
+			       sizeof(struct acpi_object_integer));
+		acpi_os_printf("String         %3d\n",
+			       sizeof(struct acpi_object_string));
+		acpi_os_printf("Buffer         %3d\n",
+			       sizeof(struct acpi_object_buffer));
+		acpi_os_printf("Package        %3d\n",
+			       sizeof(struct acpi_object_package));
+		acpi_os_printf("BufferField    %3d\n",
+			       sizeof(struct acpi_object_buffer_field));
+		acpi_os_printf("Device         %3d\n",
+			       sizeof(struct acpi_object_device));
+		acpi_os_printf("Event          %3d\n",
+			       sizeof(struct acpi_object_event));
+		acpi_os_printf("Method         %3d\n",
+			       sizeof(struct acpi_object_method));
+		acpi_os_printf("Mutex          %3d\n",
+			       sizeof(struct acpi_object_mutex));
+		acpi_os_printf("Region         %3d\n",
+			       sizeof(struct acpi_object_region));
+		acpi_os_printf("PowerResource  %3d\n",
+			       sizeof(struct acpi_object_power_resource));
+		acpi_os_printf("Processor      %3d\n",
+			       sizeof(struct acpi_object_processor));
+		acpi_os_printf("ThermalZone    %3d\n",
+			       sizeof(struct acpi_object_thermal_zone));
+		acpi_os_printf("RegionField    %3d\n",
+			       sizeof(struct acpi_object_region_field));
+		acpi_os_printf("BankField      %3d\n",
+			       sizeof(struct acpi_object_bank_field));
+		acpi_os_printf("IndexField     %3d\n",
+			       sizeof(struct acpi_object_index_field));
+		acpi_os_printf("Reference      %3d\n",
+			       sizeof(struct acpi_object_reference));
+		acpi_os_printf("Notify         %3d\n",
+			       sizeof(struct acpi_object_notify_handler));
+		acpi_os_printf("AddressSpace   %3d\n",
+			       sizeof(struct acpi_object_addr_handler));
+		acpi_os_printf("Extra          %3d\n",
+			       sizeof(struct acpi_object_extra));
+		acpi_os_printf("Data           %3d\n",
+			       sizeof(struct acpi_object_data));
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("ParseObject    %3d\n",
+			       sizeof(struct acpi_parse_obj_common));
+		acpi_os_printf("ParseObjectNamed %3d\n",
+			       sizeof(struct acpi_parse_obj_named));
+		acpi_os_printf("ParseObjectAsl %3d\n",
+			       sizeof(struct acpi_parse_obj_asl));
+		acpi_os_printf("OperandObject  %3d\n",
+			       sizeof(union acpi_operand_object));
+		acpi_os_printf("NamespaceNode  %3d\n",
+			       sizeof(struct acpi_namespace_node));
+		acpi_os_printf("AcpiObject     %3d\n",
+			       sizeof(union acpi_object));
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("Generic State  %3d\n",
+			       sizeof(union acpi_generic_state));
+		acpi_os_printf("Common State   %3d\n",
+			       sizeof(struct acpi_common_state));
+		acpi_os_printf("Control State  %3d\n",
+			       sizeof(struct acpi_control_state));
+		acpi_os_printf("Update State   %3d\n",
+			       sizeof(struct acpi_update_state));
+		acpi_os_printf("Scope State    %3d\n",
+			       sizeof(struct acpi_scope_state));
+		acpi_os_printf("Parse Scope    %3d\n",
+			       sizeof(struct acpi_pscope_state));
+		acpi_os_printf("Package State  %3d\n",
+			       sizeof(struct acpi_pkg_state));
+		acpi_os_printf("Thread State   %3d\n",
+			       sizeof(struct acpi_thread_state));
+		acpi_os_printf("Result Values  %3d\n",
+			       sizeof(struct acpi_result_values));
+		acpi_os_printf("Notify Info    %3d\n",
+			       sizeof(struct acpi_notify_info));
+		break;
+
+	case CMD_STAT_STACK:
+#if defined(ACPI_DEBUG_OUTPUT)
+
+		temp =
+		    (u32)ACPI_PTR_DIFF(acpi_gbl_entry_stack_pointer,
+				       acpi_gbl_lowest_stack_pointer);
+
+		acpi_os_printf("\nSubsystem Stack Usage:\n\n");
+		acpi_os_printf("Entry Stack Pointer        %p\n",
+			       acpi_gbl_entry_stack_pointer);
+		acpi_os_printf("Lowest Stack Pointer       %p\n",
+			       acpi_gbl_lowest_stack_pointer);
+		acpi_os_printf("Stack Use                  %X (%u)\n", temp,
+			       temp);
+		acpi_os_printf("Deepest Procedure Nesting  %u\n",
+			       acpi_gbl_deepest_nesting);
+#endif
+		break;
+
+	default:
+
+		break;
+	}
+
+	acpi_os_printf("\n");
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c
new file mode 100644
index 0000000..10ea8bf
--- /dev/null
+++ b/drivers/acpi/acpica/dbtest.c
@@ -0,0 +1,1057 @@
+/*******************************************************************************
+ *
+ * Module Name: dbtest - Various debug-related tests
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbtest")
+
+/* Local prototypes */
+static void acpi_db_test_all_objects(void);
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+			u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length);
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+			 acpi_object_type expected_type,
+			 union acpi_object **value);
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+			union acpi_object *value);
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg);
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+				     u32 nesting_level,
+				     void *context, void **return_value);
+
+/*
+ * Test subcommands
+ */
+static struct acpi_db_argument_info acpi_db_test_types[] = {
+	{"OBJECTS"},
+	{"PREDEFINED"},
+	{NULL}			/* Must be null terminated */
+};
+
+#define CMD_TEST_OBJECTS        0
+#define CMD_TEST_PREDEFINED     1
+
+#define BUFFER_FILL_VALUE       0xFF
+
+/*
+ * Support for the special debugger read/write control methods.
+ * These methods are installed into the current namespace and are
+ * used to read and write the various namespace objects. The point
+ * is to force the AML interpreter do all of the work.
+ */
+#define ACPI_DB_READ_METHOD     "\\_T98"
+#define ACPI_DB_WRITE_METHOD    "\\_T99"
+
+static acpi_handle read_handle = NULL;
+static acpi_handle write_handle = NULL;
+
+/* ASL Definitions of the debugger read/write control methods */
+
+#if 0
+definition_block("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+	method(_T98, 1, not_serialized) {	/* Read */
+		return (de_ref_of(arg0))
+	}
+}
+
+definition_block("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+	method(_T99, 2, not_serialized) {	/* Write */
+		store(arg1, arg0)
+	}
+}
+#endif
+
+static unsigned char read_method_code[] = {
+	0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00,	/* 00000000    "SSDT...." */
+	0x02, 0xC9, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00,	/* 00000008    "..Intel." */
+	0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00,	/* 00000010    "DEBUG..." */
+	0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,	/* 00000018    "....INTL" */
+	0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54,	/* 00000020    "... .._T" */
+	0x39, 0x38, 0x01, 0xA4, 0x83, 0x68	/* 00000028    "98...h"   */
+};
+
+static unsigned char write_method_code[] = {
+	0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00,	/* 00000000    "SSDT...." */
+	0x02, 0x15, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00,	/* 00000008    "..Intel." */
+	0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00,	/* 00000010    "DEBUG..." */
+	0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,	/* 00000018    "....INTL" */
+	0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54,	/* 00000020    "... .._T" */
+	0x39, 0x39, 0x02, 0x70, 0x69, 0x68	/* 00000028    "99.pih"   */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_test
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute various debug tests.
+ *
+ * Note: Code is prepared for future expansion of the TEST command.
+ *
+ ******************************************************************************/
+
+void acpi_db_execute_test(char *type_arg)
+{
+	u32 temp;
+
+	acpi_ut_strupr(type_arg);
+	temp = acpi_db_match_argument(type_arg, acpi_db_test_types);
+	if (temp == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return;
+	}
+
+	switch (temp) {
+	case CMD_TEST_OBJECTS:
+
+		acpi_db_test_all_objects();
+		break;
+
+	case CMD_TEST_PREDEFINED:
+
+		acpi_db_evaluate_all_predefined_names(NULL);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_all_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the
+ *              namespace by reading/writing/comparing all data objects such
+ *              as integers, strings, buffers, fields, buffer fields, etc.
+ *
+ ******************************************************************************/
+
+static void acpi_db_test_all_objects(void)
+{
+	acpi_status status;
+
+	/* Install the debugger read-object control method if necessary */
+
+	if (!read_handle) {
+		status = acpi_install_method(read_method_code);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s, Could not install debugger read method\n",
+			     acpi_format_exception(status));
+			return;
+		}
+
+		status =
+		    acpi_get_handle(NULL, ACPI_DB_READ_METHOD, &read_handle);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not obtain handle for debug method %s\n",
+			     ACPI_DB_READ_METHOD);
+			return;
+		}
+	}
+
+	/* Install the debugger write-object control method if necessary */
+
+	if (!write_handle) {
+		status = acpi_install_method(write_method_code);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s, Could not install debugger write method\n",
+			     acpi_format_exception(status));
+			return;
+		}
+
+		status =
+		    acpi_get_handle(NULL, ACPI_DB_WRITE_METHOD, &write_handle);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not obtain handle for debug method %s\n",
+			     ACPI_DB_WRITE_METHOD);
+			return;
+		}
+	}
+
+	/* Walk the entire namespace, testing each supported named data object */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_test_one_object,
+				  NULL, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_one_object
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test one namespace object. Supported types are Integer,
+ *              String, Buffer, buffer_field, and field_unit. All other object
+ *              types are simply ignored.
+ *
+ *              Note: Support for Packages is not implemented.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+			u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *region_obj;
+	acpi_object_type local_type;
+	u32 bit_length = 0;
+	u32 byte_length = 0;
+	acpi_status status = AE_OK;
+
+	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	obj_desc = node->object;
+
+	/*
+	 * For the supported types, get the actual bit length or
+	 * byte length. Map the type to one of Integer/String/Buffer.
+	 */
+	switch (node->type) {
+	case ACPI_TYPE_INTEGER:
+
+		/* Integer width is either 32 or 64 */
+
+		local_type = ACPI_TYPE_INTEGER;
+		bit_length = acpi_gbl_integer_bit_width;
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		local_type = ACPI_TYPE_STRING;
+		byte_length = obj_desc->string.length;
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		local_type = ACPI_TYPE_BUFFER;
+		byte_length = obj_desc->buffer.length;
+		bit_length = byte_length * 8;
+		break;
+
+	case ACPI_TYPE_FIELD_UNIT:
+	case ACPI_TYPE_BUFFER_FIELD:
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+	case ACPI_TYPE_LOCAL_INDEX_FIELD:
+	case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+		local_type = ACPI_TYPE_INTEGER;
+		if (obj_desc) {
+			/*
+			 * Returned object will be a Buffer if the field length
+			 * is larger than the size of an Integer (32 or 64 bits
+			 * depending on the DSDT version).
+			 */
+			bit_length = obj_desc->common_field.bit_length;
+			byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+			if (bit_length > acpi_gbl_integer_bit_width) {
+				local_type = ACPI_TYPE_BUFFER;
+			}
+		}
+		break;
+
+	default:
+
+		/* Ignore all other types */
+
+		return (AE_OK);
+	}
+
+	/* Emit the common prefix: Type:Name */
+
+	acpi_os_printf("%14s: %4.4s",
+		       acpi_ut_get_type_name(node->type), node->name.ascii);
+	if (!obj_desc) {
+		acpi_os_printf(" Ignoring, no attached object\n");
+		return (AE_OK);
+	}
+
+	/*
+	 * Check for unsupported region types. Note: acpi_exec simulates
+	 * access to system_memory, system_IO, PCI_Config, and EC.
+	 */
+	switch (node->type) {
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+		region_obj = obj_desc->field.region_obj;
+		switch (region_obj->region.space_id) {
+		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+		case ACPI_ADR_SPACE_SYSTEM_IO:
+		case ACPI_ADR_SPACE_PCI_CONFIG:
+		case ACPI_ADR_SPACE_EC:
+
+			break;
+
+		default:
+
+			acpi_os_printf
+			    ("    %s space is not supported [%4.4s]\n",
+			     acpi_ut_get_region_name(region_obj->region.
+						     space_id),
+			     region_obj->region.node->name.ascii);
+			return (AE_OK);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	/* At this point, we have resolved the object to one of the major types */
+
+	switch (local_type) {
+	case ACPI_TYPE_INTEGER:
+
+		status = acpi_db_test_integer_type(node, bit_length);
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		status = acpi_db_test_string_type(node, byte_length);
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		status = acpi_db_test_buffer_type(node, bit_length);
+		break;
+
+	default:
+
+		acpi_os_printf(" Ignoring, type not implemented (%2.2X)",
+			       local_type);
+		break;
+	}
+
+	switch (node->type) {
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+		region_obj = obj_desc->field.region_obj;
+		acpi_os_printf(" (%s)",
+			       acpi_ut_get_region_name(region_obj->region.
+						       space_id));
+		break;
+
+	default:
+		break;
+	}
+
+	acpi_os_printf("\n");
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_integer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object. Used for
+ *                                    support of arbitrary length field_unit
+ *                                    and buffer_field objects.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Integer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	union acpi_object write_value;
+	u64 value_to_write;
+	acpi_status status;
+
+	if (bit_length > 64) {
+		acpi_os_printf(" Invalid length for an Integer: %u",
+			       bit_length);
+		return (AE_OK);
+	}
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	acpi_os_printf(" (%4.4X/%3.3X) %8.8X%8.8X",
+		       bit_length, ACPI_ROUND_BITS_UP_TO_BYTES(bit_length),
+		       ACPI_FORMAT_UINT64(temp1->integer.value));
+
+	value_to_write = ACPI_UINT64_MAX >> (64 - bit_length);
+	if (temp1->integer.value == value_to_write) {
+		value_to_write = 0;
+	}
+
+	/* Write a new value */
+
+	write_value.type = ACPI_TYPE_INTEGER;
+	write_value.integer.value = value_to_write;
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (temp2->integer.value != value_to_write) {
+		acpi_os_printf(" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(temp2->integer.value),
+			       ACPI_FORMAT_UINT64(value_to_write));
+	}
+
+	/* Write back the original value */
+
+	write_value.integer.value = temp1->integer.value;
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (temp3->integer.value != temp1->integer.value) {
+		acpi_os_printf(" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(temp3->integer.value),
+			       ACPI_FORMAT_UINT64(temp1->integer.value));
+	}
+
+exit:
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_buffer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Buffer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	u8 *buffer;
+	union acpi_object write_value;
+	acpi_status status;
+	u32 byte_length;
+	u32 i;
+	u8 extra_bits;
+
+	byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+	if (byte_length == 0) {
+		acpi_os_printf(" Ignoring zero length buffer");
+		return (AE_OK);
+	}
+
+	/* Allocate a local buffer */
+
+	buffer = ACPI_ALLOCATE_ZEROED(byte_length);
+	if (!buffer) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Emit a few bytes of the buffer */
+
+	acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length);
+	for (i = 0; ((i < 4) && (i < byte_length)); i++) {
+		acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]);
+	}
+	acpi_os_printf("... ");
+
+	/*
+	 * Write a new value.
+	 *
+	 * Handle possible extra bits at the end of the buffer. Can
+	 * happen for field_units larger than an integer, but the bit
+	 * count is not an integral number of bytes. Zero out the
+	 * unused bits.
+	 */
+	memset(buffer, BUFFER_FILL_VALUE, byte_length);
+	extra_bits = bit_length % 8;
+	if (extra_bits) {
+		buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits);
+	}
+
+	write_value.type = ACPI_TYPE_BUFFER;
+	write_value.buffer.length = byte_length;
+	write_value.buffer.pointer = buffer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (memcmp(temp2->buffer.pointer, buffer, byte_length)) {
+		acpi_os_printf(" MISMATCH 2: New buffer value");
+	}
+
+	/* Write back the original value */
+
+	write_value.buffer.length = byte_length;
+	write_value.buffer.pointer = temp1->buffer.pointer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) {
+		acpi_os_printf(" MISMATCH 3: While restoring original buffer");
+	}
+
+exit:
+	ACPI_FREE(buffer);
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_string_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              byte_length         - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an String-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	char *value_to_write = "Test String from AML Debugger";
+	union acpi_object write_value;
+	acpi_status status;
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	acpi_os_printf(" (%4.4X/%3.3X) \"%s\"", (temp1->string.length * 8),
+		       temp1->string.length, temp1->string.pointer);
+
+	/* Write a new value */
+
+	write_value.type = ACPI_TYPE_STRING;
+	write_value.string.length = strlen(value_to_write);
+	write_value.string.pointer = value_to_write;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (strcmp(temp2->string.pointer, value_to_write)) {
+		acpi_os_printf(" MISMATCH 2: %s, expecting %s",
+			       temp2->string.pointer, value_to_write);
+	}
+
+	/* Write back the original value */
+
+	write_value.string.length = strlen(temp1->string.pointer);
+	write_value.string.pointer = temp1->string.pointer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (strcmp(temp1->string.pointer, temp3->string.pointer)) {
+		acpi_os_printf(" MISMATCH 3: %s, expecting %s",
+			       temp3->string.pointer, temp1->string.pointer);
+	}
+
+exit:
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_read_from_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              expected_type       - Object type expected from the read
+ *              value               - Where the value read is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a read from the specified object by invoking the
+ *              special debugger control method that reads the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+			 acpi_object_type expected_type,
+			 union acpi_object **value)
+{
+	union acpi_object *ret_value;
+	struct acpi_object_list param_objects;
+	union acpi_object params[2];
+	struct acpi_buffer return_obj;
+	acpi_status status;
+
+	params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+	params[0].reference.actual_type = node->type;
+	params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+	param_objects.count = 1;
+	param_objects.pointer = params;
+
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(read_handle, NULL,
+				      &param_objects, &return_obj);
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not read from object, %s",
+			       acpi_format_exception(status));
+		return (status);
+	}
+
+	ret_value = (union acpi_object *)return_obj.pointer;
+
+	switch (ret_value->type) {
+	case ACPI_TYPE_INTEGER:
+	case ACPI_TYPE_BUFFER:
+	case ACPI_TYPE_STRING:
+		/*
+		 * Did we receive the type we wanted? Most important for the
+		 * Integer/Buffer case (when a field is larger than an Integer,
+		 * it should return a Buffer).
+		 */
+		if (ret_value->type != expected_type) {
+			acpi_os_printf
+			    (" Type mismatch: Expected %s, Received %s",
+			     acpi_ut_get_type_name(expected_type),
+			     acpi_ut_get_type_name(ret_value->type));
+
+			return (AE_TYPE);
+		}
+
+		*value = ret_value;
+		break;
+
+	default:
+
+		acpi_os_printf(" Unsupported return object type, %s",
+			       acpi_ut_get_type_name(ret_value->type));
+
+		acpi_os_free(return_obj.pointer);
+		return (AE_TYPE);
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_write_to_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              value               - Value to be written
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a write to the specified object by invoking the
+ *              special debugger control method that writes the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+			union acpi_object *value)
+{
+	struct acpi_object_list param_objects;
+	union acpi_object params[2];
+	acpi_status status;
+
+	params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+	params[0].reference.actual_type = node->type;
+	params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+	/* Copy the incoming user parameter */
+
+	memcpy(&params[1], value, sizeof(union acpi_object));
+
+	param_objects.count = 2;
+	param_objects.pointer = params;
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(write_handle, NULL, &param_objects, NULL);
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not write to object, %s",
+			       acpi_format_exception(status));
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_all_predefined_names
+ *
+ * PARAMETERS:  count_arg           - Max number of methods to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Namespace batch execution. Execute predefined names in the
+ *              namespace, up to the max count, if specified.
+ *
+ ******************************************************************************/
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg)
+{
+	struct acpi_db_execute_walk info;
+
+	info.count = 0;
+	info.max_count = ACPI_UINT32_MAX;
+
+	if (count_arg) {
+		info.max_count = strtoul(count_arg, NULL, 0);
+	}
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_evaluate_one_predefined_name, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf("Evaluated %u predefined names in the namespace\n",
+		       info.count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_one_predefined_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Batch execution module. Currently only executes predefined
+ *              ACPI names.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+				     u32 nesting_level,
+				     void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	struct acpi_db_execute_walk *info =
+	    (struct acpi_db_execute_walk *)context;
+	char *pathname;
+	const union acpi_predefined_info *predefined;
+	struct acpi_device_info *obj_info;
+	struct acpi_object_list param_objects;
+	union acpi_object params[ACPI_METHOD_NUM_ARGS];
+	union acpi_object *this_param;
+	struct acpi_buffer return_obj;
+	acpi_status status;
+	u16 arg_type_list;
+	u8 arg_count;
+	u8 arg_type;
+	u32 i;
+
+	/* The name must be a predefined ACPI name */
+
+	predefined = acpi_ut_match_predefined_method(node->name.ascii);
+	if (!predefined) {
+		return (AE_OK);
+	}
+
+	if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* Get the object info for number of method parameters */
+
+	status = acpi_get_object_info(obj_handle, &obj_info);
+	if (ACPI_FAILURE(status)) {
+		ACPI_FREE(pathname);
+		return (status);
+	}
+
+	param_objects.count = 0;
+	param_objects.pointer = NULL;
+
+	if (obj_info->type == ACPI_TYPE_METHOD) {
+
+		/* Setup default parameters (with proper types) */
+
+		arg_type_list = predefined->info.argument_list;
+		arg_count = METHOD_GET_ARG_COUNT(arg_type_list);
+
+		/*
+		 * Setup the ACPI-required number of arguments, regardless of what
+		 * the actual method defines. If there is a difference, then the
+		 * method is wrong and a warning will be issued during execution.
+		 */
+		this_param = params;
+		for (i = 0; i < arg_count; i++) {
+			arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
+			this_param->type = arg_type;
+
+			switch (arg_type) {
+			case ACPI_TYPE_INTEGER:
+
+				this_param->integer.value = 1;
+				break;
+
+			case ACPI_TYPE_STRING:
+
+				this_param->string.pointer =
+				    "This is the default argument string";
+				this_param->string.length =
+				    strlen(this_param->string.pointer);
+				break;
+
+			case ACPI_TYPE_BUFFER:
+
+				this_param->buffer.pointer = (u8 *)params;	/* just a garbage buffer */
+				this_param->buffer.length = 48;
+				break;
+
+			case ACPI_TYPE_PACKAGE:
+
+				this_param->package.elements = NULL;
+				this_param->package.count = 0;
+				break;
+
+			default:
+
+				acpi_os_printf
+				    ("%s: Unsupported argument type: %u\n",
+				     pathname, arg_type);
+				break;
+			}
+
+			this_param++;
+		}
+
+		param_objects.count = arg_count;
+		param_objects.pointer = params;
+	}
+
+	ACPI_FREE(obj_info);
+	return_obj.pointer = NULL;
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	/* Do the actual method execution */
+
+	acpi_gbl_method_executing = TRUE;
+
+	status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
+
+	acpi_os_printf("%-32s returned %s\n",
+		       pathname, acpi_format_exception(status));
+	acpi_gbl_method_executing = FALSE;
+	ACPI_FREE(pathname);
+
+	/* Ignore status from method execution */
+
+	status = AE_OK;
+
+	/* Update count, check if we have executed enough methods */
+
+	info->count++;
+	if (info->count >= info->max_count) {
+		status = AE_CTRL_TERMINATE;
+	}
+
+	return (status);
+}
diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c
new file mode 100644
index 0000000..86790e0
--- /dev/null
+++ b/drivers/acpi/acpica/dbutils.c
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ *
+ * Module Name: dbutils - AML debugger utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbutils")
+
+/* Local prototypes */
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root);
+
+void acpi_db_dump_buffer(u32 address);
+#endif
+
+static char *gbl_hex_to_ascii = "0123456789ABCDEF";
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_argument
+ *
+ * PARAMETERS:  user_argument           - User command line
+ *              arguments               - Array of commands to match against
+ *
+ * RETURN:      Index into command array or ACPI_TYPE_NOT_FOUND if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_db_match_argument(char *user_argument,
+		       struct acpi_db_argument_info *arguments)
+{
+	u32 i;
+
+	if (!user_argument || user_argument[0] == 0) {
+		return (ACPI_TYPE_NOT_FOUND);
+	}
+
+	for (i = 0; arguments[i].name; i++) {
+		if (strstr(arguments[i].name, user_argument) ==
+		    arguments[i].name) {
+			return (i);
+		}
+	}
+
+	/* Argument not recognized */
+
+	return (ACPI_TYPE_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_output_destination
+ *
+ * PARAMETERS:  output_flags        - Current flags word
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set the current destination for debugger output. Also sets
+ *              the debug output level accordingly.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_output_destination(u32 output_flags)
+{
+
+	acpi_gbl_db_output_flags = (u8)output_flags;
+
+	if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) &&
+	    acpi_gbl_db_output_to_file) {
+		acpi_dbg_level = acpi_gbl_db_debug_level;
+	} else {
+		acpi_dbg_level = acpi_gbl_db_console_debug_level;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_external_object
+ *
+ * PARAMETERS:  obj_desc        - External ACPI object to dump
+ *              level           - Nesting level.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump the contents of an ACPI external object
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		acpi_os_printf("[Null Object]\n");
+		return;
+	}
+
+	for (i = 0; i < level; i++) {
+		acpi_os_printf(" ");
+	}
+
+	switch (obj_desc->type) {
+	case ACPI_TYPE_ANY:
+
+		acpi_os_printf("[Null Object] (Type=0)\n");
+		break;
+
+	case ACPI_TYPE_INTEGER:
+
+		acpi_os_printf("[Integer] = %8.8X%8.8X\n",
+			       ACPI_FORMAT_UINT64(obj_desc->integer.value));
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		acpi_os_printf("[String] Length %.2X = ",
+			       obj_desc->string.length);
+		acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
+		acpi_os_printf("\n");
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		acpi_os_printf("[Buffer] Length %.2X = ",
+			       obj_desc->buffer.length);
+		if (obj_desc->buffer.length) {
+			if (obj_desc->buffer.length > 16) {
+				acpi_os_printf("\n");
+			}
+			acpi_ut_debug_dump_buffer(ACPI_CAST_PTR
+						  (u8,
+						   obj_desc->buffer.pointer),
+						  obj_desc->buffer.length,
+						  DB_BYTE_DISPLAY, _COMPONENT);
+		} else {
+			acpi_os_printf("\n");
+		}
+		break;
+
+	case ACPI_TYPE_PACKAGE:
+
+		acpi_os_printf("[Package] Contains %u Elements:\n",
+			       obj_desc->package.count);
+
+		for (i = 0; i < obj_desc->package.count; i++) {
+			acpi_db_dump_external_object(&obj_desc->package.
+						     elements[i], level + 1);
+		}
+		break;
+
+	case ACPI_TYPE_LOCAL_REFERENCE:
+
+		acpi_os_printf("[Object Reference] = ");
+		acpi_db_display_internal_object(obj_desc->reference.handle,
+						NULL);
+		break;
+
+	case ACPI_TYPE_PROCESSOR:
+
+		acpi_os_printf("[Processor]\n");
+		break;
+
+	case ACPI_TYPE_POWER:
+
+		acpi_os_printf("[Power Resource]\n");
+		break;
+
+	default:
+
+		acpi_os_printf("[Unknown Type] %X\n", obj_desc->type);
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_prep_namestring
+ *
+ * PARAMETERS:  name            - String to prepare
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Translate all forward slashes and dots to backslashes.
+ *
+ ******************************************************************************/
+
+void acpi_db_prep_namestring(char *name)
+{
+
+	if (!name) {
+		return;
+	}
+
+	acpi_ut_strupr(name);
+
+	/* Convert a leading forward slash to a backslash */
+
+	if (*name == '/') {
+		*name = '\\';
+	}
+
+	/* Ignore a leading backslash, this is the root prefix */
+
+	if (ACPI_IS_ROOT_PREFIX(*name)) {
+		name++;
+	}
+
+	/* Convert all slash path separators to dots */
+
+	while (*name) {
+		if ((*name == '/') || (*name == '\\')) {
+			*name = '.';
+		}
+
+		name++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_local_ns_lookup
+ *
+ * PARAMETERS:  name            - Name to lookup
+ *
+ * RETURN:      Pointer to a namespace node, null on failure
+ *
+ * DESCRIPTION: Lookup a name in the ACPI namespace
+ *
+ * Note: Currently begins search from the root. Could be enhanced to use
+ * the current prefix (scope) node as the search beginning point.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name)
+{
+	char *internal_path;
+	acpi_status status;
+	struct acpi_namespace_node *node = NULL;
+
+	acpi_db_prep_namestring(name);
+
+	/* Build an internal namestring */
+
+	status = acpi_ns_internalize_name(name, &internal_path);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Invalid namestring: %s\n", name);
+		return (NULL);
+	}
+
+	/*
+	 * Lookup the name.
+	 * (Uses root node as the search starting point)
+	 */
+	status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
+				ACPI_IMODE_EXECUTE,
+				ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE,
+				NULL, &node);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not locate name: %s, %s\n",
+			       name, acpi_format_exception(status));
+	}
+
+	ACPI_FREE(internal_path);
+	return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_uint32_to_hex_string
+ *
+ * PARAMETERS:  value           - The value to be converted to string
+ *              buffer          - Buffer for result (not less than 11 bytes)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image
+ *
+ * NOTE: It is the caller's responsibility to ensure that the length of buffer
+ *       is sufficient.
+ *
+ ******************************************************************************/
+
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer)
+{
+	int i;
+
+	if (value == 0) {
+		strcpy(buffer, "0");
+		return;
+	}
+
+	buffer[8] = '\0';
+
+	for (i = 7; i >= 0; i--) {
+		buffer[i] = gbl_hex_to_ascii[value & 0x0F];
+		value = value >> 4;
+	}
+}
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_second_pass_parse
+ *
+ * PARAMETERS:  root            - Root of the parse tree
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until
+ *              second pass to parse the control methods
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root)
+{
+	union acpi_parse_object *op = root;
+	union acpi_parse_object *method;
+	union acpi_parse_object *search_op;
+	union acpi_parse_object *start_op;
+	acpi_status status = AE_OK;
+	u32 base_aml_offset;
+	struct acpi_walk_state *walk_state;
+
+	ACPI_FUNCTION_ENTRY();
+
+	acpi_os_printf("Pass two parse ....\n");
+
+	while (op) {
+		if (op->common.aml_opcode == AML_METHOD_OP) {
+			method = op;
+
+			/* Create a new walk state for the parse */
+
+			walk_state =
+			    acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+			if (!walk_state) {
+				return (AE_NO_MEMORY);
+			}
+
+			/* Init the Walk State */
+
+			walk_state->parser_state.aml =
+			    walk_state->parser_state.aml_start =
+			    method->named.data;
+			walk_state->parser_state.aml_end =
+			    walk_state->parser_state.pkg_end =
+			    method->named.data + method->named.length;
+			walk_state->parser_state.start_scope = op;
+
+			walk_state->descending_callback =
+			    acpi_ds_load1_begin_op;
+			walk_state->ascending_callback = acpi_ds_load1_end_op;
+
+			/* Perform the AML parse */
+
+			status = acpi_ps_parse_aml(walk_state);
+
+			base_aml_offset =
+			    (method->common.value.arg)->common.aml_offset + 1;
+			start_op = (method->common.value.arg)->common.next;
+			search_op = start_op;
+
+			while (search_op) {
+				search_op->common.aml_offset += base_aml_offset;
+				search_op =
+				    acpi_ps_get_depth_next(start_op, search_op);
+			}
+		}
+
+		if (op->common.aml_opcode == AML_REGION_OP) {
+
+			/* TBD: [Investigate] this isn't quite the right thing to do! */
+			/*
+			 *
+			 * Method = (ACPI_DEFERRED_OP *) Op;
+			 * Status = acpi_ps_parse_aml (Op, Method->Body, Method->body_length);
+			 */
+		}
+
+		if (ACPI_FAILURE(status)) {
+			break;
+		}
+
+		op = acpi_ps_get_depth_next(root, op);
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_buffer
+ *
+ * PARAMETERS:  address             - Pointer to the buffer
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print a portion of a buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_buffer(u32 address)
+{
+
+	acpi_os_printf("\nLocation %X:\n", address);
+
+	acpi_dbg_level |= ACPI_LV_TABLES;
+	acpi_ut_debug_dump_buffer(ACPI_TO_POINTER(address), 64, DB_BYTE_DISPLAY,
+				  ACPI_UINT32_MAX);
+}
+#endif
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
new file mode 100644
index 0000000..26023bd
--- /dev/null
+++ b/drivers/acpi/acpica/dbxface.c
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ *
+ * Module Name: dbxface - AML Debugger external interfaces
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbxface")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+		      union acpi_parse_object *op);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+void acpi_db_method_end(struct acpi_walk_state *walk_state);
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_start_command
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing Op, from AML interpreter
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enter debugger command loop
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+		      union acpi_parse_object *op)
+{
+	acpi_status status;
+
+	/* TBD: [Investigate] are there namespace locking issues here? */
+
+	/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
+
+	/* Go into the command loop and await next user command */
+
+	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 */
+
+			acpi_os_release_mutex(acpi_gbl_db_command_complete);
+
+			status =
+			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
+						  ACPI_WAIT_FOREVER);
+			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);
+			}
+
+			/* Get the user input line */
+
+			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);
+			}
+		}
+
+		status =
+		    acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
+					     op);
+	}
+
+	/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_single_step
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing op (from aml interpreter)
+ *              opcode_class    - Class of the current AML Opcode
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Called just before execution of an AML opcode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_single_step(struct acpi_walk_state * walk_state,
+		    union acpi_parse_object * op, u32 opcode_class)
+{
+	union acpi_parse_object *next;
+	acpi_status status = AE_OK;
+	u32 original_debug_level;
+	union acpi_parse_object *display_op;
+	union acpi_parse_object *parent_op;
+	u32 aml_offset;
+
+	ACPI_FUNCTION_ENTRY();
+
+	/* Check the abort flag */
+
+	if (acpi_gbl_abort_method) {
+		acpi_gbl_abort_method = FALSE;
+		return (AE_ABORT_METHOD);
+	}
+
+	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+					walk_state->parser_state.aml_start);
+
+	/* Check for single-step breakpoint */
+
+	if (walk_state->method_breakpoint &&
+	    (walk_state->method_breakpoint <= aml_offset)) {
+
+		/* Check if the breakpoint has been reached or passed */
+		/* Hit the breakpoint, resume single step, reset breakpoint */
+
+		acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_gbl_step_to_next_call = FALSE;
+		walk_state->method_breakpoint = 0;
+	}
+
+	/* Check for user breakpoint (Must be on exact Aml offset) */
+
+	else if (walk_state->user_breakpoint &&
+		 (walk_state->user_breakpoint == aml_offset)) {
+		acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
+			       aml_offset);
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_gbl_step_to_next_call = FALSE;
+		walk_state->method_breakpoint = 0;
+	}
+
+	/*
+	 * Check if this is an opcode that we are interested in --
+	 * namely, opcodes that have arguments
+	 */
+	if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+		return (AE_OK);
+	}
+
+	switch (opcode_class) {
+	case AML_CLASS_UNKNOWN:
+	case AML_CLASS_ARGUMENT:	/* constants, literals, etc. do nothing */
+
+		return (AE_OK);
+
+	default:
+
+		/* All other opcodes -- continue */
+		break;
+	}
+
+	/*
+	 * Under certain debug conditions, display this opcode and its operands
+	 */
+	if ((acpi_gbl_db_output_to_file) ||
+	    (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
+		if ((acpi_gbl_db_output_to_file) ||
+		    (acpi_dbg_level & ACPI_LV_PARSE)) {
+			acpi_os_printf
+			    ("\n[AmlDebug] Next AML Opcode to execute:\n");
+		}
+
+		/*
+		 * Display this op (and only this op - zero out the NEXT field
+		 * temporarily, and disable parser trace output for the duration of
+		 * the display because we don't want the extraneous debug output)
+		 */
+		original_debug_level = acpi_dbg_level;
+		acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
+		next = op->common.next;
+		op->common.next = NULL;
+
+		display_op = op;
+		parent_op = op->common.parent;
+		if (parent_op) {
+			if ((walk_state->control_state) &&
+			    (walk_state->control_state->common.state ==
+			     ACPI_CONTROL_PREDICATE_EXECUTING)) {
+				/*
+				 * We are executing the predicate of an IF or WHILE statement
+				 * Search upwards for the containing IF or WHILE so that the
+				 * entire predicate can be displayed.
+				 */
+				while (parent_op) {
+					if ((parent_op->common.aml_opcode ==
+					     AML_IF_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_WHILE_OP)) {
+						display_op = parent_op;
+						break;
+					}
+					parent_op = parent_op->common.parent;
+				}
+			} else {
+				while (parent_op) {
+					if ((parent_op->common.aml_opcode ==
+					     AML_IF_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_ELSE_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_SCOPE_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_METHOD_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_WHILE_OP)) {
+						break;
+					}
+					display_op = parent_op;
+					parent_op = parent_op->common.parent;
+				}
+			}
+		}
+
+		/* Now we can display it */
+
+#ifdef ACPI_DISASSEMBLER
+		acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
+#endif
+
+		if ((op->common.aml_opcode == AML_IF_OP) ||
+		    (op->common.aml_opcode == AML_WHILE_OP)) {
+			if (walk_state->control_state->common.value) {
+				acpi_os_printf
+				    ("Predicate = [True], IF block was executed\n");
+			} else {
+				acpi_os_printf
+				    ("Predicate = [False], Skipping IF block\n");
+			}
+		} else if (op->common.aml_opcode == AML_ELSE_OP) {
+			acpi_os_printf
+			    ("Predicate = [False], ELSE block was executed\n");
+		}
+
+		/* Restore everything */
+
+		op->common.next = next;
+		acpi_os_printf("\n");
+		if ((acpi_gbl_db_output_to_file) ||
+		    (acpi_dbg_level & ACPI_LV_PARSE)) {
+			acpi_os_printf("\n");
+		}
+		acpi_dbg_level = original_debug_level;
+	}
+
+	/* If we are not single stepping, just continue executing the method */
+
+	if (!acpi_gbl_cm_single_step) {
+		return (AE_OK);
+	}
+
+	/*
+	 * If we are executing a step-to-call command,
+	 * Check if this is a method call.
+	 */
+	if (acpi_gbl_step_to_next_call) {
+		if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
+
+			/* Not a method call, just keep executing */
+
+			return (AE_OK);
+		}
+
+		/* Found a method call, stop executing */
+
+		acpi_gbl_step_to_next_call = FALSE;
+	}
+
+	/*
+	 * If the next opcode is a method call, we will "step over" it
+	 * by default.
+	 */
+	if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
+
+		/* Force no more single stepping while executing called method */
+
+		acpi_gbl_cm_single_step = FALSE;
+
+		/*
+		 * Set the breakpoint on/before the call, it will stop execution
+		 * as soon as we return
+		 */
+		walk_state->method_breakpoint = 1;	/* Must be non-zero! */
+	}
+
+	status = acpi_db_start_command(walk_state, op);
+
+	/* User commands complete, continue execution of the interrupted method */
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_initialize_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Init and start debugger
+ *
+ ******************************************************************************/
+
+acpi_status acpi_initialize_debugger(void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
+
+	/* Init globals */
+
+	acpi_gbl_db_buffer = NULL;
+	acpi_gbl_db_filename = NULL;
+	acpi_gbl_db_output_to_file = FALSE;
+
+	acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
+	acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
+	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
+
+	acpi_gbl_db_opt_no_ini_methods = FALSE;
+
+	acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
+	if (!acpi_gbl_db_buffer) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+	memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
+
+	/* Initial scope is the root */
+
+	acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
+	acpi_gbl_db_scope_buf[1] = 0;
+	acpi_gbl_db_scope_node = acpi_gbl_root_node;
+
+	/*
+	 * If configured for multi-thread support, the debug executor runs in
+	 * a separate thread so that the front end can be in another address
+	 * space, environment, or even another machine.
+	 */
+	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
+
+		/* 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);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not get debugger mutex\n");
+			return_ACPI_STATUS(status);
+		}
+
+		/* Create the debug execution thread to execute commands */
+
+		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
+					 acpi_db_execute_thread, NULL);
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Could not start debugger thread"));
+			return_ACPI_STATUS(status);
+		}
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_terminate_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Stop debugger
+ *
+ ******************************************************************************/
+void acpi_terminate_debugger(void)
+{
+
+	if (acpi_gbl_db_buffer) {
+		acpi_os_free(acpi_gbl_db_buffer);
+		acpi_gbl_db_buffer = NULL;
+	}
+
+	/* Ensure that debug output is now disabled */
+
+	acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 08/14] ACPICA: Linuxize: Export debugger files to Linux
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit bc2d3daa4bd429611451f28800def9fea55e63de

This patch exports debugger files to Linux.

Link: https://github.com/acpica/acpica/commit/bc2d3daa
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbcmds.c    | 1187 ++++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbconvert.c |  484 +++++++++++++++
 drivers/acpi/acpica/dbdisply.c  | 1108 ++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbexec.c    |  753 +++++++++++++++++++++++
 drivers/acpi/acpica/dbfileio.c  |  256 ++++++++
 drivers/acpi/acpica/dbhistry.c  |  239 ++++++++
 drivers/acpi/acpica/dbinput.c   | 1274 +++++++++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbmethod.c  |  369 ++++++++++++
 drivers/acpi/acpica/dbnames.c   |  947 +++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbobject.c  |  533 ++++++++++++++++
 drivers/acpi/acpica/dbstats.c   |  546 +++++++++++++++++
 drivers/acpi/acpica/dbtest.c    | 1057 ++++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dbutils.c   |  457 ++++++++++++++
 drivers/acpi/acpica/dbxface.c   |  467 ++++++++++++++
 14 files changed, 9677 insertions(+)
 create mode 100644 drivers/acpi/acpica/dbcmds.c
 create mode 100644 drivers/acpi/acpica/dbconvert.c
 create mode 100644 drivers/acpi/acpica/dbdisply.c
 create mode 100644 drivers/acpi/acpica/dbexec.c
 create mode 100644 drivers/acpi/acpica/dbfileio.c
 create mode 100644 drivers/acpi/acpica/dbhistry.c
 create mode 100644 drivers/acpi/acpica/dbinput.c
 create mode 100644 drivers/acpi/acpica/dbmethod.c
 create mode 100644 drivers/acpi/acpica/dbnames.c
 create mode 100644 drivers/acpi/acpica/dbobject.c
 create mode 100644 drivers/acpi/acpica/dbstats.c
 create mode 100644 drivers/acpi/acpica/dbtest.c
 create mode 100644 drivers/acpi/acpica/dbutils.c
 create mode 100644 drivers/acpi/acpica/dbxface.c

diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c
new file mode 100644
index 0000000..30414b3
--- /dev/null
+++ b/drivers/acpi/acpica/dbcmds.c
@@ -0,0 +1,1187 @@
+/*******************************************************************************
+ *
+ * Module Name: dbcmds - Miscellaneous debug commands and output routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acresrc.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbcmds")
+
+/* Local prototypes */
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+			      acpi_rsdesc_size aml1_buffer_length,
+			      u8 *aml2_buffer,
+			      acpi_rsdesc_size aml2_buffer_length);
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name);
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context);
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+			 u32 nesting_level, void *context, void **return_value);
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state);
+
+static char *acpi_db_trace_method_name = NULL;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_node
+ *
+ * PARAMETERS:  in_string           - String to convert
+ *
+ * RETURN:      Pointer to a NS node
+ *
+ * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or
+ *              alphanumeric strings.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string)
+{
+	struct acpi_namespace_node *node;
+	acpi_size address;
+
+	if ((*in_string >= 0x30) && (*in_string <= 0x39)) {
+
+		/* Numeric argument, convert */
+
+		address = strtoul(in_string, NULL, 16);
+		node = ACPI_TO_POINTER(address);
+		if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+			acpi_os_printf("Address %p is invalid", node);
+			return (NULL);
+		}
+
+		/* Make sure pointer is valid NS node */
+
+		if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+			acpi_os_printf
+			    ("Address %p is not a valid namespace node [%s]\n",
+			     node, acpi_ut_get_descriptor_name(node));
+			return (NULL);
+		}
+	} else {
+		/*
+		 * Alpha argument: The parameter is a name string that must be
+		 * resolved to a Namespace object.
+		 */
+		node = acpi_db_local_ns_lookup(in_string);
+		if (!node) {
+			acpi_os_printf
+			    ("Could not find [%s] in namespace, defaulting to root node\n",
+			     in_string);
+			node = acpi_gbl_root_node;
+		}
+	}
+
+	return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_sleep
+ *
+ * PARAMETERS:  object_arg          - Desired sleep state (0-5). NULL means
+ *                                    invoke all possible sleep states.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simulate sleep/wake sequences
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_sleep(char *object_arg)
+{
+	u8 sleep_state;
+	u32 i;
+
+	ACPI_FUNCTION_TRACE(acpi_db_sleep);
+
+	/* Null input (no arguments) means to invoke all sleep states */
+
+	if (!object_arg) {
+		acpi_os_printf("Invoking all possible sleep states, 0-%d\n",
+			       ACPI_S_STATES_MAX);
+
+		for (i = 0; i <= ACPI_S_STATES_MAX; i++) {
+			acpi_db_do_one_sleep_state((u8)i);
+		}
+
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* Convert argument to binary and invoke the sleep state */
+
+	sleep_state = (u8)strtoul(object_arg, NULL, 0);
+	acpi_db_do_one_sleep_state(sleep_state);
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_do_one_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Desired sleep state (0-5)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate a sleep/wake sequence
+ *
+ ******************************************************************************/
+
+static void acpi_db_do_one_sleep_state(u8 sleep_state)
+{
+	acpi_status status;
+	u8 sleep_type_a;
+	u8 sleep_type_b;
+
+	/* Validate parameter */
+
+	if (sleep_state > ACPI_S_STATES_MAX) {
+		acpi_os_printf("Sleep state %d out of range (%d max)\n",
+			       sleep_state, ACPI_S_STATES_MAX);
+		return;
+	}
+
+	acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n",
+		       sleep_state, acpi_gbl_sleep_state_names[sleep_state]);
+
+	/* Get the values for the sleep type registers (for display only) */
+
+	status =
+	    acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not evaluate [%s] method, %s\n",
+			       acpi_gbl_sleep_state_names[sleep_state],
+			       acpi_format_exception(status));
+		return;
+	}
+
+	acpi_os_printf
+	    ("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n",
+	     sleep_state, sleep_type_a, sleep_type_b);
+
+	/* Invoke the various sleep/wake interfaces */
+
+	acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_enter_sleep_state_prep(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state);
+	status = acpi_enter_sleep_state(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_leave_sleep_state_prep(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n",
+		       sleep_state);
+	status = acpi_leave_sleep_state(sleep_state);
+	if (ACPI_FAILURE(status)) {
+		goto error_exit;
+	}
+
+	return;
+
+error_exit:
+	ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d",
+			sleep_state));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locks
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about internal mutexes.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locks(void)
+{
+	u32 i;
+
+	for (i = 0; i < ACPI_MAX_MUTEX; i++) {
+		acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i),
+			       acpi_gbl_mutex_info[i].thread_id ==
+			       ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked");
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_table_info
+ *
+ * PARAMETERS:  table_arg           - Name of table to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about loaded tables. Current
+ *              implementation displays all loaded tables.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_table_info(char *table_arg)
+{
+	u32 i;
+	struct acpi_table_desc *table_desc;
+	acpi_status status;
+
+	/* Header */
+
+	acpi_os_printf("Idx ID  Status Type                    "
+		       "TableHeader (Sig, Address, Length, Misc)\n");
+
+	/* Walk the entire root table list */
+
+	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+		table_desc = &acpi_gbl_root_table_list.tables[i];
+
+		/* Index and Table ID */
+
+		acpi_os_printf("%3u %.2u ", i, table_desc->owner_id);
+
+		/* Decode the table flags */
+
+		if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) {
+			acpi_os_printf("NotLoaded ");
+		} else {
+			acpi_os_printf(" Loaded ");
+		}
+
+		switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+		case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+			acpi_os_printf("External/virtual ");
+			break;
+
+		case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+			acpi_os_printf("Internal/physical ");
+			break;
+
+		case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+
+			acpi_os_printf("Internal/virtual ");
+			break;
+
+		default:
+
+			acpi_os_printf("INVALID TYPE    ");
+			break;
+		}
+
+		/* Make sure that the table is mapped */
+
+		status = acpi_tb_validate_table(table_desc);
+		if (ACPI_FAILURE(status)) {
+			return;
+		}
+
+		/* Dump the table header */
+
+		if (table_desc->pointer) {
+			acpi_tb_print_table_header(table_desc->address,
+						   table_desc->pointer);
+		} else {
+			/* If the pointer is null, the table has been unloaded */
+
+			ACPI_INFO((AE_INFO, "%4.4s - Table has been unloaded",
+				   table_desc->signature.ascii));
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_unload_acpi_table
+ *
+ * PARAMETERS:  object_name         - Namespace pathname for an object that
+ *                                    is owned by the table to be unloaded
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned
+ *              by the table.
+ *
+ ******************************************************************************/
+
+void acpi_db_unload_acpi_table(char *object_name)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	/* Translate name to an Named object */
+
+	node = acpi_db_convert_to_node(object_name);
+	if (!node) {
+		return;
+	}
+
+	status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node));
+	if (ACPI_SUCCESS(status)) {
+		acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n",
+			       object_name, node);
+	} else {
+		acpi_os_printf("%s, while unloading parent table of [%s]\n",
+			       acpi_format_exception(status), object_name);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_send_notify
+ *
+ * PARAMETERS:  name                - Name of ACPI object where to send notify
+ *              value               - Value of the notify to send.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Send an ACPI notification. The value specified is sent to the
+ *              named object as an ACPI notify.
+ *
+ ******************************************************************************/
+
+void acpi_db_send_notify(char *name, u32 value)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	/* Translate name to an Named object */
+
+	node = acpi_db_convert_to_node(name);
+	if (!node) {
+		return;
+	}
+
+	/* Dispatch the notify if legal */
+
+	if (acpi_ev_is_notify_object(node)) {
+		status = acpi_ev_queue_notify_request(node, value);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not queue notify\n");
+		}
+	} else {
+		acpi_os_printf("Named object [%4.4s] Type %s, "
+			       "must be Device/Thermal/Processor type\n",
+			       acpi_ut_get_node_name(node),
+			       acpi_ut_get_type_name(node->type));
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_interfaces
+ *
+ * PARAMETERS:  action_arg          - Null, "install", or "remove"
+ *              interface_name_arg  - Name for install/remove options
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display or modify the global _OSI interface list
+ *
+ ******************************************************************************/
+
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg)
+{
+	struct acpi_interface_info *next_interface;
+	char *sub_string;
+	acpi_status status;
+
+	/* If no arguments, just display current interface list */
+
+	if (!action_arg) {
+		(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex,
+					    ACPI_WAIT_FOREVER);
+
+		next_interface = acpi_gbl_supported_interfaces;
+		while (next_interface) {
+			if (!(next_interface->flags & ACPI_OSI_INVALID)) {
+				acpi_os_printf("%s\n", next_interface->name);
+			}
+
+			next_interface = next_interface->next;
+		}
+
+		acpi_os_release_mutex(acpi_gbl_osi_mutex);
+		return;
+	}
+
+	/* If action_arg exists, so must interface_name_arg */
+
+	if (!interface_name_arg) {
+		acpi_os_printf("Missing Interface Name argument\n");
+		return;
+	}
+
+	/* Uppercase the action for match below */
+
+	acpi_ut_strupr(action_arg);
+
+	/* install - install an interface */
+
+	sub_string = strstr("INSTALL", action_arg);
+	if (sub_string) {
+		status = acpi_install_interface(interface_name_arg);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("%s, while installing \"%s\"\n",
+				       acpi_format_exception(status),
+				       interface_name_arg);
+		}
+		return;
+	}
+
+	/* remove - remove an interface */
+
+	sub_string = strstr("REMOVE", action_arg);
+	if (sub_string) {
+		status = acpi_remove_interface(interface_name_arg);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("%s, while removing \"%s\"\n",
+				       acpi_format_exception(status),
+				       interface_name_arg);
+		}
+		return;
+	}
+
+	/* Invalid action_arg */
+
+	acpi_os_printf("Invalid action argument: %s\n", action_arg);
+	return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_template
+ *
+ * PARAMETERS:  buffer_arg          - Buffer name or address
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump a buffer that contains a resource template
+ *
+ ******************************************************************************/
+
+void acpi_db_display_template(char *buffer_arg)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+	struct acpi_buffer return_buffer;
+
+	/* Translate buffer_arg to an Named object */
+
+	node = acpi_db_convert_to_node(buffer_arg);
+	if (!node || (node == acpi_gbl_root_node)) {
+		acpi_os_printf("Invalid argument: %s\n", buffer_arg);
+		return;
+	}
+
+	/* We must have a buffer object */
+
+	if (node->type != ACPI_TYPE_BUFFER) {
+		acpi_os_printf
+		    ("Not a Buffer object, cannot be a template: %s\n",
+		     buffer_arg);
+		return;
+	}
+
+	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+	return_buffer.pointer = acpi_gbl_db_buffer;
+
+	/* Attempt to convert the raw buffer to a resource list */
+
+	status = acpi_rs_create_resource_list(node->object, &return_buffer);
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf
+		    ("Could not convert Buffer to a resource list: %s, %s\n",
+		     buffer_arg, acpi_format_exception(status));
+		goto dump_buffer;
+	}
+
+	/* Now we can dump the resource list */
+
+	acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+						 return_buffer.pointer));
+
+dump_buffer:
+	acpi_os_printf("\nRaw data buffer:\n");
+	acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer,
+				  node->object->buffer.length,
+				  DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_compare_aml_resources
+ *
+ * PARAMETERS:  aml1_buffer         - Contains first resource list
+ *              aml1_buffer_length  - Length of first resource list
+ *              aml2_buffer         - Contains second resource list
+ *              aml2_buffer_length  - Length of second resource list
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in
+ *              order to isolate a miscompare to an individual resource)
+ *
+ ******************************************************************************/
+
+static void
+acpi_dm_compare_aml_resources(u8 *aml1_buffer,
+			      acpi_rsdesc_size aml1_buffer_length,
+			      u8 *aml2_buffer,
+			      acpi_rsdesc_size aml2_buffer_length)
+{
+	u8 *aml1;
+	u8 *aml2;
+	u8 *aml1_end;
+	u8 *aml2_end;
+	acpi_rsdesc_size aml1_length;
+	acpi_rsdesc_size aml2_length;
+	acpi_rsdesc_size offset = 0;
+	u8 resource_type;
+	u32 count = 0;
+	u32 i;
+
+	/* Compare overall buffer sizes (may be different due to size rounding) */
+
+	if (aml1_buffer_length != aml2_buffer_length) {
+		acpi_os_printf("**** Buffer length mismatch in converted "
+			       "AML: Original %X, New %X ****\n",
+			       aml1_buffer_length, aml2_buffer_length);
+	}
+
+	aml1 = aml1_buffer;
+	aml2 = aml2_buffer;
+	aml1_end = aml1_buffer + aml1_buffer_length;
+	aml2_end = aml2_buffer + aml2_buffer_length;
+
+	/* Walk the descriptor lists, comparing each descriptor */
+
+	while ((aml1 < aml1_end) && (aml2 < aml2_end)) {
+
+		/* Get the lengths of each descriptor */
+
+		aml1_length = acpi_ut_get_descriptor_length(aml1);
+		aml2_length = acpi_ut_get_descriptor_length(aml2);
+		resource_type = acpi_ut_get_resource_type(aml1);
+
+		/* Check for descriptor length match */
+
+		if (aml1_length != aml2_length) {
+			acpi_os_printf
+			    ("**** Length mismatch in descriptor [%.2X] type %2.2X, "
+			     "Offset %8.8X Len1 %X, Len2 %X ****\n", count,
+			     resource_type, offset, aml1_length, aml2_length);
+		}
+
+		/* Check for descriptor byte match */
+
+		else if (memcmp(aml1, aml2, aml1_length)) {
+			acpi_os_printf
+			    ("**** Data mismatch in descriptor [%.2X] type %2.2X, "
+			     "Offset %8.8X ****\n", count, resource_type,
+			     offset);
+
+			for (i = 0; i < aml1_length; i++) {
+				if (aml1[i] != aml2[i]) {
+					acpi_os_printf
+					    ("Mismatch at byte offset %.2X: is %2.2X, "
+					     "should be %2.2X\n", i, aml2[i],
+					     aml1[i]);
+				}
+			}
+		}
+
+		/* Exit on end_tag descriptor */
+
+		if (resource_type == ACPI_RESOURCE_NAME_END_TAG) {
+			return;
+		}
+
+		/* Point to next descriptor in each buffer */
+
+		count++;
+		offset += aml1_length;
+		aml1 += aml1_length;
+		aml2 += aml2_length;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_dm_test_resource_conversion
+ *
+ * PARAMETERS:  node                - Parent device node
+ *              name                - resource method name (_CRS)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Compare the original AML with a conversion of the AML to
+ *              internal resource list, then back to AML.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name)
+{
+	acpi_status status;
+	struct acpi_buffer return_buffer;
+	struct acpi_buffer resource_buffer;
+	struct acpi_buffer new_aml;
+	union acpi_object *original_aml;
+
+	acpi_os_printf("Resource Conversion Comparison:\n");
+
+	new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+	/* Get the original _CRS AML resource template */
+
+	status = acpi_evaluate_object(node, name, NULL, &return_buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not obtain %s: %s\n",
+			       name, acpi_format_exception(status));
+		return (status);
+	}
+
+	/* Get the AML resource template, converted to internal resource structs */
+
+	status = acpi_get_current_resources(node, &resource_buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+			       acpi_format_exception(status));
+		goto exit1;
+	}
+
+	/* Convert internal resource list to external AML resource template */
+
+	status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n",
+			       acpi_format_exception(status));
+		goto exit2;
+	}
+
+	/* Compare original AML to the newly created AML resource list */
+
+	original_aml = return_buffer.pointer;
+
+	acpi_dm_compare_aml_resources(original_aml->buffer.pointer,
+				      (acpi_rsdesc_size) original_aml->buffer.
+				      length, new_aml.pointer,
+				      (acpi_rsdesc_size) new_aml.length);
+
+	/* Cleanup and exit */
+
+	ACPI_FREE(new_aml.pointer);
+exit2:
+	ACPI_FREE(resource_buffer.pointer);
+exit1:
+	ACPI_FREE(return_buffer.pointer);
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_resource_callback
+ *
+ * PARAMETERS:  acpi_walk_resource_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Simple callback to exercise acpi_walk_resources and
+ *              acpi_walk_resource_buffer.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_resource_callback(struct acpi_resource *resource, void *context)
+{
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_device_resources
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_device_resources(acpi_handle obj_handle,
+			 u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	struct acpi_namespace_node *prt_node = NULL;
+	struct acpi_namespace_node *crs_node = NULL;
+	struct acpi_namespace_node *prs_node = NULL;
+	struct acpi_namespace_node *aei_node = NULL;
+	char *parent_path;
+	struct acpi_buffer return_buffer;
+	acpi_status status;
+
+	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	parent_path = acpi_ns_get_external_pathname(node);
+	if (!parent_path) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Get handles to the resource methods for this device */
+
+	(void)acpi_get_handle(node, METHOD_NAME__PRT,
+			      ACPI_CAST_PTR(acpi_handle, &prt_node));
+	(void)acpi_get_handle(node, METHOD_NAME__CRS,
+			      ACPI_CAST_PTR(acpi_handle, &crs_node));
+	(void)acpi_get_handle(node, METHOD_NAME__PRS,
+			      ACPI_CAST_PTR(acpi_handle, &prs_node));
+	(void)acpi_get_handle(node, METHOD_NAME__AEI,
+			      ACPI_CAST_PTR(acpi_handle, &aei_node));
+
+	if (!prt_node && !crs_node && !prs_node && !aei_node) {
+		goto cleanup;	/* Nothing to do */
+	}
+
+	acpi_os_printf("\nDevice: %s\n", parent_path);
+
+	/* Prepare for a return object of arbitrary size */
+
+	return_buffer.pointer = acpi_gbl_db_buffer;
+	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+	/* _PRT */
+
+	if (prt_node) {
+		acpi_os_printf("Evaluating _PRT\n");
+
+		status =
+		    acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _PRT: %s\n",
+				       acpi_format_exception(status));
+			goto get_crs;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_irq_routing_table(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("GetIrqRoutingTable failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_crs;
+		}
+
+		acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer));
+	}
+
+	/* _CRS */
+
+get_crs:
+	if (crs_node) {
+		acpi_os_printf("Evaluating _CRS\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _CRS: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* This code exercises the acpi_walk_resources interface */
+
+		status = acpi_walk_resources(node, METHOD_NAME__CRS,
+					     acpi_db_resource_callback, NULL);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiWalkResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* Get the _CRS resource list (test ALLOCATE buffer) */
+
+		return_buffer.pointer = NULL;
+		return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+		status = acpi_get_current_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_prs;
+		}
+
+		/* This code exercises the acpi_walk_resource_buffer interface */
+
+		status = acpi_walk_resource_buffer(&return_buffer,
+						   acpi_db_resource_callback,
+						   NULL);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n",
+				       acpi_format_exception(status));
+			goto end_crs;
+		}
+
+		/* Dump the _CRS resource list */
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
+							 return_buffer.
+							 pointer));
+
+		/*
+		 * Perform comparison of original AML to newly created AML. This
+		 * tests both the AML->Resource conversion and the Resource->AML
+		 * conversion.
+		 */
+		(void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS);
+
+		/* Execute _SRS with the resource list */
+
+		acpi_os_printf("Evaluating _SRS\n");
+
+		status = acpi_set_current_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiSetCurrentResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto end_crs;
+		}
+
+end_crs:
+		ACPI_FREE(return_buffer.pointer);
+	}
+
+	/* _PRS */
+
+get_prs:
+	if (prs_node) {
+		acpi_os_printf("Evaluating _PRS\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _PRS: %s\n",
+				       acpi_format_exception(status));
+			goto get_aei;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_possible_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetPossibleResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto get_aei;
+		}
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR
+					   (struct acpi_resource,
+					    acpi_gbl_db_buffer));
+	}
+
+	/* _AEI */
+
+get_aei:
+	if (aei_node) {
+		acpi_os_printf("Evaluating _AEI\n");
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status =
+		    acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not evaluate _AEI: %s\n",
+				       acpi_format_exception(status));
+			goto cleanup;
+		}
+
+		return_buffer.pointer = acpi_gbl_db_buffer;
+		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
+
+		status = acpi_get_event_resources(node, &return_buffer);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiGetEventResources failed: %s\n",
+				       acpi_format_exception(status));
+			goto cleanup;
+		}
+
+		acpi_rs_dump_resource_list(ACPI_CAST_PTR
+					   (struct acpi_resource,
+					    acpi_gbl_db_buffer));
+	}
+
+cleanup:
+	ACPI_FREE(parent_path);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_resources
+ *
+ * PARAMETERS:  object_arg          - String object name or object pointer.
+ *                                    NULL or "*" means "display resources for
+ *                                    all devices"
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the resource objects associated with a device.
+ *
+ ******************************************************************************/
+
+void acpi_db_display_resources(char *object_arg)
+{
+	struct acpi_namespace_node *node;
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_dbg_level |= ACPI_LV_RESOURCES;
+
+	/* Asterisk means "display resources for all devices" */
+
+	if (!object_arg || (!strcmp(object_arg, "*"))) {
+		(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_device_resources, NULL, NULL,
+					  NULL);
+	} else {
+		/* Convert string to object pointer */
+
+		node = acpi_db_convert_to_node(object_arg);
+		if (node) {
+			if (node->type != ACPI_TYPE_DEVICE) {
+				acpi_os_printf
+				    ("%4.4s: Name is not a device object (%s)\n",
+				     node->name.ascii,
+				     acpi_ut_get_type_name(node->type));
+			} else {
+				(void)acpi_db_device_resources(node, 0, NULL,
+							       NULL);
+			}
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_gpe
+ *
+ * PARAMETERS:  gpe_arg             - Raw GPE number, ascii string
+ *              block_arg           - GPE block number, ascii string
+ *                                    0 or 1 for FADT GPE blocks
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate firing of a GPE
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
+{
+	u32 block_number = 0;
+	u32 gpe_number;
+	struct acpi_gpe_event_info *gpe_event_info;
+
+	gpe_number = strtoul(gpe_arg, NULL, 0);
+
+	/*
+	 * If no block arg, or block arg == 0 or 1, use the FADT-defined
+	 * GPE blocks.
+	 */
+	if (block_arg) {
+		block_number = strtoul(block_arg, NULL, 0);
+		if (block_number == 1) {
+			block_number = 0;
+		}
+	}
+
+	gpe_event_info =
+	    acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
+				       gpe_number);
+	if (!gpe_event_info) {
+		acpi_os_printf("Invalid GPE\n");
+		return;
+	}
+
+	(void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_generate_sci
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch.
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_sci(void)
+{
+	acpi_ev_sci_dispatch();
+}
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_trace
+ *
+ * PARAMETERS:  enable_arg          - ENABLE/AML to enable tracer
+ *                                    DISABLE to disable tracer
+ *              method_arg          - Method to trace
+ *              once_arg            - Whether trace once
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Control method tracing facility
+ *
+ ******************************************************************************/
+
+void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg)
+{
+	u32 debug_level = 0;
+	u32 debug_layer = 0;
+	u32 flags = 0;
+
+	if (enable_arg) {
+		acpi_ut_strupr(enable_arg);
+	}
+
+	if (once_arg) {
+		acpi_ut_strupr(once_arg);
+	}
+
+	if (method_arg) {
+		if (acpi_db_trace_method_name) {
+			ACPI_FREE(acpi_db_trace_method_name);
+			acpi_db_trace_method_name = NULL;
+		}
+
+		acpi_db_trace_method_name =
+		    ACPI_ALLOCATE(strlen(method_arg) + 1);
+		if (!acpi_db_trace_method_name) {
+			acpi_os_printf("Failed to allocate method name (%s)\n",
+				       method_arg);
+			return;
+		}
+
+		strcpy(acpi_db_trace_method_name, method_arg);
+	}
+
+	if (!strcmp(enable_arg, "ENABLE") ||
+	    !strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) {
+		if (!strcmp(enable_arg, "ENABLE")) {
+
+			/* Inherit current console settings */
+
+			debug_level = acpi_gbl_db_console_debug_level;
+			debug_layer = acpi_dbg_layer;
+		} else {
+			/* Restrict console output to trace points only */
+
+			debug_level = ACPI_LV_TRACE_POINT;
+			debug_layer = ACPI_EXECUTER;
+		}
+
+		flags = ACPI_TRACE_ENABLED;
+
+		if (!strcmp(enable_arg, "OPCODE")) {
+			flags |= ACPI_TRACE_OPCODE;
+		}
+
+		if (once_arg && !strcmp(once_arg, "ONCE")) {
+			flags |= ACPI_TRACE_ONESHOT;
+		}
+	}
+
+	(void)acpi_debug_trace(acpi_db_trace_method_name,
+			       debug_level, debug_layer, flags);
+}
diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
new file mode 100644
index 0000000..a71632c
--- /dev/null
+++ b/drivers/acpi/acpica/dbconvert.c
@@ -0,0 +1,484 @@
+/*******************************************************************************
+ *
+ * Module Name: dbconvert - debugger miscellaneous conversion routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbconvert")
+
+#define DB_DEFAULT_PKG_ELEMENTS     33
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_char_to_value
+ *
+ * PARAMETERS:  hex_char            - Ascii Hex digit, 0-9|a-f|A-F
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16).
+ *
+ ******************************************************************************/
+acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value)
+{
+	u8 value;
+
+	/* Digit must be ascii [0-9a-fA-F] */
+
+	if (!isxdigit(hex_char)) {
+		return (AE_BAD_HEX_CONSTANT);
+	}
+
+	if (hex_char <= 0x39) {
+		value = (u8)(hex_char - 0x30);
+	} else {
+		value = (u8)(toupper(hex_char) - 0x37);
+	}
+
+	*return_value = value;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_hex_byte_to_binary
+ *
+ * PARAMETERS:  hex_byte            - Double hex digit (0x00 - 0xFF) in format:
+ *                                    hi_byte then lo_byte.
+ *              return_value        - Where the converted value is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255).
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_hex_byte_to_binary(char *hex_byte, u8 *return_value)
+{
+	u8 local0;
+	u8 local1;
+	acpi_status status;
+
+	/* High byte */
+
+	status = acpi_db_hex_char_to_value(hex_byte[0], &local0);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Low byte */
+
+	status = acpi_db_hex_char_to_value(hex_byte[1], &local1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	*return_value = (u8)((local0 << 4) | local1);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_buffer
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the buffer object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a buffer object. String is treated a list
+ *              of buffer elements, each separated by a space or comma.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_convert_to_buffer(char *string, union acpi_object *object)
+{
+	u32 i;
+	u32 j;
+	u32 length;
+	u8 *buffer;
+	acpi_status status;
+
+	/* Generate the final buffer length */
+
+	for (i = 0, length = 0; string[i];) {
+		i += 2;
+		length++;
+
+		while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+			i++;
+		}
+	}
+
+	buffer = ACPI_ALLOCATE(length);
+	if (!buffer) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Convert the command line bytes to the buffer */
+
+	for (i = 0, j = 0; string[i];) {
+		status = acpi_db_hex_byte_to_binary(&string[i], &buffer[j]);
+		if (ACPI_FAILURE(status)) {
+			ACPI_FREE(buffer);
+			return (status);
+		}
+
+		j++;
+		i += 2;
+		while (string[i] && ((string[i] == ',') || (string[i] == ' '))) {
+			i++;
+		}
+	}
+
+	object->type = ACPI_TYPE_BUFFER;
+	object->buffer.pointer = buffer;
+	object->buffer.length = length;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_package
+ *
+ * PARAMETERS:  string              - Input string to be converted
+ *              object              - Where the package object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a string to a package object. Handles nested packages
+ *              via recursion with acpi_db_convert_to_object.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_convert_to_package(char *string, union acpi_object * object)
+{
+	char *this;
+	char *next;
+	u32 i;
+	acpi_object_type type;
+	union acpi_object *elements;
+	acpi_status status;
+
+	elements =
+	    ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
+				 sizeof(union acpi_object));
+
+	this = string;
+	for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
+		this = acpi_db_get_next_token(this, &next, &type);
+		if (!this) {
+			break;
+		}
+
+		/* Recursive call to convert each package element */
+
+		status = acpi_db_convert_to_object(type, this, &elements[i]);
+		if (ACPI_FAILURE(status)) {
+			acpi_db_delete_objects(i + 1, elements);
+			ACPI_FREE(elements);
+			return (status);
+		}
+
+		this = next;
+	}
+
+	object->type = ACPI_TYPE_PACKAGE;
+	object->package.count = i;
+	object->package.elements = elements;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_convert_to_object
+ *
+ * PARAMETERS:  type                - Object type as determined by parser
+ *              string              - Input string to be converted
+ *              object              - Where the new object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a typed and tokenized string to an union acpi_object. Typing:
+ *              1) String objects were surrounded by quotes.
+ *              2) Buffer objects were surrounded by parentheses.
+ *              3) Package objects were surrounded by brackets "[]".
+ *              4) All standalone tokens are treated as integers.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_convert_to_object(acpi_object_type type,
+			  char *string, union acpi_object * object)
+{
+	acpi_status status = AE_OK;
+
+	switch (type) {
+	case ACPI_TYPE_STRING:
+
+		object->type = ACPI_TYPE_STRING;
+		object->string.pointer = string;
+		object->string.length = (u32)strlen(string);
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		status = acpi_db_convert_to_buffer(string, object);
+		break;
+
+	case ACPI_TYPE_PACKAGE:
+
+		status = acpi_db_convert_to_package(string, object);
+		break;
+
+	default:
+
+		object->type = ACPI_TYPE_INTEGER;
+		status = acpi_ut_strtoul64(string, 16, &object->integer.value);
+		break;
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_encode_pld_buffer
+ *
+ * PARAMETERS:  pld_info            - _PLD buffer struct (Using local struct)
+ *
+ * RETURN:      Encode _PLD buffer suitable for return value from _PLD
+ *
+ * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros
+ *
+ ******************************************************************************/
+
+u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info)
+{
+	u32 *buffer;
+	u32 dword;
+
+	buffer = ACPI_ALLOCATE_ZEROED(ACPI_PLD_BUFFER_SIZE);
+	if (!buffer) {
+		return (NULL);
+	}
+
+	/* First 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_REVISION(&dword, pld_info->revision);
+	ACPI_PLD_SET_IGNORE_COLOR(&dword, pld_info->ignore_color);
+	ACPI_PLD_SET_RED(&dword, pld_info->red);
+	ACPI_PLD_SET_GREEN(&dword, pld_info->green);
+	ACPI_PLD_SET_BLUE(&dword, pld_info->blue);
+	ACPI_MOVE_32_TO_32(&buffer[0], &dword);
+
+	/* Second 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_WIDTH(&dword, pld_info->width);
+	ACPI_PLD_SET_HEIGHT(&dword, pld_info->height);
+	ACPI_MOVE_32_TO_32(&buffer[1], &dword);
+
+	/* Third 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_USER_VISIBLE(&dword, pld_info->user_visible);
+	ACPI_PLD_SET_DOCK(&dword, pld_info->dock);
+	ACPI_PLD_SET_LID(&dword, pld_info->lid);
+	ACPI_PLD_SET_PANEL(&dword, pld_info->panel);
+	ACPI_PLD_SET_VERTICAL(&dword, pld_info->vertical_position);
+	ACPI_PLD_SET_HORIZONTAL(&dword, pld_info->horizontal_position);
+	ACPI_PLD_SET_SHAPE(&dword, pld_info->shape);
+	ACPI_PLD_SET_ORIENTATION(&dword, pld_info->group_orientation);
+	ACPI_PLD_SET_TOKEN(&dword, pld_info->group_token);
+	ACPI_PLD_SET_POSITION(&dword, pld_info->group_position);
+	ACPI_PLD_SET_BAY(&dword, pld_info->bay);
+	ACPI_MOVE_32_TO_32(&buffer[2], &dword);
+
+	/* Fourth 32 bits */
+
+	dword = 0;
+	ACPI_PLD_SET_EJECTABLE(&dword, pld_info->ejectable);
+	ACPI_PLD_SET_OSPM_EJECT(&dword, pld_info->ospm_eject_required);
+	ACPI_PLD_SET_CABINET(&dword, pld_info->cabinet_number);
+	ACPI_PLD_SET_CARD_CAGE(&dword, pld_info->card_cage_number);
+	ACPI_PLD_SET_REFERENCE(&dword, pld_info->reference);
+	ACPI_PLD_SET_ROTATION(&dword, pld_info->rotation);
+	ACPI_PLD_SET_ORDER(&dword, pld_info->order);
+	ACPI_MOVE_32_TO_32(&buffer[3], &dword);
+
+	if (pld_info->revision >= 2) {
+
+		/* Fifth 32 bits */
+
+		dword = 0;
+		ACPI_PLD_SET_VERT_OFFSET(&dword, pld_info->vertical_offset);
+		ACPI_PLD_SET_HORIZ_OFFSET(&dword, pld_info->horizontal_offset);
+		ACPI_MOVE_32_TO_32(&buffer[4], &dword);
+	}
+
+	return (ACPI_CAST_PTR(u8, buffer));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_pld_buffer
+ *
+ * PARAMETERS:  obj_desc            - Object returned from _PLD method
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Dumps formatted contents of a _PLD return buffer.
+ *
+ ******************************************************************************/
+
+#define ACPI_PLD_OUTPUT     "%20s : %-6X\n"
+
+void acpi_db_dump_pld_buffer(union acpi_object *obj_desc)
+{
+	union acpi_object *buffer_desc;
+	struct acpi_pld_info *pld_info;
+	u8 *new_buffer;
+	acpi_status status;
+
+	/* Object must be of type Package with at least one Buffer element */
+
+	if (obj_desc->type != ACPI_TYPE_PACKAGE) {
+		return;
+	}
+
+	buffer_desc = &obj_desc->package.elements[0];
+	if (buffer_desc->type != ACPI_TYPE_BUFFER) {
+		return;
+	}
+
+	/* Convert _PLD buffer to local _PLD struct */
+
+	status = acpi_decode_pld_buffer(buffer_desc->buffer.pointer,
+					buffer_desc->buffer.length, &pld_info);
+	if (ACPI_FAILURE(status)) {
+		return;
+	}
+
+	/* Encode local _PLD struct back to a _PLD buffer */
+
+	new_buffer = acpi_db_encode_pld_buffer(pld_info);
+	if (!new_buffer) {
+		return;
+	}
+
+	/* The two bit-packed buffers should match */
+
+	if (memcmp(new_buffer, buffer_desc->buffer.pointer,
+		   buffer_desc->buffer.length)) {
+		acpi_os_printf
+		    ("Converted _PLD buffer does not compare. New:\n");
+
+		acpi_ut_dump_buffer(new_buffer,
+				    buffer_desc->buffer.length, DB_BYTE_DISPLAY,
+				    0);
+	}
+
+	/* First 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Revision", pld_info->revision);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_IgnoreColor",
+		       pld_info->ignore_color);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Red", pld_info->red);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Green", pld_info->green);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Blue", pld_info->blue);
+
+	/* Second 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Width", pld_info->width);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Height", pld_info->height);
+
+	/* Third 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_UserVisible",
+		       pld_info->user_visible);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Dock", pld_info->dock);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Lid", pld_info->lid);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Panel", pld_info->panel);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalPosition",
+		       pld_info->vertical_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalPosition",
+		       pld_info->horizontal_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Shape", pld_info->shape);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupOrientation",
+		       pld_info->group_orientation);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupToken",
+		       pld_info->group_token);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupPosition",
+		       pld_info->group_position);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Bay", pld_info->bay);
+
+	/* Fourth 32-bit dword */
+
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Ejectable", pld_info->ejectable);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_EjectRequired",
+		       pld_info->ospm_eject_required);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CabinetNumber",
+		       pld_info->cabinet_number);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CardCageNumber",
+		       pld_info->card_cage_number);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Reference", pld_info->reference);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Rotation", pld_info->rotation);
+	acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Order", pld_info->order);
+
+	/* Fifth 32-bit dword */
+
+	if (buffer_desc->buffer.length > 16) {
+		acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalOffset",
+			       pld_info->vertical_offset);
+		acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalOffset",
+			       pld_info->horizontal_offset);
+	}
+
+	ACPI_FREE(pld_info);
+	ACPI_FREE(new_buffer);
+}
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
new file mode 100644
index 0000000..672977e
--- /dev/null
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -0,0 +1,1108 @@
+/*******************************************************************************
+ *
+ * Module Name: dbdisply - debug display commands
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbdisply")
+
+/* Local prototypes */
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op);
+
+static void *acpi_db_get_pointer(void *target);
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+/*
+ * System handler information.
+ * Used for Handlers command, in acpi_db_display_handlers.
+ */
+#define ACPI_PREDEFINED_PREFIX          "%25s (%.2X) : "
+#define ACPI_HANDLER_NAME_STRING               "%30s : "
+#define ACPI_HANDLER_PRESENT_STRING                    "%-9s (%p)\n"
+#define ACPI_HANDLER_PRESENT_STRING2                   "%-9s (%p)"
+#define ACPI_HANDLER_NOT_PRESENT_STRING                "%-9s\n"
+
+/* All predefined Address Space IDs */
+
+static acpi_adr_space_type acpi_gbl_space_id_list[] = {
+	ACPI_ADR_SPACE_SYSTEM_MEMORY,
+	ACPI_ADR_SPACE_SYSTEM_IO,
+	ACPI_ADR_SPACE_PCI_CONFIG,
+	ACPI_ADR_SPACE_EC,
+	ACPI_ADR_SPACE_SMBUS,
+	ACPI_ADR_SPACE_CMOS,
+	ACPI_ADR_SPACE_PCI_BAR_TARGET,
+	ACPI_ADR_SPACE_IPMI,
+	ACPI_ADR_SPACE_GPIO,
+	ACPI_ADR_SPACE_GSBUS,
+	ACPI_ADR_SPACE_DATA_TABLE,
+	ACPI_ADR_SPACE_FIXED_HARDWARE
+};
+
+/* Global handler information */
+
+typedef struct acpi_handler_info {
+	void *handler;
+	char *name;
+
+} acpi_handler_info;
+
+static struct acpi_handler_info acpi_gbl_handler_list[] = {
+	{&acpi_gbl_global_notify[0].handler, "System Notifications"},
+	{&acpi_gbl_global_notify[1].handler, "Device Notifications"},
+	{&acpi_gbl_table_handler, "ACPI Table Events"},
+	{&acpi_gbl_exception_handler, "Control Method Exceptions"},
+	{&acpi_gbl_interface_handler, "OSI Invocations"}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_pointer
+ *
+ * PARAMETERS:  target          - Pointer to string to be converted
+ *
+ * RETURN:      Converted pointer
+ *
+ * DESCRIPTION: Convert an ascii pointer value to a real value
+ *
+ ******************************************************************************/
+
+static void *acpi_db_get_pointer(void *target)
+{
+	void *obj_ptr;
+	acpi_size address;
+
+	address = strtoul(target, NULL, 16);
+	obj_ptr = ACPI_TO_POINTER(address);
+	return (obj_ptr);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_parser_descriptor
+ *
+ * PARAMETERS:  op              - A parser Op descriptor
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted parser object
+ *
+ ******************************************************************************/
+
+static void acpi_db_dump_parser_descriptor(union acpi_parse_object *op)
+{
+	const struct acpi_opcode_info *info;
+
+	info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+
+	acpi_os_printf("Parser Op Descriptor:\n");
+	acpi_os_printf("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode);
+
+	ACPI_DEBUG_ONLY_MEMBERS(acpi_os_printf("%20.20s : %s\n", "Opcode Name",
+					       info->name));
+
+	acpi_os_printf("%20.20s : %p\n", "Value/ArgList", op->common.value.arg);
+	acpi_os_printf("%20.20s : %p\n", "Parent", op->common.parent);
+	acpi_os_printf("%20.20s : %p\n", "NextOp", op->common.next);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_and_display_object
+ *
+ * PARAMETERS:  target          - String with object to be displayed. Names
+ *                                and hex pointers are supported.
+ *              output_type     - Byte, Word, Dword, or Qword (B|W|D|Q)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display a formatted ACPI object
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_and_display_object(char *target, char *output_type)
+{
+	void *obj_ptr;
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	u32 display = DB_BYTE_DISPLAY;
+	char buffer[80];
+	struct acpi_buffer ret_buf;
+	acpi_status status;
+	u32 size;
+
+	if (!target) {
+		return;
+	}
+
+	/* Decode the output type */
+
+	if (output_type) {
+		acpi_ut_strupr(output_type);
+		if (output_type[0] == 'W') {
+			display = DB_WORD_DISPLAY;
+		} else if (output_type[0] == 'D') {
+			display = DB_DWORD_DISPLAY;
+		} else if (output_type[0] == 'Q') {
+			display = DB_QWORD_DISPLAY;
+		}
+	}
+
+	ret_buf.length = sizeof(buffer);
+	ret_buf.pointer = buffer;
+
+	/* Differentiate between a number and a name */
+
+	if ((target[0] >= 0x30) && (target[0] <= 0x39)) {
+		obj_ptr = acpi_db_get_pointer(target);
+		if (!acpi_os_readable(obj_ptr, 16)) {
+			acpi_os_printf
+			    ("Address %p is invalid in this address space\n",
+			     obj_ptr);
+			return;
+		}
+
+		/* Decode the object type */
+
+		switch (ACPI_GET_DESCRIPTOR_TYPE(obj_ptr)) {
+		case ACPI_DESC_TYPE_NAMED:
+
+			/* This is a namespace Node */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(struct acpi_namespace_node))) {
+				acpi_os_printf
+				    ("Cannot read entire Named object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			node = obj_ptr;
+			goto dump_node;
+
+		case ACPI_DESC_TYPE_OPERAND:
+
+			/* This is a ACPI OPERAND OBJECT */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(union acpi_operand_object))) {
+				acpi_os_printf
+				    ("Cannot read entire ACPI object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			acpi_ut_debug_dump_buffer(obj_ptr,
+						  sizeof(union
+							 acpi_operand_object),
+						  display, ACPI_UINT32_MAX);
+			acpi_ex_dump_object_descriptor(obj_ptr, 1);
+			break;
+
+		case ACPI_DESC_TYPE_PARSER:
+
+			/* This is a Parser Op object */
+
+			if (!acpi_os_readable
+			    (obj_ptr, sizeof(union acpi_parse_object))) {
+				acpi_os_printf
+				    ("Cannot read entire Parser object at address %p\n",
+				     obj_ptr);
+				return;
+			}
+
+			acpi_ut_debug_dump_buffer(obj_ptr,
+						  sizeof(union
+							 acpi_parse_object),
+						  display, ACPI_UINT32_MAX);
+			acpi_db_dump_parser_descriptor((union acpi_parse_object
+							*)obj_ptr);
+			break;
+
+		default:
+
+			/* Is not a recognizeable object */
+
+			acpi_os_printf
+			    ("Not a known ACPI internal object, descriptor type %2.2X\n",
+			     ACPI_GET_DESCRIPTOR_TYPE(obj_ptr));
+
+			size = 16;
+			if (acpi_os_readable(obj_ptr, 64)) {
+				size = 64;
+			}
+
+			/* Just dump some memory */
+
+			acpi_ut_debug_dump_buffer(obj_ptr, size, display,
+						  ACPI_UINT32_MAX);
+			break;
+		}
+
+		return;
+	}
+
+	/* The parameter is a name string that must be resolved to a Named obj */
+
+	node = acpi_db_local_ns_lookup(target);
+	if (!node) {
+		return;
+	}
+
+dump_node:
+	/* Now dump the NS node */
+
+	status = acpi_get_name(node, ACPI_FULL_PATHNAME_NO_TRAILING, &ret_buf);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not convert name to pathname\n");
+	}
+
+	else {
+		acpi_os_printf("Object (%p) Pathname: %s\n",
+			       node, (char *)ret_buf.pointer);
+	}
+
+	if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
+		acpi_os_printf("Invalid Named object at address %p\n", node);
+		return;
+	}
+
+	acpi_ut_debug_dump_buffer((void *)node,
+				  sizeof(struct acpi_namespace_node), display,
+				  ACPI_UINT32_MAX);
+	acpi_ex_dump_namespace_node(node, 1);
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
+		acpi_os_printf("\nAttached Object (%p):\n", obj_desc);
+		if (!acpi_os_readable
+		    (obj_desc, sizeof(union acpi_operand_object))) {
+			acpi_os_printf
+			    ("Invalid internal ACPI Object at address %p\n",
+			     obj_desc);
+			return;
+		}
+
+		acpi_ut_debug_dump_buffer((void *)obj_desc,
+					  sizeof(union acpi_operand_object),
+					  display, ACPI_UINT32_MAX);
+		acpi_ex_dump_object_descriptor(obj_desc, 1);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_method_info
+ *
+ * PARAMETERS:  start_op        - Root of the control method parse tree
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the current method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_method_info(union acpi_parse_object *start_op)
+{
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	union acpi_parse_object *root_op;
+	union acpi_parse_object *op;
+	const struct acpi_opcode_info *op_info;
+	u32 num_ops = 0;
+	u32 num_operands = 0;
+	u32 num_operators = 0;
+	u32 num_remaining_ops = 0;
+	u32 num_remaining_operands = 0;
+	u32 num_remaining_operators = 0;
+	u8 count_remaining = FALSE;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	acpi_os_printf("Currently executing control method is [%4.4s]\n",
+		       acpi_ut_get_node_name(node));
+	acpi_os_printf("%X Arguments, SyncLevel = %X\n",
+		       (u32)obj_desc->method.param_count,
+		       (u32)obj_desc->method.sync_level);
+
+	root_op = start_op;
+	while (root_op->common.parent) {
+		root_op = root_op->common.parent;
+	}
+
+	op = root_op;
+
+	while (op) {
+		if (op == start_op) {
+			count_remaining = TRUE;
+		}
+
+		num_ops++;
+		if (count_remaining) {
+			num_remaining_ops++;
+		}
+
+		/* Decode the opcode */
+
+		op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
+		switch (op_info->class) {
+		case AML_CLASS_ARGUMENT:
+
+			if (count_remaining) {
+				num_remaining_operands++;
+			}
+
+			num_operands++;
+			break;
+
+		case AML_CLASS_UNKNOWN:
+
+			/* Bad opcode or ASCII character */
+
+			continue;
+
+		default:
+
+			if (count_remaining) {
+				num_remaining_operators++;
+			}
+
+			num_operators++;
+			break;
+		}
+
+		op = acpi_ps_get_depth_next(start_op, op);
+	}
+
+	acpi_os_printf
+	    ("Method contains:       %X AML Opcodes - %X Operators, %X Operands\n",
+	     num_ops, num_operators, num_operands);
+
+	acpi_os_printf
+	    ("Remaining to execute:  %X AML Opcodes - %X Operators, %X Operands\n",
+	     num_remaining_ops, num_remaining_operators,
+	     num_remaining_operands);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_locals
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_locals(void)
+{
+	struct acpi_walk_state *walk_state;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_db_decode_locals(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_arguments
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_display_arguments(void)
+{
+	struct acpi_walk_state *walk_state;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_db_decode_arguments(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_results
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current contents of a method result stack
+ *
+ ******************************************************************************/
+
+void acpi_db_display_results(void)
+{
+	u32 i;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	u32 result_count = 0;
+	struct acpi_namespace_node *node;
+	union acpi_generic_state *frame;
+	u32 index;		/* Index onto current frame */
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	if (walk_state->results) {
+		result_count = walk_state->result_count;
+	}
+
+	acpi_os_printf("Method [%4.4s] has %X stacked result objects\n",
+		       acpi_ut_get_node_name(node), result_count);
+
+	/* From the top element of result stack */
+
+	frame = walk_state->results;
+	index = (result_count - 1) % ACPI_RESULTS_FRAME_OBJ_NUM;
+
+	for (i = 0; i < result_count; i++) {
+		obj_desc = frame->results.obj_desc[index];
+		acpi_os_printf("Result%u: ", i);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+
+		if (index == 0) {
+			frame = frame->results.next;
+			index = ACPI_RESULTS_FRAME_OBJ_NUM;
+		}
+
+		index--;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_calling_tree
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display current calling tree of nested control methods
+ *
+ ******************************************************************************/
+
+void acpi_db_display_calling_tree(void)
+{
+	struct acpi_walk_state *walk_state;
+	struct acpi_namespace_node *node;
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	node = walk_state->method_node;
+	acpi_os_printf("Current Control Method Call Tree\n");
+
+	while (walk_state) {
+		node = walk_state->method_node;
+		acpi_os_printf("  [%4.4s]\n", acpi_ut_get_node_name(node));
+
+		walk_state = walk_state->next;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_object_type
+ *
+ * PARAMETERS:  name            - User entered NS node handle or name
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display type of an arbitrary NS node
+ *
+ ******************************************************************************/
+
+void acpi_db_display_object_type(char *name)
+{
+	struct acpi_namespace_node *node;
+	struct acpi_device_info *info;
+	acpi_status status;
+	u32 i;
+
+	node = acpi_db_convert_to_node(name);
+	if (!node) {
+		return;
+	}
+
+	status = acpi_get_object_info(ACPI_CAST_PTR(acpi_handle, node), &info);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not get object info, %s\n",
+			       acpi_format_exception(status));
+		return;
+	}
+
+	if (info->valid & ACPI_VALID_ADR) {
+		acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n",
+			       ACPI_FORMAT_UINT64(info->address),
+			       info->current_status, info->flags);
+	}
+	if (info->valid & ACPI_VALID_SXDS) {
+		acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n",
+			       info->highest_dstates[0],
+			       info->highest_dstates[1],
+			       info->highest_dstates[2],
+			       info->highest_dstates[3]);
+	}
+	if (info->valid & ACPI_VALID_SXWS) {
+		acpi_os_printf
+		    ("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n",
+		     info->lowest_dstates[0], info->lowest_dstates[1],
+		     info->lowest_dstates[2], info->lowest_dstates[3],
+		     info->lowest_dstates[4]);
+	}
+
+	if (info->valid & ACPI_VALID_HID) {
+		acpi_os_printf("HID: %s\n", info->hardware_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_UID) {
+		acpi_os_printf("UID: %s\n", info->unique_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_SUB) {
+		acpi_os_printf("SUB: %s\n", info->subsystem_id.string);
+	}
+
+	if (info->valid & ACPI_VALID_CID) {
+		for (i = 0; i < info->compatible_id_list.count; i++) {
+			acpi_os_printf("CID %u: %s\n", i,
+				       info->compatible_id_list.ids[i].string);
+		}
+	}
+
+	ACPI_FREE(info);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_result_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ * Note: Curently only displays the result object if we are single stepping.
+ * However, this output may be useful in other contexts and could be enabled
+ * to do so if needed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_result_object(union acpi_operand_object *obj_desc,
+			      struct acpi_walk_state *walk_state)
+{
+
+	/* Only display if single stepping */
+
+	if (!acpi_gbl_cm_single_step) {
+		return;
+	}
+
+	acpi_os_printf("ResultObj: ");
+	acpi_db_display_internal_object(obj_desc, walk_state);
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_argument_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the result of an AML opcode
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
+				struct acpi_walk_state *walk_state)
+{
+
+	if (!acpi_gbl_cm_single_step) {
+		return;
+	}
+
+	acpi_os_printf("ArgObj:  ");
+	acpi_db_display_internal_object(obj_desc, walk_state);
+}
+
+#if (!ACPI_REDUCED_HARDWARE)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the current GPE structures
+ *
+ ******************************************************************************/
+
+void acpi_db_display_gpes(void)
+{
+	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+	struct acpi_gpe_event_info *gpe_event_info;
+	struct acpi_gpe_register_info *gpe_register_info;
+	char *gpe_type;
+	struct acpi_gpe_notify_info *notify;
+	u32 gpe_index;
+	u32 block = 0;
+	u32 i;
+	u32 j;
+	u32 count;
+	char buffer[80];
+	struct acpi_buffer ret_buf;
+	acpi_status status;
+
+	ret_buf.length = sizeof(buffer);
+	ret_buf.pointer = buffer;
+
+	block = 0;
+
+	/* Walk the GPE lists */
+
+	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+	while (gpe_xrupt_info) {
+		gpe_block = gpe_xrupt_info->gpe_block_list_head;
+		while (gpe_block) {
+			status = acpi_get_name(gpe_block->node,
+					       ACPI_FULL_PATHNAME_NO_TRAILING,
+					       &ret_buf);
+			if (ACPI_FAILURE(status)) {
+				acpi_os_printf
+				    ("Could not convert name to pathname\n");
+			}
+
+			if (gpe_block->node == acpi_gbl_fadt_gpe_device) {
+				gpe_type = "FADT-defined GPE block";
+			} else {
+				gpe_type = "GPE Block Device";
+			}
+
+			acpi_os_printf
+			    ("\nBlock %u - Info %p  DeviceNode %p [%s] - %s\n",
+			     block, gpe_block, gpe_block->node, buffer,
+			     gpe_type);
+
+			acpi_os_printf("    Registers:    %u (%u GPEs)\n",
+				       gpe_block->register_count,
+				       gpe_block->gpe_count);
+
+			acpi_os_printf
+			    ("    GPE range:    0x%X to 0x%X on interrupt %u\n",
+			     gpe_block->block_base_number,
+			     gpe_block->block_base_number +
+			     (gpe_block->gpe_count - 1),
+			     gpe_xrupt_info->interrupt_number);
+
+			acpi_os_printf
+			    ("    RegisterInfo: %p  Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+			     gpe_block->register_info,
+			     ACPI_FORMAT_UINT64(gpe_block->register_info->
+						status_address.address),
+			     ACPI_FORMAT_UINT64(gpe_block->register_info->
+						enable_address.address));
+
+			acpi_os_printf("  EventInfo:    %p\n",
+				       gpe_block->event_info);
+
+			/* Examine each GPE Register within the block */
+
+			for (i = 0; i < gpe_block->register_count; i++) {
+				gpe_register_info =
+				    &gpe_block->register_info[i];
+
+				acpi_os_printf("    Reg %u: (GPE %.2X-%.2X)  "
+					       "RunEnable %2.2X WakeEnable %2.2X"
+					       " Status %8.8X%8.8X Enable %8.8X%8.8X\n",
+					       i,
+					       gpe_register_info->
+					       base_gpe_number,
+					       gpe_register_info->
+					       base_gpe_number +
+					       (ACPI_GPE_REGISTER_WIDTH - 1),
+					       gpe_register_info->
+					       enable_for_run,
+					       gpe_register_info->
+					       enable_for_wake,
+					       ACPI_FORMAT_UINT64
+					       (gpe_register_info->
+						status_address.address),
+					       ACPI_FORMAT_UINT64
+					       (gpe_register_info->
+						enable_address.address));
+
+				/* Now look at the individual GPEs in this byte register */
+
+				for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+					gpe_index =
+					    (i * ACPI_GPE_REGISTER_WIDTH) + j;
+					gpe_event_info =
+					    &gpe_block->event_info[gpe_index];
+
+					if (ACPI_GPE_DISPATCH_TYPE
+					    (gpe_event_info->flags) ==
+					    ACPI_GPE_DISPATCH_NONE) {
+
+						/* This GPE is not used (no method or handler), ignore it */
+
+						continue;
+					}
+
+					acpi_os_printf
+					    ("        GPE %.2X: %p  RunRefs %2.2X Flags %2.2X (",
+					     gpe_block->block_base_number +
+					     gpe_index, gpe_event_info,
+					     gpe_event_info->runtime_count,
+					     gpe_event_info->flags);
+
+					/* Decode the flags byte */
+
+					if (gpe_event_info->
+					    flags & ACPI_GPE_LEVEL_TRIGGERED) {
+						acpi_os_printf("Level, ");
+					} else {
+						acpi_os_printf("Edge, ");
+					}
+
+					if (gpe_event_info->
+					    flags & ACPI_GPE_CAN_WAKE) {
+						acpi_os_printf("CanWake, ");
+					} else {
+						acpi_os_printf("RunOnly, ");
+					}
+
+					switch (ACPI_GPE_DISPATCH_TYPE
+						(gpe_event_info->flags)) {
+					case ACPI_GPE_DISPATCH_NONE:
+
+						acpi_os_printf("NotUsed");
+						break;
+
+					case ACPI_GPE_DISPATCH_METHOD:
+
+						acpi_os_printf("Method");
+						break;
+
+					case ACPI_GPE_DISPATCH_HANDLER:
+
+						acpi_os_printf("Handler");
+						break;
+
+					case ACPI_GPE_DISPATCH_NOTIFY:
+
+						count = 0;
+						notify =
+						    gpe_event_info->dispatch.
+						    notify_list;
+						while (notify) {
+							count++;
+							notify = notify->next;
+						}
+
+						acpi_os_printf
+						    ("Implicit Notify on %u devices",
+						     count);
+						break;
+
+					case ACPI_GPE_DISPATCH_RAW_HANDLER:
+
+						acpi_os_printf("RawHandler");
+						break;
+
+					default:
+
+						acpi_os_printf("UNKNOWN: %X",
+							       ACPI_GPE_DISPATCH_TYPE
+							       (gpe_event_info->
+								flags));
+						break;
+					}
+
+					acpi_os_printf(")\n");
+				}
+			}
+
+			block++;
+			gpe_block = gpe_block->next;
+		}
+
+		gpe_xrupt_info = gpe_xrupt_info->next;
+	}
+}
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_handlers
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the currently installed global handlers
+ *
+ ******************************************************************************/
+
+void acpi_db_display_handlers(void)
+{
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+	acpi_adr_space_type space_id;
+	u32 i;
+
+	/* Operation region handlers */
+
+	acpi_os_printf("\nOperation Region Handlers at the namespace root:\n");
+
+	obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node);
+	if (obj_desc) {
+		for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) {
+			space_id = acpi_gbl_space_id_list[i];
+			handler_obj = obj_desc->device.handler;
+
+			acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+				       acpi_ut_get_region_name((u8)space_id),
+				       space_id);
+
+			while (handler_obj) {
+				if (acpi_gbl_space_id_list[i] ==
+				    handler_obj->address_space.space_id) {
+					acpi_os_printf
+					    (ACPI_HANDLER_PRESENT_STRING,
+					     (handler_obj->address_space.
+					      handler_flags &
+					      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+					     ? "Default" : "User",
+					     handler_obj->address_space.
+					     handler);
+
+					goto found_handler;
+				}
+
+				handler_obj = handler_obj->address_space.next;
+			}
+
+			/* There is no handler for this space_id */
+
+			acpi_os_printf("None\n");
+
+found_handler:		;
+		}
+
+		/* Find all handlers for user-defined space_IDs */
+
+		handler_obj = obj_desc->device.handler;
+		while (handler_obj) {
+			if (handler_obj->address_space.space_id >=
+			    ACPI_USER_REGION_BEGIN) {
+				acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+					       "User-defined ID",
+					       handler_obj->address_space.
+					       space_id);
+				acpi_os_printf(ACPI_HANDLER_PRESENT_STRING,
+					       (handler_obj->address_space.
+						handler_flags &
+						ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
+					       ? "Default" : "User",
+					       handler_obj->address_space.
+					       handler);
+			}
+
+			handler_obj = handler_obj->address_space.next;
+		}
+	}
+#if (!ACPI_REDUCED_HARDWARE)
+
+	/* Fixed event handlers */
+
+	acpi_os_printf("\nFixed Event Handlers:\n");
+
+	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+		acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+			       acpi_ut_get_event_name(i), i);
+		if (acpi_gbl_fixed_event_handlers[i].handler) {
+			acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+				       acpi_gbl_fixed_event_handlers[i].
+				       handler);
+		} else {
+			acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+		}
+	}
+
+#endif				/* !ACPI_REDUCED_HARDWARE */
+
+	/* Miscellaneous global handlers */
+
+	acpi_os_printf("\nMiscellaneous Global Handlers:\n");
+
+	for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_handler_list); i++) {
+		acpi_os_printf(ACPI_HANDLER_NAME_STRING,
+			       acpi_gbl_handler_list[i].name);
+
+		if (acpi_gbl_handler_list[i].handler) {
+			acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User",
+				       acpi_gbl_handler_list[i].handler);
+		} else {
+			acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None");
+		}
+	}
+
+	/* Other handlers that are installed throughout the namespace */
+
+	acpi_os_printf("\nOperation Region Handlers for specific devices:\n");
+
+	(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_display_non_root_handlers, NULL, NULL,
+				  NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_non_root_handlers
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display information about all handlers installed for a
+ *              device object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_display_non_root_handlers(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+	char *pathname;
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* Display all handlers associated with this device */
+
+	handler_obj = obj_desc->device.handler;
+	while (handler_obj) {
+		acpi_os_printf(ACPI_PREDEFINED_PREFIX,
+			       acpi_ut_get_region_name((u8)handler_obj->
+						       address_space.space_id),
+			       handler_obj->address_space.space_id);
+
+		acpi_os_printf(ACPI_HANDLER_PRESENT_STRING2,
+			       (handler_obj->address_space.handler_flags &
+				ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default"
+			       : "User", handler_obj->address_space.handler);
+
+		acpi_os_printf(" Device Name: %s (%p)\n", pathname, node);
+
+		handler_obj = handler_obj->address_space.next;
+	}
+
+	ACPI_FREE(pathname);
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
new file mode 100644
index 0000000..8eef298
--- /dev/null
+++ b/drivers/acpi/acpica/dbexec.c
@@ -0,0 +1,753 @@
+/*******************************************************************************
+ *
+ * Module Name: dbexec - debugger control method execution
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbexec")
+
+static struct acpi_db_method_info acpi_gbl_db_method_info;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+		       struct acpi_buffer *return_obj);
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
+
+static u32 acpi_db_get_outstanding_allocations(void);
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_delete_objects
+ *
+ * PARAMETERS:  count               - Count of objects in the list
+ *              objects             - Array of ACPI_OBJECTs to be deleted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
+ *              packages via recursion.
+ *
+ ******************************************************************************/
+
+void acpi_db_delete_objects(u32 count, union acpi_object *objects)
+{
+	u32 i;
+
+	for (i = 0; i < count; i++) {
+		switch (objects[i].type) {
+		case ACPI_TYPE_BUFFER:
+
+			ACPI_FREE(objects[i].buffer.pointer);
+			break;
+
+		case ACPI_TYPE_PACKAGE:
+
+			/* Recursive call to delete package elements */
+
+			acpi_db_delete_objects(objects[i].package.count,
+					       objects[i].package.elements);
+
+			/* Free the elements array */
+
+			ACPI_FREE(objects[i].package.elements);
+			break;
+
+		default:
+
+			break;
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_method
+ *
+ * PARAMETERS:  info            - Valid info segment
+ *              return_obj      - Where to put return object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execute_method(struct acpi_db_method_info *info,
+		       struct acpi_buffer *return_obj)
+{
+	acpi_status status;
+	struct acpi_object_list param_objects;
+	union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
+	u32 i;
+
+	ACPI_FUNCTION_TRACE(db_execute_method);
+
+	if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
+		acpi_os_printf("Warning: debug output is not enabled!\n");
+	}
+
+	param_objects.count = 0;
+	param_objects.pointer = NULL;
+
+	/* Pass through any command-line arguments */
+
+	if (info->args && info->args[0]) {
+
+		/* Get arguments passed on the command line */
+
+		for (i = 0; (info->args[i] && *(info->args[i])); i++) {
+
+			/* Convert input string (token) to an actual union acpi_object */
+
+			status = acpi_db_convert_to_object(info->types[i],
+							   info->args[i],
+							   &params[i]);
+			if (ACPI_FAILURE(status)) {
+				ACPI_EXCEPTION((AE_INFO, status,
+						"While parsing method arguments"));
+				goto cleanup;
+			}
+		}
+
+		param_objects.count = i;
+		param_objects.pointer = params;
+	}
+
+	/* Prepare for a return object of arbitrary size */
+
+	return_obj->pointer = acpi_gbl_db_buffer;
+	return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
+
+	/* Do the actual method execution */
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(NULL, info->pathname,
+				      &param_objects, return_obj);
+
+	acpi_gbl_cm_single_step = FALSE;
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"while executing %s from debugger",
+				info->pathname));
+
+		if (status == AE_BUFFER_OVERFLOW) {
+			ACPI_ERROR((AE_INFO,
+				    "Possible overflow of internal debugger "
+				    "buffer (size 0x%X needed 0x%X)",
+				    ACPI_DEBUG_BUFFER_SIZE,
+				    (u32)return_obj->length));
+		}
+	}
+
+cleanup:
+	acpi_db_delete_objects(param_objects.count, params);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_setup
+ *
+ * PARAMETERS:  info            - Valid method info
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Setup info segment prior to method execution
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_NAME(db_execute_setup);
+
+	/* Catenate the current scope to the supplied name */
+
+	info->pathname[0] = 0;
+	if ((info->name[0] != '\\') && (info->name[0] != '/')) {
+		if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+					acpi_gbl_db_scope_buf)) {
+			status = AE_BUFFER_OVERFLOW;
+			goto error_exit;
+		}
+	}
+
+	if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
+				info->name)) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	acpi_db_prep_namestring(info->pathname);
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("Evaluating %s\n", info->pathname);
+
+	if (info->flags & EX_SINGLE_STEP) {
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	}
+
+	else {
+		/* No single step, allow redirection to a file */
+
+		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	}
+
+	return (AE_OK);
+
+error_exit:
+
+	ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
+	return (status);
+}
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
+{
+
+	return (cache->total_allocated - cache->total_freed -
+		cache->current_depth);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_outstanding_allocations
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Current global allocation count minus cache entries
+ *
+ * DESCRIPTION: Determine the current number of "outstanding" allocations --
+ *              those allocations that have not been freed and also are not
+ *              in one of the various object caches.
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_outstanding_allocations(void)
+{
+	u32 outstanding = 0;
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+	outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
+	outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
+#endif
+
+	return (outstanding);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execution_walk
+ *
+ * PARAMETERS:  WALK_CALLBACK
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_execution_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value)
+{
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	struct acpi_buffer return_obj;
+	acpi_status status;
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc->method.param_count) {
+		return (AE_OK);
+	}
+
+	return_obj.pointer = NULL;
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	acpi_ns_print_node_pathname(node, "Evaluating");
+
+	/* Do the actual method execution */
+
+	acpi_os_printf("\n");
+	acpi_gbl_method_executing = TRUE;
+
+	status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
+
+	acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
+		       acpi_ut_get_node_name(node),
+		       acpi_format_exception(status));
+
+	acpi_gbl_method_executing = FALSE;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute
+ *
+ * PARAMETERS:  name                - Name of method to execute
+ *              args                - Parameters to the method
+ *              Types               -
+ *              flags               - single step/no single step
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute a control method. Name is relative to the current
+ *              scope.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
+{
+	acpi_status status;
+	struct acpi_buffer return_obj;
+	char *name_string;
+
+#ifdef ACPI_DEBUG_OUTPUT
+	u32 previous_allocations;
+	u32 allocations;
+
+	/* Memory allocation tracking */
+
+	previous_allocations = acpi_db_get_outstanding_allocations();
+#endif
+
+	if (*name == '*') {
+		(void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_execution_walk, NULL, NULL,
+					  NULL);
+		return;
+	} else {
+		name_string = ACPI_ALLOCATE(strlen(name) + 1);
+		if (!name_string) {
+			return;
+		}
+
+		memset(&acpi_gbl_db_method_info, 0,
+		       sizeof(struct acpi_db_method_info));
+
+		strcpy(name_string, name);
+		acpi_ut_strupr(name_string);
+		acpi_gbl_db_method_info.name = name_string;
+		acpi_gbl_db_method_info.args = args;
+		acpi_gbl_db_method_info.types = types;
+		acpi_gbl_db_method_info.flags = flags;
+
+		return_obj.pointer = NULL;
+		return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+		status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+		if (ACPI_FAILURE(status)) {
+			ACPI_FREE(name_string);
+			return;
+		}
+
+		/* Get the NS node, determines existence also */
+
+		status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+					 &acpi_gbl_db_method_info.method);
+		if (ACPI_SUCCESS(status)) {
+			status =
+			    acpi_db_execute_method(&acpi_gbl_db_method_info,
+						   &return_obj);
+		}
+		ACPI_FREE(name_string);
+	}
+
+	/*
+	 * Allow any handlers in separate threads to complete.
+	 * (Such as Notify handlers invoked from AML executed above).
+	 */
+	acpi_os_sleep((u64)10);
+
+#ifdef ACPI_DEBUG_OUTPUT
+
+	/* Memory allocation tracking */
+
+	allocations =
+	    acpi_db_get_outstanding_allocations() - previous_allocations;
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+
+	if (allocations > 0) {
+		acpi_os_printf
+		    ("0x%X Outstanding allocations after evaluation of %s\n",
+		     allocations, acpi_gbl_db_method_info.pathname);
+	}
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Evaluation of %s failed with status %s\n",
+			       acpi_gbl_db_method_info.pathname,
+			       acpi_format_exception(status));
+	} else {
+		/* Display a return object, if any */
+
+		if (return_obj.length) {
+			acpi_os_printf("Evaluation of %s returned object %p, "
+				       "external buffer length %X\n",
+				       acpi_gbl_db_method_info.pathname,
+				       return_obj.pointer,
+				       (u32)return_obj.length);
+
+			acpi_db_dump_external_object(return_obj.pointer, 1);
+
+			/* Dump a _PLD buffer if present */
+
+			if (ACPI_COMPARE_NAME
+			    ((ACPI_CAST_PTR
+			      (struct acpi_namespace_node,
+			       acpi_gbl_db_method_info.method)->name.ascii),
+			     METHOD_NAME__PLD)) {
+				acpi_db_dump_pld_buffer(return_obj.pointer);
+			}
+		} else {
+			acpi_os_printf
+			    ("No object was returned from evaluation of %s\n",
+			     acpi_gbl_db_method_info.pathname);
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_method_thread
+ *
+ * PARAMETERS:  context             - Execution info segment
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
+{
+	acpi_status status;
+	struct acpi_db_method_info *info = context;
+	struct acpi_db_method_info local_info;
+	u32 i;
+	u8 allow;
+	struct acpi_buffer return_obj;
+
+	/*
+	 * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
+	 * Prevent acpi_gbl_db_method_info from being modified by multiple threads
+	 * concurrently.
+	 *
+	 * Note: The arguments we are passing are used by the ASL test suite
+	 * (aslts). Do not change them without updating the tests.
+	 */
+	(void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
+
+	if (info->init_args) {
+		acpi_db_uint32_to_hex_string(info->num_created,
+					     info->index_of_thread_str);
+		acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
+					     info->id_of_thread_str);
+	}
+
+	if (info->threads && (info->num_created < info->num_threads)) {
+		info->threads[info->num_created++] = acpi_os_get_thread_id();
+	}
+
+	local_info = *info;
+	local_info.args = local_info.arguments;
+	local_info.arguments[0] = local_info.num_threads_str;
+	local_info.arguments[1] = local_info.id_of_thread_str;
+	local_info.arguments[2] = local_info.index_of_thread_str;
+	local_info.arguments[3] = NULL;
+
+	local_info.types = local_info.arg_types;
+
+	(void)acpi_os_signal_semaphore(info->info_gate, 1);
+
+	for (i = 0; i < info->num_loops; i++) {
+		status = acpi_db_execute_method(&local_info, &return_obj);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s During evaluation of %s at iteration %X\n",
+			     acpi_format_exception(status), info->pathname, i);
+			if (status == AE_ABORT_METHOD) {
+				break;
+			}
+		}
+#if 0
+		if ((i % 100) == 0) {
+			acpi_os_printf("%u loops, Thread 0x%x\n",
+				       i, acpi_os_get_thread_id());
+		}
+
+		if (return_obj.length) {
+			acpi_os_printf
+			    ("Evaluation of %s returned object %p Buflen %X\n",
+			     info->pathname, return_obj.pointer,
+			     (u32)return_obj.length);
+			acpi_db_dump_external_object(return_obj.pointer, 1);
+		}
+#endif
+	}
+
+	/* Signal our completion */
+
+	allow = 0;
+	(void)acpi_os_wait_semaphore(info->thread_complete_gate,
+				     1, ACPI_WAIT_FOREVER);
+	info->num_completed++;
+
+	if (info->num_completed == info->num_threads) {
+
+		/* Do signal for main thread once only */
+		allow = 1;
+	}
+
+	(void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
+
+	if (allow) {
+		status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not signal debugger thread sync semaphore, %s\n",
+			     acpi_format_exception(status));
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_create_execution_threads
+ *
+ * PARAMETERS:  num_threads_arg         - Number of threads to create
+ *              num_loops_arg           - Loop count for the thread(s)
+ *              method_name_arg         - Control method to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Create threads to execute method(s)
+ *
+ ******************************************************************************/
+
+void
+acpi_db_create_execution_threads(char *num_threads_arg,
+				 char *num_loops_arg, char *method_name_arg)
+{
+	acpi_status status;
+	u32 num_threads;
+	u32 num_loops;
+	u32 i;
+	u32 size;
+	acpi_mutex main_thread_gate;
+	acpi_mutex thread_complete_gate;
+	acpi_mutex info_gate;
+
+	/* Get the arguments */
+
+	num_threads = strtoul(num_threads_arg, NULL, 0);
+	num_loops = strtoul(num_loops_arg, NULL, 0);
+
+	if (!num_threads || !num_loops) {
+		acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
+			       num_threads, num_loops);
+		return;
+	}
+
+	/*
+	 * Create the semaphore for synchronization of
+	 * the created threads with the main thread.
+	 */
+	status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization with the main thread, %s\n",
+			       acpi_format_exception(status));
+		return;
+	}
+
+	/*
+	 * Create the semaphore for synchronization
+	 * between the created threads.
+	 */
+	status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization between the created threads, %s\n",
+			       acpi_format_exception(status));
+
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		return;
+	}
+
+	status = acpi_os_create_semaphore(1, 1, &info_gate);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not create semaphore for "
+			       "synchronization of AcpiGbl_DbMethodInfo, %s\n",
+			       acpi_format_exception(status));
+
+		(void)acpi_os_delete_semaphore(thread_complete_gate);
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		return;
+	}
+
+	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
+
+	/* Array to store IDs of threads */
+
+	acpi_gbl_db_method_info.num_threads = num_threads;
+	size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
+
+	acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
+	if (acpi_gbl_db_method_info.threads == NULL) {
+		acpi_os_printf("No memory for thread IDs array\n");
+		(void)acpi_os_delete_semaphore(main_thread_gate);
+		(void)acpi_os_delete_semaphore(thread_complete_gate);
+		(void)acpi_os_delete_semaphore(info_gate);
+		return;
+	}
+	memset(acpi_gbl_db_method_info.threads, 0, size);
+
+	/* Setup the context to be passed to each thread */
+
+	acpi_gbl_db_method_info.name = method_name_arg;
+	acpi_gbl_db_method_info.flags = 0;
+	acpi_gbl_db_method_info.num_loops = num_loops;
+	acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
+	acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
+	acpi_gbl_db_method_info.info_gate = info_gate;
+
+	/* Init arguments to be passed to method */
+
+	acpi_gbl_db_method_info.init_args = 1;
+	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
+	acpi_gbl_db_method_info.arguments[0] =
+	    acpi_gbl_db_method_info.num_threads_str;
+	acpi_gbl_db_method_info.arguments[1] =
+	    acpi_gbl_db_method_info.id_of_thread_str;
+	acpi_gbl_db_method_info.arguments[2] =
+	    acpi_gbl_db_method_info.index_of_thread_str;
+	acpi_gbl_db_method_info.arguments[3] = NULL;
+
+	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
+	acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
+	acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
+	acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
+
+	acpi_db_uint32_to_hex_string(num_threads,
+				     acpi_gbl_db_method_info.num_threads_str);
+
+	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
+	if (ACPI_FAILURE(status)) {
+		goto cleanup_and_exit;
+	}
+
+	/* Get the NS node, determines existence also */
+
+	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
+				 &acpi_gbl_db_method_info.method);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("%s Could not get handle for %s\n",
+			       acpi_format_exception(status),
+			       acpi_gbl_db_method_info.pathname);
+		goto cleanup_and_exit;
+	}
+
+	/* Create the threads */
+
+	acpi_os_printf("Creating %X threads to execute %X times each\n",
+		       num_threads, num_loops);
+
+	for (i = 0; i < (num_threads); i++) {
+		status =
+		    acpi_os_execute(OSL_DEBUGGER_THREAD, acpi_db_method_thread,
+				    &acpi_gbl_db_method_info);
+		if (ACPI_FAILURE(status)) {
+			break;
+		}
+	}
+
+	/* Wait for all threads to complete */
+
+	(void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("All threads (%X) have completed\n", num_threads);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+
+cleanup_and_exit:
+
+	/* Cleanup and exit */
+
+	(void)acpi_os_delete_semaphore(main_thread_gate);
+	(void)acpi_os_delete_semaphore(thread_complete_gate);
+	(void)acpi_os_delete_semaphore(info_gate);
+
+	acpi_os_free(acpi_gbl_db_method_info.threads);
+	acpi_gbl_db_method_info.threads = NULL;
+}
diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c
new file mode 100644
index 0000000..d0e6b20
--- /dev/null
+++ b/drivers/acpi/acpica/dbfileio.c
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ *
+ * Module Name: dbfileio - Debugger file I/O commands. These can't usually
+ *              be used when running the debugger in Ring 0 (Kernel mode)
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbfileio")
+
+#ifdef ACPI_DEBUGGER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_close_debug_file
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: If open, close the current debug output file
+ *
+ ******************************************************************************/
+void acpi_db_close_debug_file(void)
+{
+
+#ifdef ACPI_APPLICATION
+
+	if (acpi_gbl_debug_file) {
+		fclose(acpi_gbl_debug_file);
+		acpi_gbl_debug_file = NULL;
+		acpi_gbl_db_output_to_file = FALSE;
+		acpi_os_printf("Debug output file %s closed\n",
+			       acpi_gbl_db_debug_filename);
+	}
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_open_debug_file
+ *
+ * PARAMETERS:  name                - Filename to open
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Open a file where debug output will be directed.
+ *
+ ******************************************************************************/
+
+void acpi_db_open_debug_file(char *name)
+{
+
+#ifdef ACPI_APPLICATION
+
+	acpi_db_close_debug_file();
+	acpi_gbl_debug_file = fopen(name, "w+");
+	if (!acpi_gbl_debug_file) {
+		acpi_os_printf("Could not open debug file %s\n", name);
+		return;
+	}
+
+	acpi_os_printf("Debug output file %s opened\n", name);
+	strncpy(acpi_gbl_db_debug_filename, name,
+		sizeof(acpi_gbl_db_debug_filename));
+	acpi_gbl_db_output_to_file = TRUE;
+
+#endif
+}
+#endif
+
+#ifdef ACPI_APPLICATION
+#include "acapps.h"
+
+/*******************************************************************************
+ *
+ * FUNCTION:    ae_local_load_table
+ *
+ * PARAMETERS:  table           - pointer to a buffer containing the entire
+ *                                table to be loaded
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to load a table from the caller's
+ *              buffer. The buffer must contain an entire ACPI Table including
+ *              a valid header. The header fields will be verified, and if it
+ *              is determined that the table is invalid, the call will fail.
+ *
+ ******************************************************************************/
+
+static acpi_status ae_local_load_table(struct acpi_table_header *table)
+{
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE(ae_local_load_table);
+
+#if 0
+/*    struct acpi_table_desc          table_info; */
+
+	if (!table) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	table_info.pointer = table;
+	status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Install the new table into the local data structures */
+
+	status = acpi_tb_init_table_descriptor(&table_info);
+	if (ACPI_FAILURE(status)) {
+		if (status == AE_ALREADY_EXISTS) {
+
+			/* Table already exists, no error */
+
+			status = AE_OK;
+		}
+
+		/* Free table allocated by acpi_tb_get_table */
+
+		acpi_tb_delete_single_table(&table_info);
+		return_ACPI_STATUS(status);
+	}
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+	status =
+	    acpi_ns_load_table(table_info.installed_desc, acpi_gbl_root_node);
+	if (ACPI_FAILURE(status)) {
+
+		/* Uninstall table and free the buffer */
+
+		acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_DSDT);
+		return_ACPI_STATUS(status);
+	}
+#endif
+#endif
+
+	return_ACPI_STATUS(status);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_table_from_file
+ *
+ * PARAMETERS:  filename        - File where table is located
+ *              return_table    - Where a pointer to the table is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load an ACPI table from a file
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_get_table_from_file(char *filename,
+			    struct acpi_table_header **return_table,
+			    u8 must_be_aml_file)
+{
+#ifdef ACPI_APPLICATION
+	acpi_status status;
+	struct acpi_table_header *table;
+	u8 is_aml_table = TRUE;
+
+	status = acpi_ut_read_table_from_file(filename, &table);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	if (must_be_aml_file) {
+		is_aml_table = acpi_ut_is_aml_table(table);
+		if (!is_aml_table) {
+			ACPI_EXCEPTION((AE_INFO, AE_OK,
+					"Input for -e is not an AML table: "
+					"\"%4.4s\" (must be DSDT/SSDT)",
+					table->signature));
+			return (AE_TYPE);
+		}
+	}
+
+	if (is_aml_table) {
+
+		/* Attempt to recognize and install the table */
+
+		status = ae_local_load_table(table);
+		if (ACPI_FAILURE(status)) {
+			if (status == AE_ALREADY_EXISTS) {
+				acpi_os_printf
+				    ("Table %4.4s is already installed\n",
+				     table->signature);
+			} else {
+				acpi_os_printf("Could not install table, %s\n",
+					       acpi_format_exception(status));
+			}
+
+			return (status);
+		}
+
+		acpi_tb_print_table_header(0, table);
+
+		fprintf(stderr,
+			"Acpi table [%4.4s] successfully installed and loaded\n",
+			table->signature);
+	}
+
+	acpi_gbl_acpi_hardware_present = FALSE;
+	if (return_table) {
+		*return_table = table;
+	}
+
+#endif				/* ACPI_APPLICATION */
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c
new file mode 100644
index 0000000..9c66a9e
--- /dev/null
+++ b/drivers/acpi/acpica/dbhistry.c
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * Module Name: dbhistry - debugger HISTORY command
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbhistry")
+
+#define HI_NO_HISTORY       0
+#define HI_RECORD_HISTORY   1
+#define HISTORY_SIZE        40
+typedef struct history_info {
+	char *command;
+	u32 cmd_num;
+
+} HISTORY_INFO;
+
+static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
+static u16 acpi_gbl_lo_history = 0;
+static u16 acpi_gbl_num_history = 0;
+static u16 acpi_gbl_next_history_index = 0;
+u32 acpi_gbl_next_cmd_num = 1;
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_add_to_history
+ *
+ * PARAMETERS:  command_line    - Command to add
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add a command line to the history buffer.
+ *
+ ******************************************************************************/
+
+void acpi_db_add_to_history(char *command_line)
+{
+	u16 cmd_len;
+	u16 buffer_len;
+
+	/* Put command into the next available slot */
+
+	cmd_len = (u16)strlen(command_line);
+	if (!cmd_len) {
+		return;
+	}
+
+	if (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command !=
+	    NULL) {
+		buffer_len =
+		    (u16)
+		    strlen(acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+			   command);
+
+		if (cmd_len > buffer_len) {
+			acpi_os_free(acpi_gbl_history_buffer
+				     [acpi_gbl_next_history_index].command);
+			acpi_gbl_history_buffer[acpi_gbl_next_history_index].
+			    command = acpi_os_allocate(cmd_len + 1);
+		}
+	} else {
+		acpi_gbl_history_buffer[acpi_gbl_next_history_index].command =
+		    acpi_os_allocate(cmd_len + 1);
+	}
+
+	strcpy(acpi_gbl_history_buffer[acpi_gbl_next_history_index].command,
+	       command_line);
+
+	acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num =
+	    acpi_gbl_next_cmd_num;
+
+	/* Adjust indexes */
+
+	if ((acpi_gbl_num_history == HISTORY_SIZE) &&
+	    (acpi_gbl_next_history_index == acpi_gbl_lo_history)) {
+		acpi_gbl_lo_history++;
+		if (acpi_gbl_lo_history >= HISTORY_SIZE) {
+			acpi_gbl_lo_history = 0;
+		}
+	}
+
+	acpi_gbl_next_history_index++;
+	if (acpi_gbl_next_history_index >= HISTORY_SIZE) {
+		acpi_gbl_next_history_index = 0;
+	}
+
+	acpi_gbl_next_cmd_num++;
+	if (acpi_gbl_num_history < HISTORY_SIZE) {
+		acpi_gbl_num_history++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_history
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display the contents of the history buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_display_history(void)
+{
+	u32 i;
+	u16 history_index;
+
+	history_index = acpi_gbl_lo_history;
+
+	/* Dump entire history buffer */
+
+	for (i = 0; i < acpi_gbl_num_history; i++) {
+		if (acpi_gbl_history_buffer[history_index].command) {
+			acpi_os_printf("%3ld %s\n",
+				       acpi_gbl_history_buffer[history_index].
+				       cmd_num,
+				       acpi_gbl_history_buffer[history_index].
+				       command);
+		}
+
+		history_index++;
+		if (history_index >= HISTORY_SIZE) {
+			history_index = 0;
+		}
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_from_history
+ *
+ * PARAMETERS:  command_num_arg         - String containing the number of the
+ *                                        command to be retrieved
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_from_history(char *command_num_arg)
+{
+	u32 cmd_num;
+
+	if (command_num_arg == NULL) {
+		cmd_num = acpi_gbl_next_cmd_num - 1;
+	}
+
+	else {
+		cmd_num = strtoul(command_num_arg, NULL, 0);
+	}
+
+	return (acpi_db_get_history_by_index(cmd_num));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_history_by_index
+ *
+ * PARAMETERS:  cmd_num             - Index of the desired history entry.
+ *                                    Values are 0...(acpi_gbl_next_cmd_num - 1)
+ *
+ * RETURN:      Pointer to the retrieved command. Null on error.
+ *
+ * DESCRIPTION: Get a command from the history buffer
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_history_by_index(u32 cmd_num)
+{
+	u32 i;
+	u16 history_index;
+
+	/* Search history buffer */
+
+	history_index = acpi_gbl_lo_history;
+	for (i = 0; i < acpi_gbl_num_history; i++) {
+		if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) {
+
+			/* Found the command, return it */
+
+			return (acpi_gbl_history_buffer[history_index].command);
+		}
+
+		/* History buffer is circular */
+
+		history_index++;
+		if (history_index >= HISTORY_SIZE) {
+			history_index = 0;
+		}
+	}
+
+	acpi_os_printf("Invalid history number: %u\n", history_index);
+	return (NULL);
+}
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
new file mode 100644
index 0000000..7f1b6ec
--- /dev/null
+++ b/drivers/acpi/acpica/dbinput.c
@@ -0,0 +1,1274 @@
+/*******************************************************************************
+ *
+ * Module Name: dbinput - user front-end to the AML debugger
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbinput")
+
+/* Local prototypes */
+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);
+
+static u8
+acpi_db_match_command_help(char *command,
+			   const struct acpi_db_command_help *help);
+
+/*
+ * Top-level debugger commands.
+ *
+ * This list of commands must match the string table below it
+ */
+enum acpi_ex_debugger_commands {
+	CMD_NOT_FOUND = 0,
+	CMD_NULL,
+	CMD_ALLOCATIONS,
+	CMD_ARGS,
+	CMD_ARGUMENTS,
+	CMD_BREAKPOINT,
+	CMD_BUSINFO,
+	CMD_CALL,
+	CMD_DEBUG,
+	CMD_DISASSEMBLE,
+	CMD_DISASM,
+	CMD_DUMP,
+	CMD_EVALUATE,
+	CMD_EXECUTE,
+	CMD_EXIT,
+	CMD_FIND,
+	CMD_GO,
+	CMD_HANDLERS,
+	CMD_HELP,
+	CMD_HELP2,
+	CMD_HISTORY,
+	CMD_HISTORY_EXE,
+	CMD_HISTORY_LAST,
+	CMD_INFORMATION,
+	CMD_INTEGRITY,
+	CMD_INTO,
+	CMD_LEVEL,
+	CMD_LIST,
+	CMD_LOCALS,
+	CMD_LOCKS,
+	CMD_METHODS,
+	CMD_NAMESPACE,
+	CMD_NOTIFY,
+	CMD_OBJECTS,
+	CMD_OSI,
+	CMD_OWNER,
+	CMD_PATHS,
+	CMD_PREDEFINED,
+	CMD_PREFIX,
+	CMD_QUIT,
+	CMD_REFERENCES,
+	CMD_RESOURCES,
+	CMD_RESULTS,
+	CMD_SET,
+	CMD_STATS,
+	CMD_STOP,
+	CMD_TABLES,
+	CMD_TEMPLATE,
+	CMD_TRACE,
+	CMD_TREE,
+	CMD_TYPE,
+#ifdef ACPI_APPLICATION
+	CMD_ENABLEACPI,
+	CMD_EVENT,
+	CMD_GPE,
+	CMD_GPES,
+	CMD_SCI,
+	CMD_SLEEP,
+
+	CMD_CLOSE,
+	CMD_LOAD,
+	CMD_OPEN,
+	CMD_UNLOAD,
+
+	CMD_TERMINATE,
+	CMD_THREADS,
+
+	CMD_TEST,
+#endif
+};
+
+#define CMD_FIRST_VALID     2
+
+/* Second parameter is the required argument count */
+
+static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
+	{"<NOT FOUND>", 0},
+	{"<NULL>", 0},
+	{"ALLOCATIONS", 0},
+	{"ARGS", 0},
+	{"ARGUMENTS", 0},
+	{"BREAKPOINT", 1},
+	{"BUSINFO", 0},
+	{"CALL", 0},
+	{"DEBUG", 1},
+	{"DISASSEMBLE", 1},
+	{"DISASM", 1},
+	{"DUMP", 1},
+	{"EVALUATE", 1},
+	{"EXECUTE", 1},
+	{"EXIT", 0},
+	{"FIND", 1},
+	{"GO", 0},
+	{"HANDLERS", 0},
+	{"HELP", 0},
+	{"?", 0},
+	{"HISTORY", 0},
+	{"!", 1},
+	{"!!", 0},
+	{"INFORMATION", 0},
+	{"INTEGRITY", 0},
+	{"INTO", 0},
+	{"LEVEL", 0},
+	{"LIST", 0},
+	{"LOCALS", 0},
+	{"LOCKS", 0},
+	{"METHODS", 0},
+	{"NAMESPACE", 0},
+	{"NOTIFY", 2},
+	{"OBJECTS", 0},
+	{"OSI", 0},
+	{"OWNER", 1},
+	{"PATHS", 0},
+	{"PREDEFINED", 0},
+	{"PREFIX", 0},
+	{"QUIT", 0},
+	{"REFERENCES", 1},
+	{"RESOURCES", 0},
+	{"RESULTS", 0},
+	{"SET", 3},
+	{"STATS", 1},
+	{"STOP", 0},
+	{"TABLES", 0},
+	{"TEMPLATE", 1},
+	{"TRACE", 1},
+	{"TREE", 0},
+	{"TYPE", 1},
+#ifdef ACPI_APPLICATION
+	{"ENABLEACPI", 0},
+	{"EVENT", 1},
+	{"GPE", 1},
+	{"GPES", 0},
+	{"SCI", 0},
+	{"SLEEP", 0},
+
+	{"CLOSE", 0},
+	{"LOAD", 1},
+	{"OPEN", 1},
+	{"UNLOAD", 1},
+
+	{"TERMINATE", 0},
+	{"THREADS", 3},
+
+	{"TEST", 1},
+#endif
+	{NULL, 0}
+};
+
+/*
+ * Help for all debugger commands. First argument is the number of lines
+ * of help to output for the command.
+ */
+static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
+	{0, "\nGeneral-Purpose Commands:", "\n"},
+	{1, "  Allocations", "Display list of current memory allocations\n"},
+	{2, "  Dump <Address>|<Namepath>", "\n"},
+	{0, "       [Byte|Word|Dword|Qword]",
+	 "Display ACPI objects or memory\n"},
+	{1, "  Handlers", "Info about global handlers\n"},
+	{1, "  Help [Command]", "This help screen or individual command\n"},
+	{1, "  History", "Display command history buffer\n"},
+	{1, "  Level <DebugLevel>] [console]",
+	 "Get/Set debug level for file or console\n"},
+	{1, "  Locks", "Current status of internal mutexes\n"},
+	{1, "  Osi [Install|Remove <name>]",
+	 "Display or modify global _OSI list\n"},
+	{1, "  Quit or Exit", "Exit this command\n"},
+	{8, "  Stats <SubCommand>",
+	 "Display namespace and memory statistics\n"},
+	{1, "     Allocations", "Display list of current memory allocations\n"},
+	{1, "     Memory", "Dump internal memory lists\n"},
+	{1, "     Misc", "Namespace search and mutex stats\n"},
+	{1, "     Objects", "Summary of namespace objects\n"},
+	{1, "     Sizes", "Sizes for each of the internal objects\n"},
+	{1, "     Stack", "Display CPU stack usage\n"},
+	{1, "     Tables", "Info about current ACPI table(s)\n"},
+	{1, "  Tables", "Display info about loaded ACPI tables\n"},
+	{1, "  ! <CommandNumber>", "Execute command from history buffer\n"},
+	{1, "  !!", "Execute last command again\n"},
+
+	{0, "\nNamespace Access Commands:", "\n"},
+	{1, "  Businfo", "Display system bus info\n"},
+	{1, "  Disassemble <Method>", "Disassemble a control method\n"},
+	{1, "  Find <AcpiName> (? is wildcard)",
+	 "Find ACPI name(s) with wildcards\n"},
+	{1, "  Integrity", "Validate namespace integrity\n"},
+	{1, "  Methods", "Display list of loaded control methods\n"},
+	{1, "  Namespace [Object] [Depth]",
+	 "Display loaded namespace tree/subtree\n"},
+	{1, "  Notify <Object> <Value>", "Send a notification on Object\n"},
+	{1, "  Objects [ObjectType]",
+	 "Display summary of all objects or just given type\n"},
+	{1, "  Owner <OwnerId> [Depth]",
+	 "Display loaded namespace by object owner\n"},
+	{1, "  Paths", "Display full pathnames of namespace objects\n"},
+	{1, "  Predefined", "Check all predefined names\n"},
+	{1, "  Prefix [<Namepath>]", "Set or Get current execution prefix\n"},
+	{1, "  References <Addr>", "Find all references to object at addr\n"},
+	{1, "  Resources [DeviceName]",
+	 "Display Device resources (no arg = all devices)\n"},
+	{1, "  Set N <NamedObject> <Value>", "Set value for named integer\n"},
+	{1, "  Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"},
+	{1, "  Type <Object>", "Display object type\n"},
+
+	{0, "\nControl Method Execution Commands:", "\n"},
+	{1, "  Arguments (or Args)", "Display method arguments\n"},
+	{1, "  Breakpoint <AmlOffset>", "Set an AML execution breakpoint\n"},
+	{1, "  Call", "Run to next control method invocation\n"},
+	{1, "  Debug <Namepath> [Arguments]", "Single Step a control method\n"},
+	{6, "  Evaluate", "Synonym for Execute\n"},
+	{5, "  Execute <Namepath> [Arguments]", "Execute control method\n"},
+	{1, "     Hex Integer", "Integer method argument\n"},
+	{1, "     \"Ascii String\"", "String method argument\n"},
+	{1, "     (Hex Byte List)", "Buffer method argument\n"},
+	{1, "     [Package Element List]", "Package method argument\n"},
+	{1, "  Go", "Allow method to run to completion\n"},
+	{1, "  Information", "Display info about the current method\n"},
+	{1, "  Into", "Step into (not over) a method call\n"},
+	{1, "  List [# of Aml Opcodes]", "Display method ASL statements\n"},
+	{1, "  Locals", "Display method local variables\n"},
+	{1, "  Results", "Display method result stack\n"},
+	{1, "  Set <A|L> <#> <Value>", "Set method data (Arguments/Locals)\n"},
+	{1, "  Stop", "Terminate control method\n"},
+	{5, "  Trace <State> [<Namepath>] [Once]",
+	 "Trace control method execution\n"},
+	{1, "     Enable", "Enable all messages\n"},
+	{1, "     Disable", "Disable tracing\n"},
+	{1, "     Method", "Enable method execution messages\n"},
+	{1, "     Opcode", "Enable opcode execution messages\n"},
+	{1, "  Tree", "Display control method calling tree\n"},
+	{1, "  <Enter>", "Single step next AML opcode (over calls)\n"},
+
+#ifdef ACPI_APPLICATION
+	{0, "\nHardware Simulation Commands:", "\n"},
+	{1, "  EnableAcpi", "Enable ACPI (hardware) mode\n"},
+	{1, "  Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"},
+	{1, "  Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"},
+	{1, "  Gpes", "Display info on all GPE devices\n"},
+	{1, "  Sci", "Generate an SCI\n"},
+	{1, "  Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"},
+
+	{0, "\nFile I/O Commands:", "\n"},
+	{1, "  Close", "Close debug output file\n"},
+	{1, "  Load <Input Filename>", "Load ACPI table from a file\n"},
+	{1, "  Open <Output Filename>", "Open a file for debug output\n"},
+	{1, "  Unload <Namepath>",
+	 "Unload an ACPI table via namespace object\n"},
+
+	{0, "\nUser Space Commands:", "\n"},
+	{1, "  Terminate", "Delete namespace and all internal objects\n"},
+	{1, "  Thread <Threads><Loops><NamePath>",
+	 "Spawn threads to execute method(s)\n"},
+
+	{0, "\nDebug Test Commands:", "\n"},
+	{3, "  Test <TestName>", "Invoke a debug test\n"},
+	{1, "     Objects", "Read/write/compare all namespace data objects\n"},
+	{1, "     Predefined",
+	 "Execute all ACPI predefined names (_STA, etc.)\n"},
+#endif
+	{0, NULL, NULL}
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command_help
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              help                - Help table entry to attempt match
+ *
+ * RETURN:      TRUE if command matched, FALSE otherwise
+ *
+ * DESCRIPTION: Attempt to match a command in the help table in order to
+ *              print help information for a single command.
+ *
+ ******************************************************************************/
+
+static u8
+acpi_db_match_command_help(char *command,
+			   const struct acpi_db_command_help *help)
+{
+	char *invocation = help->invocation;
+	u32 line_count;
+
+	/* Valid commands in the help table begin with a couple of spaces */
+
+	if (*invocation != ' ') {
+		return (FALSE);
+	}
+
+	while (*invocation == ' ') {
+		invocation++;
+	}
+
+	/* Match command name (full command or substring) */
+
+	while ((*command) && (*invocation) && (*invocation != ' ')) {
+		if (tolower((int)*command) != tolower((int)*invocation)) {
+			return (FALSE);
+		}
+
+		invocation++;
+		command++;
+	}
+
+	/* Print the appropriate number of help lines */
+
+	line_count = help->line_count;
+	while (line_count) {
+		acpi_os_printf("%-38s : %s", help->invocation,
+			       help->description);
+		help++;
+		line_count--;
+	}
+
+	return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_command_info
+ *
+ * PARAMETERS:  command             - Command string to match
+ *              display_all         - Display all matching commands, or just
+ *                                    the first one (substring match)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help information for a Debugger command.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_command_info(char *command, u8 display_all)
+{
+	const struct acpi_db_command_help *next;
+	u8 matched;
+
+	next = acpi_gbl_db_command_help;
+	while (next->invocation) {
+		matched = acpi_db_match_command_help(command, next);
+		if (!display_all && matched) {
+			return;
+		}
+
+		next++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_help
+ *
+ * PARAMETERS:  command             - Optional command string to display help.
+ *                                    if not specified, all debugger command
+ *                                    help strings are displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display help for a single debugger command, or all of them.
+ *
+ ******************************************************************************/
+
+static void acpi_db_display_help(char *command)
+{
+	const struct acpi_db_command_help *next = acpi_gbl_db_command_help;
+
+	if (!command) {
+
+		/* No argument to help, display help for all commands */
+
+		while (next->invocation) {
+			acpi_os_printf("%-38s%s", next->invocation,
+				       next->description);
+			next++;
+		}
+	} else {
+		/* Display help for all commands that match the subtring */
+
+		acpi_db_display_command_info(command, TRUE);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_next_token
+ *
+ * PARAMETERS:  string          - Command buffer
+ *              next            - Return value, end of next token
+ *
+ * RETURN:      Pointer to the start of the next token.
+ *
+ * DESCRIPTION: Command line parsing. Get the next token on the command line
+ *
+ ******************************************************************************/
+
+char *acpi_db_get_next_token(char *string,
+			     char **next, acpi_object_type * return_type)
+{
+	char *start;
+	u32 depth;
+	acpi_object_type type = ACPI_TYPE_INTEGER;
+
+	/* At end of buffer? */
+
+	if (!string || !(*string)) {
+		return (NULL);
+	}
+
+	/* Remove any spaces at the beginning */
+
+	if (*string == ' ') {
+		while (*string && (*string == ' ')) {
+			string++;
+		}
+
+		if (!(*string)) {
+			return (NULL);
+		}
+	}
+
+	switch (*string) {
+	case '"':
+
+		/* This is a quoted string, scan until closing quote */
+
+		string++;
+		start = string;
+		type = ACPI_TYPE_STRING;
+
+		/* Find end of string */
+
+		while (*string && (*string != '"')) {
+			string++;
+		}
+		break;
+
+	case '(':
+
+		/* This is the start of a buffer, scan until closing paren */
+
+		string++;
+		start = string;
+		type = ACPI_TYPE_BUFFER;
+
+		/* Find end of buffer */
+
+		while (*string && (*string != ')')) {
+			string++;
+		}
+		break;
+
+	case '[':
+
+		/* This is the start of a package, scan until closing bracket */
+
+		string++;
+		depth = 1;
+		start = string;
+		type = ACPI_TYPE_PACKAGE;
+
+		/* Find end of package (closing bracket) */
+
+		while (*string) {
+
+			/* Handle String package elements */
+
+			if (*string == '"') {
+				/* Find end of string */
+
+				string++;
+				while (*string && (*string != '"')) {
+					string++;
+				}
+				if (!(*string)) {
+					break;
+				}
+			} else if (*string == '[') {
+				depth++;	/* A nested package declaration */
+			} else if (*string == ']') {
+				depth--;
+				if (depth == 0) {	/* Found final package closing bracket */
+					break;
+				}
+			}
+
+			string++;
+		}
+		break;
+
+	default:
+
+		start = string;
+
+		/* Find end of token */
+
+		while (*string && (*string != ' ')) {
+			string++;
+		}
+		break;
+	}
+
+	if (!(*string)) {
+		*next = NULL;
+	} else {
+		*string = 0;
+		*next = string + 1;
+	}
+
+	*return_type = type;
+	return (start);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_line
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *
+ * RETURN:      Count of arguments to the command
+ *
+ * DESCRIPTION: Get the next command line from the user. Gets entire line
+ *              up to the next newline
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_get_line(char *input_buffer)
+{
+	u32 i;
+	u32 count;
+	char *next;
+	char *this;
+
+	if (acpi_ut_safe_strcpy
+	    (acpi_gbl_db_parsed_buf, sizeof(acpi_gbl_db_parsed_buf),
+	     input_buffer)) {
+		acpi_os_printf
+		    ("Buffer overflow while parsing input line (max %u characters)\n",
+		     sizeof(acpi_gbl_db_parsed_buf));
+		return (0);
+	}
+
+	this = acpi_gbl_db_parsed_buf;
+	for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++) {
+		acpi_gbl_db_args[i] = acpi_db_get_next_token(this, &next,
+							     &acpi_gbl_db_arg_types
+							     [i]);
+		if (!acpi_gbl_db_args[i]) {
+			break;
+		}
+
+		this = next;
+	}
+
+	/* Uppercase the actual command */
+
+	if (acpi_gbl_db_args[0]) {
+		acpi_ut_strupr(acpi_gbl_db_args[0]);
+	}
+
+	count = i;
+	if (count) {
+		count--;	/* Number of args only */
+	}
+
+	return (count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_command
+ *
+ * PARAMETERS:  user_command            - User command line
+ *
+ * RETURN:      Index into command array, -1 if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+static u32 acpi_db_match_command(char *user_command)
+{
+	u32 i;
+
+	if (!user_command || user_command[0] == 0) {
+		return (CMD_NULL);
+	}
+
+	for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++) {
+		if (strstr(acpi_gbl_db_commands[i].name, user_command) ==
+		    acpi_gbl_db_commands[i].name) {
+			return (i);
+		}
+	}
+
+	/* Command not recognized */
+
+	return (CMD_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_command_dispatch
+ *
+ * PARAMETERS:  input_buffer        - Command line buffer
+ *              walk_state          - Current walk
+ *              op                  - Current (executing) parse op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Command dispatcher.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_command_dispatch(char *input_buffer,
+			 struct acpi_walk_state * walk_state,
+			 union acpi_parse_object * op)
+{
+	u32 temp;
+	u32 command_index;
+	u32 param_count;
+	char *command_line;
+	acpi_status status = AE_CTRL_TRUE;
+
+	/* If acpi_terminate has been called, terminate this thread */
+
+	if (acpi_gbl_db_terminate_threads) {
+		return (AE_CTRL_TERMINATE);
+	}
+
+	/* Find command and add to the history buffer */
+
+	param_count = acpi_db_get_line(input_buffer);
+	command_index = acpi_db_match_command(acpi_gbl_db_args[0]);
+	temp = 0;
+
+	/*
+	 * We don't want to add the !! command to the history buffer. It
+	 * would cause an infinite loop because it would always be the
+	 * previous command.
+	 */
+	if (command_index != CMD_HISTORY_LAST) {
+		acpi_db_add_to_history(input_buffer);
+	}
+
+	/* Verify that we have the minimum number of params */
+
+	if (param_count < acpi_gbl_db_commands[command_index].min_args) {
+		acpi_os_printf
+		    ("%u parameters entered, [%s] requires %u parameters\n",
+		     param_count, acpi_gbl_db_commands[command_index].name,
+		     acpi_gbl_db_commands[command_index].min_args);
+
+		acpi_db_display_command_info(acpi_gbl_db_commands
+					     [command_index].name, FALSE);
+		return (AE_CTRL_TRUE);
+	}
+
+	/* Decode and dispatch the command */
+
+	switch (command_index) {
+	case CMD_NULL:
+
+		if (op) {
+			return (AE_OK);
+		}
+		break;
+
+	case CMD_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_ut_dump_allocations((u32)-1, NULL);
+#endif
+		break;
+
+	case CMD_ARGS:
+	case CMD_ARGUMENTS:
+
+		acpi_db_display_arguments();
+		break;
+
+	case CMD_BREAKPOINT:
+
+		acpi_db_set_method_breakpoint(acpi_gbl_db_args[1], walk_state,
+					      op);
+		break;
+
+	case CMD_BUSINFO:
+
+		acpi_db_get_bus_info();
+		break;
+
+	case CMD_CALL:
+
+		acpi_db_set_method_call_breakpoint(op);
+		status = AE_OK;
+		break;
+
+	case CMD_DEBUG:
+
+		acpi_db_execute(acpi_gbl_db_args[1],
+				&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+				EX_SINGLE_STEP);
+		break;
+
+	case CMD_DISASSEMBLE:
+	case CMD_DISASM:
+
+		(void)acpi_db_disassemble_method(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_DUMP:
+
+		acpi_db_decode_and_display_object(acpi_gbl_db_args[1],
+						  acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_EVALUATE:
+	case CMD_EXECUTE:
+
+		acpi_db_execute(acpi_gbl_db_args[1],
+				&acpi_gbl_db_args[2], &acpi_gbl_db_arg_types[2],
+				EX_NO_SINGLE_STEP);
+		break;
+
+	case CMD_FIND:
+
+		status = acpi_db_find_name_in_namespace(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_GO:
+
+		acpi_gbl_cm_single_step = FALSE;
+		return (AE_OK);
+
+	case CMD_HANDLERS:
+
+		acpi_db_display_handlers();
+		break;
+
+	case CMD_HELP:
+	case CMD_HELP2:
+
+		acpi_db_display_help(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_HISTORY:
+
+		acpi_db_display_history();
+		break;
+
+	case CMD_HISTORY_EXE:	/* ! command */
+
+		command_line = acpi_db_get_from_history(acpi_gbl_db_args[1]);
+		if (!command_line) {
+			return (AE_CTRL_TRUE);
+		}
+
+		status = acpi_db_command_dispatch(command_line, walk_state, op);
+		return (status);
+
+	case CMD_HISTORY_LAST:	/* !! command */
+
+		command_line = acpi_db_get_from_history(NULL);
+		if (!command_line) {
+			return (AE_CTRL_TRUE);
+		}
+
+		status = acpi_db_command_dispatch(command_line, walk_state, op);
+		return (status);
+
+	case CMD_INFORMATION:
+
+		acpi_db_display_method_info(op);
+		break;
+
+	case CMD_INTEGRITY:
+
+		acpi_db_check_integrity();
+		break;
+
+	case CMD_INTO:
+
+		if (op) {
+			acpi_gbl_cm_single_step = TRUE;
+			return (AE_OK);
+		}
+		break;
+
+	case CMD_LEVEL:
+
+		if (param_count == 0) {
+			acpi_os_printf
+			    ("Current debug level for file output is:    %8.8lX\n",
+			     acpi_gbl_db_debug_level);
+			acpi_os_printf
+			    ("Current debug level for console output is: %8.8lX\n",
+			     acpi_gbl_db_console_debug_level);
+		} else if (param_count == 2) {
+			temp = acpi_gbl_db_console_debug_level;
+			acpi_gbl_db_console_debug_level =
+			    strtoul(acpi_gbl_db_args[1], NULL, 16);
+			acpi_os_printf
+			    ("Debug Level for console output was %8.8lX, now %8.8lX\n",
+			     temp, acpi_gbl_db_console_debug_level);
+		} else {
+			temp = acpi_gbl_db_debug_level;
+			acpi_gbl_db_debug_level =
+			    strtoul(acpi_gbl_db_args[1], NULL, 16);
+			acpi_os_printf
+			    ("Debug Level for file output was %8.8lX, now %8.8lX\n",
+			     temp, acpi_gbl_db_debug_level);
+		}
+		break;
+
+	case CMD_LIST:
+
+		acpi_db_disassemble_aml(acpi_gbl_db_args[1], op);
+		break;
+
+	case CMD_LOCKS:
+
+		acpi_db_display_locks();
+		break;
+
+	case CMD_LOCALS:
+
+		acpi_db_display_locals();
+		break;
+
+	case CMD_METHODS:
+
+		status = acpi_db_display_objects("METHOD", acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_NAMESPACE:
+
+		acpi_db_dump_namespace(acpi_gbl_db_args[1],
+				       acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_NOTIFY:
+
+		temp = strtoul(acpi_gbl_db_args[2], NULL, 0);
+		acpi_db_send_notify(acpi_gbl_db_args[1], temp);
+		break;
+
+	case CMD_OBJECTS:
+
+		acpi_ut_strupr(acpi_gbl_db_args[1]);
+		status =
+		    acpi_db_display_objects(acpi_gbl_db_args[1],
+					    acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_OSI:
+
+		acpi_db_display_interfaces(acpi_gbl_db_args[1],
+					   acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_OWNER:
+
+		acpi_db_dump_namespace_by_owner(acpi_gbl_db_args[1],
+						acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_PATHS:
+
+		acpi_db_dump_namespace_paths();
+		break;
+
+	case CMD_PREFIX:
+
+		acpi_db_set_scope(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_REFERENCES:
+
+		acpi_db_find_references(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_RESOURCES:
+
+		acpi_db_display_resources(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_RESULTS:
+
+		acpi_db_display_results();
+		break;
+
+	case CMD_SET:
+
+		acpi_db_set_method_data(acpi_gbl_db_args[1],
+					acpi_gbl_db_args[2],
+					acpi_gbl_db_args[3]);
+		break;
+
+	case CMD_STATS:
+
+		status = acpi_db_display_statistics(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_STOP:
+
+		return (AE_NOT_IMPLEMENTED);
+
+	case CMD_TABLES:
+
+		acpi_db_display_table_info(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_TEMPLATE:
+
+		acpi_db_display_template(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_TRACE:
+
+		acpi_db_trace(acpi_gbl_db_args[1], acpi_gbl_db_args[2],
+			      acpi_gbl_db_args[3]);
+		break;
+
+	case CMD_TREE:
+
+		acpi_db_display_calling_tree();
+		break;
+
+	case CMD_TYPE:
+
+		acpi_db_display_object_type(acpi_gbl_db_args[1]);
+		break;
+
+#ifdef ACPI_APPLICATION
+
+		/* Hardware simulation commands. */
+
+	case CMD_ENABLEACPI:
+#if (!ACPI_REDUCED_HARDWARE)
+
+		status = acpi_enable();
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("AcpiEnable failed (Status=%X)\n",
+				       status);
+			return (status);
+		}
+#endif				/* !ACPI_REDUCED_HARDWARE */
+		break;
+
+	case CMD_EVENT:
+
+		acpi_os_printf("Event command not implemented\n");
+		break;
+
+	case CMD_GPE:
+
+		acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
+		break;
+
+	case CMD_GPES:
+
+		acpi_db_display_gpes();
+		break;
+
+	case CMD_SCI:
+
+		acpi_db_generate_sci();
+		break;
+
+	case CMD_SLEEP:
+
+		status = acpi_db_sleep(acpi_gbl_db_args[1]);
+		break;
+
+		/* File I/O commands. */
+
+	case CMD_CLOSE:
+
+		acpi_db_close_debug_file();
+		break;
+
+	case CMD_LOAD:
+
+		status =
+		    acpi_db_get_table_from_file(acpi_gbl_db_args[1], NULL,
+						FALSE);
+		break;
+
+	case CMD_OPEN:
+
+		acpi_db_open_debug_file(acpi_gbl_db_args[1]);
+		break;
+
+		/* User space commands. */
+
+	case CMD_TERMINATE:
+
+		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+		acpi_ut_subsystem_shutdown();
+
+		/*
+		 * TBD: [Restructure] Need some way to re-initialize without
+		 * re-creating the semaphores!
+		 */
+
+		/*  acpi_initialize (NULL); */
+		break;
+
+	case CMD_THREADS:
+
+		acpi_db_create_execution_threads(acpi_gbl_db_args[1],
+						 acpi_gbl_db_args[2],
+						 acpi_gbl_db_args[3]);
+		break;
+
+		/* Debug test commands. */
+
+	case CMD_PREDEFINED:
+
+		acpi_db_check_predefined_names();
+		break;
+
+	case CMD_TEST:
+
+		acpi_db_execute_test(acpi_gbl_db_args[1]);
+		break;
+
+	case CMD_UNLOAD:
+
+		acpi_db_unload_acpi_table(acpi_gbl_db_args[1]);
+		break;
+#endif
+
+	case CMD_EXIT:
+	case CMD_QUIT:
+
+		if (op) {
+			acpi_os_printf("Method execution terminated\n");
+			return (AE_CTRL_TERMINATE);
+		}
+
+		if (!acpi_gbl_db_output_to_file) {
+			acpi_dbg_level = ACPI_DEBUG_DEFAULT;
+		}
+#ifdef ACPI_APPLICATION
+		acpi_db_close_debug_file();
+#endif
+		acpi_gbl_db_terminate_threads = TRUE;
+		return (AE_CTRL_TERMINATE);
+
+	case CMD_NOT_FOUND:
+	default:
+
+		acpi_os_printf("%s: unknown command\n", acpi_gbl_db_args[0]);
+		return (AE_CTRL_TRUE);
+	}
+
+	if (ACPI_SUCCESS(status)) {
+		status = AE_CTRL_TRUE;
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_thread
+ *
+ * PARAMETERS:  context         - Not used
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Debugger execute thread. Waits for a command line, then
+ *              simply dispatches it.
+ *
+ ******************************************************************************/
+
+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_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);
+	}
+}
+
+/*******************************************************************************
+ *
+ * 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
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Command line execution for the AML debugger. Commands are
+ *              matched and dispatched here.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
+{
+	acpi_status status = AE_OK;
+
+	acpi_os_printf("\n");
+
+	/* TBD: [Restructure] Need a separate command line buffer for step mode */
+
+	while (!acpi_gbl_db_terminate_threads) {
+
+		/* 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);
+		}
+
+		/* Get the user input line */
+
+		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);
+		}
+
+		/* Check for single or multithreaded debug */
+
+		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);
+			}
+
+			status =
+			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
+						  ACPI_WAIT_FOREVER);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+		} else {
+			/* Just call to the command line interpreter */
+
+			acpi_db_single_thread();
+		}
+	}
+
+	/* Shut down the debugger */
+
+	acpi_terminate_debugger();
+
+	/*
+	 * Only this thread (the original thread) should actually terminate the
+	 * subsystem, because all the semaphores are deleted during termination
+	 */
+	status = acpi_terminate();
+	return (status);
+}
diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c
new file mode 100644
index 0000000..01e5a71
--- /dev/null
+++ b/drivers/acpi/acpica/dbmethod.c
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ *
+ * Module Name: dbmethod - Debug commands for control methods
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acparser.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbmethod")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_breakpoint
+ *
+ * PARAMETERS:  location            - AML offset of breakpoint
+ *              walk_state          - Current walk info
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+void
+acpi_db_set_method_breakpoint(char *location,
+			      struct acpi_walk_state *walk_state,
+			      union acpi_parse_object *op)
+{
+	u32 address;
+	u32 aml_offset;
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	/* Get and verify the breakpoint address */
+
+	address = strtoul(location, NULL, 16);
+	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+					walk_state->parser_state.aml_start);
+	if (address <= aml_offset) {
+		acpi_os_printf("Breakpoint %X is beyond current address %X\n",
+			       address, aml_offset);
+	}
+
+	/* Save breakpoint in current walk */
+
+	walk_state->user_breakpoint = address;
+	acpi_os_printf("Breakpoint set at AML offset %X\n", address);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_call_breakpoint
+ *
+ * PARAMETERS:  op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a breakpoint in a control method at the specified
+ *              AML offset
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op)
+{
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	acpi_gbl_step_to_next_call = TRUE;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_method_data
+ *
+ * PARAMETERS:  type_arg        - L for local, A for argument
+ *              index_arg       - which one
+ *              value_arg       - Value to set.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set a local or argument for the running control method.
+ *              NOTE: only object supported is Number.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg)
+{
+	char type;
+	u32 index;
+	u32 value;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	acpi_status status;
+	struct acpi_namespace_node *node;
+
+	/* Validate type_arg */
+
+	acpi_ut_strupr(type_arg);
+	type = type_arg[0];
+	if ((type != 'L') && (type != 'A') && (type != 'N')) {
+		acpi_os_printf("Invalid SET operand: %s\n", type_arg);
+		return;
+	}
+
+	value = strtoul(value_arg, NULL, 16);
+
+	if (type == 'N') {
+		node = acpi_db_convert_to_node(index_arg);
+		if (!node) {
+			return;
+		}
+
+		if (node->type != ACPI_TYPE_INTEGER) {
+			acpi_os_printf("Can only set Integer nodes\n");
+			return;
+		}
+		obj_desc = node->object;
+		obj_desc->integer.value = value;
+		return;
+	}
+
+	/* Get the index and value */
+
+	index = strtoul(index_arg, NULL, 16);
+
+	walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list);
+	if (!walk_state) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	/* Create and initialize the new object */
+
+	obj_desc = acpi_ut_create_integer_object((u64)value);
+	if (!obj_desc) {
+		acpi_os_printf("Could not create an internal object\n");
+		return;
+	}
+
+	/* Store the new object into the target */
+
+	switch (type) {
+	case 'A':
+
+		/* Set a method argument */
+
+		if (index > ACPI_METHOD_MAX_ARG) {
+			acpi_os_printf("Arg%u - Invalid argument name\n",
+				       index);
+			goto cleanup;
+		}
+
+		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG,
+						       index, obj_desc,
+						       walk_state);
+		if (ACPI_FAILURE(status)) {
+			goto cleanup;
+		}
+
+		obj_desc = walk_state->arguments[index].object;
+
+		acpi_os_printf("Arg%u: ", index);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+		break;
+
+	case 'L':
+
+		/* Set a method local */
+
+		if (index > ACPI_METHOD_MAX_LOCAL) {
+			acpi_os_printf
+			    ("Local%u - Invalid local variable name\n", index);
+			goto cleanup;
+		}
+
+		status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL,
+						       index, obj_desc,
+						       walk_state);
+		if (ACPI_FAILURE(status)) {
+			goto cleanup;
+		}
+
+		obj_desc = walk_state->local_variables[index].object;
+
+		acpi_os_printf("Local%u: ", index);
+		acpi_db_display_internal_object(obj_desc, walk_state);
+		break;
+
+	default:
+
+		break;
+	}
+
+cleanup:
+	acpi_ut_remove_reference(obj_desc);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_aml
+ *
+ * PARAMETERS:  statements          - Number of statements to disassemble
+ *              op                  - Current Op (from parse walk)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op)
+{
+	u32 num_statements = 8;
+
+	if (!op) {
+		acpi_os_printf("There is no method currently executing\n");
+		return;
+	}
+
+	if (statements) {
+		num_statements = strtoul(statements, NULL, 0);
+	}
+#ifdef ACPI_DISASSEMBLER
+	acpi_dm_disassemble(NULL, op, num_statements);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_disassemble_method
+ *
+ * PARAMETERS:  name            - Name of control method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
+ *              of statements specified.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_disassemble_method(char *name)
+{
+	acpi_status status;
+	union acpi_parse_object *op;
+	struct acpi_walk_state *walk_state;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *method;
+
+	method = acpi_db_convert_to_node(name);
+	if (!method) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	if (method->type != ACPI_TYPE_METHOD) {
+		ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method",
+			    name, acpi_ut_get_type_name(method->type)));
+		return (AE_BAD_PARAMETER);
+	}
+
+	obj_desc = method->object;
+
+	op = acpi_ps_create_scope_op(obj_desc->method.aml_start);
+	if (!op) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Create and initialize a new walk state */
+
+	walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL);
+	if (!walk_state) {
+		return (AE_NO_MEMORY);
+	}
+
+	status = acpi_ds_init_aml_walk(walk_state, op, NULL,
+				       obj_desc->method.aml_start,
+				       obj_desc->method.aml_length, NULL,
+				       ACPI_IMODE_LOAD_PASS1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+	walk_state->owner_id = obj_desc->method.owner_id;
+
+	/* Push start scope on scope stack and make it current */
+
+	status = acpi_ds_scope_stack_push(method, method->type, walk_state);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Parse the entire method AML including deferred operators */
+
+	walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE;
+	walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
+
+	status = acpi_ps_parse_aml(walk_state);
+
+#ifdef ACPI_DISASSEMBLER
+	(void)acpi_dm_parse_deferred_ops(op);
+
+	/* Now we can disassemble the method */
+
+	acpi_gbl_dm_opt_verbose = FALSE;
+	acpi_dm_disassemble(NULL, op, 0);
+	acpi_gbl_dm_opt_verbose = TRUE;
+#endif
+
+	acpi_ps_delete_parse_tree(op);
+
+	/* Method cleanup */
+
+	acpi_ns_delete_namespace_subtree(method);
+	acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
+	acpi_ut_release_owner_id(&obj_desc->method.owner_id);
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c
new file mode 100644
index 0000000..04ff1eb
--- /dev/null
+++ b/drivers/acpi/acpica/dbnames.c
@@ -0,0 +1,947 @@
+/*******************************************************************************
+ *
+ * Module Name: dbnames - Debugger commands for the acpi namespace
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbnames")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+			       u32 nesting_level,
+			       void *context, void **return_value);
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+		 u32 nesting_level, void *context, void **return_value);
+
+/*
+ * Arguments for the Objects command
+ * These object types map directly to the ACPI_TYPES
+ */
+static struct acpi_db_argument_info acpi_db_object_types[] = {
+	{"ANY"},
+	{"INTEGERS"},
+	{"STRINGS"},
+	{"BUFFERS"},
+	{"PACKAGES"},
+	{"FIELDS"},
+	{"DEVICES"},
+	{"EVENTS"},
+	{"METHODS"},
+	{"MUTEXES"},
+	{"REGIONS"},
+	{"POWERRESOURCES"},
+	{"PROCESSORS"},
+	{"THERMALZONES"},
+	{"BUFFERFIELDS"},
+	{"DDBHANDLES"},
+	{"DEBUG"},
+	{"REGIONFIELDS"},
+	{"BANKFIELDS"},
+	{"INDEXFIELDS"},
+	{"REFERENCES"},
+	{"ALIASES"},
+	{"METHODALIASES"},
+	{"NOTIFY"},
+	{"ADDRESSHANDLER"},
+	{"RESOURCE"},
+	{"RESOURCEFIELD"},
+	{"SCOPES"},
+	{NULL}			/* Must be null terminated */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_scope
+ *
+ * PARAMETERS:  name                - New scope path
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Set the "current scope" as maintained by this utility.
+ *              The scope is used as a prefix to ACPI paths.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_scope(char *name)
+{
+	acpi_status status;
+	struct acpi_namespace_node *node;
+
+	if (!name || name[0] == 0) {
+		acpi_os_printf("Current scope: %s\n", acpi_gbl_db_scope_buf);
+		return;
+	}
+
+	acpi_db_prep_namestring(name);
+
+	if (ACPI_IS_ROOT_PREFIX(name[0])) {
+
+		/* Validate new scope from the root */
+
+		status = acpi_ns_get_node(acpi_gbl_root_node, name,
+					  ACPI_NS_NO_UPSEARCH, &node);
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
+		}
+
+		acpi_gbl_db_scope_buf[0] = 0;
+	} else {
+		/* Validate new scope relative to old scope */
+
+		status = acpi_ns_get_node(acpi_gbl_db_scope_node, name,
+					  ACPI_NS_NO_UPSEARCH, &node);
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
+		}
+	}
+
+	/* Build the final pathname */
+
+	if (acpi_ut_safe_strcat
+	    (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), name)) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	if (acpi_ut_safe_strcat
+	    (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), "\\")) {
+		status = AE_BUFFER_OVERFLOW;
+		goto error_exit;
+	}
+
+	acpi_gbl_db_scope_node = node;
+	acpi_os_printf("New scope: %s\n", acpi_gbl_db_scope_buf);
+	return;
+
+error_exit:
+
+	acpi_os_printf("Could not attach scope: %s, %s\n",
+		       name, acpi_format_exception(status));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace
+ *
+ * PARAMETERS:  start_arg       - Node to begin namespace dump
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed
+ *              with type and other information.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace(char *start_arg, char *depth_arg)
+{
+	acpi_handle subtree_entry = acpi_gbl_root_node;
+	u32 max_depth = ACPI_UINT32_MAX;
+
+	/* No argument given, just start at the root and dump entire namespace */
+
+	if (start_arg) {
+		subtree_entry = acpi_db_convert_to_node(start_arg);
+		if (!subtree_entry) {
+			return;
+		}
+
+		/* Now we can check for the depth argument */
+
+		if (depth_arg) {
+			max_depth = strtoul(depth_arg, NULL, 0);
+		}
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n",
+		       ((struct acpi_namespace_node *)subtree_entry)->name.
+		       ascii, subtree_entry);
+
+	/* Display the subtree */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+			     ACPI_OWNER_ID_MAX, subtree_entry);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_paths
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump entire namespace with full object pathnames and object
+ *              type information. Alternative to "namespace" command.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_paths(void)
+{
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace (from root):\n");
+
+	/* Display the entire namespace */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY,
+				  ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX,
+				  acpi_gbl_root_node);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_namespace_by_owner
+ *
+ * PARAMETERS:  owner_arg       - Owner ID whose nodes will be displayed
+ *              depth_arg       - Maximum tree depth to be dumped
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump elements of the namespace that are owned by the owner_id.
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg)
+{
+	acpi_handle subtree_entry = acpi_gbl_root_node;
+	u32 max_depth = ACPI_UINT32_MAX;
+	acpi_owner_id owner_id;
+
+	owner_id = (acpi_owner_id) strtoul(owner_arg, NULL, 0);
+
+	/* Now we can check for the depth argument */
+
+	if (depth_arg) {
+		max_depth = strtoul(depth_arg, NULL, 0);
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf("ACPI Namespace by owner %X:\n", owner_id);
+
+	/* Display the subtree */
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+	acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth,
+			     owner_id, subtree_entry);
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_and_match_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Find a particular name/names within the namespace. Wildcards
+ *              are supported -- '?' matches any character.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_and_match_name(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	acpi_status status;
+	char *requested_name = (char *)context;
+	u32 i;
+	struct acpi_buffer buffer;
+	struct acpi_walk_info info;
+
+	/* Check for a name match */
+
+	for (i = 0; i < 4; i++) {
+
+		/* Wildcard support */
+
+		if ((requested_name[i] != '?') &&
+		    (requested_name[i] != ((struct acpi_namespace_node *)
+					   obj_handle)->name.ascii[i])) {
+
+			/* No match, just exit */
+
+			return (AE_OK);
+		}
+	}
+
+	/* Get the full pathname to this object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+	} else {
+		info.owner_id = ACPI_OWNER_ID_MAX;
+		info.debug_level = ACPI_UINT32_MAX;
+		info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+		acpi_os_printf("%32s", (char *)buffer.pointer);
+		(void)acpi_ns_dump_one_object(obj_handle, nesting_level, &info,
+					      NULL);
+		ACPI_FREE(buffer.pointer);
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_name_in_namespace
+ *
+ * PARAMETERS:  name_arg        - The 4-character ACPI name to find.
+ *                                wildcards are supported.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search the namespace for a given name (with wildcards)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_find_name_in_namespace(char *name_arg)
+{
+	char acpi_name[5] = "____";
+	char *acpi_name_ptr = acpi_name;
+
+	if (strlen(name_arg) > ACPI_NAME_SIZE) {
+		acpi_os_printf("Name must be no longer than 4 characters\n");
+		return (AE_OK);
+	}
+
+	/* Pad out name with underscores as necessary to create a 4-char name */
+
+	acpi_ut_strupr(name_arg);
+	while (*name_arg) {
+		*acpi_name_ptr = *name_arg;
+		acpi_name_ptr++;
+		name_arg++;
+	}
+
+	/* Walk the namespace from the root */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_walk_and_match_name,
+				  NULL, acpi_name, NULL);
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_predefined_names
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Detect and display predefined ACPI names (names that start with
+ *              an underscore)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_predefined_names(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	u32 *count = (u32 *)context;
+	const union acpi_predefined_info *predefined;
+	const union acpi_predefined_info *package = NULL;
+	char *pathname;
+	char string_buffer[48];
+
+	predefined = acpi_ut_match_predefined_method(node->name.ascii);
+	if (!predefined) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* If method returns a package, the info is in the next table entry */
+
+	if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
+		package = predefined + 1;
+	}
+
+	acpi_ut_get_expected_return_types(string_buffer,
+					  predefined->info.expected_btypes);
+
+	acpi_os_printf("%-32s Arguments %X, Return Types: %s", pathname,
+		       METHOD_GET_ARG_COUNT(predefined->info.argument_list),
+		       string_buffer);
+
+	if (package) {
+		acpi_os_printf(" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)",
+			       package->ret_info.type,
+			       package->ret_info.object_type1,
+			       package->ret_info.count1);
+	}
+
+	acpi_os_printf("\n");
+
+	/* Check that the declared argument count matches the ACPI spec */
+
+	acpi_ns_check_acpi_compliance(pathname, node, predefined);
+
+	ACPI_FREE(pathname);
+	(*count)++;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_predefined_names
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Validate all predefined names in the namespace
+ *
+ ******************************************************************************/
+
+void acpi_db_check_predefined_names(void)
+{
+	u32 count = 0;
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_walk_for_predefined_names, NULL,
+				  (void *)&count, NULL);
+
+	acpi_os_printf("Found %u predefined names in the namespace\n", count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_object_counts
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_object_counts(acpi_handle obj_handle,
+			       u32 nesting_level,
+			       void *context, void **return_value)
+{
+	struct acpi_object_info *info = (struct acpi_object_info *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+
+	if (node->type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_os_printf("[%4.4s]: Unknown object type %X\n",
+			       node->name.ascii, node->type);
+	} else {
+		info->types[node->type]++;
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_specific_objects
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_specific_objects(acpi_handle obj_handle,
+				  u32 nesting_level,
+				  void *context, void **return_value)
+{
+	struct acpi_walk_info *info = (struct acpi_walk_info *)context;
+	struct acpi_buffer buffer;
+	acpi_status status;
+
+	info->count++;
+
+	/* Get and display the full pathname to this object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+		return (AE_OK);
+	}
+
+	acpi_os_printf("%32s", (char *)buffer.pointer);
+	ACPI_FREE(buffer.pointer);
+
+	/* Dump short info about the object */
+
+	(void)acpi_ns_dump_one_object(obj_handle, nesting_level, info, NULL);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_objects
+ *
+ * PARAMETERS:  obj_type_arg        - Type of object to display
+ *              display_count_arg   - Max depth to display
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display objects in the namespace of the requested type
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg)
+{
+	struct acpi_walk_info info;
+	acpi_object_type type;
+	struct acpi_object_info *object_info;
+	u32 i;
+	u32 total_objects = 0;
+
+	/* No argument means display summary/count of all object types */
+
+	if (!obj_type_arg) {
+		object_info =
+		    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info));
+
+		/* Walk the namespace from the root */
+
+		(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+					  ACPI_UINT32_MAX,
+					  acpi_db_walk_for_object_counts, NULL,
+					  (void *)object_info, NULL);
+
+		acpi_os_printf("\nSummary of namespace objects:\n\n");
+
+		for (i = 0; i < ACPI_TOTAL_TYPES; i++) {
+			acpi_os_printf("%8u %s\n", object_info->types[i],
+				       acpi_ut_get_type_name(i));
+
+			total_objects += object_info->types[i];
+		}
+
+		acpi_os_printf("\n%8u Total namespace objects\n\n",
+			       total_objects);
+
+		ACPI_FREE(object_info);
+		return (AE_OK);
+	}
+
+	/* Get the object type */
+
+	type = acpi_db_match_argument(obj_type_arg, acpi_db_object_types);
+	if (type == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return (AE_OK);
+	}
+
+	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
+	acpi_os_printf
+	    ("Objects of type [%s] defined in the current ACPI Namespace:\n",
+	     acpi_ut_get_type_name(type));
+
+	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
+
+	info.count = 0;
+	info.owner_id = ACPI_OWNER_ID_MAX;
+	info.debug_level = ACPI_UINT32_MAX;
+	info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+
+	/* Walk the namespace from the root */
+
+	(void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+				  acpi_db_walk_for_specific_objects, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf
+	    ("\nFound %u objects of type [%s] in the current ACPI Namespace\n",
+	     info.count, acpi_ut_get_type_name(type));
+
+	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_integrity_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Examine one NS node for valid values.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_integrity_walk(acpi_handle obj_handle,
+		       u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_integrity_info *info =
+	    (struct acpi_integrity_info *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	union acpi_operand_object *object;
+	u8 alias = TRUE;
+
+	info->nodes++;
+
+	/* Verify the NS node, and dereference aliases */
+
+	while (alias) {
+		if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+			acpi_os_printf
+			    ("Invalid Descriptor Type for Node %p [%s] - "
+			     "is %2.2X should be %2.2X\n", node,
+			     acpi_ut_get_descriptor_name(node),
+			     ACPI_GET_DESCRIPTOR_TYPE(node),
+			     ACPI_DESC_TYPE_NAMED);
+			return (AE_OK);
+		}
+
+		if ((node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+		    (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+			node = (struct acpi_namespace_node *)node->object;
+		} else {
+			alias = FALSE;
+		}
+	}
+
+	if (node->type > ACPI_TYPE_LOCAL_MAX) {
+		acpi_os_printf("Invalid Object Type for Node %p, Type = %X\n",
+			       node, node->type);
+		return (AE_OK);
+	}
+
+	if (!acpi_ut_valid_acpi_name(node->name.ascii)) {
+		acpi_os_printf("Invalid AcpiName for Node %p\n", node);
+		return (AE_OK);
+	}
+
+	object = acpi_ns_get_attached_object(node);
+	if (object) {
+		info->objects++;
+		if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
+			acpi_os_printf
+			    ("Invalid Descriptor Type for Object %p [%s]\n",
+			     object, acpi_ut_get_descriptor_name(object));
+		}
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_check_integrity
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check entire namespace for data structure integrity
+ *
+ ******************************************************************************/
+
+void acpi_db_check_integrity(void)
+{
+	struct acpi_integrity_info info = { 0, 0 };
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_integrity_walk, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf("Verified %u namespace nodes with %u Objects\n",
+		       info.nodes, info.objects);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_walk_for_references
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check if this namespace object refers to the target object
+ *              that is passed in as the context value.
+ *
+ * Note: Currently doesn't check subobjects within the Node's object
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_references(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	union acpi_operand_object *obj_desc =
+	    (union acpi_operand_object *)context;
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+
+	/* Check for match against the namespace node itself */
+
+	if (node == (void *)obj_desc) {
+		acpi_os_printf("Object is a Node [%4.4s]\n",
+			       acpi_ut_get_node_name(node));
+	}
+
+	/* Check for match against the object attached to the node */
+
+	if (acpi_ns_get_attached_object(node) == obj_desc) {
+		acpi_os_printf("Reference at Node->Object %p [%4.4s]\n",
+			       node, acpi_ut_get_node_name(node));
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_find_references
+ *
+ * PARAMETERS:  object_arg      - String with hex value of the object
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Search namespace for all references to the input object
+ *
+ ******************************************************************************/
+
+void acpi_db_find_references(char *object_arg)
+{
+	union acpi_operand_object *obj_desc;
+	acpi_size address;
+
+	/* Convert string to object pointer */
+
+	address = strtoul(object_arg, NULL, 16);
+	obj_desc = ACPI_TO_POINTER(address);
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_walk_for_references,
+				  NULL, (void *)obj_desc, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_bus_walk
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display info about device objects that have a corresponding
+ *              _PRT method.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_bus_walk(acpi_handle obj_handle,
+		 u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	acpi_status status;
+	struct acpi_buffer buffer;
+	struct acpi_namespace_node *temp_node;
+	struct acpi_device_info *info;
+	u32 i;
+
+	if ((node->type != ACPI_TYPE_DEVICE) &&
+	    (node->type != ACPI_TYPE_PROCESSOR)) {
+		return (AE_OK);
+	}
+
+	/* Exit if there is no _PRT under this device */
+
+	status = acpi_get_handle(node, METHOD_NAME__PRT,
+				 ACPI_CAST_PTR(acpi_handle, &temp_node));
+	if (ACPI_FAILURE(status)) {
+		return (AE_OK);
+	}
+
+	/* Get the full path to this device object */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could Not get pathname for object %p\n",
+			       obj_handle);
+		return (AE_OK);
+	}
+
+	status = acpi_get_object_info(obj_handle, &info);
+	if (ACPI_FAILURE(status)) {
+		return (AE_OK);
+	}
+
+	/* Display the full path */
+
+	acpi_os_printf("%-32s Type %X", (char *)buffer.pointer, node->type);
+	ACPI_FREE(buffer.pointer);
+
+	if (info->flags & ACPI_PCI_ROOT_BRIDGE) {
+		acpi_os_printf(" - Is PCI Root Bridge");
+	}
+	acpi_os_printf("\n");
+
+	/* _PRT info */
+
+	acpi_os_printf("_PRT: %p\n", temp_node);
+
+	/* Dump _ADR, _HID, _UID, _CID */
+
+	if (info->valid & ACPI_VALID_ADR) {
+		acpi_os_printf("_ADR: %8.8X%8.8X\n",
+			       ACPI_FORMAT_UINT64(info->address));
+	} else {
+		acpi_os_printf("_ADR: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_HID) {
+		acpi_os_printf("_HID: %s\n", info->hardware_id.string);
+	} else {
+		acpi_os_printf("_HID: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_UID) {
+		acpi_os_printf("_UID: %s\n", info->unique_id.string);
+	} else {
+		acpi_os_printf("_UID: <Not Present>\n");
+	}
+
+	if (info->valid & ACPI_VALID_CID) {
+		for (i = 0; i < info->compatible_id_list.count; i++) {
+			acpi_os_printf("_CID: %s\n",
+				       info->compatible_id_list.ids[i].string);
+		}
+	} else {
+		acpi_os_printf("_CID: <Not Present>\n");
+	}
+
+	ACPI_FREE(info);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_get_bus_info
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display info about system busses.
+ *
+ ******************************************************************************/
+
+void acpi_db_get_bus_info(void)
+{
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_bus_walk, NULL, NULL,
+				  NULL);
+}
diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c
new file mode 100644
index 0000000..116f6db8
--- /dev/null
+++ b/drivers/acpi/acpica/dbobject.c
@@ -0,0 +1,533 @@
+/*******************************************************************************
+ *
+ * Module Name: dbobject - ACPI object decode and display
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbobject")
+
+/* Local prototypes */
+static void acpi_db_decode_node(struct acpi_namespace_node *node);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_method_info
+ *
+ * PARAMETERS:  status          - Method execution status
+ *              walk_state      - Current state of the parse tree walk
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Called when a method has been aborted because of an error.
+ *              Dumps the method execution stack, and the method locals/args,
+ *              and disassembles the AML opcode that failed.
+ *
+ ******************************************************************************/
+
+void
+acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state)
+{
+	struct acpi_thread_state *thread;
+
+	/* Ignore control codes, they are not errors */
+
+	if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) {
+		return;
+	}
+
+	/* We may be executing a deferred opcode */
+
+	if (walk_state->deferred_node) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/*
+	 * If there is no Thread, we are not actually executing a method.
+	 * This can happen when the iASL compiler calls the interpreter
+	 * to perform constant folding.
+	 */
+	thread = walk_state->thread;
+	if (!thread) {
+		return;
+	}
+
+	/* Display the method locals and arguments */
+
+	acpi_os_printf("\n");
+	acpi_db_decode_locals(walk_state);
+	acpi_os_printf("\n");
+	acpi_db_decode_arguments(walk_state);
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers.
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		acpi_os_printf(" Uninitialized");
+		return;
+	}
+
+	if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+		acpi_os_printf(" %p [%s]", obj_desc,
+			       acpi_ut_get_descriptor_name(obj_desc));
+		return;
+	}
+
+	acpi_os_printf(" %s", acpi_ut_get_object_type_name(obj_desc));
+
+	switch (obj_desc->common.type) {
+	case ACPI_TYPE_INTEGER:
+
+		acpi_os_printf(" %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(obj_desc->integer.value));
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		acpi_os_printf("(%u) \"%.24s",
+			       obj_desc->string.length,
+			       obj_desc->string.pointer);
+
+		if (obj_desc->string.length > 24) {
+			acpi_os_printf("...");
+		} else {
+			acpi_os_printf("\"");
+		}
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		acpi_os_printf("(%u)", obj_desc->buffer.length);
+		for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) {
+			acpi_os_printf(" %2.2X", obj_desc->buffer.pointer[i]);
+		}
+		break;
+
+	default:
+
+		acpi_os_printf(" %p", obj_desc);
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_node
+ *
+ * PARAMETERS:  node        - Object to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of a namespace node
+ *
+ ******************************************************************************/
+
+static void acpi_db_decode_node(struct acpi_namespace_node *node)
+{
+
+	acpi_os_printf("<Node>          Name %4.4s",
+		       acpi_ut_get_node_name(node));
+
+	if (node->flags & ANOBJ_METHOD_ARG) {
+		acpi_os_printf(" [Method Arg]");
+	}
+	if (node->flags & ANOBJ_METHOD_LOCAL) {
+		acpi_os_printf(" [Method Local]");
+	}
+
+	switch (node->type) {
+
+		/* These types have no attached object */
+
+	case ACPI_TYPE_DEVICE:
+
+		acpi_os_printf(" Device");
+		break;
+
+	case ACPI_TYPE_THERMAL:
+
+		acpi_os_printf(" Thermal Zone");
+		break;
+
+	default:
+
+		acpi_db_decode_internal_object(acpi_ns_get_attached_object
+					       (node));
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_internal_object
+ *
+ * PARAMETERS:  obj_desc        - Object to be displayed
+ *              walk_state      - Current walk state
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Short display of an internal object
+ *
+ ******************************************************************************/
+
+void
+acpi_db_display_internal_object(union acpi_operand_object *obj_desc,
+				struct acpi_walk_state *walk_state)
+{
+	u8 type;
+
+	acpi_os_printf("%p ", obj_desc);
+
+	if (!obj_desc) {
+		acpi_os_printf("<Null Object>\n");
+		return;
+	}
+
+	/* Decode the object type */
+
+	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
+	case ACPI_DESC_TYPE_PARSER:
+
+		acpi_os_printf("<Parser> ");
+		break;
+
+	case ACPI_DESC_TYPE_NAMED:
+
+		acpi_db_decode_node((struct acpi_namespace_node *)obj_desc);
+		break;
+
+	case ACPI_DESC_TYPE_OPERAND:
+
+		type = obj_desc->common.type;
+		if (type > ACPI_TYPE_LOCAL_MAX) {
+			acpi_os_printf(" Type %X [Invalid Type]", (u32)type);
+			return;
+		}
+
+		/* Decode the ACPI object type */
+
+		switch (obj_desc->common.type) {
+		case ACPI_TYPE_LOCAL_REFERENCE:
+
+			acpi_os_printf("[%s] ",
+				       acpi_ut_get_reference_name(obj_desc));
+
+			/* Decode the refererence */
+
+			switch (obj_desc->reference.class) {
+			case ACPI_REFCLASS_LOCAL:
+
+				acpi_os_printf("%X ",
+					       obj_desc->reference.value);
+				if (walk_state) {
+					obj_desc = walk_state->local_variables
+					    [obj_desc->reference.value].object;
+					acpi_os_printf("%p", obj_desc);
+					acpi_db_decode_internal_object
+					    (obj_desc);
+				}
+				break;
+
+			case ACPI_REFCLASS_ARG:
+
+				acpi_os_printf("%X ",
+					       obj_desc->reference.value);
+				if (walk_state) {
+					obj_desc = walk_state->arguments
+					    [obj_desc->reference.value].object;
+					acpi_os_printf("%p", obj_desc);
+					acpi_db_decode_internal_object
+					    (obj_desc);
+				}
+				break;
+
+			case ACPI_REFCLASS_INDEX:
+
+				switch (obj_desc->reference.target_type) {
+				case ACPI_TYPE_BUFFER_FIELD:
+
+					acpi_os_printf("%p",
+						       obj_desc->reference.
+						       object);
+					acpi_db_decode_internal_object
+					    (obj_desc->reference.object);
+					break;
+
+				case ACPI_TYPE_PACKAGE:
+
+					acpi_os_printf("%p",
+						       obj_desc->reference.
+						       where);
+					if (!obj_desc->reference.where) {
+						acpi_os_printf
+						    (" Uninitialized WHERE pointer");
+					} else {
+						acpi_db_decode_internal_object(*
+									       (obj_desc->
+										reference.
+										where));
+					}
+					break;
+
+				default:
+
+					acpi_os_printf
+					    ("Unknown index target type");
+					break;
+				}
+				break;
+
+			case ACPI_REFCLASS_REFOF:
+
+				if (!obj_desc->reference.object) {
+					acpi_os_printf
+					    ("Uninitialized reference subobject pointer");
+					break;
+				}
+
+				/* Reference can be to a Node or an Operand object */
+
+				switch (ACPI_GET_DESCRIPTOR_TYPE
+					(obj_desc->reference.object)) {
+				case ACPI_DESC_TYPE_NAMED:
+
+					acpi_db_decode_node(obj_desc->reference.
+							    object);
+					break;
+
+				case ACPI_DESC_TYPE_OPERAND:
+
+					acpi_db_decode_internal_object
+					    (obj_desc->reference.object);
+					break;
+
+				default:
+					break;
+				}
+				break;
+
+			case ACPI_REFCLASS_NAME:
+
+				acpi_db_decode_node(obj_desc->reference.node);
+				break;
+
+			case ACPI_REFCLASS_DEBUG:
+			case ACPI_REFCLASS_TABLE:
+
+				acpi_os_printf("\n");
+				break;
+
+			default:	/* Unknown reference class */
+
+				acpi_os_printf("%2.2X\n",
+					       obj_desc->reference.class);
+				break;
+			}
+			break;
+
+		default:
+
+			acpi_os_printf("<Obj>          ");
+			acpi_db_decode_internal_object(obj_desc);
+			break;
+		}
+		break;
+
+	default:
+
+		acpi_os_printf("<Not a valid ACPI Object Descriptor> [%s]",
+			       acpi_ut_get_descriptor_name(obj_desc));
+		break;
+	}
+
+	acpi_os_printf("\n");
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_locals
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all locals for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_locals(struct acpi_walk_state *walk_state)
+{
+	u32 i;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	u8 display_locals = FALSE;
+
+	obj_desc = walk_state->method_desc;
+	node = walk_state->method_node;
+
+	if (!node) {
+		acpi_os_printf
+		    ("No method node (Executing subtree for buffer or opregion)\n");
+		return;
+	}
+
+	if (node->type != ACPI_TYPE_METHOD) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/* Are any locals actually set? */
+
+	for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+		obj_desc = walk_state->local_variables[i].object;
+		if (obj_desc) {
+			display_locals = TRUE;
+			break;
+		}
+	}
+
+	/* If any are set, only display the ones that are set */
+
+	if (display_locals) {
+		acpi_os_printf
+		    ("\nInitialized Local Variables for method [%4.4s]:\n",
+		     acpi_ut_get_node_name(node));
+
+		for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+			obj_desc = walk_state->local_variables[i].object;
+			if (obj_desc) {
+				acpi_os_printf("  Local%X: ", i);
+				acpi_db_display_internal_object(obj_desc,
+								walk_state);
+			}
+		}
+	} else {
+		acpi_os_printf
+		    ("No Local Variables are initialized for method [%4.4s]\n",
+		     acpi_ut_get_node_name(node));
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_decode_arguments
+ *
+ * PARAMETERS:  walk_state      - State for current method
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display all arguments for the currently running control method
+ *
+ ******************************************************************************/
+
+void acpi_db_decode_arguments(struct acpi_walk_state *walk_state)
+{
+	u32 i;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	u8 display_args = FALSE;
+
+	node = walk_state->method_node;
+	obj_desc = walk_state->method_desc;
+
+	if (!node) {
+		acpi_os_printf
+		    ("No method node (Executing subtree for buffer or opregion)\n");
+		return;
+	}
+
+	if (node->type != ACPI_TYPE_METHOD) {
+		acpi_os_printf("Executing subtree for Buffer/Package/Region\n");
+		return;
+	}
+
+	/* Are any arguments actually set? */
+
+	for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+		obj_desc = walk_state->arguments[i].object;
+		if (obj_desc) {
+			display_args = TRUE;
+			break;
+		}
+	}
+
+	/* If any are set, only display the ones that are set */
+
+	if (display_args) {
+		acpi_os_printf("Initialized Arguments for Method [%4.4s]:  "
+			       "(%X arguments defined for method invocation)\n",
+			       acpi_ut_get_node_name(node),
+			       obj_desc->method.param_count);
+
+		for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+			obj_desc = walk_state->arguments[i].object;
+			if (obj_desc) {
+				acpi_os_printf("  Arg%u:   ", i);
+				acpi_db_display_internal_object(obj_desc,
+								walk_state);
+			}
+		}
+	} else {
+		acpi_os_printf
+		    ("No Arguments are initialized for method [%4.4s]\n",
+		     acpi_ut_get_node_name(node));
+	}
+}
diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c
new file mode 100644
index 0000000..4ba0a20
--- /dev/null
+++ b/drivers/acpi/acpica/dbstats.c
@@ -0,0 +1,546 @@
+/*******************************************************************************
+ *
+ * Module Name: dbstats - Generation and display of ACPI table statistics
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbstats")
+
+/* Local prototypes */
+static void acpi_db_count_namespace_objects(void);
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc);
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value);
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+static void acpi_db_list_info(struct acpi_memory_list *list);
+#endif
+
+/*
+ * Statistics subcommands
+ */
+static struct acpi_db_argument_info acpi_db_stat_types[] = {
+	{"ALLOCATIONS"},
+	{"OBJECTS"},
+	{"MEMORY"},
+	{"MISC"},
+	{"TABLES"},
+	{"SIZES"},
+	{"STACK"},
+	{NULL}			/* Must be null terminated */
+};
+
+#define CMD_STAT_ALLOCATIONS     0
+#define CMD_STAT_OBJECTS         1
+#define CMD_STAT_MEMORY          2
+#define CMD_STAT_MISC            3
+#define CMD_STAT_TABLES          4
+#define CMD_STAT_SIZES           5
+#define CMD_STAT_STACK           6
+
+#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_list_info
+ *
+ * PARAMETERS:  list            - Memory list/cache to be displayed
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display information about the input memory list or cache.
+ *
+ ******************************************************************************/
+
+static void acpi_db_list_info(struct acpi_memory_list *list)
+{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	u32 outstanding;
+#endif
+
+	acpi_os_printf("\n%s\n", list->list_name);
+
+	/* max_depth > 0 indicates a cache object */
+
+	if (list->max_depth > 0) {
+		acpi_os_printf
+		    ("    Cache: [Depth    MaxD Avail  Size]                "
+		     "%8.2X %8.2X %8.2X %8.2X\n", list->current_depth,
+		     list->max_depth, list->max_depth - list->current_depth,
+		     (list->current_depth * list->object_size));
+	}
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+	if (list->max_depth > 0) {
+		acpi_os_printf
+		    ("    Cache: [Requests Hits Misses ObjSize]             "
+		     "%8.2X %8.2X %8.2X %8.2X\n", list->requests, list->hits,
+		     list->requests - list->hits, list->object_size);
+	}
+
+	outstanding = acpi_db_get_cache_info(list);
+
+	if (list->object_size) {
+		acpi_os_printf
+		    ("    Mem:   [Alloc    Free Max    CurSize Outstanding] "
+		     "%8.2X %8.2X %8.2X %8.2X %8.2X\n", list->total_allocated,
+		     list->total_freed, list->max_occupied,
+		     outstanding * list->object_size, outstanding);
+	} else {
+		acpi_os_printf
+		    ("    Mem:   [Alloc Free Max CurSize Outstanding Total] "
+		     "%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n",
+		     list->total_allocated, list->total_freed,
+		     list->max_occupied, list->current_total_size, outstanding,
+		     list->total_size);
+	}
+#endif
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_enumerate_object
+ *
+ * PARAMETERS:  obj_desc            - Object to be counted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Add this object to the global counts, by object type.
+ *              Limited recursion handles subobjects and packages, and this
+ *              is probably acceptable within the AML debugger only.
+ *
+ ******************************************************************************/
+
+static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		return;
+	}
+
+	/* Enumerate this object first */
+
+	acpi_gbl_num_objects++;
+
+	if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_gbl_obj_type_count_misc++;
+	} else {
+		acpi_gbl_obj_type_count[obj_desc->common.type]++;
+	}
+
+	/* Count the sub-objects */
+
+	switch (obj_desc->common.type) {
+	case ACPI_TYPE_PACKAGE:
+
+		for (i = 0; i < obj_desc->package.count; i++) {
+			acpi_db_enumerate_object(obj_desc->package.elements[i]);
+		}
+		break;
+
+	case ACPI_TYPE_DEVICE:
+
+		acpi_db_enumerate_object(obj_desc->device.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->device.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->device.handler);
+		break;
+
+	case ACPI_TYPE_BUFFER_FIELD:
+
+		if (acpi_ns_get_secondary_object(obj_desc)) {
+			acpi_gbl_obj_type_count[ACPI_TYPE_BUFFER_FIELD]++;
+		}
+		break;
+
+	case ACPI_TYPE_REGION:
+
+		acpi_gbl_obj_type_count[ACPI_TYPE_LOCAL_REGION_FIELD]++;
+		acpi_db_enumerate_object(obj_desc->region.handler);
+		break;
+
+	case ACPI_TYPE_POWER:
+
+		acpi_db_enumerate_object(obj_desc->power_resource.
+					 notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->power_resource.
+					 notify_list[1]);
+		break;
+
+	case ACPI_TYPE_PROCESSOR:
+
+		acpi_db_enumerate_object(obj_desc->processor.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->processor.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->processor.handler);
+		break;
+
+	case ACPI_TYPE_THERMAL:
+
+		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[0]);
+		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[1]);
+		acpi_db_enumerate_object(obj_desc->thermal_zone.handler);
+		break;
+
+	default:
+
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_classify_one_object
+ *
+ * PARAMETERS:  Callback for walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
+ *              the parent namespace node.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_classify_one_object(acpi_handle obj_handle,
+			    u32 nesting_level,
+			    void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	u32 type;
+
+	acpi_gbl_num_nodes++;
+
+	node = (struct acpi_namespace_node *)obj_handle;
+	obj_desc = acpi_ns_get_attached_object(node);
+
+	acpi_db_enumerate_object(obj_desc);
+
+	type = node->type;
+	if (type > ACPI_TYPE_NS_NODE_MAX) {
+		acpi_gbl_node_type_count_misc++;
+	} else {
+		acpi_gbl_node_type_count[type]++;
+	}
+
+	return (AE_OK);
+
+#ifdef ACPI_FUTURE_IMPLEMENTATION
+
+	/* TBD: These need to be counted during the initial parsing phase */
+
+	if (acpi_ps_is_named_op(op->opcode)) {
+		num_nodes++;
+	}
+
+	if (is_method) {
+		num_method_elements++;
+	}
+
+	num_grammar_elements++;
+	op = acpi_ps_get_depth_next(root, op);
+
+	size_of_parse_tree = (num_grammar_elements - num_method_elements) *
+	    (u32)sizeof(union acpi_parse_object);
+	size_of_method_trees =
+	    num_method_elements * (u32)sizeof(union acpi_parse_object);
+	size_of_node_entries =
+	    num_nodes * (u32)sizeof(struct acpi_namespace_node);
+	size_of_acpi_objects =
+	    num_nodes * (u32)sizeof(union acpi_operand_object);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_count_namespace_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Count and classify the entire namespace, including all
+ *              namespace nodes and attached objects.
+ *
+ ******************************************************************************/
+
+static void acpi_db_count_namespace_objects(void)
+{
+	u32 i;
+
+	acpi_gbl_num_nodes = 0;
+	acpi_gbl_num_objects = 0;
+
+	acpi_gbl_obj_type_count_misc = 0;
+	for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX - 1); i++) {
+		acpi_gbl_obj_type_count[i] = 0;
+		acpi_gbl_node_type_count[i] = 0;
+	}
+
+	(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, FALSE,
+				     acpi_db_classify_one_object, NULL, NULL,
+				     NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_display_statistics
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display various statistics
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_statistics(char *type_arg)
+{
+	u32 i;
+	u32 temp;
+
+	acpi_ut_strupr(type_arg);
+	temp = acpi_db_match_argument(type_arg, acpi_db_stat_types);
+	if (temp == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return (AE_OK);
+	}
+
+	switch (temp) {
+	case CMD_STAT_ALLOCATIONS:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_ut_dump_allocation_info();
+#endif
+		break;
+
+	case CMD_STAT_TABLES:
+
+		acpi_os_printf("ACPI Table Information (not implemented):\n\n");
+		break;
+
+	case CMD_STAT_OBJECTS:
+
+		acpi_db_count_namespace_objects();
+
+		acpi_os_printf
+		    ("\nObjects defined in the current namespace:\n\n");
+
+		acpi_os_printf("%16.16s %10.10s %10.10s\n",
+			       "ACPI_TYPE", "NODES", "OBJECTS");
+
+		for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) {
+			acpi_os_printf("%16.16s % 10ld% 10ld\n",
+				       acpi_ut_get_type_name(i),
+				       acpi_gbl_node_type_count[i],
+				       acpi_gbl_obj_type_count[i]);
+		}
+		acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
+			       acpi_gbl_node_type_count_misc,
+			       acpi_gbl_obj_type_count_misc);
+
+		acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:",
+			       acpi_gbl_num_nodes, acpi_gbl_num_objects);
+		break;
+
+	case CMD_STAT_MEMORY:
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+		acpi_os_printf
+		    ("\n----Object Statistics (all in hex)---------\n");
+
+		acpi_db_list_info(acpi_gbl_global_list);
+		acpi_db_list_info(acpi_gbl_ns_node_list);
+#endif
+
+#ifdef ACPI_USE_LOCAL_CACHE
+		acpi_os_printf
+		    ("\n----Cache Statistics (all in hex)---------\n");
+		acpi_db_list_info(acpi_gbl_operand_cache);
+		acpi_db_list_info(acpi_gbl_ps_node_cache);
+		acpi_db_list_info(acpi_gbl_ps_node_ext_cache);
+		acpi_db_list_info(acpi_gbl_state_cache);
+#endif
+
+		break;
+
+	case CMD_STAT_MISC:
+
+		acpi_os_printf("\nMiscellaneous Statistics:\n\n");
+		acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n",
+			       acpi_gbl_ps_find_count);
+		acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n",
+			       acpi_gbl_ns_lookup_count);
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("Mutex usage:\n\n");
+		for (i = 0; i < ACPI_NUM_MUTEX; i++) {
+			acpi_os_printf("%-28s:     % 7ld\n",
+				       acpi_ut_get_mutex_name(i),
+				       acpi_gbl_mutex_info[i].use_count);
+		}
+		break;
+
+	case CMD_STAT_SIZES:
+
+		acpi_os_printf("\nInternal object sizes:\n\n");
+
+		acpi_os_printf("Common         %3d\n",
+			       sizeof(struct acpi_object_common));
+		acpi_os_printf("Number         %3d\n",
+			       sizeof(struct acpi_object_integer));
+		acpi_os_printf("String         %3d\n",
+			       sizeof(struct acpi_object_string));
+		acpi_os_printf("Buffer         %3d\n",
+			       sizeof(struct acpi_object_buffer));
+		acpi_os_printf("Package        %3d\n",
+			       sizeof(struct acpi_object_package));
+		acpi_os_printf("BufferField    %3d\n",
+			       sizeof(struct acpi_object_buffer_field));
+		acpi_os_printf("Device         %3d\n",
+			       sizeof(struct acpi_object_device));
+		acpi_os_printf("Event          %3d\n",
+			       sizeof(struct acpi_object_event));
+		acpi_os_printf("Method         %3d\n",
+			       sizeof(struct acpi_object_method));
+		acpi_os_printf("Mutex          %3d\n",
+			       sizeof(struct acpi_object_mutex));
+		acpi_os_printf("Region         %3d\n",
+			       sizeof(struct acpi_object_region));
+		acpi_os_printf("PowerResource  %3d\n",
+			       sizeof(struct acpi_object_power_resource));
+		acpi_os_printf("Processor      %3d\n",
+			       sizeof(struct acpi_object_processor));
+		acpi_os_printf("ThermalZone    %3d\n",
+			       sizeof(struct acpi_object_thermal_zone));
+		acpi_os_printf("RegionField    %3d\n",
+			       sizeof(struct acpi_object_region_field));
+		acpi_os_printf("BankField      %3d\n",
+			       sizeof(struct acpi_object_bank_field));
+		acpi_os_printf("IndexField     %3d\n",
+			       sizeof(struct acpi_object_index_field));
+		acpi_os_printf("Reference      %3d\n",
+			       sizeof(struct acpi_object_reference));
+		acpi_os_printf("Notify         %3d\n",
+			       sizeof(struct acpi_object_notify_handler));
+		acpi_os_printf("AddressSpace   %3d\n",
+			       sizeof(struct acpi_object_addr_handler));
+		acpi_os_printf("Extra          %3d\n",
+			       sizeof(struct acpi_object_extra));
+		acpi_os_printf("Data           %3d\n",
+			       sizeof(struct acpi_object_data));
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("ParseObject    %3d\n",
+			       sizeof(struct acpi_parse_obj_common));
+		acpi_os_printf("ParseObjectNamed %3d\n",
+			       sizeof(struct acpi_parse_obj_named));
+		acpi_os_printf("ParseObjectAsl %3d\n",
+			       sizeof(struct acpi_parse_obj_asl));
+		acpi_os_printf("OperandObject  %3d\n",
+			       sizeof(union acpi_operand_object));
+		acpi_os_printf("NamespaceNode  %3d\n",
+			       sizeof(struct acpi_namespace_node));
+		acpi_os_printf("AcpiObject     %3d\n",
+			       sizeof(union acpi_object));
+
+		acpi_os_printf("\n");
+
+		acpi_os_printf("Generic State  %3d\n",
+			       sizeof(union acpi_generic_state));
+		acpi_os_printf("Common State   %3d\n",
+			       sizeof(struct acpi_common_state));
+		acpi_os_printf("Control State  %3d\n",
+			       sizeof(struct acpi_control_state));
+		acpi_os_printf("Update State   %3d\n",
+			       sizeof(struct acpi_update_state));
+		acpi_os_printf("Scope State    %3d\n",
+			       sizeof(struct acpi_scope_state));
+		acpi_os_printf("Parse Scope    %3d\n",
+			       sizeof(struct acpi_pscope_state));
+		acpi_os_printf("Package State  %3d\n",
+			       sizeof(struct acpi_pkg_state));
+		acpi_os_printf("Thread State   %3d\n",
+			       sizeof(struct acpi_thread_state));
+		acpi_os_printf("Result Values  %3d\n",
+			       sizeof(struct acpi_result_values));
+		acpi_os_printf("Notify Info    %3d\n",
+			       sizeof(struct acpi_notify_info));
+		break;
+
+	case CMD_STAT_STACK:
+#if defined(ACPI_DEBUG_OUTPUT)
+
+		temp =
+		    (u32)ACPI_PTR_DIFF(acpi_gbl_entry_stack_pointer,
+				       acpi_gbl_lowest_stack_pointer);
+
+		acpi_os_printf("\nSubsystem Stack Usage:\n\n");
+		acpi_os_printf("Entry Stack Pointer        %p\n",
+			       acpi_gbl_entry_stack_pointer);
+		acpi_os_printf("Lowest Stack Pointer       %p\n",
+			       acpi_gbl_lowest_stack_pointer);
+		acpi_os_printf("Stack Use                  %X (%u)\n", temp,
+			       temp);
+		acpi_os_printf("Deepest Procedure Nesting  %u\n",
+			       acpi_gbl_deepest_nesting);
+#endif
+		break;
+
+	default:
+
+		break;
+	}
+
+	acpi_os_printf("\n");
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c
new file mode 100644
index 0000000..10ea8bf
--- /dev/null
+++ b/drivers/acpi/acpica/dbtest.c
@@ -0,0 +1,1057 @@
+/*******************************************************************************
+ *
+ * Module Name: dbtest - Various debug-related tests
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdebug.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbtest")
+
+/* Local prototypes */
+static void acpi_db_test_all_objects(void);
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+			u32 nesting_level, void *context, void **return_value);
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length);
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length);
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+			 acpi_object_type expected_type,
+			 union acpi_object **value);
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+			union acpi_object *value);
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg);
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+				     u32 nesting_level,
+				     void *context, void **return_value);
+
+/*
+ * Test subcommands
+ */
+static struct acpi_db_argument_info acpi_db_test_types[] = {
+	{"OBJECTS"},
+	{"PREDEFINED"},
+	{NULL}			/* Must be null terminated */
+};
+
+#define CMD_TEST_OBJECTS        0
+#define CMD_TEST_PREDEFINED     1
+
+#define BUFFER_FILL_VALUE       0xFF
+
+/*
+ * Support for the special debugger read/write control methods.
+ * These methods are installed into the current namespace and are
+ * used to read and write the various namespace objects. The point
+ * is to force the AML interpreter do all of the work.
+ */
+#define ACPI_DB_READ_METHOD     "\\_T98"
+#define ACPI_DB_WRITE_METHOD    "\\_T99"
+
+static acpi_handle read_handle = NULL;
+static acpi_handle write_handle = NULL;
+
+/* ASL Definitions of the debugger read/write control methods */
+
+#if 0
+definition_block("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+	method(_T98, 1, not_serialized) {	/* Read */
+		return (de_ref_of(arg0))
+	}
+}
+
+definition_block("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
+{
+	method(_T99, 2, not_serialized) {	/* Write */
+		store(arg1, arg0)
+	}
+}
+#endif
+
+static unsigned char read_method_code[] = {
+	0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00,	/* 00000000    "SSDT...." */
+	0x02, 0xC9, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00,	/* 00000008    "..Intel." */
+	0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00,	/* 00000010    "DEBUG..." */
+	0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,	/* 00000018    "....INTL" */
+	0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54,	/* 00000020    "... .._T" */
+	0x39, 0x38, 0x01, 0xA4, 0x83, 0x68	/* 00000028    "98...h"   */
+};
+
+static unsigned char write_method_code[] = {
+	0x53, 0x53, 0x44, 0x54, 0x2E, 0x00, 0x00, 0x00,	/* 00000000    "SSDT...." */
+	0x02, 0x15, 0x49, 0x6E, 0x74, 0x65, 0x6C, 0x00,	/* 00000008    "..Intel." */
+	0x44, 0x45, 0x42, 0x55, 0x47, 0x00, 0x00, 0x00,	/* 00000010    "DEBUG..." */
+	0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,	/* 00000018    "....INTL" */
+	0x18, 0x12, 0x13, 0x20, 0x14, 0x09, 0x5F, 0x54,	/* 00000020    "... .._T" */
+	0x39, 0x39, 0x02, 0x70, 0x69, 0x68	/* 00000028    "99.pih"   */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_execute_test
+ *
+ * PARAMETERS:  type_arg        - Subcommand
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Execute various debug tests.
+ *
+ * Note: Code is prepared for future expansion of the TEST command.
+ *
+ ******************************************************************************/
+
+void acpi_db_execute_test(char *type_arg)
+{
+	u32 temp;
+
+	acpi_ut_strupr(type_arg);
+	temp = acpi_db_match_argument(type_arg, acpi_db_test_types);
+	if (temp == ACPI_TYPE_NOT_FOUND) {
+		acpi_os_printf("Invalid or unsupported argument\n");
+		return;
+	}
+
+	switch (temp) {
+	case CMD_TEST_OBJECTS:
+
+		acpi_db_test_all_objects();
+		break;
+
+	case CMD_TEST_PREDEFINED:
+
+		acpi_db_evaluate_all_predefined_names(NULL);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_all_objects
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the
+ *              namespace by reading/writing/comparing all data objects such
+ *              as integers, strings, buffers, fields, buffer fields, etc.
+ *
+ ******************************************************************************/
+
+static void acpi_db_test_all_objects(void)
+{
+	acpi_status status;
+
+	/* Install the debugger read-object control method if necessary */
+
+	if (!read_handle) {
+		status = acpi_install_method(read_method_code);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s, Could not install debugger read method\n",
+			     acpi_format_exception(status));
+			return;
+		}
+
+		status =
+		    acpi_get_handle(NULL, ACPI_DB_READ_METHOD, &read_handle);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not obtain handle for debug method %s\n",
+			     ACPI_DB_READ_METHOD);
+			return;
+		}
+	}
+
+	/* Install the debugger write-object control method if necessary */
+
+	if (!write_handle) {
+		status = acpi_install_method(write_method_code);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("%s, Could not install debugger write method\n",
+			     acpi_format_exception(status));
+			return;
+		}
+
+		status =
+		    acpi_get_handle(NULL, ACPI_DB_WRITE_METHOD, &write_handle);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf
+			    ("Could not obtain handle for debug method %s\n",
+			     ACPI_DB_WRITE_METHOD);
+			return;
+		}
+	}
+
+	/* Walk the entire namespace, testing each supported named data object */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, acpi_db_test_one_object,
+				  NULL, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_one_object
+ *
+ * PARAMETERS:  acpi_walk_callback
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test one namespace object. Supported types are Integer,
+ *              String, Buffer, buffer_field, and field_unit. All other object
+ *              types are simply ignored.
+ *
+ *              Note: Support for Packages is not implemented.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_one_object(acpi_handle obj_handle,
+			u32 nesting_level, void *context, void **return_value)
+{
+	struct acpi_namespace_node *node;
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *region_obj;
+	acpi_object_type local_type;
+	u32 bit_length = 0;
+	u32 byte_length = 0;
+	acpi_status status = AE_OK;
+
+	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
+	obj_desc = node->object;
+
+	/*
+	 * For the supported types, get the actual bit length or
+	 * byte length. Map the type to one of Integer/String/Buffer.
+	 */
+	switch (node->type) {
+	case ACPI_TYPE_INTEGER:
+
+		/* Integer width is either 32 or 64 */
+
+		local_type = ACPI_TYPE_INTEGER;
+		bit_length = acpi_gbl_integer_bit_width;
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		local_type = ACPI_TYPE_STRING;
+		byte_length = obj_desc->string.length;
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		local_type = ACPI_TYPE_BUFFER;
+		byte_length = obj_desc->buffer.length;
+		bit_length = byte_length * 8;
+		break;
+
+	case ACPI_TYPE_FIELD_UNIT:
+	case ACPI_TYPE_BUFFER_FIELD:
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+	case ACPI_TYPE_LOCAL_INDEX_FIELD:
+	case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+		local_type = ACPI_TYPE_INTEGER;
+		if (obj_desc) {
+			/*
+			 * Returned object will be a Buffer if the field length
+			 * is larger than the size of an Integer (32 or 64 bits
+			 * depending on the DSDT version).
+			 */
+			bit_length = obj_desc->common_field.bit_length;
+			byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+			if (bit_length > acpi_gbl_integer_bit_width) {
+				local_type = ACPI_TYPE_BUFFER;
+			}
+		}
+		break;
+
+	default:
+
+		/* Ignore all other types */
+
+		return (AE_OK);
+	}
+
+	/* Emit the common prefix: Type:Name */
+
+	acpi_os_printf("%14s: %4.4s",
+		       acpi_ut_get_type_name(node->type), node->name.ascii);
+	if (!obj_desc) {
+		acpi_os_printf(" Ignoring, no attached object\n");
+		return (AE_OK);
+	}
+
+	/*
+	 * Check for unsupported region types. Note: acpi_exec simulates
+	 * access to system_memory, system_IO, PCI_Config, and EC.
+	 */
+	switch (node->type) {
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+		region_obj = obj_desc->field.region_obj;
+		switch (region_obj->region.space_id) {
+		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+		case ACPI_ADR_SPACE_SYSTEM_IO:
+		case ACPI_ADR_SPACE_PCI_CONFIG:
+		case ACPI_ADR_SPACE_EC:
+
+			break;
+
+		default:
+
+			acpi_os_printf
+			    ("    %s space is not supported [%4.4s]\n",
+			     acpi_ut_get_region_name(region_obj->region.
+						     space_id),
+			     region_obj->region.node->name.ascii);
+			return (AE_OK);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	/* At this point, we have resolved the object to one of the major types */
+
+	switch (local_type) {
+	case ACPI_TYPE_INTEGER:
+
+		status = acpi_db_test_integer_type(node, bit_length);
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		status = acpi_db_test_string_type(node, byte_length);
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		status = acpi_db_test_buffer_type(node, bit_length);
+		break;
+
+	default:
+
+		acpi_os_printf(" Ignoring, type not implemented (%2.2X)",
+			       local_type);
+		break;
+	}
+
+	switch (node->type) {
+	case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+		region_obj = obj_desc->field.region_obj;
+		acpi_os_printf(" (%s)",
+			       acpi_ut_get_region_name(region_obj->region.
+						       space_id));
+		break;
+
+	default:
+		break;
+	}
+
+	acpi_os_printf("\n");
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_integer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object. Used for
+ *                                    support of arbitrary length field_unit
+ *                                    and buffer_field objects.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Integer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	union acpi_object write_value;
+	u64 value_to_write;
+	acpi_status status;
+
+	if (bit_length > 64) {
+		acpi_os_printf(" Invalid length for an Integer: %u",
+			       bit_length);
+		return (AE_OK);
+	}
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	acpi_os_printf(" (%4.4X/%3.3X) %8.8X%8.8X",
+		       bit_length, ACPI_ROUND_BITS_UP_TO_BYTES(bit_length),
+		       ACPI_FORMAT_UINT64(temp1->integer.value));
+
+	value_to_write = ACPI_UINT64_MAX >> (64 - bit_length);
+	if (temp1->integer.value == value_to_write) {
+		value_to_write = 0;
+	}
+
+	/* Write a new value */
+
+	write_value.type = ACPI_TYPE_INTEGER;
+	write_value.integer.value = value_to_write;
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (temp2->integer.value != value_to_write) {
+		acpi_os_printf(" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(temp2->integer.value),
+			       ACPI_FORMAT_UINT64(value_to_write));
+	}
+
+	/* Write back the original value */
+
+	write_value.integer.value = temp1->integer.value;
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (temp3->integer.value != temp1->integer.value) {
+		acpi_os_printf(" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
+			       ACPI_FORMAT_UINT64(temp3->integer.value),
+			       ACPI_FORMAT_UINT64(temp1->integer.value));
+	}
+
+exit:
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_buffer_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              bit_length          - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an Buffer-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	u8 *buffer;
+	union acpi_object write_value;
+	acpi_status status;
+	u32 byte_length;
+	u32 i;
+	u8 extra_bits;
+
+	byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
+	if (byte_length == 0) {
+		acpi_os_printf(" Ignoring zero length buffer");
+		return (AE_OK);
+	}
+
+	/* Allocate a local buffer */
+
+	buffer = ACPI_ALLOCATE_ZEROED(byte_length);
+	if (!buffer) {
+		return (AE_NO_MEMORY);
+	}
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Emit a few bytes of the buffer */
+
+	acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length);
+	for (i = 0; ((i < 4) && (i < byte_length)); i++) {
+		acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]);
+	}
+	acpi_os_printf("... ");
+
+	/*
+	 * Write a new value.
+	 *
+	 * Handle possible extra bits at the end of the buffer. Can
+	 * happen for field_units larger than an integer, but the bit
+	 * count is not an integral number of bytes. Zero out the
+	 * unused bits.
+	 */
+	memset(buffer, BUFFER_FILL_VALUE, byte_length);
+	extra_bits = bit_length % 8;
+	if (extra_bits) {
+		buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits);
+	}
+
+	write_value.type = ACPI_TYPE_BUFFER;
+	write_value.buffer.length = byte_length;
+	write_value.buffer.pointer = buffer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (memcmp(temp2->buffer.pointer, buffer, byte_length)) {
+		acpi_os_printf(" MISMATCH 2: New buffer value");
+	}
+
+	/* Write back the original value */
+
+	write_value.buffer.length = byte_length;
+	write_value.buffer.pointer = temp1->buffer.pointer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) {
+		acpi_os_printf(" MISMATCH 3: While restoring original buffer");
+	}
+
+exit:
+	ACPI_FREE(buffer);
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_test_string_type
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              byte_length         - Actual length of the object.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Test read/write for an String-valued object. Performs a
+ *              write/read/compare of an arbitrary new value, then performs
+ *              a write/read/compare of the original value.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length)
+{
+	union acpi_object *temp1 = NULL;
+	union acpi_object *temp2 = NULL;
+	union acpi_object *temp3 = NULL;
+	char *value_to_write = "Test String from AML Debugger";
+	union acpi_object write_value;
+	acpi_status status;
+
+	/* Read the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp1);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	acpi_os_printf(" (%4.4X/%3.3X) \"%s\"", (temp1->string.length * 8),
+		       temp1->string.length, temp1->string.pointer);
+
+	/* Write a new value */
+
+	write_value.type = ACPI_TYPE_STRING;
+	write_value.string.length = strlen(value_to_write);
+	write_value.string.pointer = value_to_write;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the new value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp2);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (strcmp(temp2->string.pointer, value_to_write)) {
+		acpi_os_printf(" MISMATCH 2: %s, expecting %s",
+			       temp2->string.pointer, value_to_write);
+	}
+
+	/* Write back the original value */
+
+	write_value.string.length = strlen(temp1->string.pointer);
+	write_value.string.pointer = temp1->string.pointer;
+
+	status = acpi_db_write_to_object(node, &write_value);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	/* Ensure that we can read back the original value */
+
+	status = acpi_db_read_from_object(node, ACPI_TYPE_STRING, &temp3);
+	if (ACPI_FAILURE(status)) {
+		goto exit;
+	}
+
+	if (strcmp(temp1->string.pointer, temp3->string.pointer)) {
+		acpi_os_printf(" MISMATCH 3: %s, expecting %s",
+			       temp3->string.pointer, temp1->string.pointer);
+	}
+
+exit:
+	if (temp1) {
+		acpi_os_free(temp1);
+	}
+	if (temp2) {
+		acpi_os_free(temp2);
+	}
+	if (temp3) {
+		acpi_os_free(temp3);
+	}
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_read_from_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              expected_type       - Object type expected from the read
+ *              value               - Where the value read is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a read from the specified object by invoking the
+ *              special debugger control method that reads the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_read_from_object(struct acpi_namespace_node *node,
+			 acpi_object_type expected_type,
+			 union acpi_object **value)
+{
+	union acpi_object *ret_value;
+	struct acpi_object_list param_objects;
+	union acpi_object params[2];
+	struct acpi_buffer return_obj;
+	acpi_status status;
+
+	params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+	params[0].reference.actual_type = node->type;
+	params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+	param_objects.count = 1;
+	param_objects.pointer = params;
+
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(read_handle, NULL,
+				      &param_objects, &return_obj);
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not read from object, %s",
+			       acpi_format_exception(status));
+		return (status);
+	}
+
+	ret_value = (union acpi_object *)return_obj.pointer;
+
+	switch (ret_value->type) {
+	case ACPI_TYPE_INTEGER:
+	case ACPI_TYPE_BUFFER:
+	case ACPI_TYPE_STRING:
+		/*
+		 * Did we receive the type we wanted? Most important for the
+		 * Integer/Buffer case (when a field is larger than an Integer,
+		 * it should return a Buffer).
+		 */
+		if (ret_value->type != expected_type) {
+			acpi_os_printf
+			    (" Type mismatch: Expected %s, Received %s",
+			     acpi_ut_get_type_name(expected_type),
+			     acpi_ut_get_type_name(ret_value->type));
+
+			return (AE_TYPE);
+		}
+
+		*value = ret_value;
+		break;
+
+	default:
+
+		acpi_os_printf(" Unsupported return object type, %s",
+			       acpi_ut_get_type_name(ret_value->type));
+
+		acpi_os_free(return_obj.pointer);
+		return (AE_TYPE);
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_write_to_object
+ *
+ * PARAMETERS:  node                - Parent NS node for the object
+ *              value               - Value to be written
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Performs a write to the specified object by invoking the
+ *              special debugger control method that writes the object. Thus,
+ *              the AML interpreter is doing all of the work, increasing the
+ *              validity of the test.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_write_to_object(struct acpi_namespace_node *node,
+			union acpi_object *value)
+{
+	struct acpi_object_list param_objects;
+	union acpi_object params[2];
+	acpi_status status;
+
+	params[0].type = ACPI_TYPE_LOCAL_REFERENCE;
+	params[0].reference.actual_type = node->type;
+	params[0].reference.handle = ACPI_CAST_PTR(acpi_handle, node);
+
+	/* Copy the incoming user parameter */
+
+	memcpy(&params[1], value, sizeof(union acpi_object));
+
+	param_objects.count = 2;
+	param_objects.pointer = params;
+
+	acpi_gbl_method_executing = TRUE;
+	status = acpi_evaluate_object(write_handle, NULL, &param_objects, NULL);
+	acpi_gbl_method_executing = FALSE;
+
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not write to object, %s",
+			       acpi_format_exception(status));
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_all_predefined_names
+ *
+ * PARAMETERS:  count_arg           - Max number of methods to execute
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Namespace batch execution. Execute predefined names in the
+ *              namespace, up to the max count, if specified.
+ *
+ ******************************************************************************/
+
+static void acpi_db_evaluate_all_predefined_names(char *count_arg)
+{
+	struct acpi_db_execute_walk info;
+
+	info.count = 0;
+	info.max_count = ACPI_UINT32_MAX;
+
+	if (count_arg) {
+		info.max_count = strtoul(count_arg, NULL, 0);
+	}
+
+	/* Search all nodes in namespace */
+
+	(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX,
+				  acpi_db_evaluate_one_predefined_name, NULL,
+				  (void *)&info, NULL);
+
+	acpi_os_printf("Evaluated %u predefined names in the namespace\n",
+		       info.count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_evaluate_one_predefined_name
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Batch execution module. Currently only executes predefined
+ *              ACPI names.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle,
+				     u32 nesting_level,
+				     void *context, void **return_value)
+{
+	struct acpi_namespace_node *node =
+	    (struct acpi_namespace_node *)obj_handle;
+	struct acpi_db_execute_walk *info =
+	    (struct acpi_db_execute_walk *)context;
+	char *pathname;
+	const union acpi_predefined_info *predefined;
+	struct acpi_device_info *obj_info;
+	struct acpi_object_list param_objects;
+	union acpi_object params[ACPI_METHOD_NUM_ARGS];
+	union acpi_object *this_param;
+	struct acpi_buffer return_obj;
+	acpi_status status;
+	u16 arg_type_list;
+	u8 arg_count;
+	u8 arg_type;
+	u32 i;
+
+	/* The name must be a predefined ACPI name */
+
+	predefined = acpi_ut_match_predefined_method(node->name.ascii);
+	if (!predefined) {
+		return (AE_OK);
+	}
+
+	if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
+		return (AE_OK);
+	}
+
+	pathname = acpi_ns_get_external_pathname(node);
+	if (!pathname) {
+		return (AE_OK);
+	}
+
+	/* Get the object info for number of method parameters */
+
+	status = acpi_get_object_info(obj_handle, &obj_info);
+	if (ACPI_FAILURE(status)) {
+		ACPI_FREE(pathname);
+		return (status);
+	}
+
+	param_objects.count = 0;
+	param_objects.pointer = NULL;
+
+	if (obj_info->type == ACPI_TYPE_METHOD) {
+
+		/* Setup default parameters (with proper types) */
+
+		arg_type_list = predefined->info.argument_list;
+		arg_count = METHOD_GET_ARG_COUNT(arg_type_list);
+
+		/*
+		 * Setup the ACPI-required number of arguments, regardless of what
+		 * the actual method defines. If there is a difference, then the
+		 * method is wrong and a warning will be issued during execution.
+		 */
+		this_param = params;
+		for (i = 0; i < arg_count; i++) {
+			arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
+			this_param->type = arg_type;
+
+			switch (arg_type) {
+			case ACPI_TYPE_INTEGER:
+
+				this_param->integer.value = 1;
+				break;
+
+			case ACPI_TYPE_STRING:
+
+				this_param->string.pointer =
+				    "This is the default argument string";
+				this_param->string.length =
+				    strlen(this_param->string.pointer);
+				break;
+
+			case ACPI_TYPE_BUFFER:
+
+				this_param->buffer.pointer = (u8 *)params;	/* just a garbage buffer */
+				this_param->buffer.length = 48;
+				break;
+
+			case ACPI_TYPE_PACKAGE:
+
+				this_param->package.elements = NULL;
+				this_param->package.count = 0;
+				break;
+
+			default:
+
+				acpi_os_printf
+				    ("%s: Unsupported argument type: %u\n",
+				     pathname, arg_type);
+				break;
+			}
+
+			this_param++;
+		}
+
+		param_objects.count = arg_count;
+		param_objects.pointer = params;
+	}
+
+	ACPI_FREE(obj_info);
+	return_obj.pointer = NULL;
+	return_obj.length = ACPI_ALLOCATE_BUFFER;
+
+	/* Do the actual method execution */
+
+	acpi_gbl_method_executing = TRUE;
+
+	status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
+
+	acpi_os_printf("%-32s returned %s\n",
+		       pathname, acpi_format_exception(status));
+	acpi_gbl_method_executing = FALSE;
+	ACPI_FREE(pathname);
+
+	/* Ignore status from method execution */
+
+	status = AE_OK;
+
+	/* Update count, check if we have executed enough methods */
+
+	info->count++;
+	if (info->count >= info->max_count) {
+		status = AE_CTRL_TERMINATE;
+	}
+
+	return (status);
+}
diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c
new file mode 100644
index 0000000..86790e0
--- /dev/null
+++ b/drivers/acpi/acpica/dbutils.c
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ *
+ * Module Name: dbutils - AML debugger utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbutils")
+
+/* Local prototypes */
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root);
+
+void acpi_db_dump_buffer(u32 address);
+#endif
+
+static char *gbl_hex_to_ascii = "0123456789ABCDEF";
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_match_argument
+ *
+ * PARAMETERS:  user_argument           - User command line
+ *              arguments               - Array of commands to match against
+ *
+ * RETURN:      Index into command array or ACPI_TYPE_NOT_FOUND if not found
+ *
+ * DESCRIPTION: Search command array for a command match
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_db_match_argument(char *user_argument,
+		       struct acpi_db_argument_info *arguments)
+{
+	u32 i;
+
+	if (!user_argument || user_argument[0] == 0) {
+		return (ACPI_TYPE_NOT_FOUND);
+	}
+
+	for (i = 0; arguments[i].name; i++) {
+		if (strstr(arguments[i].name, user_argument) ==
+		    arguments[i].name) {
+			return (i);
+		}
+	}
+
+	/* Argument not recognized */
+
+	return (ACPI_TYPE_NOT_FOUND);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_set_output_destination
+ *
+ * PARAMETERS:  output_flags        - Current flags word
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set the current destination for debugger output. Also sets
+ *              the debug output level accordingly.
+ *
+ ******************************************************************************/
+
+void acpi_db_set_output_destination(u32 output_flags)
+{
+
+	acpi_gbl_db_output_flags = (u8)output_flags;
+
+	if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) &&
+	    acpi_gbl_db_output_to_file) {
+		acpi_dbg_level = acpi_gbl_db_debug_level;
+	} else {
+		acpi_dbg_level = acpi_gbl_db_console_debug_level;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_external_object
+ *
+ * PARAMETERS:  obj_desc        - External ACPI object to dump
+ *              level           - Nesting level.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump the contents of an ACPI external object
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level)
+{
+	u32 i;
+
+	if (!obj_desc) {
+		acpi_os_printf("[Null Object]\n");
+		return;
+	}
+
+	for (i = 0; i < level; i++) {
+		acpi_os_printf(" ");
+	}
+
+	switch (obj_desc->type) {
+	case ACPI_TYPE_ANY:
+
+		acpi_os_printf("[Null Object] (Type=0)\n");
+		break;
+
+	case ACPI_TYPE_INTEGER:
+
+		acpi_os_printf("[Integer] = %8.8X%8.8X\n",
+			       ACPI_FORMAT_UINT64(obj_desc->integer.value));
+		break;
+
+	case ACPI_TYPE_STRING:
+
+		acpi_os_printf("[String] Length %.2X = ",
+			       obj_desc->string.length);
+		acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
+		acpi_os_printf("\n");
+		break;
+
+	case ACPI_TYPE_BUFFER:
+
+		acpi_os_printf("[Buffer] Length %.2X = ",
+			       obj_desc->buffer.length);
+		if (obj_desc->buffer.length) {
+			if (obj_desc->buffer.length > 16) {
+				acpi_os_printf("\n");
+			}
+			acpi_ut_debug_dump_buffer(ACPI_CAST_PTR
+						  (u8,
+						   obj_desc->buffer.pointer),
+						  obj_desc->buffer.length,
+						  DB_BYTE_DISPLAY, _COMPONENT);
+		} else {
+			acpi_os_printf("\n");
+		}
+		break;
+
+	case ACPI_TYPE_PACKAGE:
+
+		acpi_os_printf("[Package] Contains %u Elements:\n",
+			       obj_desc->package.count);
+
+		for (i = 0; i < obj_desc->package.count; i++) {
+			acpi_db_dump_external_object(&obj_desc->package.
+						     elements[i], level + 1);
+		}
+		break;
+
+	case ACPI_TYPE_LOCAL_REFERENCE:
+
+		acpi_os_printf("[Object Reference] = ");
+		acpi_db_display_internal_object(obj_desc->reference.handle,
+						NULL);
+		break;
+
+	case ACPI_TYPE_PROCESSOR:
+
+		acpi_os_printf("[Processor]\n");
+		break;
+
+	case ACPI_TYPE_POWER:
+
+		acpi_os_printf("[Power Resource]\n");
+		break;
+
+	default:
+
+		acpi_os_printf("[Unknown Type] %X\n", obj_desc->type);
+		break;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_prep_namestring
+ *
+ * PARAMETERS:  name            - String to prepare
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Translate all forward slashes and dots to backslashes.
+ *
+ ******************************************************************************/
+
+void acpi_db_prep_namestring(char *name)
+{
+
+	if (!name) {
+		return;
+	}
+
+	acpi_ut_strupr(name);
+
+	/* Convert a leading forward slash to a backslash */
+
+	if (*name == '/') {
+		*name = '\\';
+	}
+
+	/* Ignore a leading backslash, this is the root prefix */
+
+	if (ACPI_IS_ROOT_PREFIX(*name)) {
+		name++;
+	}
+
+	/* Convert all slash path separators to dots */
+
+	while (*name) {
+		if ((*name == '/') || (*name == '\\')) {
+			*name = '.';
+		}
+
+		name++;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_local_ns_lookup
+ *
+ * PARAMETERS:  name            - Name to lookup
+ *
+ * RETURN:      Pointer to a namespace node, null on failure
+ *
+ * DESCRIPTION: Lookup a name in the ACPI namespace
+ *
+ * Note: Currently begins search from the root. Could be enhanced to use
+ * the current prefix (scope) node as the search beginning point.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name)
+{
+	char *internal_path;
+	acpi_status status;
+	struct acpi_namespace_node *node = NULL;
+
+	acpi_db_prep_namestring(name);
+
+	/* Build an internal namestring */
+
+	status = acpi_ns_internalize_name(name, &internal_path);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Invalid namestring: %s\n", name);
+		return (NULL);
+	}
+
+	/*
+	 * Lookup the name.
+	 * (Uses root node as the search starting point)
+	 */
+	status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
+				ACPI_IMODE_EXECUTE,
+				ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE,
+				NULL, &node);
+	if (ACPI_FAILURE(status)) {
+		acpi_os_printf("Could not locate name: %s, %s\n",
+			       name, acpi_format_exception(status));
+	}
+
+	ACPI_FREE(internal_path);
+	return (node);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_uint32_to_hex_string
+ *
+ * PARAMETERS:  value           - The value to be converted to string
+ *              buffer          - Buffer for result (not less than 11 bytes)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image
+ *
+ * NOTE: It is the caller's responsibility to ensure that the length of buffer
+ *       is sufficient.
+ *
+ ******************************************************************************/
+
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer)
+{
+	int i;
+
+	if (value == 0) {
+		strcpy(buffer, "0");
+		return;
+	}
+
+	buffer[8] = '\0';
+
+	for (i = 7; i >= 0; i--) {
+		buffer[i] = gbl_hex_to_ascii[value & 0x0F];
+		value = value >> 4;
+	}
+}
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_second_pass_parse
+ *
+ * PARAMETERS:  root            - Root of the parse tree
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until
+ *              second pass to parse the control methods
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root)
+{
+	union acpi_parse_object *op = root;
+	union acpi_parse_object *method;
+	union acpi_parse_object *search_op;
+	union acpi_parse_object *start_op;
+	acpi_status status = AE_OK;
+	u32 base_aml_offset;
+	struct acpi_walk_state *walk_state;
+
+	ACPI_FUNCTION_ENTRY();
+
+	acpi_os_printf("Pass two parse ....\n");
+
+	while (op) {
+		if (op->common.aml_opcode == AML_METHOD_OP) {
+			method = op;
+
+			/* Create a new walk state for the parse */
+
+			walk_state =
+			    acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+			if (!walk_state) {
+				return (AE_NO_MEMORY);
+			}
+
+			/* Init the Walk State */
+
+			walk_state->parser_state.aml =
+			    walk_state->parser_state.aml_start =
+			    method->named.data;
+			walk_state->parser_state.aml_end =
+			    walk_state->parser_state.pkg_end =
+			    method->named.data + method->named.length;
+			walk_state->parser_state.start_scope = op;
+
+			walk_state->descending_callback =
+			    acpi_ds_load1_begin_op;
+			walk_state->ascending_callback = acpi_ds_load1_end_op;
+
+			/* Perform the AML parse */
+
+			status = acpi_ps_parse_aml(walk_state);
+
+			base_aml_offset =
+			    (method->common.value.arg)->common.aml_offset + 1;
+			start_op = (method->common.value.arg)->common.next;
+			search_op = start_op;
+
+			while (search_op) {
+				search_op->common.aml_offset += base_aml_offset;
+				search_op =
+				    acpi_ps_get_depth_next(start_op, search_op);
+			}
+		}
+
+		if (op->common.aml_opcode == AML_REGION_OP) {
+
+			/* TBD: [Investigate] this isn't quite the right thing to do! */
+			/*
+			 *
+			 * Method = (ACPI_DEFERRED_OP *) Op;
+			 * Status = acpi_ps_parse_aml (Op, Method->Body, Method->body_length);
+			 */
+		}
+
+		if (ACPI_FAILURE(status)) {
+			break;
+		}
+
+		op = acpi_ps_get_depth_next(root, op);
+	}
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_dump_buffer
+ *
+ * PARAMETERS:  address             - Pointer to the buffer
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print a portion of a buffer
+ *
+ ******************************************************************************/
+
+void acpi_db_dump_buffer(u32 address)
+{
+
+	acpi_os_printf("\nLocation %X:\n", address);
+
+	acpi_dbg_level |= ACPI_LV_TABLES;
+	acpi_ut_debug_dump_buffer(ACPI_TO_POINTER(address), 64, DB_BYTE_DISPLAY,
+				  ACPI_UINT32_MAX);
+}
+#endif
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
new file mode 100644
index 0000000..26023bd
--- /dev/null
+++ b/drivers/acpi/acpica/dbxface.c
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ *
+ * Module Name: dbxface - AML Debugger external interfaces
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdebug.h"
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("dbxface")
+
+/* Local prototypes */
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+		      union acpi_parse_object *op);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+void acpi_db_method_end(struct acpi_walk_state *walk_state);
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_start_command
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing Op, from AML interpreter
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enter debugger command loop
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_start_command(struct acpi_walk_state *walk_state,
+		      union acpi_parse_object *op)
+{
+	acpi_status status;
+
+	/* TBD: [Investigate] are there namespace locking issues here? */
+
+	/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
+
+	/* Go into the command loop and await next user command */
+
+	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 */
+
+			acpi_os_release_mutex(acpi_gbl_db_command_complete);
+
+			status =
+			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
+						  ACPI_WAIT_FOREVER);
+			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);
+			}
+
+			/* Get the user input line */
+
+			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);
+			}
+		}
+
+		status =
+		    acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,
+					     op);
+	}
+
+	/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_db_single_step
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              op              - Current executing op (from aml interpreter)
+ *              opcode_class    - Class of the current AML Opcode
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Called just before execution of an AML opcode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_single_step(struct acpi_walk_state * walk_state,
+		    union acpi_parse_object * op, u32 opcode_class)
+{
+	union acpi_parse_object *next;
+	acpi_status status = AE_OK;
+	u32 original_debug_level;
+	union acpi_parse_object *display_op;
+	union acpi_parse_object *parent_op;
+	u32 aml_offset;
+
+	ACPI_FUNCTION_ENTRY();
+
+	/* Check the abort flag */
+
+	if (acpi_gbl_abort_method) {
+		acpi_gbl_abort_method = FALSE;
+		return (AE_ABORT_METHOD);
+	}
+
+	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,
+					walk_state->parser_state.aml_start);
+
+	/* Check for single-step breakpoint */
+
+	if (walk_state->method_breakpoint &&
+	    (walk_state->method_breakpoint <= aml_offset)) {
+
+		/* Check if the breakpoint has been reached or passed */
+		/* Hit the breakpoint, resume single step, reset breakpoint */
+
+		acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_gbl_step_to_next_call = FALSE;
+		walk_state->method_breakpoint = 0;
+	}
+
+	/* Check for user breakpoint (Must be on exact Aml offset) */
+
+	else if (walk_state->user_breakpoint &&
+		 (walk_state->user_breakpoint == aml_offset)) {
+		acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",
+			       aml_offset);
+		acpi_gbl_cm_single_step = TRUE;
+		acpi_gbl_step_to_next_call = FALSE;
+		walk_state->method_breakpoint = 0;
+	}
+
+	/*
+	 * Check if this is an opcode that we are interested in --
+	 * namely, opcodes that have arguments
+	 */
+	if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+		return (AE_OK);
+	}
+
+	switch (opcode_class) {
+	case AML_CLASS_UNKNOWN:
+	case AML_CLASS_ARGUMENT:	/* constants, literals, etc. do nothing */
+
+		return (AE_OK);
+
+	default:
+
+		/* All other opcodes -- continue */
+		break;
+	}
+
+	/*
+	 * Under certain debug conditions, display this opcode and its operands
+	 */
+	if ((acpi_gbl_db_output_to_file) ||
+	    (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {
+		if ((acpi_gbl_db_output_to_file) ||
+		    (acpi_dbg_level & ACPI_LV_PARSE)) {
+			acpi_os_printf
+			    ("\n[AmlDebug] Next AML Opcode to execute:\n");
+		}
+
+		/*
+		 * Display this op (and only this op - zero out the NEXT field
+		 * temporarily, and disable parser trace output for the duration of
+		 * the display because we don't want the extraneous debug output)
+		 */
+		original_debug_level = acpi_dbg_level;
+		acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
+		next = op->common.next;
+		op->common.next = NULL;
+
+		display_op = op;
+		parent_op = op->common.parent;
+		if (parent_op) {
+			if ((walk_state->control_state) &&
+			    (walk_state->control_state->common.state ==
+			     ACPI_CONTROL_PREDICATE_EXECUTING)) {
+				/*
+				 * We are executing the predicate of an IF or WHILE statement
+				 * Search upwards for the containing IF or WHILE so that the
+				 * entire predicate can be displayed.
+				 */
+				while (parent_op) {
+					if ((parent_op->common.aml_opcode ==
+					     AML_IF_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_WHILE_OP)) {
+						display_op = parent_op;
+						break;
+					}
+					parent_op = parent_op->common.parent;
+				}
+			} else {
+				while (parent_op) {
+					if ((parent_op->common.aml_opcode ==
+					     AML_IF_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_ELSE_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_SCOPE_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_METHOD_OP)
+					    || (parent_op->common.aml_opcode ==
+						AML_WHILE_OP)) {
+						break;
+					}
+					display_op = parent_op;
+					parent_op = parent_op->common.parent;
+				}
+			}
+		}
+
+		/* Now we can display it */
+
+#ifdef ACPI_DISASSEMBLER
+		acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX);
+#endif
+
+		if ((op->common.aml_opcode == AML_IF_OP) ||
+		    (op->common.aml_opcode == AML_WHILE_OP)) {
+			if (walk_state->control_state->common.value) {
+				acpi_os_printf
+				    ("Predicate = [True], IF block was executed\n");
+			} else {
+				acpi_os_printf
+				    ("Predicate = [False], Skipping IF block\n");
+			}
+		} else if (op->common.aml_opcode == AML_ELSE_OP) {
+			acpi_os_printf
+			    ("Predicate = [False], ELSE block was executed\n");
+		}
+
+		/* Restore everything */
+
+		op->common.next = next;
+		acpi_os_printf("\n");
+		if ((acpi_gbl_db_output_to_file) ||
+		    (acpi_dbg_level & ACPI_LV_PARSE)) {
+			acpi_os_printf("\n");
+		}
+		acpi_dbg_level = original_debug_level;
+	}
+
+	/* If we are not single stepping, just continue executing the method */
+
+	if (!acpi_gbl_cm_single_step) {
+		return (AE_OK);
+	}
+
+	/*
+	 * If we are executing a step-to-call command,
+	 * Check if this is a method call.
+	 */
+	if (acpi_gbl_step_to_next_call) {
+		if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
+
+			/* Not a method call, just keep executing */
+
+			return (AE_OK);
+		}
+
+		/* Found a method call, stop executing */
+
+		acpi_gbl_step_to_next_call = FALSE;
+	}
+
+	/*
+	 * If the next opcode is a method call, we will "step over" it
+	 * by default.
+	 */
+	if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
+
+		/* Force no more single stepping while executing called method */
+
+		acpi_gbl_cm_single_step = FALSE;
+
+		/*
+		 * Set the breakpoint on/before the call, it will stop execution
+		 * as soon as we return
+		 */
+		walk_state->method_breakpoint = 1;	/* Must be non-zero! */
+	}
+
+	status = acpi_db_start_command(walk_state, op);
+
+	/* User commands complete, continue execution of the interrupted method */
+
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_initialize_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Init and start debugger
+ *
+ ******************************************************************************/
+
+acpi_status acpi_initialize_debugger(void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_initialize_debugger);
+
+	/* Init globals */
+
+	acpi_gbl_db_buffer = NULL;
+	acpi_gbl_db_filename = NULL;
+	acpi_gbl_db_output_to_file = FALSE;
+
+	acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
+	acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
+	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
+
+	acpi_gbl_db_opt_no_ini_methods = FALSE;
+
+	acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
+	if (!acpi_gbl_db_buffer) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+	memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
+
+	/* Initial scope is the root */
+
+	acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
+	acpi_gbl_db_scope_buf[1] = 0;
+	acpi_gbl_db_scope_node = acpi_gbl_root_node;
+
+	/*
+	 * If configured for multi-thread support, the debug executor runs in
+	 * a separate thread so that the front end can be in another address
+	 * space, environment, or even another machine.
+	 */
+	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
+
+		/* 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);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("Could not get debugger mutex\n");
+			return_ACPI_STATUS(status);
+		}
+
+		/* Create the debug execution thread to execute commands */
+
+		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
+					 acpi_db_execute_thread, NULL);
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status,
+					"Could not start debugger thread"));
+			return_ACPI_STATUS(status);
+		}
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_terminate_debugger
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Stop debugger
+ *
+ ******************************************************************************/
+void acpi_terminate_debugger(void)
+{
+
+	if (acpi_gbl_db_buffer) {
+		acpi_os_free(acpi_gbl_db_buffer);
+		acpi_gbl_db_buffer = NULL;
+	}
+
+	/* Ensure that debug output is now disabled */
+
+	acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108

The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
acpi_terminate() right in the user command loop, because when the debugger
exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
and the debugger should only be terminated by its users
(acpi_terminate_debugger()) rather than being terminated itself. Leaving such
invocations causes kernel panic when the debugger is shipped in the Linux
kernel.

This patch fixes this issue. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/0dd68e16
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    3 ++-
 drivers/acpi/acpica/dbinput.c  |   16 ++++------------
 drivers/acpi/acpica/dbxface.c  |   20 ++++++++++++++++++++
 drivers/acpi/acpica/utinit.c   |    2 --
 drivers/acpi/acpica/utxface.c  |    4 ----
 5 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 593de41..d82249c 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -324,7 +324,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 
 #ifdef ACPI_DEBUGGER
 
-ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
 
@@ -336,6 +335,8 @@ ACPI_GLOBAL(char *, acpi_gbl_db_filename);
 ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
 ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
 ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
+ACPI_GLOBAL(u8, acpi_gbl_db_terminate_loop);
+ACPI_GLOBAL(u8, acpi_gbl_db_threads_terminated);
 
 ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
 ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 7f1b6ec..f8cddd6 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -694,7 +694,7 @@ acpi_db_command_dispatch(char *input_buffer,
 
 	/* If acpi_terminate has been called, terminate this thread */
 
-	if (acpi_gbl_db_terminate_threads) {
+	if (acpi_gbl_db_terminate_loop) {
 		return (AE_CTRL_TERMINATE);
 	}
 
@@ -1116,7 +1116,7 @@ acpi_db_command_dispatch(char *input_buffer,
 #ifdef ACPI_APPLICATION
 		acpi_db_close_debug_file();
 #endif
-		acpi_gbl_db_terminate_threads = TRUE;
+		acpi_gbl_db_terminate_loop = TRUE;
 		return (AE_CTRL_TERMINATE);
 
 	case CMD_NOT_FOUND:
@@ -1166,6 +1166,7 @@ void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
 
 		acpi_os_release_mutex(acpi_gbl_db_command_complete);
 	}
+	acpi_gbl_db_threads_terminated = TRUE;
 }
 
 /*******************************************************************************
@@ -1212,7 +1213,7 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 
 	/* TBD: [Restructure] Need a separate command line buffer for step mode */
 
-	while (!acpi_gbl_db_terminate_threads) {
+	while (!acpi_gbl_db_terminate_loop) {
 
 		/* Force output to console until a command is entered */
 
@@ -1261,14 +1262,5 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 		}
 	}
 
-	/* Shut down the debugger */
-
-	acpi_terminate_debugger();
-
-	/*
-	 * Only this thread (the original thread) should actually terminate the
-	 * subsystem, because all the semaphores are deleted during termination
-	 */
-	status = acpi_terminate();
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 26023bd..bef5f4e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -401,6 +401,10 @@ acpi_status acpi_initialize_debugger(void)
 	acpi_gbl_db_scope_buf[1] = 0;
 	acpi_gbl_db_scope_node = acpi_gbl_root_node;
 
+	/* Initialize user commands loop */
+
+	acpi_gbl_db_terminate_loop = FALSE;
+
 	/*
 	 * If configured for multi-thread support, the debug executor runs in
 	 * a separate thread so that the front end can be in another address
@@ -426,11 +430,13 @@ acpi_status acpi_initialize_debugger(void)
 
 		/* Create the debug execution thread to execute commands */
 
+		acpi_gbl_db_threads_terminated = FALSE;
 		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
 					 acpi_db_execute_thread, NULL);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
 					"Could not start debugger thread"));
+			acpi_gbl_db_threads_terminated = TRUE;
 			return_ACPI_STATUS(status);
 		}
 	}
@@ -454,6 +460,20 @@ ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
 void acpi_terminate_debugger(void)
 {
 
+	/* Terminate the AML Debugger */
+
+	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);
+		}
+	}
+
 	if (acpi_gbl_db_buffer) {
 		acpi_os_free(acpi_gbl_db_buffer);
 		acpi_gbl_db_buffer = NULL;
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 28ab3a1..d8699df 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -241,8 +241,6 @@ acpi_status acpi_ut_init_globals(void)
 	acpi_gbl_disable_mem_tracking = FALSE;
 #endif
 
-	ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE);
-
 	return_ACPI_STATUS(AE_OK);
 }
 
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 4f33281..f183daf 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -80,10 +80,6 @@ acpi_status __init acpi_terminate(void)
 	acpi_gbl_startup_flags = 0;
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
 
-	/* Terminate the AML Debugger if present */
-
-	ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE);
-
 	/* Shutdown and free all resources */
 
 	acpi_ut_subsystem_shutdown();
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108

The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
acpi_terminate() right in the user command loop, because when the debugger
exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
and the debugger should only be terminated by its users
(acpi_terminate_debugger()) rather than being terminated itself. Leaving such
invocations causes kernel panic when the debugger is shipped in the Linux
kernel.

This patch fixes this issue. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/0dd68e16
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    3 ++-
 drivers/acpi/acpica/dbinput.c  |   16 ++++------------
 drivers/acpi/acpica/dbxface.c  |   20 ++++++++++++++++++++
 drivers/acpi/acpica/utinit.c   |    2 --
 drivers/acpi/acpica/utxface.c  |    4 ----
 5 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 593de41..d82249c 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -324,7 +324,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 
 #ifdef ACPI_DEBUGGER
 
-ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
 
@@ -336,6 +335,8 @@ ACPI_GLOBAL(char *, acpi_gbl_db_filename);
 ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
 ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
 ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
+ACPI_GLOBAL(u8, acpi_gbl_db_terminate_loop);
+ACPI_GLOBAL(u8, acpi_gbl_db_threads_terminated);
 
 ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
 ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 7f1b6ec..f8cddd6 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -694,7 +694,7 @@ acpi_db_command_dispatch(char *input_buffer,
 
 	/* If acpi_terminate has been called, terminate this thread */
 
-	if (acpi_gbl_db_terminate_threads) {
+	if (acpi_gbl_db_terminate_loop) {
 		return (AE_CTRL_TERMINATE);
 	}
 
@@ -1116,7 +1116,7 @@ acpi_db_command_dispatch(char *input_buffer,
 #ifdef ACPI_APPLICATION
 		acpi_db_close_debug_file();
 #endif
-		acpi_gbl_db_terminate_threads = TRUE;
+		acpi_gbl_db_terminate_loop = TRUE;
 		return (AE_CTRL_TERMINATE);
 
 	case CMD_NOT_FOUND:
@@ -1166,6 +1166,7 @@ void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
 
 		acpi_os_release_mutex(acpi_gbl_db_command_complete);
 	}
+	acpi_gbl_db_threads_terminated = TRUE;
 }
 
 /*******************************************************************************
@@ -1212,7 +1213,7 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 
 	/* TBD: [Restructure] Need a separate command line buffer for step mode */
 
-	while (!acpi_gbl_db_terminate_threads) {
+	while (!acpi_gbl_db_terminate_loop) {
 
 		/* Force output to console until a command is entered */
 
@@ -1261,14 +1262,5 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 		}
 	}
 
-	/* Shut down the debugger */
-
-	acpi_terminate_debugger();
-
-	/*
-	 * Only this thread (the original thread) should actually terminate the
-	 * subsystem, because all the semaphores are deleted during termination
-	 */
-	status = acpi_terminate();
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 26023bd..bef5f4e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -401,6 +401,10 @@ acpi_status acpi_initialize_debugger(void)
 	acpi_gbl_db_scope_buf[1] = 0;
 	acpi_gbl_db_scope_node = acpi_gbl_root_node;
 
+	/* Initialize user commands loop */
+
+	acpi_gbl_db_terminate_loop = FALSE;
+
 	/*
 	 * If configured for multi-thread support, the debug executor runs in
 	 * a separate thread so that the front end can be in another address
@@ -426,11 +430,13 @@ acpi_status acpi_initialize_debugger(void)
 
 		/* Create the debug execution thread to execute commands */
 
+		acpi_gbl_db_threads_terminated = FALSE;
 		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
 					 acpi_db_execute_thread, NULL);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
 					"Could not start debugger thread"));
+			acpi_gbl_db_threads_terminated = TRUE;
 			return_ACPI_STATUS(status);
 		}
 	}
@@ -454,6 +460,20 @@ ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)
 void acpi_terminate_debugger(void)
 {
 
+	/* Terminate the AML Debugger */
+
+	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);
+		}
+	}
+
 	if (acpi_gbl_db_buffer) {
 		acpi_os_free(acpi_gbl_db_buffer);
 		acpi_gbl_db_buffer = NULL;
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 28ab3a1..d8699df 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -241,8 +241,6 @@ acpi_status acpi_ut_init_globals(void)
 	acpi_gbl_disable_mem_tracking = FALSE;
 #endif
 
-	ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE);
-
 	return_ACPI_STATUS(AE_OK);
 }
 
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 4f33281..f183daf 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -80,10 +80,6 @@ acpi_status __init acpi_terminate(void)
 	acpi_gbl_startup_flags = 0;
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
 
-	/* Terminate the AML Debugger if present */
-
-	ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE);
-
 	/* Shutdown and free all resources */
 
 	acpi_ut_subsystem_shutdown();
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 10/14] ACPICA: Debugger: Fix "terminate" command by cleaning up subsystem shutdown logic
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 7e823714911480be47e310fb1b3590d289b9fd99

Segmentation fault can be seen for executing the "terminate" command. This
is because acpi_ut_subsystem_shutdown() is errnously called multiple times.

This patch cleans up acpi_ut_subsystem_shutdown() logics to fix this
issue. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/7e823714
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ++-
 drivers/acpi/acpica/utinit.c  |   13 +++++++++++++
 drivers/acpi/acpica/utxface.c |   13 -------------
 3 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index f8cddd6..0480254 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1074,6 +1074,7 @@ acpi_db_command_dispatch(char *input_buffer,
 		 * re-creating the semaphores!
 		 */
 
+		acpi_gbl_db_terminate_loop = TRUE;
 		/*  acpi_initialize (NULL); */
 		break;
 
@@ -1151,7 +1152,7 @@ void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
 	acpi_status status = AE_OK;
 	acpi_status Mstatus;
 
-	while (status != AE_CTRL_TERMINATE) {
+	while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) {
 		acpi_gbl_method_executing = FALSE;
 		acpi_gbl_step_to_next_call = FALSE;
 
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index d8699df..ccd0745 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -282,6 +282,19 @@ void acpi_ut_subsystem_shutdown(void)
 {
 	ACPI_FUNCTION_TRACE(ut_subsystem_shutdown);
 
+	/* Just exit if subsystem is already shutdown */
+
+	if (acpi_gbl_shutdown) {
+		ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
+		return_VOID;
+	}
+
+	/* Subsystem appears active, go ahead and shut it down */
+
+	acpi_gbl_shutdown = TRUE;
+	acpi_gbl_startup_flags = 0;
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+
 #ifndef ACPI_ASL_COMPILER
 
 	/* Close the acpi_event Handling */
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index f183daf..a6b0eb0 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -67,19 +67,6 @@ acpi_status __init acpi_terminate(void)
 
 	ACPI_FUNCTION_TRACE(acpi_terminate);
 
-	/* Just exit if subsystem is already shutdown */
-
-	if (acpi_gbl_shutdown) {
-		ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Subsystem appears active, go ahead and shut it down */
-
-	acpi_gbl_shutdown = TRUE;
-	acpi_gbl_startup_flags = 0;
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
-
 	/* Shutdown and free all resources */
 
 	acpi_ut_subsystem_shutdown();
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 10/14] ACPICA: Debugger: Fix "terminate" command by cleaning up subsystem shutdown logic
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 7e823714911480be47e310fb1b3590d289b9fd99

Segmentation fault can be seen for executing the "terminate" command. This
is because acpi_ut_subsystem_shutdown() is errnously called multiple times.

This patch cleans up acpi_ut_subsystem_shutdown() logics to fix this
issue. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/7e823714
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ++-
 drivers/acpi/acpica/utinit.c  |   13 +++++++++++++
 drivers/acpi/acpica/utxface.c |   13 -------------
 3 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index f8cddd6..0480254 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1074,6 +1074,7 @@ acpi_db_command_dispatch(char *input_buffer,
 		 * re-creating the semaphores!
 		 */
 
+		acpi_gbl_db_terminate_loop = TRUE;
 		/*  acpi_initialize (NULL); */
 		break;
 
@@ -1151,7 +1152,7 @@ void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context)
 	acpi_status status = AE_OK;
 	acpi_status Mstatus;
 
-	while (status != AE_CTRL_TERMINATE) {
+	while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) {
 		acpi_gbl_method_executing = FALSE;
 		acpi_gbl_step_to_next_call = FALSE;
 
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index d8699df..ccd0745 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -282,6 +282,19 @@ void acpi_ut_subsystem_shutdown(void)
 {
 	ACPI_FUNCTION_TRACE(ut_subsystem_shutdown);
 
+	/* Just exit if subsystem is already shutdown */
+
+	if (acpi_gbl_shutdown) {
+		ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
+		return_VOID;
+	}
+
+	/* Subsystem appears active, go ahead and shut it down */
+
+	acpi_gbl_shutdown = TRUE;
+	acpi_gbl_startup_flags = 0;
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+
 #ifndef ACPI_ASL_COMPILER
 
 	/* Close the acpi_event Handling */
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index f183daf..a6b0eb0 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -67,19 +67,6 @@ acpi_status __init acpi_terminate(void)
 
 	ACPI_FUNCTION_TRACE(acpi_terminate);
 
-	/* Just exit if subsystem is already shutdown */
-
-	if (acpi_gbl_shutdown) {
-		ACPI_ERROR((AE_INFO, "ACPI Subsystem is already terminated"));
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Subsystem appears active, go ahead and shut it down */
-
-	acpi_gbl_shutdown = TRUE;
-	acpi_gbl_startup_flags = 0;
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
-
 	/* Shutdown and free all resources */
 
 	acpi_ut_subsystem_shutdown();
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 11/14] ACPICA: Debugger: Add thread ID support so that single step mode can only apply to the debugger thread
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

When the debugger is running in the kernel mode, acpi_db_single_step() may
also be invoked by the kernel runtime code path but the single stepping
command prompt may be erronously logged as the kernel logs and runtime code
path cannot proceed.

This patch fixes this issue by adding acpi_gbl_db_thread_id for the debugger
thread and preventing acpi_db_single_step() to be invoked from other threads.

It is not suitable to add acpi_thread_id parameter for acpi_os_execute() as
the function may be implemented as work queue on some hosts. So it is
better to let the hosts invoke acpi_set_debugger_thread_id(). Currently
acpiexec is not configured as DEBUGGER_MULTI_THREADED, but we can do this.
When we do this, it is better to invoke acpi_set_debugger_thread_id() in
acpi_os_execute() when the execution type is OSL_DEBUGGER_MAIN_THREAD. The
support should look like:
  create_thread(&tid);
  if (type == OSL_DEBUGGER_MAIN_THREAD)
      acpi_set_debugger_thread_id(tid);
  resume_thread(tid);
Similarly, semop() may be used for pthread implementation. But this patch
simply skips debugger thread ID check for application instead of
introducing such complications as there is no need to skip
acpi_db_single_step() for an application debugger - acpiexec.

Note that the debugger thread ID can also be used by acpi_os_printf() to
filter out debugger output. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    8 ++++++++
 drivers/acpi/acpica/dbexec.c   |    3 ++-
 drivers/acpi/acpica/dbxface.c  |   28 +++++++++++++++++++++++++++-
 include/acpi/acpiosxf.h        |    3 ++-
 include/acpi/acpixf.h          |    2 ++
 6 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index d82249c..fdef15f 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -326,6 +326,7 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 
 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);
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 4e41b43..e1dd784 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -109,6 +109,14 @@ struct acpi_rw_lock {
 
 #define ACPI_MUTEX_NOT_ACQUIRED         (acpi_thread_id) 0
 
+/* This Thread ID means an invalid thread ID */
+
+#ifdef ACPI_OS_INVALID_THREAD_ID
+#define ACPI_INVALID_THREAD_ID          ACPI_OS_INVALID_THREAD_ID
+#else
+#define ACPI_INVALID_THREAD_ID          ((acpi_thread_id) 0xFFFFFFFF)
+#endif
+
 /* Table for the global mutexes */
 
 struct acpi_mutex_info {
diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
index 8eef298..258e615 100644
--- a/drivers/acpi/acpica/dbexec.c
+++ b/drivers/acpi/acpica/dbexec.c
@@ -725,7 +725,8 @@ acpi_db_create_execution_threads(char *num_threads_arg,
 
 	for (i = 0; i < (num_threads); i++) {
 		status =
-		    acpi_os_execute(OSL_DEBUGGER_THREAD, acpi_db_method_thread,
+		    acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
+				    acpi_db_method_thread,
 				    &acpi_gbl_db_method_info);
 		if (ACPI_FAILURE(status)) {
 			break;
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index bef5f4e..342298a 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -164,6 +164,12 @@ acpi_db_single_step(struct acpi_walk_state * walk_state,
 
 	ACPI_FUNCTION_ENTRY();
 
+#ifndef ACPI_APPLICATION
+	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
+		return (AE_OK);
+	}
+#endif
+
 	/* Check the abort flag */
 
 	if (acpi_gbl_abort_method) {
@@ -431,7 +437,7 @@ acpi_status acpi_initialize_debugger(void)
 		/* Create the debug execution thread to execute commands */
 
 		acpi_gbl_db_threads_terminated = FALSE;
-		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
+		status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
 					 acpi_db_execute_thread, NULL);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
@@ -439,6 +445,8 @@ acpi_status acpi_initialize_debugger(void)
 			acpi_gbl_db_threads_terminated = TRUE;
 			return_ACPI_STATUS(status);
 		}
+	} else {
+		acpi_gbl_db_thread_id = acpi_os_get_thread_id();
 	}
 
 	return_ACPI_STATUS(AE_OK);
@@ -485,3 +493,21 @@ void acpi_terminate_debugger(void)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_debugger_thread_id
+ *
+ * PARAMETERS:  thread_id       - Debugger thread ID
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set debugger thread ID
+ *
+ ******************************************************************************/
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
+{
+	acpi_gbl_db_thread_id = thread_id;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index a54ad1c..fbc2baf 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -55,7 +55,8 @@ typedef enum {
 	OSL_GLOBAL_LOCK_HANDLER,
 	OSL_NOTIFY_HANDLER,
 	OSL_GPE_HANDLER,
-	OSL_DEBUGGER_THREAD,
+	OSL_DEBUGGER_MAIN_THREAD,
+	OSL_DEBUGGER_EXEC_THREAD,
 	OSL_EC_POLL_HANDLER,
 	OSL_EC_BURST_HANDLER
 } acpi_execute_type;
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index c33eeab..f837adf 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -939,4 +939,6 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 					       void **data,
 					       void (*callback)(void *)))
 
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id);
+
 #endif				/* __ACXFACE_H__ */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 11/14] ACPICA: Debugger: Add thread ID support so that single step mode can only apply to the debugger thread
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

When the debugger is running in the kernel mode, acpi_db_single_step() may
also be invoked by the kernel runtime code path but the single stepping
command prompt may be erronously logged as the kernel logs and runtime code
path cannot proceed.

This patch fixes this issue by adding acpi_gbl_db_thread_id for the debugger
thread and preventing acpi_db_single_step() to be invoked from other threads.

It is not suitable to add acpi_thread_id parameter for acpi_os_execute() as
the function may be implemented as work queue on some hosts. So it is
better to let the hosts invoke acpi_set_debugger_thread_id(). Currently
acpiexec is not configured as DEBUGGER_MULTI_THREADED, but we can do this.
When we do this, it is better to invoke acpi_set_debugger_thread_id() in
acpi_os_execute() when the execution type is OSL_DEBUGGER_MAIN_THREAD. The
support should look like:
  create_thread(&tid);
  if (type == OSL_DEBUGGER_MAIN_THREAD)
      acpi_set_debugger_thread_id(tid);
  resume_thread(tid);
Similarly, semop() may be used for pthread implementation. But this patch
simply skips debugger thread ID check for application instead of
introducing such complications as there is no need to skip
acpi_db_single_step() for an application debugger - acpiexec.

Note that the debugger thread ID can also be used by acpi_os_printf() to
filter out debugger output. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acglobal.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    8 ++++++++
 drivers/acpi/acpica/dbexec.c   |    3 ++-
 drivers/acpi/acpica/dbxface.c  |   28 +++++++++++++++++++++++++++-
 include/acpi/acpiosxf.h        |    3 ++-
 include/acpi/acpixf.h          |    2 ++
 6 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index d82249c..fdef15f 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -326,6 +326,7 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 
 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);
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 4e41b43..e1dd784 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -109,6 +109,14 @@ struct acpi_rw_lock {
 
 #define ACPI_MUTEX_NOT_ACQUIRED         (acpi_thread_id) 0
 
+/* This Thread ID means an invalid thread ID */
+
+#ifdef ACPI_OS_INVALID_THREAD_ID
+#define ACPI_INVALID_THREAD_ID          ACPI_OS_INVALID_THREAD_ID
+#else
+#define ACPI_INVALID_THREAD_ID          ((acpi_thread_id) 0xFFFFFFFF)
+#endif
+
 /* Table for the global mutexes */
 
 struct acpi_mutex_info {
diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
index 8eef298..258e615 100644
--- a/drivers/acpi/acpica/dbexec.c
+++ b/drivers/acpi/acpica/dbexec.c
@@ -725,7 +725,8 @@ acpi_db_create_execution_threads(char *num_threads_arg,
 
 	for (i = 0; i < (num_threads); i++) {
 		status =
-		    acpi_os_execute(OSL_DEBUGGER_THREAD, acpi_db_method_thread,
+		    acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
+				    acpi_db_method_thread,
 				    &acpi_gbl_db_method_info);
 		if (ACPI_FAILURE(status)) {
 			break;
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index bef5f4e..342298a 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -164,6 +164,12 @@ acpi_db_single_step(struct acpi_walk_state * walk_state,
 
 	ACPI_FUNCTION_ENTRY();
 
+#ifndef ACPI_APPLICATION
+	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {
+		return (AE_OK);
+	}
+#endif
+
 	/* Check the abort flag */
 
 	if (acpi_gbl_abort_method) {
@@ -431,7 +437,7 @@ acpi_status acpi_initialize_debugger(void)
 		/* Create the debug execution thread to execute commands */
 
 		acpi_gbl_db_threads_terminated = FALSE;
-		status = acpi_os_execute(OSL_DEBUGGER_THREAD,
+		status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
 					 acpi_db_execute_thread, NULL);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
@@ -439,6 +445,8 @@ acpi_status acpi_initialize_debugger(void)
 			acpi_gbl_db_threads_terminated = TRUE;
 			return_ACPI_STATUS(status);
 		}
+	} else {
+		acpi_gbl_db_thread_id = acpi_os_get_thread_id();
 	}
 
 	return_ACPI_STATUS(AE_OK);
@@ -485,3 +493,21 @@ void acpi_terminate_debugger(void)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_debugger_thread_id
+ *
+ * PARAMETERS:  thread_id       - Debugger thread ID
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Set debugger thread ID
+ *
+ ******************************************************************************/
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id)
+{
+	acpi_gbl_db_thread_id = thread_id;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index a54ad1c..fbc2baf 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -55,7 +55,8 @@ typedef enum {
 	OSL_GLOBAL_LOCK_HANDLER,
 	OSL_NOTIFY_HANDLER,
 	OSL_GPE_HANDLER,
-	OSL_DEBUGGER_THREAD,
+	OSL_DEBUGGER_MAIN_THREAD,
+	OSL_DEBUGGER_EXEC_THREAD,
 	OSL_EC_POLL_HANDLER,
 	OSL_EC_BURST_HANDLER
 } acpi_execute_type;
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index c33eeab..f837adf 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -939,4 +939,6 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 					       void **data,
 					       void (*callback)(void *)))
 
+void acpi_set_debugger_thread_id(acpi_thread_id thread_id);
+
 #endif				/* __ACXFACE_H__ */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 12/14] ACPI: Enable build of AML interpreter debugger
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:25     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch enables ACPICA debugger files using a configurable
CONFIG_ACPI_DEBUGGER configuration item. Those debugger related code that
was originally masked as ACPI_FUTURE_USAGE now gets unmasked.

Necessary OSL stubs are also added in this patch:
1. acpi_os_readable(): This should be arch specific in Linux, while this
    patch doesn't introduce real implementation and a complex mechanism to
    allow architecture specific acpi_os_readable() to be implemented to
    validate the address. It may be done by future commits.
2. acpi_os_get_line(): This is used to obtain debugger command input. This
    patch only introduces a simple KDB concept example in it and the
    example should be co-working with the code implemented in
    acpi_os_printf(). Since this KDB example won't be compiled unless
    ENABLE_DEBUGGER is defined and it seems Linux has already stopped to
    use ENABLE_DEBUGGER, thus do not expect it can work properly.

This patch also cleans up all other ACPI_FUTURE_USAGE surroundings
accordingly.
1. Since linkage error can be automatically detected, declaration in the
   headers needn't be surrounded by ACPI_FUTURE_USAGE.
   So only the following separate exported fuction bodies are masked by
   this macro (other exported fucntions may have already been masked at
   entire module level via drivers/acpi/acpica/Makefile):
     acpi_install_exception_handler()
     acpi_subsystem_status()
     acpi_get_system_info()
     acpi_get_statistics()
     acpi_install_initialization_handler()
2. Since strip can automatically zap the no-user functions, functions that
   are not marked with ACPI_EXPORT_SYMBOL() needn't get surrounded by
   ACPI_FUTURE_USAGE.
   So the following function which is not used by Linux kernel now won't
   get surrounded by this macro:
     acpi_ps_get_name()

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    9 +++++++++
 drivers/acpi/acpica/Makefile      |   18 +++++++++++++++++-
 drivers/acpi/acpica/acinterp.h    |    2 --
 drivers/acpi/acpica/acnamesp.h    |    4 ----
 drivers/acpi/acpica/acparser.h    |    4 ----
 drivers/acpi/acpica/acutils.h     |    2 --
 drivers/acpi/acpica/evxface.c     |    2 +-
 drivers/acpi/acpica/nsdump.c      |    6 ------
 drivers/acpi/acpica/pstree.c      |    2 --
 drivers/acpi/acpica/psutils.c     |    2 --
 drivers/acpi/acpica/rsutils.c     |    2 --
 drivers/acpi/acpica/rsxface.c     |    4 ++--
 drivers/acpi/acpica/utxface.c     |    2 +-
 drivers/acpi/osl.c                |   11 +++--------
 include/acpi/acpixf.h             |   10 ----------
 include/acpi/platform/aclinux.h   |    7 +++++--
 include/acpi/platform/aclinuxex.h |    5 +++++
 17 files changed, 43 insertions(+), 49 deletions(-)

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5d1015c..706c2e9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,15 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_DEBUGGER
+	bool "In-kernel debugger (EXPERIMENTAL)"
+	select ACPI_DEBUG
+	help
+	  Enable in-kernel debugging 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.
+
 config ACPI_SLEEP
 	bool
 	depends on SUSPEND || HIBERNATION
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index ac78d76..885936f 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -177,8 +177,24 @@ acpi-y +=		\
 	utxferror.o	\
 	utxfmutex.o
 
-acpi-$(ACPI_FUTURE_USAGE) +=	\
+acpi-$(CONFIG_ACPI_DEBUGGER) +=	\
+	dbcmds.o		\
+	dbconvert.o		\
+	dbdisply.o		\
+	dbexec.o		\
+	dbhistry.o		\
+	dbinput.o		\
+	dbmethod.o		\
+	dbnames.o		\
+	dbobject.o		\
+	dbstats.o		\
+	dbutils.o		\
+	dbxface.o		\
 	rsdump.o		\
+
+acpi-$(ACPI_FUTURE_USAGE) +=	\
+	dbfileio.o		\
+	dbtest.o		\
 	utcache.o		\
 	utfileio.o		\
 	utprint.o		\
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index e820ed8..e9e936e 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -397,12 +397,10 @@ void
 acpi_ex_dump_operands(union acpi_operand_object **operands,
 		      const char *opcode_name, u32 num_opcodes);
 
-#ifdef	ACPI_FUTURE_USAGE
 void
 acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags);
 
 void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * exnames - AML namestring support
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index ea0d907..5d261c9 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -193,9 +193,7 @@ acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
 /*
  * nsdump - Namespace dump/print utilities
  */
-#ifdef	ACPI_FUTURE_USAGE
 void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level);
 
@@ -208,7 +206,6 @@ acpi_status
 acpi_ns_dump_one_object(acpi_handle obj_handle,
 			u32 level, void *context, void **return_value);
 
-#ifdef	ACPI_FUTURE_USAGE
 void
 acpi_ns_dump_objects(acpi_object_type type,
 		     u8 display_type,
@@ -220,7 +217,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
 			  u8 display_type,
 			  u32 max_depth,
 			  acpi_owner_id owner_id, acpi_handle start_handle);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * nseval - Namespace evaluation functions
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 6021ccf..8fc8c7c 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -194,10 +194,8 @@ union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope,
 
 union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn);
 
-#ifdef	ACPI_FUTURE_USAGE
 union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
 						union acpi_parse_object *op);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * pswalk - parse tree walk routines
@@ -235,9 +233,7 @@ void acpi_ps_free_op(union acpi_parse_object *op);
 
 u8 acpi_ps_is_leading_char(u32 c);
 
-#ifdef	ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object *op);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ps_set_name(union acpi_parse_object *op, u32 name);
 
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index fb2aa50..8b8fef6 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -635,9 +635,7 @@ void
 acpi_ut_free_and_track(void *address,
 		       u32 component, const char *module, u32 line);
 
-#ifdef	ACPI_FUTURE_USAGE
 void acpi_ut_dump_allocation_info(void);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ut_dump_allocations(u32 component, const char *module);
 
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 81f2d9e..07d22bf 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -405,7 +405,7 @@ cleanup:
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
-#endif				/*  ACPI_FUTURE_USAGE  */
+#endif
 
 #if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 0f1daba..37aa5c4 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -60,7 +60,6 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
 
 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
-#ifdef	ACPI_FUTURE_USAGE
 static acpi_status
 acpi_ns_dump_one_object_path(acpi_handle obj_handle,
 			     u32 level, void *context, void **return_value);
@@ -68,7 +67,6 @@ acpi_ns_dump_one_object_path(acpi_handle obj_handle,
 static acpi_status
 acpi_ns_get_max_depth(acpi_handle obj_handle,
 		      u32 level, void *context, void **return_value);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
@@ -625,7 +623,6 @@ cleanup:
 	return (AE_OK);
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_objects
@@ -680,9 +677,7 @@ acpi_ns_dump_objects(acpi_object_type type,
 
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif				/* ACPI_FUTURE_USAGE */
 
-#ifdef	ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_one_object_path, acpi_ns_get_max_depth
@@ -810,7 +805,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
 
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 89984f3..cf2f2fa 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -183,7 +183,6 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
 	}
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_get_depth_next
@@ -317,4 +316,3 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
 	return (child);
 }
 #endif
-#endif				/*  ACPI_FUTURE_USAGE  */
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 183cc1e..71d2877 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -205,7 +205,6 @@ u8 acpi_ps_is_leading_char(u32 c)
 /*
  * Get op's name (4-byte name segment) or 0 if unnamed
  */
-#ifdef ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object * op)
 {
 
@@ -219,7 +218,6 @@ u32 acpi_ps_get_name(union acpi_parse_object * op)
 
 	return (op->named.name);
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 /*
  * Set op's name
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 52b024d..9486992 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -564,7 +564,6 @@ acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
  *
  ******************************************************************************/
 
-#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
 			    struct acpi_buffer *ret_buffer)
@@ -596,7 +595,6 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
 	acpi_ut_remove_reference(obj_desc);
 	return_ACPI_STATUS(status);
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 /*******************************************************************************
  *
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index de51f83..1e8cd57 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -220,7 +220,7 @@ acpi_get_current_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
-#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_possible_resources
@@ -262,7 +262,7 @@ acpi_get_possible_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
-#endif				/*  ACPI_FUTURE_USAGE  */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_set_current_resources
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index a6b0eb0..f9c8f9c 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -253,7 +253,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
-#endif				/*  ACPI_FUTURE_USAGE  */
+#endif
 
 /*****************************************************************************
  *
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 739a4a6..3272915 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -66,8 +66,6 @@ struct acpi_os_dpc {
 /* stuff for debugger support */
 int acpi_in_debugger;
 EXPORT_SYMBOL(acpi_in_debugger);
-
-extern char line_buf[80];
 #endif				/*ENABLE_DEBUGGER */
 
 static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
@@ -1345,15 +1343,13 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
 	return AE_OK;
 }
 
-#ifdef ACPI_FUTURE_USAGE
-u32 acpi_os_get_line(char *buffer)
+acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 {
-
 #ifdef ENABLE_DEBUGGER
 	if (acpi_in_debugger) {
 		u32 chars;
 
-		kdb_read(buffer, sizeof(line_buf));
+		kdb_read(buffer, buffer_length);
 
 		/* remove the CR kdb includes */
 		chars = strlen(buffer) - 1;
@@ -1361,9 +1357,8 @@ u32 acpi_os_get_line(char *buffer)
 	}
 #endif
 
-	return 0;
+	return AE_OK;
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 acpi_status acpi_os_signal(u32 function, void *info)
 {
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index f837adf..ded9fa3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -393,15 +393,11 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_terminate(void))
  */
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void))
-#endif
 
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			    acpi_get_system_info(struct acpi_buffer
 						 *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_statistics(struct acpi_statistics *stats))
 ACPI_EXTERNAL_RETURN_PTR(const char
@@ -625,11 +621,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 							       space_id,
 							       acpi_adr_space_handler
 							       handler))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_install_exception_handler
 			     (acpi_exception_handler handler))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_install_interface_handler
 			     (acpi_interface_handler handler))
@@ -750,12 +744,10 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_current_resources(acpi_handle device,
 							struct acpi_buffer
 							*ret_buffer))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_possible_resources(acpi_handle device,
 							 struct acpi_buffer
 							 *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_event_resources(acpi_handle device_handle,
 						      struct acpi_buffer
@@ -844,7 +836,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 /*
  * ACPI Timer interfaces
  */
-#ifdef ACPI_FUTURE_USAGE
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 				acpi_get_timer_resolution(u32 *resolution))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks))
@@ -853,7 +844,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 				acpi_get_timer_duration(u32 start_ticks,
 							u32 end_ticks,
 							u32 *time_elapsed))
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * Error/Warning output
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 74ba46c..323e5da 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -63,12 +63,16 @@
 
 #define ACPI_USE_SYSTEM_INTTYPES
 
-/* Compile for reduced hardware mode only with this kernel config */
+/* Kernel specific ACPICA configuration */
 
 #ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
 #define ACPI_REDUCED_HARDWARE 1
 #endif
 
+#ifdef CONFIG_ACPI_DEBUGGER
+#define ACPI_DEBUGGER
+#endif
+
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
@@ -151,7 +155,6 @@
  * OSL interfaces used by utilities
  */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index acedc3f..fd6d70f 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,6 +124,11 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
+static inline u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 12/14] ACPI: Enable build of AML interpreter debugger
@ 2015-10-19  2:25     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:25 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch enables ACPICA debugger files using a configurable
CONFIG_ACPI_DEBUGGER configuration item. Those debugger related code that
was originally masked as ACPI_FUTURE_USAGE now gets unmasked.

Necessary OSL stubs are also added in this patch:
1. acpi_os_readable(): This should be arch specific in Linux, while this
    patch doesn't introduce real implementation and a complex mechanism to
    allow architecture specific acpi_os_readable() to be implemented to
    validate the address. It may be done by future commits.
2. acpi_os_get_line(): This is used to obtain debugger command input. This
    patch only introduces a simple KDB concept example in it and the
    example should be co-working with the code implemented in
    acpi_os_printf(). Since this KDB example won't be compiled unless
    ENABLE_DEBUGGER is defined and it seems Linux has already stopped to
    use ENABLE_DEBUGGER, thus do not expect it can work properly.

This patch also cleans up all other ACPI_FUTURE_USAGE surroundings
accordingly.
1. Since linkage error can be automatically detected, declaration in the
   headers needn't be surrounded by ACPI_FUTURE_USAGE.
   So only the following separate exported fuction bodies are masked by
   this macro (other exported fucntions may have already been masked at
   entire module level via drivers/acpi/acpica/Makefile):
     acpi_install_exception_handler()
     acpi_subsystem_status()
     acpi_get_system_info()
     acpi_get_statistics()
     acpi_install_initialization_handler()
2. Since strip can automatically zap the no-user functions, functions that
   are not marked with ACPI_EXPORT_SYMBOL() needn't get surrounded by
   ACPI_FUTURE_USAGE.
   So the following function which is not used by Linux kernel now won't
   get surrounded by this macro:
     acpi_ps_get_name()

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    9 +++++++++
 drivers/acpi/acpica/Makefile      |   18 +++++++++++++++++-
 drivers/acpi/acpica/acinterp.h    |    2 --
 drivers/acpi/acpica/acnamesp.h    |    4 ----
 drivers/acpi/acpica/acparser.h    |    4 ----
 drivers/acpi/acpica/acutils.h     |    2 --
 drivers/acpi/acpica/evxface.c     |    2 +-
 drivers/acpi/acpica/nsdump.c      |    6 ------
 drivers/acpi/acpica/pstree.c      |    2 --
 drivers/acpi/acpica/psutils.c     |    2 --
 drivers/acpi/acpica/rsutils.c     |    2 --
 drivers/acpi/acpica/rsxface.c     |    4 ++--
 drivers/acpi/acpica/utxface.c     |    2 +-
 drivers/acpi/osl.c                |   11 +++--------
 include/acpi/acpixf.h             |   10 ----------
 include/acpi/platform/aclinux.h   |    7 +++++--
 include/acpi/platform/aclinuxex.h |    5 +++++
 17 files changed, 43 insertions(+), 49 deletions(-)

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5d1015c..706c2e9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,15 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_DEBUGGER
+	bool "In-kernel debugger (EXPERIMENTAL)"
+	select ACPI_DEBUG
+	help
+	  Enable in-kernel debugging 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.
+
 config ACPI_SLEEP
 	bool
 	depends on SUSPEND || HIBERNATION
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index ac78d76..885936f 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -177,8 +177,24 @@ acpi-y +=		\
 	utxferror.o	\
 	utxfmutex.o
 
-acpi-$(ACPI_FUTURE_USAGE) +=	\
+acpi-$(CONFIG_ACPI_DEBUGGER) +=	\
+	dbcmds.o		\
+	dbconvert.o		\
+	dbdisply.o		\
+	dbexec.o		\
+	dbhistry.o		\
+	dbinput.o		\
+	dbmethod.o		\
+	dbnames.o		\
+	dbobject.o		\
+	dbstats.o		\
+	dbutils.o		\
+	dbxface.o		\
 	rsdump.o		\
+
+acpi-$(ACPI_FUTURE_USAGE) +=	\
+	dbfileio.o		\
+	dbtest.o		\
 	utcache.o		\
 	utfileio.o		\
 	utprint.o		\
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index e820ed8..e9e936e 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -397,12 +397,10 @@ void
 acpi_ex_dump_operands(union acpi_operand_object **operands,
 		      const char *opcode_name, u32 num_opcodes);
 
-#ifdef	ACPI_FUTURE_USAGE
 void
 acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags);
 
 void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * exnames - AML namestring support
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index ea0d907..5d261c9 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -193,9 +193,7 @@ acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
 /*
  * nsdump - Namespace dump/print utilities
  */
-#ifdef	ACPI_FUTURE_USAGE
 void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level);
 
@@ -208,7 +206,6 @@ acpi_status
 acpi_ns_dump_one_object(acpi_handle obj_handle,
 			u32 level, void *context, void **return_value);
 
-#ifdef	ACPI_FUTURE_USAGE
 void
 acpi_ns_dump_objects(acpi_object_type type,
 		     u8 display_type,
@@ -220,7 +217,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
 			  u8 display_type,
 			  u32 max_depth,
 			  acpi_owner_id owner_id, acpi_handle start_handle);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * nseval - Namespace evaluation functions
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 6021ccf..8fc8c7c 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -194,10 +194,8 @@ union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope,
 
 union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn);
 
-#ifdef	ACPI_FUTURE_USAGE
 union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
 						union acpi_parse_object *op);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * pswalk - parse tree walk routines
@@ -235,9 +233,7 @@ void acpi_ps_free_op(union acpi_parse_object *op);
 
 u8 acpi_ps_is_leading_char(u32 c);
 
-#ifdef	ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object *op);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ps_set_name(union acpi_parse_object *op, u32 name);
 
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index fb2aa50..8b8fef6 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -635,9 +635,7 @@ void
 acpi_ut_free_and_track(void *address,
 		       u32 component, const char *module, u32 line);
 
-#ifdef	ACPI_FUTURE_USAGE
 void acpi_ut_dump_allocation_info(void);
-#endif				/* ACPI_FUTURE_USAGE */
 
 void acpi_ut_dump_allocations(u32 component, const char *module);
 
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 81f2d9e..07d22bf 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -405,7 +405,7 @@ cleanup:
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
-#endif				/*  ACPI_FUTURE_USAGE  */
+#endif
 
 #if (!ACPI_REDUCED_HARDWARE)
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 0f1daba..37aa5c4 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -60,7 +60,6 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
 
 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 
-#ifdef	ACPI_FUTURE_USAGE
 static acpi_status
 acpi_ns_dump_one_object_path(acpi_handle obj_handle,
 			     u32 level, void *context, void **return_value);
@@ -68,7 +67,6 @@ acpi_ns_dump_one_object_path(acpi_handle obj_handle,
 static acpi_status
 acpi_ns_get_max_depth(acpi_handle obj_handle,
 		      u32 level, void *context, void **return_value);
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
@@ -625,7 +623,6 @@ cleanup:
 	return (AE_OK);
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_objects
@@ -680,9 +677,7 @@ acpi_ns_dump_objects(acpi_object_type type,
 
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif				/* ACPI_FUTURE_USAGE */
 
-#ifdef	ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_dump_one_object_path, acpi_ns_get_max_depth
@@ -810,7 +805,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
 
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 }
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*******************************************************************************
  *
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 89984f3..cf2f2fa 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -183,7 +183,6 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
 	}
 }
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_get_depth_next
@@ -317,4 +316,3 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
 	return (child);
 }
 #endif
-#endif				/*  ACPI_FUTURE_USAGE  */
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 183cc1e..71d2877 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -205,7 +205,6 @@ u8 acpi_ps_is_leading_char(u32 c)
 /*
  * Get op's name (4-byte name segment) or 0 if unnamed
  */
-#ifdef ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object * op)
 {
 
@@ -219,7 +218,6 @@ u32 acpi_ps_get_name(union acpi_parse_object * op)
 
 	return (op->named.name);
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 /*
  * Set op's name
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 52b024d..9486992 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -564,7 +564,6 @@ acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
  *
  ******************************************************************************/
 
-#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
 			    struct acpi_buffer *ret_buffer)
@@ -596,7 +595,6 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
 	acpi_ut_remove_reference(obj_desc);
 	return_ACPI_STATUS(status);
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 /*******************************************************************************
  *
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index de51f83..1e8cd57 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -220,7 +220,7 @@ acpi_get_current_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
-#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_get_possible_resources
@@ -262,7 +262,7 @@ acpi_get_possible_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
-#endif				/*  ACPI_FUTURE_USAGE  */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_set_current_resources
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index a6b0eb0..f9c8f9c 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -253,7 +253,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
-#endif				/*  ACPI_FUTURE_USAGE  */
+#endif
 
 /*****************************************************************************
  *
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 739a4a6..3272915 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -66,8 +66,6 @@ struct acpi_os_dpc {
 /* stuff for debugger support */
 int acpi_in_debugger;
 EXPORT_SYMBOL(acpi_in_debugger);
-
-extern char line_buf[80];
 #endif				/*ENABLE_DEBUGGER */
 
 static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
@@ -1345,15 +1343,13 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
 	return AE_OK;
 }
 
-#ifdef ACPI_FUTURE_USAGE
-u32 acpi_os_get_line(char *buffer)
+acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 {
-
 #ifdef ENABLE_DEBUGGER
 	if (acpi_in_debugger) {
 		u32 chars;
 
-		kdb_read(buffer, sizeof(line_buf));
+		kdb_read(buffer, buffer_length);
 
 		/* remove the CR kdb includes */
 		chars = strlen(buffer) - 1;
@@ -1361,9 +1357,8 @@ u32 acpi_os_get_line(char *buffer)
 	}
 #endif
 
-	return 0;
+	return AE_OK;
 }
-#endif				/*  ACPI_FUTURE_USAGE  */
 
 acpi_status acpi_os_signal(u32 function, void *info)
 {
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index f837adf..ded9fa3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -393,15 +393,11 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_terminate(void))
  */
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void))
-#endif
 
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			    acpi_get_system_info(struct acpi_buffer
 						 *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_statistics(struct acpi_statistics *stats))
 ACPI_EXTERNAL_RETURN_PTR(const char
@@ -625,11 +621,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 							       space_id,
 							       acpi_adr_space_handler
 							       handler))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_install_exception_handler
 			     (acpi_exception_handler handler))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_install_interface_handler
 			     (acpi_interface_handler handler))
@@ -750,12 +744,10 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_current_resources(acpi_handle device,
 							struct acpi_buffer
 							*ret_buffer))
-#ifdef ACPI_FUTURE_USAGE
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_possible_resources(acpi_handle device,
 							 struct acpi_buffer
 							 *ret_buffer))
-#endif
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
 			     acpi_get_event_resources(acpi_handle device_handle,
 						      struct acpi_buffer
@@ -844,7 +836,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 /*
  * ACPI Timer interfaces
  */
-#ifdef ACPI_FUTURE_USAGE
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 				acpi_get_timer_resolution(u32 *resolution))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks))
@@ -853,7 +844,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 				acpi_get_timer_duration(u32 start_ticks,
 							u32 end_ticks,
 							u32 *time_elapsed))
-#endif				/* ACPI_FUTURE_USAGE */
 
 /*
  * Error/Warning output
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 74ba46c..323e5da 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -63,12 +63,16 @@
 
 #define ACPI_USE_SYSTEM_INTTYPES
 
-/* Compile for reduced hardware mode only with this kernel config */
+/* Kernel specific ACPICA configuration */
 
 #ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
 #define ACPI_REDUCED_HARDWARE 1
 #endif
 
+#ifdef CONFIG_ACPI_DEBUGGER
+#define ACPI_DEBUGGER
+#endif
+
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
@@ -151,7 +155,6 @@
  * OSL interfaces used by utilities
  */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index acedc3f..fd6d70f 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,6 +124,11 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
+static inline u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 13/14] ACPICA: Debugger: Fix dead lock issue ocurred in single stepping mode
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:26     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:26 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 35273add90da19cd8790fdb5735f52e3c9861684

When single step execution is not ended, executing another control methods
leads to dead locks around interpreter lock/namespace lock/method
serialization lock. So we should only allow one execution from the debugger
at same time. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/35273add
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbexec.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
index 258e615..d713e2d 100644
--- a/drivers/acpi/acpica/dbexec.c
+++ b/drivers/acpi/acpica/dbexec.c
@@ -370,7 +370,17 @@ acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
 #ifdef ACPI_DEBUG_OUTPUT
 	u32 previous_allocations;
 	u32 allocations;
+#endif
 
+	/*
+	 * Allow one execution to be performed by debugger or single step
+	 * execution will be dead locked by the interpreter mutexes.
+	 */
+	if (acpi_gbl_method_executing) {
+		acpi_os_printf("Only one debugger execution is allowed.\n");
+		return;
+	}
+#ifdef ACPI_DEBUG_OUTPUT
 	/* Memory allocation tracking */
 
 	previous_allocations = acpi_db_get_outstanding_allocations();
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 13/14] ACPICA: Debugger: Fix dead lock issue ocurred in single stepping mode
@ 2015-10-19  2:26     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:26 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 35273add90da19cd8790fdb5735f52e3c9861684

When single step execution is not ended, executing another control methods
leads to dead locks around interpreter lock/namespace lock/method
serialization lock. So we should only allow one execution from the debugger
at same time. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/35273add
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/dbexec.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c
index 258e615..d713e2d 100644
--- a/drivers/acpi/acpica/dbexec.c
+++ b/drivers/acpi/acpica/dbexec.c
@@ -370,7 +370,17 @@ acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
 #ifdef ACPI_DEBUG_OUTPUT
 	u32 previous_allocations;
 	u32 allocations;
+#endif
 
+	/*
+	 * Allow one execution to be performed by debugger or single step
+	 * execution will be dead locked by the interpreter mutexes.
+	 */
+	if (acpi_gbl_method_executing) {
+		acpi_os_printf("Only one debugger execution is allowed.\n");
+		return;
+	}
+#ifdef ACPI_DEBUG_OUTPUT
 	/* Memory allocation tracking */
 
 	previous_allocations = acpi_db_get_outstanding_allocations();
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 14/14] ACPICA: Update version to 20150930
  2015-10-19  2:24   ` Lv Zheng
@ 2015-10-19  2:26     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:26 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit e9c75ca267262326e80d49a290e8387a5963e2d2

Version 20150930.

Link: https://github.com/acpica/acpica/commit/e9c75ca2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 include/acpi/acpixf.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index ded9fa3..3aaaa86 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20150818
+#define ACPI_CA_VERSION                 0x20150930
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 14/14] ACPICA: Update version to 20150930
@ 2015-10-19  2:26     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-10-19  2:26 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

From: Bob Moore <robert.moore@intel.com>

ACPICA commit e9c75ca267262326e80d49a290e8387a5963e2d2

Version 20150930.

Link: https://github.com/acpica/acpica/commit/e9c75ca2
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 include/acpi/acpixf.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index ded9fa3..3aaaa86 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20150818
+#define ACPI_CA_VERSION                 0x20150930
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* Re: [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
  2015-10-19  2:25     ` Lv Zheng
  (?)
@ 2015-10-19 21:04     ` Rafael J. Wysocki
  2015-10-20  2:03         ` Zheng, Lv
  -1 siblings, 1 reply; 131+ messages in thread
From: Rafael J. Wysocki @ 2015-10-19 21:04 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Lv Zheng, linux-kernel, linux-acpi,
	Bob Moore

On Monday, October 19, 2015 10:25:32 AM Lv Zheng wrote:
> ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108
> 
> The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
> acpi_terminate() right in the user command loop, because when the debugger
> exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
> and the debugger should only be terminated by its users
> (acpi_terminate_debugger()) rather than being terminated itself. Leaving such
> invocations causes kernel panic when the debugger is shipped in the Linux
> kernel.
> 
> This patch fixes this issue. Lv Zheng.
> 
> Link: https://github.com/acpica/acpica/commit/0dd68e16
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> Signed-off-by: Bob Moore <robert.moore@intel.com>

This patch does not apply for me on top of the current mainline.

What tree is it applicable to?

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
  2015-10-19 21:04     ` Rafael J. Wysocki
@ 2015-10-20  2:03         ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-10-20  2:03 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

I was using linux-pm.git/linux-next base which I downloaded a week ago.
Maybe the conflict was caused by the fast-path ACPICA table fix merged after my downloading.
Let me check again.

Thanks and best regards
-Lv

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, October 20, 2015 5:04 AM
> 
> On Monday, October 19, 2015 10:25:32 AM Lv Zheng wrote:
> > ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108
> >
> > The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
> > acpi_terminate() right in the user command loop, because when the debugger
> > exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
> > and the debugger should only be terminated by its users
> > (acpi_terminate_debugger()) rather than being terminated itself. Leaving such
> > invocations causes kernel panic when the debugger is shipped in the Linux
> > kernel.
> >
> > This patch fixes this issue. Lv Zheng.
> >
> > Link: https://github.com/acpica/acpica/commit/0dd68e16
> > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > Signed-off-by: Bob Moore <robert.moore@intel.com>
> 
> This patch does not apply for me on top of the current mainline.
> 
> What tree is it applicable to?
> 
> Thanks,
> Rafael


^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
@ 2015-10-20  2:03         ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-10-20  2:03 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1401 bytes --]

I was using linux-pm.git/linux-next base which I downloaded a week ago.
Maybe the conflict was caused by the fast-path ACPICA table fix merged after my downloading.
Let me check again.

Thanks and best regards
-Lv

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, October 20, 2015 5:04 AM
> 
> On Monday, October 19, 2015 10:25:32 AM Lv Zheng wrote:
> > ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108
> >
> > The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
> > acpi_terminate() right in the user command loop, because when the debugger
> > exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
> > and the debugger should only be terminated by its users
> > (acpi_terminate_debugger()) rather than being terminated itself. Leaving such
> > invocations causes kernel panic when the debugger is shipped in the Linux
> > kernel.
> >
> > This patch fixes this issue. Lv Zheng.
> >
> > Link: https://github.com/acpica/acpica/commit/0dd68e16
> > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > Signed-off-by: Bob Moore <robert.moore@intel.com>
> 
> This patch does not apply for me on top of the current mainline.
> 
> What tree is it applicable to?
> 
> Thanks,
> Rafael

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
  2015-10-20  2:03         ` Zheng, Lv
@ 2015-10-20  7:14           ` Zheng, Lv
  -1 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-10-20  7:14 UTC (permalink / raw)
  To: Zheng, Lv, Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

It looks patch 08 is not listed on the https://patchwork.kernel.org/project/linux-acpi/list/.
I just re-sent it, hope it could reach the mailing list this time.
I'll also send it in attachment style via private route to you.

Thanks and best regards
-Lv

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-owner@vger.kernel.org] On Behalf Of Zheng, Lv
> Sent: Tuesday, October 20, 2015 10:04 AM
> 
> I was using linux-pm.git/linux-next base which I downloaded a week ago.
> Maybe the conflict was caused by the fast-path ACPICA table fix merged after my downloading.
> Let me check again.
> 
> Thanks and best regards
> -Lv
> 
> > From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> > Sent: Tuesday, October 20, 2015 5:04 AM
> >
> > On Monday, October 19, 2015 10:25:32 AM Lv Zheng wrote:
> > > ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108
> > >
> > > The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
> > > acpi_terminate() right in the user command loop, because when the debugger
> > > exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
> > > and the debugger should only be terminated by its users
> > > (acpi_terminate_debugger()) rather than being terminated itself. Leaving such
> > > invocations causes kernel panic when the debugger is shipped in the Linux
> > > kernel.
> > >
> > > This patch fixes this issue. Lv Zheng.
> > >
> > > Link: https://github.com/acpica/acpica/commit/0dd68e16
> > > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > > Signed-off-by: Bob Moore <robert.moore@intel.com>
> >
> > This patch does not apply for me on top of the current mainline.
> >
> > What tree is it applicable to?
> >
> > Thanks,
> > Rafael
> 
> N�����r��y���b�X��ǧv�^�)޺{.n�+����{�i�b�{ay�\x1dʇڙ�,j\r��f���h���z�\x1e�w���
> 
> ���j:+v���w�j�m����\r����zZ+�����ݢj"��!�i

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic
@ 2015-10-20  7:14           ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-10-20  7:14 UTC (permalink / raw)
  To: Zheng, Lv, Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2119 bytes --]

It looks patch 08 is not listed on the https://patchwork.kernel.org/project/linux-acpi/list/.
I just re-sent it, hope it could reach the mailing list this time.
I'll also send it in attachment style via private route to you.

Thanks and best regards
-Lv

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-owner@vger.kernel.org] On Behalf Of Zheng, Lv
> Sent: Tuesday, October 20, 2015 10:04 AM
> 
> I was using linux-pm.git/linux-next base which I downloaded a week ago.
> Maybe the conflict was caused by the fast-path ACPICA table fix merged after my downloading.
> Let me check again.
> 
> Thanks and best regards
> -Lv
> 
> > From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> > Sent: Tuesday, October 20, 2015 5:04 AM
> >
> > On Monday, October 19, 2015 10:25:32 AM Lv Zheng wrote:
> > > ACPICA commit 0dd68e16274cd38224aa4781eddc57dc2cbaa108
> > >
> > > The quit/exit commands shouldn't invoke acpi_terminate_debugger() and
> > > acpi_terminate() right in the user command loop, because when the debugger
> > > exits, the kernel ACPI subsystem shouldn't be terminated (acpi_terminate())
> > > and the debugger should only be terminated by its users
> > > (acpi_terminate_debugger()) rather than being terminated itself. Leaving such
> > > invocations causes kernel panic when the debugger is shipped in the Linux
> > > kernel.
> > >
> > > This patch fixes this issue. Lv Zheng.
> > >
> > > Link: https://github.com/acpica/acpica/commit/0dd68e16
> > > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > > Signed-off-by: Bob Moore <robert.moore@intel.com>
> >
> > This patch does not apply for me on top of the current mainline.
> >
> > What tree is it applicable to?
> >
> > Thanks,
> > Rafael
> 
> N�����r��y���b�X��ǧv�^�)޺{.n�+����{�i�b�{ay�\x1dʇڙ�,j\r��f���h���z�\x1e�w���
> 
> ���j:+v���w�j�m����\r����zZ+�����ݢj"��!�i
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 0/5] ACPICA / debugger: Add in-kernel AML debugger support
       [not found] <8c1016ca8a570ba7c7a1c9f0f88d73cd83cea490>
@ 2015-11-06  6:46   ` Lv Zheng
  2015-11-06  6:46   ` Lv Zheng
  1 sibling, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:46 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.
3. upstream the userspace acpidbg to the ACPICA upstream.

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (4):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 drivers/acpi/Kconfig                     |   13 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  818 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |    2 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   63 +--
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  250 ++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   11 +
 include/acpi/platform/aclinux.h          |    2 +
 include/acpi/platform/aclinuxex.h        |    9 +
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 18 files changed, 1699 insertions(+), 163 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 0/5] ACPICA / debugger: Add in-kernel AML debugger support
@ 2015-11-06  6:46   ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:46 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.
3. upstream the userspace acpidbg to the ACPICA upstream.

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (4):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 drivers/acpi/Kconfig                     |   13 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  818 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |    2 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   63 +--
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  250 ++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   11 +
 include/acpi/platform/aclinux.h          |    2 +
 include/acpi/platform/aclinuxex.h        |    9 +
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 18 files changed, 1699 insertions(+), 163 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 1/5] ACPICA: Debugger: Remove unnecessary status check
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-06  6:46     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:46 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 1/5] ACPICA: Debugger: Remove unnecessary status check
@ 2015-11-06  6:46     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:46 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 2/5] ACPICA: Debugger: Convert some mechanisms to OSPM specific
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-06  6:47     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 2/5] ACPICA: Debugger: Convert some mechanisms to OSPM specific
@ 2015-11-06  6:47     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 3/5] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-06  6:47     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    2 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  792 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 899 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..2b89fd7 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,7 +58,7 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..853ea94
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,792 @@
+/*
+ * 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_dbg.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.
+ */
+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);
+		/*
+		 * A control method execution may be blocked if we wait
+		 * user space here and some kernel functionalities may be
+		 * executing another control method that need to be
+		 * synchronized with the one executed by the debugger
+		 * thread. Thus we do not wait when the user space isn't
+		 * fast enough to drain the logs, so that the logs are
+		 * dropped when the buffer is overflow and the normal
+		 * kernel functionalities won't get blocked.
+		 *
+		 * A module parameter may be used to tune this if the
+		 * integrity of the debugger output is required.
+		 */
+		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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	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_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 3/5] ACPI / debugger: Add IO interface to access debugger functionalities
@ 2015-11-06  6:47     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    2 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  792 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 899 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..2b89fd7 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,7 +58,7 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..853ea94
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,792 @@
+/*
+ * 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_dbg.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.
+ */
+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);
+		/*
+		 * A control method execution may be blocked if we wait
+		 * user space here and some kernel functionalities may be
+		 * executing another control method that need to be
+		 * synchronized with the one executed by the debugger
+		 * thread. Thus we do not wait when the user space isn't
+		 * fast enough to drain the logs, so that the logs are
+		 * dropped when the buffer is overflow and the normal
+		 * kernel functionalities won't get blocked.
+		 *
+		 * A module parameter may be used to tune this if the
+		 * integrity of the debugger output is required.
+		 */
+		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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	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_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 4/5] tools/power/acpi: Add userspace AML interface support
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-06  6:47     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..e4e8316
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/aml\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 4/5] tools/power/acpi: Add userspace AML interface support
@ 2015-11-06  6:47     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..e4e8316
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/aml\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 5/5] ACPI / debugger: Add module support for ACPI debugger
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-06  6:47     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   11 +++
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 88 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 2b89fd7..c4d4a05 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -66,6 +66,17 @@ config ACPI_DEBUGGER
 	  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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 853ea94..7ca3202 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -350,7 +350,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * acpi_aml_read_cmd() - Capture debugger input
@@ -361,7 +360,7 @@ EXPORT_SYMBOL(acpi_aml_write_log);
  * the debugger input commands and store the input commands into the
  * 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 size = 0;
@@ -403,7 +402,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 static int acpi_aml_thread(void *unsed)
 {
@@ -440,7 +438,7 @@ static int acpi_aml_thread(void *unsed)
  * This function should be used to implement acpi_os_execute() which is
  * 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;
 
@@ -462,30 +460,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	if (single_step)
 		acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+	else
+		acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
 
-	status = acpi_os_get_line(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 static int acpi_aml_open(struct inode *inode, struct file *file)
 {
@@ -759,10 +754,23 @@ static const struct file_operations acpi_aml_operations = {
 	.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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -772,21 +780,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..ce5ac00 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,12 +1580,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1401,7 +1596,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [RFC PATCH v2 5/5] ACPI / debugger: Add module support for ACPI debugger
@ 2015-11-06  6:47     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-06  6:47 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   11 +++
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 88 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 2b89fd7..c4d4a05 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -66,6 +66,17 @@ config ACPI_DEBUGGER
 	  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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 853ea94..7ca3202 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -350,7 +350,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * acpi_aml_read_cmd() - Capture debugger input
@@ -361,7 +360,7 @@ EXPORT_SYMBOL(acpi_aml_write_log);
  * the debugger input commands and store the input commands into the
  * 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 size = 0;
@@ -403,7 +402,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 static int acpi_aml_thread(void *unsed)
 {
@@ -440,7 +438,7 @@ static int acpi_aml_thread(void *unsed)
  * This function should be used to implement acpi_os_execute() which is
  * 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;
 
@@ -462,30 +460,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	if (single_step)
 		acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+	else
+		acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
 
-	status = acpi_os_get_line(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 static int acpi_aml_open(struct inode *inode, struct file *file)
 {
@@ -759,10 +754,23 @@ static const struct file_operations acpi_aml_operations = {
 	.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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -772,21 +780,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..ce5ac00 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,12 +1580,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1401,7 +1596,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 0/7] ACPICA / debugger: Add in-kernel AML debugger support
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-10  8:21     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

Chen Yu (1):
  ACPI / x86: introduce acpi_os_readable() support

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 arch/x86/Kconfig                         |    1 +
 arch/x86/include/asm/acenv.h             |    1 +
 arch/x86/kernel/acpi/boot.c              |   14 +
 drivers/acpi/Kconfig                     |   16 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  818 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  262 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    3 +-
 include/acpi/platform/aclinuxex.h        |    8 +-
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 26 files changed, 1833 insertions(+), 212 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v2 0/7] ACPICA / debugger: Add in-kernel AML debugger support
@ 2015-11-10  8:21     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

Chen Yu (1):
  ACPI / x86: introduce acpi_os_readable() support

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 arch/x86/Kconfig                         |    1 +
 arch/x86/include/asm/acenv.h             |    1 +
 arch/x86/kernel/acpi/boot.c              |   14 +
 drivers/acpi/Kconfig                     |   16 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  818 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  262 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    3 +-
 include/acpi/platform/aclinuxex.h        |    8 +-
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 26 files changed, 1833 insertions(+), 212 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v2 1/7] ACPICA: Debugger: Remove unnecessary status check
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:21       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 1/7] ACPICA: Debugger: Remove unnecessary status check
@ 2015-11-10  8:21       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:21       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific
@ 2015-11-10  8:21       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:21       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
@ 2015-11-10  8:21       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:21 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:22       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  792 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 900 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..4de3517 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..7be0851
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,792 @@
+/*
+ * 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_dbg.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.
+ */
+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);
+		/*
+		 * A control method execution may be blocked if we wait
+		 * user space here and some kernel functionalities may be
+		 * executing another control method that need to be
+		 * synchronized with the one executed by the debugger
+		 * thread. Thus we do not wait when the user space isn't
+		 * fast enough to drain the logs, so that the logs are
+		 * dropped when the buffer is overflow and the normal
+		 * kernel functionalities won't get blocked.
+		 *
+		 * A module parameter may be used to tune this if the
+		 * integrity of the debugger output is required.
+		 */
+		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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
@ 2015-11-10  8:22       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  792 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 900 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..4de3517 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..7be0851
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,792 @@
+/*
+ * 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_dbg.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.
+ */
+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);
+		/*
+		 * A control method execution may be blocked if we wait
+		 * user space here and some kernel functionalities may be
+		 * executing another control method that need to be
+		 * synchronized with the one executed by the debugger
+		 * thread. Thus we do not wait when the user space isn't
+		 * fast enough to drain the logs, so that the logs are
+		 * dropped when the buffer is overflow and the normal
+		 * kernel functionalities won't get blocked.
+		 *
+		 * A module parameter may be used to tune this if the
+		 * integrity of the debugger output is required.
+		 */
+		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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:22       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPI
AML debugger to validate user specified pointers for the dumpable AML
operand objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   14 ++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 96d058a..25585ee 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..3e03fde 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,20 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long start_pfn, end_pfn;
+
+	start_pfn = page_to_pfn(virt_to_page(pointer));
+	end_pfn = page_to_pfn(virt_to_page(pointer + length));
+	/*
+	 * Since the acpi address is allocated by kmalloc, we only
+	 * need to consider the direct-mapping virtual address,
+	 * rather than the kmap/vmalloc/ioremap address.
+	 */
+	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false;
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4de3517..e67b1b5 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..bc3da95 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1387,6 +1387,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 	return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length);
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return true;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-11-10  8:22       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPI
AML debugger to validate user specified pointers for the dumpable AML
operand objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   14 ++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 96d058a..25585ee 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..3e03fde 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,20 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long start_pfn, end_pfn;
+
+	start_pfn = page_to_pfn(virt_to_page(pointer));
+	end_pfn = page_to_pfn(virt_to_page(pointer + length));
+	/*
+	 * Since the acpi address is allocated by kmalloc, we only
+	 * need to consider the direct-mapping virtual address,
+	 * rather than the kmap/vmalloc/ioremap address.
+	 */
+	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false;
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4de3517..e67b1b5 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..bc3da95 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1387,6 +1387,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 	return AE_OK;
 }
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length);
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return true;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 6/7] tools/power/acpi: Add userspace AML interface support
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:22       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 6/7] tools/power/acpi: Add userspace AML interface support
@ 2015-11-10  8:22       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 7/7] ACPI / debugger: Add module support for ACPI debugger
  2015-11-10  8:21     ` Lv Zheng
@ 2015-11-10  8:22       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   12 ++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 89 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e67b1b5..73b45f9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -63,13 +63,23 @@ config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging 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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 7be0851..8fcf752 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -350,7 +350,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * acpi_aml_read_cmd() - Capture debugger input
@@ -361,7 +360,7 @@ EXPORT_SYMBOL(acpi_aml_write_log);
  * the debugger input commands and store the input commands into the
  * 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 size = 0;
@@ -403,7 +402,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 static int acpi_aml_thread(void *unsed)
 {
@@ -440,7 +438,7 @@ static int acpi_aml_thread(void *unsed)
  * This function should be used to implement acpi_os_execute() which is
  * 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;
 
@@ -462,30 +460,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 static int acpi_aml_open(struct inode *inode, struct file *file)
 {
@@ -759,10 +754,23 @@ static const struct file_operations acpi_aml_operations = {
 	.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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -772,21 +780,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bc3da95..17fb138 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,6 +1580,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 #ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
 u8 acpi_os_readable(void *pointer, acpi_size length)
@@ -1403,7 +1598,7 @@ acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1413,7 +1608,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v2 7/7] ACPI / debugger: Add module support for ACPI debugger
@ 2015-11-10  8:22       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-10  8:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   12 ++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 89 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e67b1b5..73b45f9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -63,13 +63,23 @@ config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging 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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 7be0851..8fcf752 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -350,7 +350,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * acpi_aml_read_cmd() - Capture debugger input
@@ -361,7 +360,7 @@ EXPORT_SYMBOL(acpi_aml_write_log);
  * the debugger input commands and store the input commands into the
  * 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 size = 0;
@@ -403,7 +402,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 static int acpi_aml_thread(void *unsed)
 {
@@ -440,7 +438,7 @@ static int acpi_aml_thread(void *unsed)
  * This function should be used to implement acpi_os_execute() which is
  * 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;
 
@@ -462,30 +460,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 static int acpi_aml_open(struct inode *inode, struct file *file)
 {
@@ -759,10 +754,23 @@ static const struct file_operations acpi_aml_operations = {
 	.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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -772,21 +780,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bc3da95..17fb138 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,6 +1580,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 #ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
 u8 acpi_os_readable(void *pointer, acpi_size length)
@@ -1403,7 +1598,7 @@ acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1413,7 +1608,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10  8:22       ` Lv Zheng
  (?)
@ 2015-11-10  9:42       ` Chen, Yu C
  2015-11-10 10:46         ` Chen, Yu C
                           ` (2 more replies)
  -1 siblings, 3 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-11-10  9:42 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J, Brown, Len

Hi, Lv
Sorry for my late feedback on the patch, one minor nit below:

> -----Original Message-----
> From: Zheng, Lv
> Sent: Tuesday, November 10, 2015 4:22 PM
> To: Wysocki, Rafael J; Brown, Len
> Cc: Zheng, Lv; Lv Zheng; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Chen, Yu C
> Subject: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
> 
> From: Chen Yu <yu.c.chen@intel.com>
> 
> This patch implements acpi_os_readable(). The function is used by ACPI AML
> debugger to validate user specified pointers for the dumpable AML operand
> objects.
> 
> Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> ---
> +bool __acpi_memory_readable(void *pointer, size_t length) {
> +	unsigned long start_pfn, end_pfn;
> +
We should only check the low memory, otherwise the highmem address might
bring unexpected behavior in this function, I think we should add:
	if (pointer  >= PAGE_OFFSET)
		return false;
> +	start_pfn = page_to_pfn(virt_to_page(pointer));
> +	end_pfn = page_to_pfn(virt_to_page(pointer + length));
Convert pointer to char* first?
end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));

> +	/*
> +	 * Since the acpi address is allocated by kmalloc, we only
> +	 * need to consider the direct-mapping virtual address,
> +	 * rather than the kmap/vmalloc/ioremap address.
> +	 */
> +	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false; }
> +
Thanks!

Best Regards,
Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10  9:42       ` Chen, Yu C
@ 2015-11-10 10:46         ` Chen, Yu C
  2015-11-10 13:04         ` Andy Shevchenko
  2015-11-11  5:06         ` Zheng, Lv
  2 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-11-10 10:46 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: 'Lv Zheng', 'linux-kernel@vger.kernel.org',
	'linux-acpi@vger.kernel.org',
	Wysocki, Rafael J, Brown, Len


> -----Original Message-----
> From: Chen, Yu C
> Sent: Tuesday, November 10, 2015 5:43 PM
> To: Zheng, Lv
> Cc: Lv Zheng; linux-kernel@vger.kernel.org; linux-acpi@vger.kernel.org;
> Wysocki, Rafael J; Brown, Len
> Subject: RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
> 
> Hi, Lv
> Sorry for my late feedback on the patch, one minor nit below:
> 
> > -----Original Message-----
> > From: Zheng, Lv
> > Sent: Tuesday, November 10, 2015 4:22 PM
> > To: Wysocki, Rafael J; Brown, Len
> > Cc: Zheng, Lv; Lv Zheng; linux-kernel@vger.kernel.org; linux-
> > acpi@vger.kernel.org; Chen, Yu C
> > Subject: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable()
> > support
> >
> > From: Chen Yu <yu.c.chen@intel.com>
> >
> > This patch implements acpi_os_readable(). The function is used by ACPI
> > AML debugger to validate user specified pointers for the dumpable AML
> > operand objects.
> >
> > Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > ---
> > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > +	unsigned long start_pfn, end_pfn;
> > +
> We should only check the low memory, otherwise the highmem address
> might bring unexpected behavior in this function, I think we should add:
> 	if (pointer  >= PAGE_OFFSET)
> 		return false;
Should be :
	If (pointer < PAGE_OFFSET && pointer >= high_memory)
		return false;
> > +	start_pfn = page_to_pfn(virt_to_page(pointer));
> > +	end_pfn = page_to_pfn(virt_to_page(pointer + length));
> Convert pointer to char* first?
> end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));
> 
> > +	/*
> > +	 * Since the acpi address is allocated by kmalloc, we only
> > +	 * need to consider the direct-mapping virtual address,
> > +	 * rather than the kmap/vmalloc/ioremap address.
> > +	 */
> > +	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false; }
> > +
> Thanks!
> 
> Best Regards,
> Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10  9:42       ` Chen, Yu C
  2015-11-10 10:46         ` Chen, Yu C
@ 2015-11-10 13:04         ` Andy Shevchenko
  2015-11-10 13:56             ` Chen, Yu C
  2015-11-11  5:06         ` Zheng, Lv
  2 siblings, 1 reply; 131+ messages in thread
From: Andy Shevchenko @ 2015-11-10 13:04 UTC (permalink / raw)
  To: Chen, Yu C
  Cc: Zheng, Lv, Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J,
	Brown, Len

On Tue, Nov 10, 2015 at 11:42 AM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> Hi, Lv
> Sorry for my late feedback on the patch, one minor nit below:

>> +     start_pfn = page_to_pfn(virt_to_page(pointer));
>> +     end_pfn = page_to_pfn(virt_to_page(pointer + length));
> Convert pointer to char* first?
> end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));

Why do you need that?
void * + size_t = char * + size_t

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10 13:04         ` Andy Shevchenko
@ 2015-11-10 13:56             ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-11-10 13:56 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Zheng, Lv, Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J,
	Brown, Len

Hi, Shevchenko,
Thanks for you review

> -----Original Message-----
> From: Andy Shevchenko [mailto:andy.shevchenko@gmail.com]
> Sent: Tuesday, November 10, 2015 9:04 PM
> To: Chen, Yu C
> Cc: Zheng, Lv; Lv Zheng; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Wysocki, Rafael J; Brown, Len
> Subject: Re: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Nov 10, 2015 at 11:42 AM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> > Hi, Lv
> > Sorry for my late feedback on the patch, one minor nit below:
> 
> >> +     start_pfn = page_to_pfn(virt_to_page(pointer));
> >> +     end_pfn = page_to_pfn(virt_to_page(pointer + length));
> > Convert pointer to char* first?
> > end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));
> 
> Why do you need that?
> void * + size_t = char * + size_t
> 
Hum, I was under impression it was a pointer, so I converted it to char* for safety,
but it seems a wrong impression,and I've just tested it on gcc, it is OK without
char*.

> --
> With Best Regards,
> Andy Shevchenko

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-11-10 13:56             ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-11-10 13:56 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Zheng, Lv, Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J,
	Brown, Len

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1214 bytes --]

Hi, Shevchenko,
Thanks for you review

> -----Original Message-----
> From: Andy Shevchenko [mailto:andy.shevchenko@gmail.com]
> Sent: Tuesday, November 10, 2015 9:04 PM
> To: Chen, Yu C
> Cc: Zheng, Lv; Lv Zheng; linux-kernel@vger.kernel.org; linux-
> acpi@vger.kernel.org; Wysocki, Rafael J; Brown, Len
> Subject: Re: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Nov 10, 2015 at 11:42 AM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> > Hi, Lv
> > Sorry for my late feedback on the patch, one minor nit below:
> 
> >> +     start_pfn = page_to_pfn(virt_to_page(pointer));
> >> +     end_pfn = page_to_pfn(virt_to_page(pointer + length));
> > Convert pointer to char* first?
> > end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));
> 
> Why do you need that?
> void * + size_t = char * + size_t
> 
Hum, I was under impression it was a pointer, so I converted it to char* for safety,
but it seems a wrong impression,and I've just tested it on gcc, it is OK without
char*.

> --
> With Best Regards,
> Andy Shevchenko
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-10  9:42       ` Chen, Yu C
  2015-11-10 10:46         ` Chen, Yu C
  2015-11-10 13:04         ` Andy Shevchenko
@ 2015-11-11  5:06         ` Zheng, Lv
  2015-11-11  5:27           ` Chen, Yu C
  2015-11-17  1:49           ` Zheng, Lv
  2 siblings, 2 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-11-11  5:06 UTC (permalink / raw)
  To: Chen, Yu C
  Cc: Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J, Brown, Len

Hi, Yu

> From: Chen, Yu C
> Sent: Tuesday, November 10, 2015 5:43 PM
> 
> Hi, Lv
> Sorry for my late feedback on the patch, one minor nit below:
> 
> > From: Zheng, Lv
> > Sent: Tuesday, November 10, 2015 4:22 PM
> >
> > From: Chen Yu <yu.c.chen@intel.com>
> >
> > This patch implements acpi_os_readable(). The function is used by ACPI AML
> > debugger to validate user specified pointers for the dumpable AML operand
> > objects.
> >
> > Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > ---
> > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > +	unsigned long start_pfn, end_pfn;
> > +
> We should only check the low memory, otherwise the highmem address might
> bring unexpected behavior in this function, I think we should add:
> 	if (pointer  >= PAGE_OFFSET)
> 		return false;

I think pfn_range_is_mapped() can ensure this.
If you want to add some sanity checks, IMO, virt_addr_valid() could be better.

> > +	start_pfn = page_to_pfn(virt_to_page(pointer));
> > +	end_pfn = page_to_pfn(virt_to_page(pointer + length));
> Convert pointer to char* first?
> end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));

Either a compiler supports such a conversion or a compiler ends up fatal error by complaining unknown sizeof(void *).
So there is no need to do this here as the build test has passed.

Thanks and best regards
-Lv

> 
> > +	/*
> > +	 * Since the acpi address is allocated by kmalloc, we only
> > +	 * need to consider the direct-mapping virtual address,
> > +	 * rather than the kmap/vmalloc/ioremap address.
> > +	 */
> > +	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false; }
> > +
> Thanks!
> 
> Best Regards,
> Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-11  5:06         ` Zheng, Lv
@ 2015-11-11  5:27           ` Chen, Yu C
  2015-11-17  1:49           ` Zheng, Lv
  1 sibling, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-11-11  5:27 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: Lv Zheng, linux-kernel, linux-acpi, Wysocki, Rafael J, Brown, Len

Hi, 

> -----Original Message-----
> From: Zheng, Lv
> Sent: Wednesday, November 11, 2015 1:07 PM
> To: Chen, Yu C
> Cc: Lv Zheng; linux-kernel@vger.kernel.org; linux-acpi@vger.kernel.org;
> Wysocki, Rafael J; Brown, Len
> Subject: RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
> 
> Hi, Yu
> 
> > From: Chen, Yu C
> > Sent: Tuesday, November 10, 2015 5:43 PM
> >
> > Hi, Lv
> > Sorry for my late feedback on the patch, one minor nit below:
> >
> > > From: Zheng, Lv
> > > Sent: Tuesday, November 10, 2015 4:22 PM
> > >
> > > From: Chen Yu <yu.c.chen@intel.com>
> > >
> > > This patch implements acpi_os_readable(). The function is used by
> > > ACPI AML debugger to validate user specified pointers for the
> > > dumpable AML operand objects.
> > >
> > > Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> > > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > > ---
> > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > +	unsigned long start_pfn, end_pfn;
> > > +
> > We should only check the low memory, otherwise the highmem address
> > might bring unexpected behavior in this function, I think we should add:
> > 	if (pointer  >= PAGE_OFFSET)
> > 		return false;
> 
> I think pfn_range_is_mapped() can ensure this.
virt_to_page might return an invalid page struct if pointer is not a valid kernel address.
> If you want to add some sanity checks, IMO, virt_addr_valid() could be
> better.
Yes, virt_addr_valid is better. 
> 
> > > +	start_pfn = page_to_pfn(virt_to_page(pointer));
> > > +	end_pfn = page_to_pfn(virt_to_page(pointer + length));
> > Convert pointer to char* first?
> > end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));
> 
> Either a compiler supports such a conversion or a compiler ends up fatal error
> by complaining unknown sizeof(void *).
> So there is no need to do this here as the build test has passed.
> 
OK, got it, thanks.

> Thanks and best regards
> -Lv
> 
> >
> > > +	/*
> > > +	 * Since the acpi address is allocated by kmalloc, we only
> > > +	 * need to consider the direct-mapping virtual address,
> > > +	 * rather than the kmap/vmalloc/ioremap address.
> > > +	 */
> > > +	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false; }
> > > +
> > Thanks!
> >
> > Best Regards,
> > Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support
  2015-11-11  5:06         ` Zheng, Lv
  2015-11-11  5:27           ` Chen, Yu C
@ 2015-11-17  1:49           ` Zheng, Lv
  1 sibling, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-11-17  1:49 UTC (permalink / raw)
  To: Chen, Yu C
  Cc: 'Lv Zheng', 'linux-kernel@vger.kernel.org',
	'linux-acpi@vger.kernel.org',
	Wysocki, Rafael J, Brown, Len

Hi, Yu

> From: Zheng, Lv
> Sent: Wednesday, November 11, 2015 1:07 PM
> 
> Hi, Yu
> 
> > From: Chen, Yu C
> > Sent: Tuesday, November 10, 2015 5:43 PM
> >
> > Hi, Lv
> > Sorry for my late feedback on the patch, one minor nit below:
> >
> > > From: Zheng, Lv
> > > Sent: Tuesday, November 10, 2015 4:22 PM
> > >
> > > From: Chen Yu <yu.c.chen@intel.com>
> > >
> > > This patch implements acpi_os_readable(). The function is used by ACPI AML
> > > debugger to validate user specified pointers for the dumpable AML operand
> > > objects.
> > >
> > > Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> > > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > > ---
> > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > +	unsigned long start_pfn, end_pfn;
> > > +
> > We should only check the low memory, otherwise the highmem address might
> > bring unexpected behavior in this function, I think we should add:
> > 	if (pointer  >= PAGE_OFFSET)
> > 		return false;
> 
> I think pfn_range_is_mapped() can ensure this.
> If you want to add some sanity checks, IMO, virt_addr_valid() could be better.

I confirmed that pfn_range_is_mapped() doesn't cover this for us.
We need such a check or enhance this in pfn_range_is_mapped().
I'll remove this patch from this patchset and re-send the rest of the patches in this patchset as v3.
For acpi_os_readable() support, I'll create a separate RFC patchset with different approaches included.

Thanks and best regards
-Lv

> 
> > > +	start_pfn = page_to_pfn(virt_to_page(pointer));
> > > +	end_pfn = page_to_pfn(virt_to_page(pointer + length));
> > Convert pointer to char* first?
> > end_pfn = page_to_pfn(virt_to_page((char*)pointer + length));
> 
> Either a compiler supports such a conversion or a compiler ends up fatal error by complaining unknown sizeof(void *).
> So there is no need to do this here as the build test has passed.
> 
> Thanks and best regards
> -Lv
> 
> >
> > > +	/*
> > > +	 * Since the acpi address is allocated by kmalloc, we only
> > > +	 * need to consider the direct-mapping virtual address,
> > > +	 * rather than the kmap/vmalloc/ioremap address.
> > > +	 */
> > > +	return pfn_range_is_mapped(start_pfn, end_pfn) ? true : false; }
> > > +
> > Thanks!
> >
> > Best Regards,
> > Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v3 0/6] ACPICA / debugger: Add in-kernel AML debugger support
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-19  6:08     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

v3:
1. Remove acpi_os_readable() support from this patchset. It's sent separately.
2. Delete some deprecated comments.

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 drivers/acpi/Kconfig                     |   13 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  805 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  250 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    2 +
 include/acpi/platform/aclinuxex.h        |    9 +
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 23 files changed, 1792 insertions(+), 209 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v3 0/6] ACPICA / debugger: Add in-kernel AML debugger support
@ 2015-11-19  6:08     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

v3:
1. Remove acpi_os_readable() support from this patchset. It's sent separately.
2. Delete some deprecated comments.

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 drivers/acpi/Kconfig                     |   13 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  805 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  250 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    2 +
 include/acpi/platform/aclinuxex.h        |    9 +
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 23 files changed, 1792 insertions(+), 209 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v3 1/6] ACPICA: Debugger: Remove unnecessary status check
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:08       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 1/6] ACPICA: Debugger: Remove unnecessary status check
@ 2015-11-19  6:08       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 2/6] ACPICA: Debugger: Convert some mechanisms to OSPM specific
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:08       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 2/6] ACPICA: Debugger: Convert some mechanisms to OSPM specific
@ 2015-11-19  6:08       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 3/6] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:08       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 3/6] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
@ 2015-11-19  6:08       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 4/6] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:08       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  779 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 887 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..4de3517 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..abc23b2
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,779 @@
+/*
+ * 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_dbg.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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 4/6] ACPI / debugger: Add IO interface to access debugger functionalities
@ 2015-11-19  6:08       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  779 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 887 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..4de3517 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "In-kernel debugger (EXPERIMENTAL)"
+	bool "In-kernel debugger"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..abc23b2
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,779 @@
+/*
+ * 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_dbg.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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3272915..2de8f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -233,7 +234,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1124,6 +1126,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_aml_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
@@ -1148,11 +1159,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
@@ -1161,13 +1178,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);
@@ -1355,11 +1374,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 5/6] tools/power/acpi: Add userspace AML interface support
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:08       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 5/6] tools/power/acpi: Add userspace AML interface support
@ 2015-11-19  6:08       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 6/6] ACPI / debugger: Add module support for ACPI debugger
  2015-11-19  6:08     ` Lv Zheng
@ 2015-11-19  6:09       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   12 ++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 89 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4de3517..c4d4a05 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging 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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index abc23b2..381beb2 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -337,7 +337,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * 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
  * 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 size = 0;
@@ -390,7 +389,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 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
  * 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;
 
@@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 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,
 };
 
+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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -759,21 +767,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..ce5ac00 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,12 +1580,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1401,7 +1596,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3 6/6] ACPI / debugger: Add module support for ACPI debugger
@ 2015-11-19  6:09       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   12 ++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 338 insertions(+), 89 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4de3517..c4d4a05 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging 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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index abc23b2..381beb2 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -337,7 +337,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * 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
  * 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 size = 0;
@@ -390,7 +389,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 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
  * 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;
 
@@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 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,
 };
 
+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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -759,21 +767,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2de8f66..ce5ac00 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -220,6 +219,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,7 +234,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1100,6 +1100,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,7 +1321,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1377,7 +1571,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1386,12 +1580,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1401,7 +1596,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 51a96a8..8f24e03 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3] ACPI / x86: introduce acpi_os_readable() support
  2015-11-06  6:46   ` Lv Zheng
@ 2015-11-19  6:09     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPICA
AML debugger to validate user specified pointers for dumping the memory as
ACPICA descriptor objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Tested-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   44 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 96d058a..25585ee 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..4a5e22e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,50 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long obj_start, obj_end;
+	unsigned long start_pfn, end_pfn;
+
+	/*
+	 * All direct mapped PFNs should have been recorded by the mapped
+	 * PFN ranges. But pfn_range_is_mapped() requires the following
+	 * sanity checks to be performed before invoking.
+	 */
+	obj_start = ACPI_TO_INTEGER(pointer);
+	obj_end = obj_start + length;
+
+	/*
+	 * ACPICA core doesn't validate if the object is wrapped over, so
+	 * we should.
+	 */
+	if (length && (obj_end - 1) < obj_start)
+		return false;
+
+	/*
+	 * None direct mapping ranges contain holes. For example, high
+	 * kernel map holes (lower than _text or higher than _brk_end).
+	 * Converting a virtual address that belongs to the high map hole
+	 * results in a valid PFN because its low map has been recorded as
+	 * a mapped range.
+	 */
+	if (obj_start < PAGE_OFFSET ||
+	    obj_start >= (unsigned long)high_memory ||
+	    (length && (obj_end - 1) >= (unsigned long)high_memory))
+		return false;
+
+	/*
+	 * It is required to pass a range (end_pfn - start_pfn > 0) to
+	 * pfn_range_is_mapped().
+	 */
+	start_pfn = PFN_DOWN(__pa(obj_start));
+	end_pfn = PFN_UP(__pa(obj_end));
+	if (unlikely(end_pfn == start_pfn))
+		end_pfn++;
+
+	return pfn_range_is_mapped(start_pfn, end_pfn);
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index c4d4a05..73b45f9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index ce5ac00..edec035 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1582,6 +1582,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 }
 EXPORT_SYMBOL(acpi_os_get_line);
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length) ? TRUE : FALSE;
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v3] ACPI / x86: introduce acpi_os_readable() support
@ 2015-11-19  6:09     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-11-19  6:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPICA
AML debugger to validate user specified pointers for dumping the memory as
ACPICA descriptor objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Tested-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   44 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 96d058a..25585ee 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..4a5e22e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,50 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long obj_start, obj_end;
+	unsigned long start_pfn, end_pfn;
+
+	/*
+	 * All direct mapped PFNs should have been recorded by the mapped
+	 * PFN ranges. But pfn_range_is_mapped() requires the following
+	 * sanity checks to be performed before invoking.
+	 */
+	obj_start = ACPI_TO_INTEGER(pointer);
+	obj_end = obj_start + length;
+
+	/*
+	 * ACPICA core doesn't validate if the object is wrapped over, so
+	 * we should.
+	 */
+	if (length && (obj_end - 1) < obj_start)
+		return false;
+
+	/*
+	 * None direct mapping ranges contain holes. For example, high
+	 * kernel map holes (lower than _text or higher than _brk_end).
+	 * Converting a virtual address that belongs to the high map hole
+	 * results in a valid PFN because its low map has been recorded as
+	 * a mapped range.
+	 */
+	if (obj_start < PAGE_OFFSET ||
+	    obj_start >= (unsigned long)high_memory ||
+	    (length && (obj_end - 1) >= (unsigned long)high_memory))
+		return false;
+
+	/*
+	 * It is required to pass a range (end_pfn - start_pfn > 0) to
+	 * pfn_range_is_mapped().
+	 */
+	start_pfn = PFN_DOWN(__pa(obj_start));
+	end_pfn = PFN_UP(__pa(obj_end));
+	if (unlikely(end_pfn == start_pfn))
+		end_pfn++;
+
+	return pfn_range_is_mapped(start_pfn, end_pfn);
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index c4d4a05..73b45f9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "In-kernel debugger"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index ce5ac00..edec035 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1582,6 +1582,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 }
 EXPORT_SYMBOL(acpi_os_get_line);
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length) ? TRUE : FALSE;
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support
  2015-11-06  6:46   ` Lv Zheng
@ 2015-12-03  2:40     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:40 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

v3:
1. Remove acpi_os_readable() support from this patchset. It's sent separately.
2. Delete some deprecated comments.

v4:
1. Rebase patch 4/6 because of Kconfig changes.
2. Include acpi_os_readable() back as no objections, also test result is
   positive.

Chen Yu (1):
  ACPI / x86: introduce acpi_os_readable() support

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 arch/x86/Kconfig                         |    1 +
 arch/x86/include/asm/acenv.h             |    1 +
 arch/x86/kernel/acpi/boot.c              |   44 ++
 drivers/acpi/Kconfig                     |   20 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  805 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  262 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    3 +-
 include/acpi/platform/aclinuxex.h        |    8 +-
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 26 files changed, 1852 insertions(+), 214 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support
@ 2015-12-03  2:40     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:40 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables ACPICA debugger for Linux kernel and implements a
userspace utility to access it.

A. Build the AML debugger
In order to build the kernel support of AML debugger, the following kconfig
items should be enabled:
 CONFIG_ACPI_DEBUG=y
 CONFIG_ACPI_DEBUGGER=y
 CONFIG_DEBUG_FS=y
 CONFIG_ACPI_DEBUGGER_USER=m
The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
build this utility, staying in tools folder and type "make acpi".

B. Load the AML debugger during runtime
In order to use the in-kernel AML debugger, the following command should be
executed using root user:
 # modprobe acpi_dbg
 # mount -t debugfs none /sys/kernel/debug
 # acpidbg

C. Batch mode
In order to support scripts, the userspace utility also supports single
command batch mode:
 # acpidbg -b "help"
 # acpidbg -b "tables"
 # acpidbg -b "find _LID"
 # acpidbg -b "execute \_SB.LID0._LID"
You can find the documentation about the ACPICA debugger commands in:
 https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
 (The latest document can be found at https://acpica.org/documentation)
And refer to the chapter - ACPICA debugger reference to obtain the full
description of the debugger commands. Note that not all commands are
supported by an in-kernel AML debugger.

D. Unload the AML debugger during runtime
After terminating all acpidbg instances, the following command can be
executed to remove the AML debugger from kernel:
 # rmmod acpi_dbg

The following tasks are not completed:
1. .flush() support in the kernel debugger IO driver.
2. multi-commands batch mode.

v2:
1. Fix a help message issue for the userspace acpidbg utility (this is a
   typo fix).
2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
   lost due to too many rebase cycles).
3. Fix kconfig dependency for an intermediate patch (this is only useful in
   case the latter patches are reverted).
4. Add more accurate runtime debugger stub mechanism and remove old
   ACPI_DEBUGGER_EXEC() stub mechanism.
5. Add x86 acpi_os_readable() support.

v3:
1. Remove acpi_os_readable() support from this patchset. It's sent separately.
2. Delete some deprecated comments.

v4:
1. Rebase patch 4/6 because of Kconfig changes.
2. Include acpi_os_readable() back as no objections, also test result is
   positive.

Chen Yu (1):
  ACPI / x86: introduce acpi_os_readable() support

Colin Ian King (1):
  ACPICA: Debugger: Remove unnecessary status check

Lv Zheng (5):
  ACPICA: Debugger: Convert some mechanisms to OSPM specific
  ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
    different stub mechanism
  ACPI / debugger: Add IO interface to access debugger functionalities
  tools/power/acpi: Add userspace AML interface support
  ACPI / debugger: Add module support for ACPI debugger

 arch/x86/Kconfig                         |    1 +
 arch/x86/include/asm/acenv.h             |    1 +
 arch/x86/kernel/acpi/boot.c              |   44 ++
 drivers/acpi/Kconfig                     |   20 +-
 drivers/acpi/Makefile                    |    1 +
 drivers/acpi/acpi_dbg.c                  |  805 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/acdebug.h            |   36 +-
 drivers/acpi/acpica/acglobal.h           |    5 -
 drivers/acpi/acpica/acmacros.h           |   11 -
 drivers/acpi/acpica/dbdisply.c           |   12 +
 drivers/acpi/acpica/dbinput.c            |  100 +---
 drivers/acpi/acpica/dbxface.c            |   93 ++--
 drivers/acpi/acpica/dscontrol.c          |   10 +-
 drivers/acpi/acpica/dsutils.c            |   16 +-
 drivers/acpi/acpica/dswexec.c            |   16 +-
 drivers/acpi/acpica/utmutex.c            |   17 -
 drivers/acpi/bus.c                       |    1 +
 drivers/acpi/osl.c                       |  262 +++++++++-
 include/acpi/acpiosxf.h                  |   18 +-
 include/acpi/acpixf.h                    |   34 ++
 include/acpi/platform/aclinux.h          |    3 +-
 include/acpi/platform/aclinuxex.h        |    8 +-
 include/linux/acpi.h                     |   71 +++
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 +
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++
 26 files changed, 1852 insertions(+), 214 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

-- 
1.7.10


^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH v4 1/7] ACPICA: Debugger: Remove unnecessary status check
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:42       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 1/7] ACPICA: Debugger: Remove unnecessary status check
@ 2015-12-03  2:42       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Colin Ian King, Bob Moore

From: Colin Ian King <colin.king@canonical.com>

ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5

ACPICA BZ 1205. Colin Ian King.

Link: https://bugs.acpica.org/show_bug.cgi?id=1205
Link: https://github.com/acpica/acpica/commit/f9d5c6c9
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/dbinput.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index 0480254..fe93f67 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op)
 			 * and wait for the command to complete.
 			 */
 			acpi_os_release_mutex(acpi_gbl_db_command_ready);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
 
 			status =
 			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:42       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific
@ 2015-12-03  2:42       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The following mechanisms are OSPM specific:
1. Redirect output destination to console: no file redirection will be
   needed by an in-kernel debugger, there is even no file can be accessed
   when the debugger is running in the kernel mode.
2. Output command prompts: programs other than acpiexec can have different
   prompt characters and the prompt characters may be implemented as a
   special character sequence to form a char device IO protocol.
3. Command ready/complete handshake: OSPM debugger may wait more conditions
   to implement OSPM specific semantics (for example, FIFO full/empty
   conditions for O_NONBLOCK or IO open/close conditions).
Leaving such OSPM specific stuffs in the ACPICA debugger core blocks
Linux debugger IO driver implementation.

Several new OSL APIs are provided by this patch:
1. acpi_os_initialize_command_signals: initialize command handshake mechanism
   or any other OSPM specific stuffs.
2. acpi_os_terminate_command_signals: reversal of
   acpi_os_initialize_command_signals.
3. acpi_os_wait_command_ready: putting debugger task into wait state when a
   command is not ready. OSPMs can terminate command loop by returning
   AE_CTRL_TERMINATE from this API. Normally, wait_event() or
   wait_for_multiple_object() may be used to implement this API.
4. acpi_os_notify_command_complete: putting user task into running state when a
   command has been completed. OSPMs can terminate command loop by
   returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or
   set_event() may be used to implement this API.
This patch also converts current command signaling implementation into a
generic debugger layer (osgendbg.c) to be used by the existing OSPMs or
acpiexec, in return, Linux can have chance to implement its own command
handshake mechanism. This patch also implements acpiexec batch mode in a
multi-threading mode comaptible style as a demo (this can be confirmed by
configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode
is still working). Lv Zheng.

Note that the OSPM specific command handshake mechanism is required by
Linux kernel because:
1. Linux kernel trends to use wait queue to synchronize two threads, using
   mutexes to achieve that will cause false "dead lock" warnings.
2. The command handshake mechanism implemented by ACPICA is implemented in
   this way because of a design issue in debugger IO streaming. Debugger IO
   outputs are simply cached using a giant buffer, this should be tuned by
   Linux in the future.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h     |    2 +-
 drivers/acpi/acpica/acglobal.h    |    5 --
 drivers/acpi/acpica/dbinput.c     |   97 ++++++++-----------------------------
 drivers/acpi/acpica/dbxface.c     |   63 +++++++-----------------
 drivers/acpi/acpica/utmutex.c     |   17 -------
 include/acpi/acpiosxf.h           |   18 ++++++-
 include/acpi/acpixf.h             |   11 +++++
 include/acpi/platform/aclinux.h   |    4 ++
 include/acpi/platform/aclinuxex.h |   19 ++++++++
 9 files changed, 89 insertions(+), 147 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index c928ba4..86474d8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -257,7 +257,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);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index faa9760..3977134 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -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 */
 
 /*****************************************************************************
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index fe93f67..2bf8e6b 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -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,49 +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);
-
-		/* 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);
-		}
-
-		/* 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);
+			break;
 		}
 
-		/* Check for single or multithreaded debug */
+		/* Just call to the command line interpreter */
 
-		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);
+		acpi_gbl_method_executing = FALSE;
+		acpi_gbl_step_to_next_call = FALSE;
 
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
-						  ACPI_WAIT_FOREVER);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-		} else {
-			/* Just call to the command line interpreter */
+		(void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL,
+					       NULL);
+
+		/* Notify the completion of the command */
 
-			acpi_db_single_thread();
+		status = acpi_os_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			break;
 		}
 	}
 
+	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {
+		ACPI_EXCEPTION((AE_INFO, status, "While parsing command line"));
+	}
 	return (status);
 }
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 342298a..d95e91f 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -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 */
-
-			acpi_os_release_mutex(acpi_gbl_db_command_complete);
-
-			status =
-			    acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
-						  ACPI_WAIT_FOREVER);
-			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);
+	while (status == AE_CTRL_TRUE) {
 
-			/* Different prompt if method is executing */
+		/* Notify the completion of the command */
 
-			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_notify_command_complete();
+		if (ACPI_FAILURE(status)) {
+			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);
-			if (ACPI_FAILURE(status)) {
-				ACPI_EXCEPTION((AE_INFO, status,
-						"While parsing command line"));
-				return (status);
-			}
+		status = acpi_os_wait_command_ready();
+		if (ACPI_FAILURE(status)) {
+			goto error_exit;
 		}
 
 		status =
@@ -134,6 +109,11 @@ 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);
 }
 
@@ -420,15 +400,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 +445,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) {
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index ce406e3..ea0c207 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -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;
 }
 
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index fbc2baf..0d824a2 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -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)
  */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 3aaaa86..95ebae3 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -264,6 +264,15 @@ 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
  */
 ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT);
@@ -929,6 +938,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__ */
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 323e5da..69dbae6 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -150,6 +150,10 @@
  */
 #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
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index fd6d70f..673fdf4 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,6 +129,25 @@ 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)
+{
+}
+
+static inline acpi_status acpi_os_wait_command_ready(void)
+{
+	return AE_ERROR;
+}
+
+static inline acpi_status acpi_os_notify_command_complete(void)
+{
+	return AE_ERROR;
+}
+
 /*
  * OSL interfaces added by Linux
  */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:42       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

ACPICA commit 11522d6b894054fc4d62dd4f9863ec151296b386

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/11522d6b
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism
@ 2015-12-03  2:42       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:42 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

ACPICA commit 11522d6b894054fc4d62dd4f9863ec151296b386

The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled
but runtime disabled. They actually will get executed in this situation.
Although such executions are harmless if we can correctly make
acpi_db_single_step() a runtime stub, users may still do not want to see the
debugger print messages logged into OSPMs' kernel logs when a debugger
driver is not loaded to enable the debugger during runtime.

This patch fixes this issue by introducing new stub mechanism instead of
ACPI_DEBUGGER_EXEC. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/11522d6b
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acdebug.h   |   34 ++++++++++++++++++++++++----------
 drivers/acpi/acpica/acmacros.h  |   11 -----------
 drivers/acpi/acpica/dbdisply.c  |   12 ++++++++++++
 drivers/acpi/acpica/dbxface.c   |   30 ++++++++++++++++++++++++++++++
 drivers/acpi/acpica/dscontrol.c |   10 ++--------
 drivers/acpi/acpica/dsutils.c   |   16 ++++++++--------
 drivers/acpi/acpica/dswexec.c   |   16 +++++++---------
 include/acpi/acpixf.h           |   23 +++++++++++++++++++++++
 8 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 86474d8..dcaa15d 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -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
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index e85366c..bad5bca 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -401,17 +401,6 @@
 #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
  */
 
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c
index 672977e..c42ce8a 100644
--- a/drivers/acpi/acpica/dbdisply.c
+++ b/drivers/acpi/acpica/dbdisply.c
@@ -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;
 	}
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index d95e91f..d7ff58e 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -119,6 +119,36 @@ error_exit:
 
 /*******************************************************************************
  *
+ * 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
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 435fc16..06a6f7f 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -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 */
 
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index ebc577b..e4293a8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -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);
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index df54d46..9cc5761 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -178,8 +178,7 @@ cleanup:
 
 	/* 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 @@ cleanup:
 
 		/* 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:
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 95ebae3..5dfab9c 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -375,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
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:43       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  779 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 887 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5eef4cb..2a7e6d4 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "AML debugger interface (EXPERIMENTAL)"
+	bool "AML debugger interface"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging of AML facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..abc23b2
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,779 @@
+/*
+ * 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_dbg.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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 32d684a..4c13398 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1127,6 +1129,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_aml_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 +1162,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 +1181,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,11 +1377,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
@ 2015-12-03  2:43       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
userspace programs to access ACPICA debugger functionalities.

Known issue:
1. IO flush support
   acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can
   be used by acpi_dbg module to implement .flush() filesystem operation.
   While this patch doesn't go that far. It then becomes userspace tool's
   duty now to flush old commands before executing new batch mode commands.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig              |    3 +-
 drivers/acpi/Makefile             |    1 +
 drivers/acpi/acpi_dbg.c           |  779 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                |    2 +
 drivers/acpi/osl.c                |   55 ++-
 include/acpi/platform/aclinux.h   |    2 -
 include/acpi/platform/aclinuxex.h |   10 -
 include/linux/acpi_dbg.h          |   52 +++
 8 files changed, 887 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/acpi_dbg.c
 create mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5eef4cb..2a7e6d4 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED
 	bool
 
 config ACPI_DEBUGGER
-	bool "AML debugger interface (EXPERIMENTAL)"
+	bool "AML debugger interface"
 	select ACPI_DEBUG
+	depends on DEBUG_FS
 	help
 	  Enable in-kernel debugging of AML facilities: statistics, internal
 	  object dump, single step control method execution.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..102b5e6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,6 +50,7 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
+acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
new file mode 100644
index 0000000..abc23b2
--- /dev/null
+++ b/drivers/acpi/acpi_dbg.c
@@ -0,0 +1,779 @@
+/*
+ * 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_dbg.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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_write_log);
+
+/*
+ * 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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_read_cmd);
+
+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.
+ */
+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;
+}
+EXPORT_SYMBOL(acpi_aml_create_thread);
+
+int acpi_aml_wait_command_ready(void)
+{
+	acpi_status status;
+
+	if (!acpi_gbl_method_executing)
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+	else
+		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
+
+	status = acpi_os_get_line(acpi_gbl_db_line_buf,
+				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_wait_command_ready);
+
+int acpi_aml_notify_command_complete(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_aml_notify_command_complete);
+
+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_lock;
+		}
+		acpi_aml_io.flags |= ACPI_AML_OPENED;
+		pr_debug("Debugger thread initialized.\n");
+
+		mutex_lock(&acpi_aml_io.lock);
+		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);
+	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));
+	ret = copy_to_user(buf, p, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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));
+	ret = copy_from_user(p, buf, n);
+	if (IS_ERR_VALUE(ret))
+		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 (!buf || count < 0)
+		return -EINVAL;
+	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,
+};
+
+int __init acpi_aml_init(void)
+{
+	if (!acpi_debugfs_dir)
+		return -ENOENT;
+	/* 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)
+		return -ENODEV;
+	acpi_aml_initialized = true;
+	return 0;
+}
+
+#if 0
+void __exit acpi_aml_exit(void)
+{
+	/* TODO: Stop the in kernel debugger */
+	if (acpi_aml_dentry)
+		debugfs_remove(acpi_aml_dentry);
+	acpi_aml_initialized = false;
+}
+
+module_init(acpi_aml_init);
+module_exit(acpi_aml_exit);
+#endif
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a212cef..06fbba9 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,6 +37,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1094,6 +1095,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_aml_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 32d684a..4c13398 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,6 +40,7 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
+#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	printk(KERN_CONT "%s", buffer);
+	if (acpi_aml_write_log(buffer) < 0)
+		printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1127,6 +1129,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_aml_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 +1162,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 +1181,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,11 +1377,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_aml_read_cmd(buffer, buffer_length);
+	if (ret < 0)
+		return AE_ERROR;
+	if (bytes_read)
+		*bytes_read = ret;
 #endif
 
 	return AE_OK;
 }
 
+acpi_status acpi_os_wait_command_ready(void)
+{
+	int ret;
+
+	ret = acpi_aml_wait_command_ready();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+	int ret;
+
+	ret = acpi_aml_notify_command_complete();
+	if (ret < 0)
+		return AE_ERROR;
+	return AE_OK;
+}
+
 acpi_status acpi_os_signal(u32 function, void *info)
 {
 	switch (function) {
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 69dbae6..e21857d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -152,8 +152,6 @@
 #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
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 673fdf4..ceea026 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void)
 {
 }
 
-static inline acpi_status acpi_os_wait_command_ready(void)
-{
-	return AE_ERROR;
-}
-
-static inline acpi_status acpi_os_notify_command_complete(void)
-{
-	return AE_ERROR;
-}
-
 /*
  * OSL interfaces added by Linux
  */
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
new file mode 100644
index 0000000..60f3887
--- /dev/null
+++ b/include/linux/acpi_dbg.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef _LINUX_ACPI_DBG_H
+#define _LINUX_ACPI_DBG_H
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_DEBUGGER
+int __init acpi_aml_init(void);
+int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
+ssize_t acpi_aml_write_log(const char *msg);
+ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
+int acpi_aml_wait_command_ready(void);
+int acpi_aml_notify_command_complete(void);
+#else
+static int inline acpi_aml_init(void)
+{
+	return 0;
+}
+static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
+					 void *context)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_write_log(const char *msg)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_wait_command_ready(void)
+{
+	return -ENODEV;
+}
+static inline int acpi_aml_notify_command_complete(void)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 5/7] tools/power/acpi: Add userspace AML interface support
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:43       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 5/7] tools/power/acpi: Add userspace AML interface support
@ 2015-12-03  2:43       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds a userspace tool to access Linux kernel AML debugger
interface.

Tow modes are supported by this tool:
1. Interactive: Users are able to launch a debugging shell to talk with
   in-kernel AML debugger.
   Note that it's user duty to ensure kernel runtime integrity by using
   this debugging tool:
   A. Some control methods evaluated by the users may result in kernel
      panics if those control methods shouldn't be evaluated by the OSPMs
      according to the current BIOS/OS configurations.
   B. Currently if a single stepping evaluation couldn't run to an end,
      then the synchronization primitives acquired by the evaluation may
      block normal OSPM control method evaluations.
2. Batch: Users are able to execute debugger commands in a script.
   Note that in addition to the above duties, it's user duty to ensure
   script runtime integrity by using this debugging tool in this mode:
   C. Currently only those commands that are not used for single stepping
      are suitable to be used in this mode.
   D. If the execution of the command may cause a failure that could result
      in an endless kernel execution, the execution of the script may also
      get blocked.
To exit the utility, currently "exit/quit" commands are recommended, but
ctrl-C" can also be used.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 tools/power/acpi/Makefile                |   16 +-
 tools/power/acpi/tools/acpidbg/Makefile  |   27 ++
 tools/power/acpi/tools/acpidbg/acpidbg.c |  438 ++++++++++++++++++++++++++++++
 3 files changed, 473 insertions(+), 8 deletions(-)
 create mode 100644 tools/power/acpi/tools/acpidbg/Makefile
 create mode 100644 tools/power/acpi/tools/acpidbg/acpidbg.c

diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index e882c83..a8bf908 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -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
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..352df4b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,27 @@
+# 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
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..d070fcc
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,438 @@
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * 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.
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/circ_buf.h>
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#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_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = 0;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd < 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 6/7] ACPI / debugger: Add module support for ACPI debugger
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:43       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   16 +++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 340 insertions(+), 91 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 2a7e6d4..82b96ee 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED
 config ACPI_DEBUGGER
 	bool "AML debugger interface"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index abc23b2..381beb2 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -337,7 +337,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * 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
  * 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 size = 0;
@@ -390,7 +389,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 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
  * 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;
 
@@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 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,
 };
 
+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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -759,21 +767,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 4c13398..bb66093 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -221,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)
 {
@@ -235,7 +235,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1103,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
@@ -1130,7 +1324,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1380,7 +1574,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1389,12 +1583,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1404,7 +1599,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 1991aea..a03a054 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 6/7] ACPI / debugger: Add module support for ACPI debugger
@ 2015-12-03  2:43       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

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: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/Kconfig     |   16 +++-
 drivers/acpi/Makefile    |    2 +-
 drivers/acpi/acpi_dbg.c  |   80 ++++++++++++------
 drivers/acpi/bus.c       |    3 +-
 drivers/acpi/osl.c       |  207 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/acpi.h     |   71 ++++++++++++++++
 include/linux/acpi_dbg.h |   52 ------------
 7 files changed, 340 insertions(+), 91 deletions(-)
 delete mode 100644 include/linux/acpi_dbg.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 2a7e6d4..82b96ee 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED
 config ACPI_DEBUGGER
 	bool "AML debugger interface"
 	select ACPI_DEBUG
-	depends on DEBUG_FS
 	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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 102b5e6..c6f236f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-y				+= sysfs.o
 acpi-y				+= property.o
 acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o
-acpi-$(CONFIG_ACPI_DEBUGGER)	+= acpi_dbg.o
 acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.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_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
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index abc23b2..381beb2 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -21,7 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/acpi_dbg.h>
+#include <linux/acpi.h>
 #include "internal.h"
 
 #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
  * 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 count = 0, size = 0;
@@ -337,7 +337,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_write_log);
 
 /*
  * 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
  * 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 size = 0;
@@ -390,7 +389,6 @@ again:
 	}
 	return size > 0 ? size : ret;
 }
-EXPORT_SYMBOL(acpi_aml_read_cmd);
 
 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
  * 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;
 
@@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 	mutex_unlock(&acpi_aml_io.lock);
 	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;
 
-	if (!acpi_gbl_method_executing)
-		acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-	else
+	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(acpi_gbl_db_line_buf,
-				  ACPI_DB_LINE_BUFFER_SIZE, NULL);
+	status = acpi_os_get_line(buffer, length, NULL);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 	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;
 }
-EXPORT_SYMBOL(acpi_aml_notify_command_complete);
 
 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,
 };
 
+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)
 {
-	if (!acpi_debugfs_dir)
-		return -ENOENT;
+	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);
@@ -759,21 +767,39 @@ int __init acpi_aml_init(void)
 					      S_IFREG | S_IRUGO | S_IWUSR,
 					      acpi_debugfs_dir, NULL,
 					      &acpi_aml_operations);
-	if (acpi_aml_dentry == NULL)
-		return -ENODEV;
+	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;
-	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)
 {
-	/* TODO: Stop the in kernel debugger */
-	if (acpi_aml_dentry)
-		debugfs_remove(acpi_aml_dentry);
-	acpi_aml_initialized = false;
+	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);
-#endif
+
+MODULE_AUTHOR("Lv Zheng");
+MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 06fbba9..1a40111 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,7 +37,6 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
-#include <linux/acpi_dbg.h>
 
 #include "internal.h"
 
@@ -1095,7 +1094,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
-	acpi_aml_init();
+	acpi_debugger_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 4c13398..bb66093 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -40,7 +40,6 @@
 #include <linux/list.h>
 #include <linux/jiffies.h>
 #include <linux/semaphore.h>
-#include <linux/acpi_dbg.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -221,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)
 {
@@ -235,7 +235,7 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 		printk(KERN_CONT "%s", buffer);
 	}
 #else
-	if (acpi_aml_write_log(buffer) < 0)
+	if (acpi_debugger_write_log(buffer) < 0)
 		printk(KERN_CONT "%s", buffer);
 #endif
 }
@@ -1103,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
@@ -1130,7 +1324,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
 			  function, context));
 
 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
-		ret = acpi_aml_create_thread(function, context);
+		ret = acpi_debugger_create_thread(function, context);
 		if (ret) {
 			pr_err("Call to kthread_create() failed.\n");
 			status = AE_ERROR;
@@ -1380,7 +1574,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 #else
 	int ret;
 
-	ret = acpi_aml_read_cmd(buffer, buffer_length);
+	ret = acpi_debugger_read_cmd(buffer, buffer_length);
 	if (ret < 0)
 		return AE_ERROR;
 	if (bytes_read)
@@ -1389,12 +1583,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 
 	return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
 
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
 
-	ret = acpi_aml_wait_command_ready();
+	ret = acpi_debugger_wait_command_ready();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
@@ -1404,7 +1599,7 @@ acpi_status acpi_os_notify_command_complete(void)
 {
 	int ret;
 
-	ret = acpi_aml_notify_command_complete();
+	ret = acpi_debugger_notify_command_complete();
 	if (ret < 0)
 		return AE_ERROR;
 	return AE_OK;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 1991aea..a03a054 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h
deleted file mode 100644
index 60f3887..0000000
--- a/include/linux/acpi_dbg.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LINUX_ACPI_DBG_H
-#define _LINUX_ACPI_DBG_H
-
-#include <linux/acpi.h>
-
-#ifdef CONFIG_ACPI_DEBUGGER
-int __init acpi_aml_init(void);
-int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context);
-ssize_t acpi_aml_write_log(const char *msg);
-ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length);
-int acpi_aml_wait_command_ready(void);
-int acpi_aml_notify_command_complete(void);
-#else
-static int inline acpi_aml_init(void)
-{
-	return 0;
-}
-static inline int acpi_aml_create_thread(acpi_osd_exec_callback function,
-					 void *context)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_write_log(const char *msg)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_wait_command_ready(void)
-{
-	return -ENODEV;
-}
-static inline int acpi_aml_notify_command_complete(void)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif /* _LINUX_ACPI_DBG_H */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-03  2:40     ` Lv Zheng
@ 2015-12-03  2:43       ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPICA
AML debugger to validate user specified pointers for dumping the memory as
ACPICA descriptor objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Tested-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   44 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index db3622f..6593b6a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..4a5e22e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,50 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long obj_start, obj_end;
+	unsigned long start_pfn, end_pfn;
+
+	/*
+	 * All direct mapped PFNs should have been recorded by the mapped
+	 * PFN ranges. But pfn_range_is_mapped() requires the following
+	 * sanity checks to be performed before invoking.
+	 */
+	obj_start = ACPI_TO_INTEGER(pointer);
+	obj_end = obj_start + length;
+
+	/*
+	 * ACPICA core doesn't validate if the object is wrapped over, so
+	 * we should.
+	 */
+	if (length && (obj_end - 1) < obj_start)
+		return false;
+
+	/*
+	 * None direct mapping ranges contain holes. For example, high
+	 * kernel map holes (lower than _text or higher than _brk_end).
+	 * Converting a virtual address that belongs to the high map hole
+	 * results in a valid PFN because its low map has been recorded as
+	 * a mapped range.
+	 */
+	if (obj_start < PAGE_OFFSET ||
+	    obj_start >= (unsigned long)high_memory ||
+	    (length && (obj_end - 1) >= (unsigned long)high_memory))
+		return false;
+
+	/*
+	 * It is required to pass a range (end_pfn - start_pfn > 0) to
+	 * pfn_range_is_mapped().
+	 */
+	start_pfn = PFN_DOWN(__pa(obj_start));
+	end_pfn = PFN_UP(__pa(obj_end));
+	if (unlikely(end_pfn == start_pfn))
+		end_pfn++;
+
+	return pfn_range_is_mapped(start_pfn, end_pfn);
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..9422133 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "AML debugger interface"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bb66093..14a3beb 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1585,6 +1585,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 }
 EXPORT_SYMBOL(acpi_os_get_line);
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length) ? TRUE : FALSE;
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-03  2:43       ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-03  2:43 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Andy Lutomirski
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Chen Yu

From: Chen Yu <yu.c.chen@intel.com>

This patch implements acpi_os_readable(). The function is used by ACPICA
AML debugger to validate user specified pointers for dumping the memory as
ACPICA descriptor objects.

Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Tested-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/acenv.h      |    1 +
 arch/x86/kernel/acpi/boot.c       |   44 +++++++++++++++++++++++++++++++++++++
 drivers/acpi/Kconfig              |    3 +++
 drivers/acpi/osl.c                |   12 ++++++++++
 include/acpi/platform/aclinux.h   |    1 -
 include/acpi/platform/aclinuxex.h |    5 -----
 7 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index db3622f..6593b6a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,7 @@ config X86
 	def_bool y
 	select ACPI_LEGACY_TABLES_LOOKUP	if ACPI
 	select ACPI_SYSTEM_POWER_STATES_SUPPORT	if ACPI
+	select ACPI_MEMORY_ACCESS_CHECK_SUPPORT	if ACPI
 	select ANON_INODES
 	select ARCH_CLOCKSOURCE_DATA
 	select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 1b010a8..a2a2849 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -20,6 +20,7 @@
 
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
+bool __acpi_memory_readable(void *pointer, size_t length);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
 	((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index e759076..4a5e22e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1699,6 +1699,50 @@ int __acpi_release_global_lock(unsigned int *lock)
 	return old & 0x1;
 }
 
+bool __acpi_memory_readable(void *pointer, size_t length)
+{
+	unsigned long obj_start, obj_end;
+	unsigned long start_pfn, end_pfn;
+
+	/*
+	 * All direct mapped PFNs should have been recorded by the mapped
+	 * PFN ranges. But pfn_range_is_mapped() requires the following
+	 * sanity checks to be performed before invoking.
+	 */
+	obj_start = ACPI_TO_INTEGER(pointer);
+	obj_end = obj_start + length;
+
+	/*
+	 * ACPICA core doesn't validate if the object is wrapped over, so
+	 * we should.
+	 */
+	if (length && (obj_end - 1) < obj_start)
+		return false;
+
+	/*
+	 * None direct mapping ranges contain holes. For example, high
+	 * kernel map holes (lower than _text or higher than _brk_end).
+	 * Converting a virtual address that belongs to the high map hole
+	 * results in a valid PFN because its low map has been recorded as
+	 * a mapped range.
+	 */
+	if (obj_start < PAGE_OFFSET ||
+	    obj_start >= (unsigned long)high_memory ||
+	    (length && (obj_end - 1) >= (unsigned long)high_memory))
+		return false;
+
+	/*
+	 * It is required to pass a range (end_pfn - start_pfn > 0) to
+	 * pfn_range_is_mapped().
+	 */
+	start_pfn = PFN_DOWN(__pa(obj_start));
+	end_pfn = PFN_UP(__pa(obj_end));
+	if (unlikely(end_pfn == start_pfn))
+		end_pfn++;
+
+	return pfn_range_is_mapped(start_pfn, end_pfn);
+}
+
 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
 {
 	e820_add_region(addr, size, E820_ACPI);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..9422133 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+	bool
+
 config ACPI_DEBUGGER
 	bool "AML debugger interface"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bb66093..14a3beb 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1585,6 +1585,18 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
 }
 EXPORT_SYMBOL(acpi_os_get_line);
 
+#ifdef CONFIG_ACPI_MEMORY_ACCESS_CHECK_SUPPORT
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return __acpi_memory_readable(pointer, length) ? TRUE : FALSE;
+}
+#else
+u8 acpi_os_readable(void *pointer, acpi_size length)
+{
+	return TRUE;
+}
+#endif
+
 acpi_status acpi_os_wait_command_ready(void)
 {
 	int ret;
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e21857d..b3c493e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,7 +148,6 @@
 /*
  * OSL interfaces used by debugger/disassembler
  */
-#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
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index ceea026..94bead6 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -124,11 +124,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 		lock ? AE_OK : AE_NO_MEMORY; \
 	})
 
-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;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-12-03  2:43       ` Lv Zheng
  (?)
@ 2015-12-03 22:27       ` Andy Lutomirski
  2015-12-03 23:34         ` Rafael J. Wysocki
  -1 siblings, 1 reply; 131+ messages in thread
From: Andy Lutomirski @ 2015-12-03 22:27 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
> userspace programs to access ACPICA debugger functionalities.

What's this one generated against?  My Kconfig contains:

config ACPI_DEBUGGER
    bool "In-kernel debugger (EXPERIMENTAL)"
    select ACPI_DEBUG

which isn't quite the same as what you generated this against.  I'm
starting with 4.4-rc3.

--Andy

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 4/7] ACPI / debugger: Add IO interface to access debugger functionalities
  2015-12-03 22:27       ` Andy Lutomirski
@ 2015-12-03 23:34         ` Rafael J. Wysocki
  0 siblings, 0 replies; 131+ messages in thread
From: Rafael J. Wysocki @ 2015-12-03 23:34 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Lv Zheng, Rafael J. Wysocki, Len Brown, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI

On Thursday, December 03, 2015 02:27:41 PM Andy Lutomirski wrote:
> On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by
> > userspace programs to access ACPICA debugger functionalities.
> 
> What's this one generated against?  My Kconfig contains:
> 
> config ACPI_DEBUGGER
>     bool "In-kernel debugger (EXPERIMENTAL)"
>     select ACPI_DEBUG
> 
> which isn't quite the same as what you generated this against.  I'm
> starting with 4.4-rc3.

Probably on top of linux-next (or my linux-next branch).

There's a fix commit against Kconfig in my tree which is going to be pushed
for 4.4-rc4 tomorrow.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-03  2:43       ` Lv Zheng
  (?)
@ 2015-12-14 23:28       ` Andy Lutomirski
  2015-12-15  6:13           ` Chen, Yu C
  -1 siblings, 1 reply; 131+ messages in thread
From: Andy Lutomirski @ 2015-12-14 23:28 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI, Chen Yu

On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> From: Chen Yu <yu.c.chen@intel.com>
>
> This patch implements acpi_os_readable(). The function is used by ACPICA
> AML debugger to validate user specified pointers for dumping the memory as
> ACPICA descriptor objects.
>
> Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> Tested-by: Lv Zheng <lv.zheng@intel.com>
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> ---
>  arch/x86/Kconfig                  |    1 +
>  arch/x86/include/asm/acenv.h      |    1 +
>  arch/x86/kernel/acpi/boot.c       |   44 +++++++++++++++++++++++++++++++++++++
>  drivers/acpi/Kconfig              |    3 +++
>  drivers/acpi/osl.c                |   12 ++++++++++
>  include/acpi/platform/aclinux.h   |    1 -
>  include/acpi/platform/aclinuxex.h |    5 -----
>  7 files changed, 61 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index db3622f..6593b6a 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -19,6 +19,7 @@ config X86
>         def_bool y
>         select ACPI_LEGACY_TABLES_LOOKUP        if ACPI
>         select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
> +       select ACPI_MEMORY_ACCESS_CHECK_SUPPORT if ACPI
>         select ANON_INODES
>         select ARCH_CLOCKSOURCE_DATA
>         select ARCH_DISCARD_MEMBLOCK
> diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
> index 1b010a8..a2a2849 100644
> --- a/arch/x86/include/asm/acenv.h
> +++ b/arch/x86/include/asm/acenv.h
> @@ -20,6 +20,7 @@
>
>  int __acpi_acquire_global_lock(unsigned int *lock);
>  int __acpi_release_global_lock(unsigned int *lock);
> +bool __acpi_memory_readable(void *pointer, size_t length);
>
>  #define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
>         ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
> diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
> index e759076..4a5e22e 100644
> --- a/arch/x86/kernel/acpi/boot.c
> +++ b/arch/x86/kernel/acpi/boot.c
> @@ -1699,6 +1699,50 @@ int __acpi_release_global_lock(unsigned int *lock)
>         return old & 0x1;
>  }
>
> +bool __acpi_memory_readable(void *pointer, size_t length)
> +{
> +       unsigned long obj_start, obj_end;
> +       unsigned long start_pfn, end_pfn;

What does "readable" mean in this context?

--Andy

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-03  2:43       ` Lv Zheng
  (?)
  (?)
@ 2015-12-14 23:43       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 131+ messages in thread
From: Rafael J. Wysocki @ 2015-12-14 23:43 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Andy Lutomirski, Lv Zheng,
	linux-kernel, linux-acpi, Chen Yu

On Thursday, December 03, 2015 10:43:21 AM Lv Zheng wrote:
> From: Chen Yu <yu.c.chen@intel.com>
> 
> This patch implements acpi_os_readable(). The function is used by ACPICA
> AML debugger to validate user specified pointers for dumping the memory as
> ACPICA descriptor objects.
> 
> Signed-off-by: Chen Yu <yu.c.chen@intel.com>
> Tested-by: Lv Zheng <lv.zheng@intel.com>
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>

This has to be resent with CCs to the x86 maintainers.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support
  2015-12-03  2:40     ` Lv Zheng
                       ` (7 preceding siblings ...)
  (?)
@ 2015-12-14 23:44     ` Rafael J. Wysocki
  2015-12-15  2:55         ` Zheng, Lv
  -1 siblings, 1 reply; 131+ messages in thread
From: Rafael J. Wysocki @ 2015-12-14 23:44 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Andy Lutomirski, Lv Zheng,
	linux-kernel, linux-acpi

On Thursday, December 03, 2015 10:40:00 AM Lv Zheng wrote:
> This patchset enables ACPICA debugger for Linux kernel and implements a
> userspace utility to access it.
> 
> A. Build the AML debugger
> In order to build the kernel support of AML debugger, the following kconfig
> items should be enabled:
>  CONFIG_ACPI_DEBUG=y
>  CONFIG_ACPI_DEBUGGER=y
>  CONFIG_DEBUG_FS=y
>  CONFIG_ACPI_DEBUGGER_USER=m
> The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
> build this utility, staying in tools folder and type "make acpi".
> 
> B. Load the AML debugger during runtime
> In order to use the in-kernel AML debugger, the following command should be
> executed using root user:
>  # modprobe acpi_dbg
>  # mount -t debugfs none /sys/kernel/debug
>  # acpidbg
> 
> C. Batch mode
> In order to support scripts, the userspace utility also supports single
> command batch mode:
>  # acpidbg -b "help"
>  # acpidbg -b "tables"
>  # acpidbg -b "find _LID"
>  # acpidbg -b "execute \_SB.LID0._LID"
> You can find the documentation about the ACPICA debugger commands in:
>  https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
>  (The latest document can be found at https://acpica.org/documentation)
> And refer to the chapter - ACPICA debugger reference to obtain the full
> description of the debugger commands. Note that not all commands are
> supported by an in-kernel AML debugger.
> 
> D. Unload the AML debugger during runtime
> After terminating all acpidbg instances, the following command can be
> executed to remove the AML debugger from kernel:
>  # rmmod acpi_dbg
> 
> The following tasks are not completed:
> 1. .flush() support in the kernel debugger IO driver.
> 2. multi-commands batch mode.
> 
> v2:
> 1. Fix a help message issue for the userspace acpidbg utility (this is a
>    typo fix).
> 2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
>    lost due to too many rebase cycles).
> 3. Fix kconfig dependency for an intermediate patch (this is only useful in
>    case the latter patches are reverted).
> 4. Add more accurate runtime debugger stub mechanism and remove old
>    ACPI_DEBUGGER_EXEC() stub mechanism.
> 5. Add x86 acpi_os_readable() support.
> 
> v3:
> 1. Remove acpi_os_readable() support from this patchset. It's sent separately.
> 2. Delete some deprecated comments.
> 
> v4:
> 1. Rebase patch 4/6 because of Kconfig changes.
> 2. Include acpi_os_readable() back as no objections, also test result is
>    positive.
> 
> Chen Yu (1):
>   ACPI / x86: introduce acpi_os_readable() support
> 
> Colin Ian King (1):
>   ACPICA: Debugger: Remove unnecessary status check
> 
> Lv Zheng (5):
>   ACPICA: Debugger: Convert some mechanisms to OSPM specific
>   ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
>     different stub mechanism
>   ACPI / debugger: Add IO interface to access debugger functionalities
>   tools/power/acpi: Add userspace AML interface support
>   ACPI / debugger: Add module support for ACPI debugger

OK, I'm queuing up [1-6/7] for 4.5.

The [7/7] needs at least to be looked at by the x86 maintainers.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support
  2015-12-14 23:44     ` [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support Rafael J. Wysocki
@ 2015-12-15  2:55         ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-15  2:55 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, linux-acpi

Hi, Rafael

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, December 15, 2015 7:45 AM
> 
> On Thursday, December 03, 2015 10:40:00 AM Lv Zheng wrote:
> > This patchset enables ACPICA debugger for Linux kernel and implements a
> > userspace utility to access it.
> >
> > A. Build the AML debugger
> > In order to build the kernel support of AML debugger, the following kconfig
> > items should be enabled:
> >  CONFIG_ACPI_DEBUG=y
> >  CONFIG_ACPI_DEBUGGER=y
> >  CONFIG_DEBUG_FS=y
> >  CONFIG_ACPI_DEBUGGER_USER=m
> > The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
> > build this utility, staying in tools folder and type "make acpi".
> >
> > B. Load the AML debugger during runtime
> > In order to use the in-kernel AML debugger, the following command should
> be
> > executed using root user:
> >  # modprobe acpi_dbg
> >  # mount -t debugfs none /sys/kernel/debug
> >  # acpidbg
> >
> > C. Batch mode
> > In order to support scripts, the userspace utility also supports single
> > command batch mode:
> >  # acpidbg -b "help"
> >  # acpidbg -b "tables"
> >  # acpidbg -b "find _LID"
> >  # acpidbg -b "execute \_SB.LID0._LID"
> > You can find the documentation about the ACPICA debugger commands in:
> >  https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
> >  (The latest document can be found at https://acpica.org/documentation)
> > And refer to the chapter - ACPICA debugger reference to obtain the full
> > description of the debugger commands. Note that not all commands are
> > supported by an in-kernel AML debugger.
> >
> > D. Unload the AML debugger during runtime
> > After terminating all acpidbg instances, the following command can be
> > executed to remove the AML debugger from kernel:
> >  # rmmod acpi_dbg
> >
> > The following tasks are not completed:
> > 1. .flush() support in the kernel debugger IO driver.
> > 2. multi-commands batch mode.
> >
> > v2:
> > 1. Fix a help message issue for the userspace acpidbg utility (this is a
> >    typo fix).
> > 2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
> >    lost due to too many rebase cycles).
> > 3. Fix kconfig dependency for an intermediate patch (this is only useful in
> >    case the latter patches are reverted).
> > 4. Add more accurate runtime debugger stub mechanism and remove old
> >    ACPI_DEBUGGER_EXEC() stub mechanism.
> > 5. Add x86 acpi_os_readable() support.
> >
> > v3:
> > 1. Remove acpi_os_readable() support from this patchset. It's sent separately.
> > 2. Delete some deprecated comments.
> >
> > v4:
> > 1. Rebase patch 4/6 because of Kconfig changes.
> > 2. Include acpi_os_readable() back as no objections, also test result is
> >    positive.
> >
> > Chen Yu (1):
> >   ACPI / x86: introduce acpi_os_readable() support
> >
> > Colin Ian King (1):
> >   ACPICA: Debugger: Remove unnecessary status check
> >
> > Lv Zheng (5):
> >   ACPICA: Debugger: Convert some mechanisms to OSPM specific
> >   ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
> >     different stub mechanism
> >   ACPI / debugger: Add IO interface to access debugger functionalities
> >   tools/power/acpi: Add userspace AML interface support
> >   ACPI / debugger: Add module support for ACPI debugger
> 
> OK, I'm queuing up [1-6/7] for 4.5.
[Lv Zheng] 
Thanks!

> 
> The [7/7] needs at least to be looked at by the x86 maintainers.
[Lv Zheng] 
OK, we'll re-send this patch to both x86/acpi mailing list with an additional test patch included to make it clearer.

Thanks and best regards
-Lv

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support
@ 2015-12-15  2:55         ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-15  2:55 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, linux-acpi

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3731 bytes --]

Hi, Rafael

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, December 15, 2015 7:45 AM
> 
> On Thursday, December 03, 2015 10:40:00 AM Lv Zheng wrote:
> > This patchset enables ACPICA debugger for Linux kernel and implements a
> > userspace utility to access it.
> >
> > A. Build the AML debugger
> > In order to build the kernel support of AML debugger, the following kconfig
> > items should be enabled:
> >  CONFIG_ACPI_DEBUG=y
> >  CONFIG_ACPI_DEBUGGER=y
> >  CONFIG_DEBUG_FS=y
> >  CONFIG_ACPI_DEBUGGER_USER=m
> > The userspace tool can be found at tools/power/acpi/tools/acpidbg. To
> > build this utility, staying in tools folder and type "make acpi".
> >
> > B. Load the AML debugger during runtime
> > In order to use the in-kernel AML debugger, the following command should
> be
> > executed using root user:
> >  # modprobe acpi_dbg
> >  # mount -t debugfs none /sys/kernel/debug
> >  # acpidbg
> >
> > C. Batch mode
> > In order to support scripts, the userspace utility also supports single
> > command batch mode:
> >  # acpidbg -b "help"
> >  # acpidbg -b "tables"
> >  # acpidbg -b "find _LID"
> >  # acpidbg -b "execute \_SB.LID0._LID"
> > You can find the documentation about the ACPICA debugger commands in:
> >  https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
> >  (The latest document can be found at https://acpica.org/documentation)
> > And refer to the chapter - ACPICA debugger reference to obtain the full
> > description of the debugger commands. Note that not all commands are
> > supported by an in-kernel AML debugger.
> >
> > D. Unload the AML debugger during runtime
> > After terminating all acpidbg instances, the following command can be
> > executed to remove the AML debugger from kernel:
> >  # rmmod acpi_dbg
> >
> > The following tasks are not completed:
> > 1. .flush() support in the kernel debugger IO driver.
> > 2. multi-commands batch mode.
> >
> > v2:
> > 1. Fix a help message issue for the userspace acpidbg utility (this is a
> >    typo fix).
> > 2. Fix a batch mode issue by adding "\n" to the prompt sequence (this was
> >    lost due to too many rebase cycles).
> > 3. Fix kconfig dependency for an intermediate patch (this is only useful in
> >    case the latter patches are reverted).
> > 4. Add more accurate runtime debugger stub mechanism and remove old
> >    ACPI_DEBUGGER_EXEC() stub mechanism.
> > 5. Add x86 acpi_os_readable() support.
> >
> > v3:
> > 1. Remove acpi_os_readable() support from this patchset. It's sent separately.
> > 2. Delete some deprecated comments.
> >
> > v4:
> > 1. Rebase patch 4/6 because of Kconfig changes.
> > 2. Include acpi_os_readable() back as no objections, also test result is
> >    positive.
> >
> > Chen Yu (1):
> >   ACPI / x86: introduce acpi_os_readable() support
> >
> > Colin Ian King (1):
> >   ACPICA: Debugger: Remove unnecessary status check
> >
> > Lv Zheng (5):
> >   ACPICA: Debugger: Convert some mechanisms to OSPM specific
> >   ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using
> >     different stub mechanism
> >   ACPI / debugger: Add IO interface to access debugger functionalities
> >   tools/power/acpi: Add userspace AML interface support
> >   ACPI / debugger: Add module support for ACPI debugger
> 
> OK, I'm queuing up [1-6/7] for 4.5.
[Lv Zheng] 
Thanks!

> 
> The [7/7] needs at least to be looked at by the x86 maintainers.
[Lv Zheng] 
OK, we'll re-send this patch to both x86/acpi mailing list with an additional test patch included to make it clearer.

Thanks and best regards
-Lv
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-14 23:28       ` Andy Lutomirski
@ 2015-12-15  6:13           ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-15  6:13 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

Hi, Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Tuesday, December 15, 2015 7:28 AM
> To: Zheng, Lv
> Cc: Wysocki, Rafael J; Brown, Len; Andy Lutomirski; Lv Zheng; linux-
> kernel@vger.kernel.org; Linux ACPI; Chen, Yu C
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > From: Chen Yu <yu.c.chen@intel.com>
> >
> > This patch implements acpi_os_readable(). The function is used by
> > ACPICA AML debugger to validate user specified pointers for dumping
> > the memory as ACPICA descriptor objects.
> >
[cut]
> >
> > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > +       unsigned long obj_start, obj_end;
> > +       unsigned long start_pfn, end_pfn;
> 
> What does "readable" mean in this context?
'readable' means :  the address provided by the user, 
is a dynamically allocated  virtual address -
because  the  acpi address space are allocated by 'kmalloc',
acpi debugger must check if this address is a valid 'kmalloc'
address before accessing it.

This function does the sanity check that, the vitual address is a:
1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
than high_memory, VMALLOC_START, eg)
2.  besides, the physical address must be direct-mapped(so it would not be a hole).

Thanks,
yu


^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-15  6:13           ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-15  6:13 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1556 bytes --]

Hi, Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Tuesday, December 15, 2015 7:28 AM
> To: Zheng, Lv
> Cc: Wysocki, Rafael J; Brown, Len; Andy Lutomirski; Lv Zheng; linux-
> kernel@vger.kernel.org; Linux ACPI; Chen, Yu C
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > From: Chen Yu <yu.c.chen@intel.com>
> >
> > This patch implements acpi_os_readable(). The function is used by
> > ACPICA AML debugger to validate user specified pointers for dumping
> > the memory as ACPICA descriptor objects.
> >
[cut]
> >
> > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > +       unsigned long obj_start, obj_end;
> > +       unsigned long start_pfn, end_pfn;
> 
> What does "readable" mean in this context?
'readable' means :  the address provided by the user, 
is a dynamically allocated  virtual address -
because  the  acpi address space are allocated by 'kmalloc',
acpi debugger must check if this address is a valid 'kmalloc'
address before accessing it.

This function does the sanity check that, the vitual address is a:
1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
than high_memory, VMALLOC_START, eg)
2.  besides, the physical address must be direct-mapped(so it would not be a hole).

Thanks,
yu

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-15  6:13           ` Chen, Yu C
@ 2015-12-15  8:52             ` Zheng, Lv
  -1 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-15  8:52 UTC (permalink / raw)
  To: Chen, Yu C, Andy Lutomirski
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

Hi,

> From: Chen, Yu C
> Sent: Tuesday, December 15, 2015 2:13 PM
> 
> Hi, Andy
> 
> > From: Andy Lutomirski [mailto:luto@amacapital.net]
> > Sent: Tuesday, December 15, 2015 7:28 AM
> >
> > On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > > From: Chen Yu <yu.c.chen@intel.com>
> > >
> > > This patch implements acpi_os_readable(). The function is used by
> > > ACPICA AML debugger to validate user specified pointers for dumping
> > > the memory as ACPICA descriptor objects.
> > >
> [cut]
> > >
> > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > +       unsigned long obj_start, obj_end;
> > > +       unsigned long start_pfn, end_pfn;
> >
> > What does "readable" mean in this context?

[Lv Zheng] 
The function is used by ACPICA "dump" command.
It accepts an arbitrary address, and tries to dump the memory block specified by the address as an acpi_object.
You can try: "help dump" in the interactive mode to confirm.
While acpi_object is actually all created by kmalloc.
So we just check if the specified memory block belongs to the kernel heap.
The readable/writeable is not so meaningful here as the kernel heap should always be both readable and writeable.

We do a lot of checks in this function in order to allow it to:
1. return true if "pointer" belongs to kernel heap when "length" is 0;
2. return false if "pointer" doesn't belong to kernel heap when "length" is 0;
3. return true if "pointer ~ pointer+length-1" belongs to a kernel heap range;
4. return false if "pointer ~ pointer+length-1" doesn't belong to any kernel heap range.

These checks are weak, but can help to avoid panics if users specify wrong pointers for the "dump" command.

> 'readable' means :  the address provided by the user,
> is a dynamically allocated  virtual address -
> because  the  acpi address space are allocated by 'kmalloc',
> acpi debugger must check if this address is a valid 'kmalloc'
> address before accessing it.
> 
> This function does the sanity check that, the vitual address is a:
> 1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
> than high_memory, VMALLOC_START, eg)
> 2.  besides, the physical address must be direct-mapped(so it would not be a
> hole).

[Lv Zheng] 
There is a special case (possibly hackish) on x86_64.
x86_64 kernel maps kernel image twice.
One is called as high map and the other is called as low map.

Since we use __pa() to convert a virtual address,
If the virtual address belongs to the high map range, __pa() which takes care of converting high map addresses actually returns a physical address where there should also be low map mappings ready for it.
Thus the converted PFN from the result of __pa() will be treated as valid.

But this doesn't mean there is a high map for this virtual address.
x86_64 kernel drops several pages from high map in cleanup_highmap().
So accessing a virtual address that belongs to the holes whose page mappings have been dropped in this function could still result in panic due to no mappings.
By enforcing this check, we can avoid such a case.
Actually no acpi_object's virtual address will belong to high map range.

Thanks and best regards
-Lv

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-15  8:52             ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-15  8:52 UTC (permalink / raw)
  To: Chen, Yu C, Andy Lutomirski
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3346 bytes --]

Hi,

> From: Chen, Yu C
> Sent: Tuesday, December 15, 2015 2:13 PM
> 
> Hi, Andy
> 
> > From: Andy Lutomirski [mailto:luto@amacapital.net]
> > Sent: Tuesday, December 15, 2015 7:28 AM
> >
> > On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > > From: Chen Yu <yu.c.chen@intel.com>
> > >
> > > This patch implements acpi_os_readable(). The function is used by
> > > ACPICA AML debugger to validate user specified pointers for dumping
> > > the memory as ACPICA descriptor objects.
> > >
> [cut]
> > >
> > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > +       unsigned long obj_start, obj_end;
> > > +       unsigned long start_pfn, end_pfn;
> >
> > What does "readable" mean in this context?

[Lv Zheng] 
The function is used by ACPICA "dump" command.
It accepts an arbitrary address, and tries to dump the memory block specified by the address as an acpi_object.
You can try: "help dump" in the interactive mode to confirm.
While acpi_object is actually all created by kmalloc.
So we just check if the specified memory block belongs to the kernel heap.
The readable/writeable is not so meaningful here as the kernel heap should always be both readable and writeable.

We do a lot of checks in this function in order to allow it to:
1. return true if "pointer" belongs to kernel heap when "length" is 0;
2. return false if "pointer" doesn't belong to kernel heap when "length" is 0;
3. return true if "pointer ~ pointer+length-1" belongs to a kernel heap range;
4. return false if "pointer ~ pointer+length-1" doesn't belong to any kernel heap range.

These checks are weak, but can help to avoid panics if users specify wrong pointers for the "dump" command.

> 'readable' means :  the address provided by the user,
> is a dynamically allocated  virtual address -
> because  the  acpi address space are allocated by 'kmalloc',
> acpi debugger must check if this address is a valid 'kmalloc'
> address before accessing it.
> 
> This function does the sanity check that, the vitual address is a:
> 1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
> than high_memory, VMALLOC_START, eg)
> 2.  besides, the physical address must be direct-mapped(so it would not be a
> hole).

[Lv Zheng] 
There is a special case (possibly hackish) on x86_64.
x86_64 kernel maps kernel image twice.
One is called as high map and the other is called as low map.

Since we use __pa() to convert a virtual address,
If the virtual address belongs to the high map range, __pa() which takes care of converting high map addresses actually returns a physical address where there should also be low map mappings ready for it.
Thus the converted PFN from the result of __pa() will be treated as valid.

But this doesn't mean there is a high map for this virtual address.
x86_64 kernel drops several pages from high map in cleanup_highmap().
So accessing a virtual address that belongs to the holes whose page mappings have been dropped in this function could still result in panic due to no mappings.
By enforcing this check, we can avoid such a case.
Actually no acpi_object's virtual address will belong to high map range.

Thanks and best regards
-Lv
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-15  6:13           ` Chen, Yu C
@ 2015-12-16  0:25             ` Zheng, Lv
  -1 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-16  0:25 UTC (permalink / raw)
  To: Chen, Yu C, Andy Lutomirski, Moore, Robert
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

Hi, Andy and Yu

> From: Zheng, Lv
> Sent: Tuesday, December 15, 2015 4:52 PM
> 
> Hi,
> 
> > From: Chen, Yu C
> > Sent: Tuesday, December 15, 2015 2:13 PM
> >
> > Hi, Andy
> >
> > > From: Andy Lutomirski [mailto:luto@amacapital.net]
> > > Sent: Tuesday, December 15, 2015 7:28 AM
> > >
> > > On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > > > From: Chen Yu <yu.c.chen@intel.com>
> > > >
> > > > This patch implements acpi_os_readable(). The function is used by
> > > > ACPICA AML debugger to validate user specified pointers for dumping
> > > > the memory as ACPICA descriptor objects.
> > > >
> > [cut]
> > > >
> > > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > > +       unsigned long obj_start, obj_end;
> > > > +       unsigned long start_pfn, end_pfn;
> > >
> > > What does "readable" mean in this context?
> 
> [Lv Zheng]
> The function is used by ACPICA "dump" command.
> It accepts an arbitrary address, and tries to dump the memory block specified
> by the address as an acpi_object.
> You can try: "help dump" in the interactive mode to confirm.
> While acpi_object is actually all created by kmalloc.
[Lv Zheng] 
This statement might be wrong, Let me Cc Bob to confirm.

Hi, Bob

Do we have statically allocated acpi_objects?
If we have, we need to change this patch to allow high map .data/.bss segments addresses to pass this check.

Thanks and best regards
-Lv

> So we just check if the specified memory block belongs to the kernel heap.
> The readable/writeable is not so meaningful here as the kernel heap should
> always be both readable and writeable.
> 
> We do a lot of checks in this function in order to allow it to:
> 1. return true if "pointer" belongs to kernel heap when "length" is 0;
> 2. return false if "pointer" doesn't belong to kernel heap when "length" is 0;
> 3. return true if "pointer ~ pointer+length-1" belongs to a kernel heap range;
> 4. return false if "pointer ~ pointer+length-1" doesn't belong to any kernel heap
> range.
> 
> These checks are weak, but can help to avoid panics if users specify wrong
> pointers for the "dump" command.
> 
> > 'readable' means :  the address provided by the user,
> > is a dynamically allocated  virtual address -
> > because  the  acpi address space are allocated by 'kmalloc',
> > acpi debugger must check if this address is a valid 'kmalloc'
> > address before accessing it.
> >
> > This function does the sanity check that, the vitual address is a:
> > 1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
> > than high_memory, VMALLOC_START, eg)
> > 2.  besides, the physical address must be direct-mapped(so it would not be a
> > hole).
> 
> [Lv Zheng]
> There is a special case (possibly hackish) on x86_64.
> x86_64 kernel maps kernel image twice.
> One is called as high map and the other is called as low map.
> 
> Since we use __pa() to convert a virtual address,
> If the virtual address belongs to the high map range, __pa() which takes care of
> converting high map addresses actually returns a physical address where there
> should also be low map mappings ready for it.
> Thus the converted PFN from the result of __pa() will be treated as valid.
> 
> But this doesn't mean there is a high map for this virtual address.
> x86_64 kernel drops several pages from high map in cleanup_highmap().
> So accessing a virtual address that belongs to the holes whose page mappings
> have been dropped in this function could still result in panic due to no mappings.
> By enforcing this check, we can avoid such a case.
> Actually no acpi_object's virtual address will belong to high map range.
> 
> Thanks and best regards
> -Lv

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-16  0:25             ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-16  0:25 UTC (permalink / raw)
  To: Chen, Yu C, Andy Lutomirski, Moore, Robert
  Cc: Wysocki, Rafael J, Brown, Len, Andy Lutomirski, Lv Zheng,
	linux-kernel, Linux ACPI

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3840 bytes --]

Hi, Andy and Yu

> From: Zheng, Lv
> Sent: Tuesday, December 15, 2015 4:52 PM
> 
> Hi,
> 
> > From: Chen, Yu C
> > Sent: Tuesday, December 15, 2015 2:13 PM
> >
> > Hi, Andy
> >
> > > From: Andy Lutomirski [mailto:luto@amacapital.net]
> > > Sent: Tuesday, December 15, 2015 7:28 AM
> > >
> > > On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
> > > > From: Chen Yu <yu.c.chen@intel.com>
> > > >
> > > > This patch implements acpi_os_readable(). The function is used by
> > > > ACPICA AML debugger to validate user specified pointers for dumping
> > > > the memory as ACPICA descriptor objects.
> > > >
> > [cut]
> > > >
> > > > +bool __acpi_memory_readable(void *pointer, size_t length) {
> > > > +       unsigned long obj_start, obj_end;
> > > > +       unsigned long start_pfn, end_pfn;
> > >
> > > What does "readable" mean in this context?
> 
> [Lv Zheng]
> The function is used by ACPICA "dump" command.
> It accepts an arbitrary address, and tries to dump the memory block specified
> by the address as an acpi_object.
> You can try: "help dump" in the interactive mode to confirm.
> While acpi_object is actually all created by kmalloc.
[Lv Zheng] 
This statement might be wrong, Let me Cc Bob to confirm.

Hi, Bob

Do we have statically allocated acpi_objects?
If we have, we need to change this patch to allow high map .data/.bss segments addresses to pass this check.

Thanks and best regards
-Lv

> So we just check if the specified memory block belongs to the kernel heap.
> The readable/writeable is not so meaningful here as the kernel heap should
> always be both readable and writeable.
> 
> We do a lot of checks in this function in order to allow it to:
> 1. return true if "pointer" belongs to kernel heap when "length" is 0;
> 2. return false if "pointer" doesn't belong to kernel heap when "length" is 0;
> 3. return true if "pointer ~ pointer+length-1" belongs to a kernel heap range;
> 4. return false if "pointer ~ pointer+length-1" doesn't belong to any kernel heap
> range.
> 
> These checks are weak, but can help to avoid panics if users specify wrong
> pointers for the "dump" command.
> 
> > 'readable' means :  the address provided by the user,
> > is a dynamically allocated  virtual address -
> > because  the  acpi address space are allocated by 'kmalloc',
> > acpi debugger must check if this address is a valid 'kmalloc'
> > address before accessing it.
> >
> > This function does the sanity check that, the vitual address is a:
> > 1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
> > than high_memory, VMALLOC_START, eg)
> > 2.  besides, the physical address must be direct-mapped(so it would not be a
> > hole).
> 
> [Lv Zheng]
> There is a special case (possibly hackish) on x86_64.
> x86_64 kernel maps kernel image twice.
> One is called as high map and the other is called as low map.
> 
> Since we use __pa() to convert a virtual address,
> If the virtual address belongs to the high map range, __pa() which takes care of
> converting high map addresses actually returns a physical address where there
> should also be low map mappings ready for it.
> Thus the converted PFN from the result of __pa() will be treated as valid.
> 
> But this doesn't mean there is a high map for this virtual address.
> x86_64 kernel drops several pages from high map in cleanup_highmap().
> So accessing a virtual address that belongs to the holes whose page mappings
> have been dropped in this function could still result in panic due to no mappings.
> By enforcing this check, we can avoid such a case.
> Actually no acpi_object's virtual address will belong to high map range.
> 
> Thanks and best regards
> -Lv
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-16  0:25             ` Zheng, Lv
  (?)
@ 2015-12-17 16:59             ` Andy Lutomirski
  2015-12-22  1:03                 ` Chen, Yu C
  -1 siblings, 1 reply; 131+ messages in thread
From: Andy Lutomirski @ 2015-12-17 16:59 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: Chen, Yu C, Moore, Robert, Wysocki, Rafael J, Brown, Len,
	Andy Lutomirski, Lv Zheng, linux-kernel, Linux ACPI,
	H. Peter Anvin, Borislav Petkov

On Tue, Dec 15, 2015 at 4:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
> Hi, Andy and Yu
>
>> From: Zheng, Lv
>> Sent: Tuesday, December 15, 2015 4:52 PM
>>
>> Hi,
>>
>> > From: Chen, Yu C
>> > Sent: Tuesday, December 15, 2015 2:13 PM
>> >
>> > Hi, Andy
>> >
>> > > From: Andy Lutomirski [mailto:luto@amacapital.net]
>> > > Sent: Tuesday, December 15, 2015 7:28 AM
>> > >
>> > > On Wed, Dec 2, 2015 at 6:43 PM, Lv Zheng <lv.zheng@intel.com> wrote:
>> > > > From: Chen Yu <yu.c.chen@intel.com>
>> > > >
>> > > > This patch implements acpi_os_readable(). The function is used by
>> > > > ACPICA AML debugger to validate user specified pointers for dumping
>> > > > the memory as ACPICA descriptor objects.
>> > > >
>> > [cut]
>> > > >
>> > > > +bool __acpi_memory_readable(void *pointer, size_t length) {
>> > > > +       unsigned long obj_start, obj_end;
>> > > > +       unsigned long start_pfn, end_pfn;
>> > >
>> > > What does "readable" mean in this context?
>>
>> [Lv Zheng]
>> The function is used by ACPICA "dump" command.
>> It accepts an arbitrary address, and tries to dump the memory block specified
>> by the address as an acpi_object.
>> You can try: "help dump" in the interactive mode to confirm.
>> While acpi_object is actually all created by kmalloc.
> [Lv Zheng]
> This statement might be wrong, Let me Cc Bob to confirm.
>
> Hi, Bob
>
> Do we have statically allocated acpi_objects?
> If we have, we need to change this patch to allow high map .data/.bss segments addresses to pass this check.
>

I think that hpa or Borislav [cc'd] could address the memory map
details better than I could.  However, this functionality seems
strange.

Are these physical addresses or virtual addresses that are being
dumped?  In either case, ISTM that using something iike page_is_ram
might be a lot simpler.

--Andy

> Thanks and best regards
> -Lv
>
>> So we just check if the specified memory block belongs to the kernel heap.
>> The readable/writeable is not so meaningful here as the kernel heap should
>> always be both readable and writeable.
>>
>> We do a lot of checks in this function in order to allow it to:
>> 1. return true if "pointer" belongs to kernel heap when "length" is 0;
>> 2. return false if "pointer" doesn't belong to kernel heap when "length" is 0;
>> 3. return true if "pointer ~ pointer+length-1" belongs to a kernel heap range;
>> 4. return false if "pointer ~ pointer+length-1" doesn't belong to any kernel heap
>> range.
>>
>> These checks are weak, but can help to avoid panics if users specify wrong
>> pointers for the "dump" command.
>>
>> > 'readable' means :  the address provided by the user,
>> > is a dynamically allocated  virtual address -
>> > because  the  acpi address space are allocated by 'kmalloc',
>> > acpi debugger must check if this address is a valid 'kmalloc'
>> > address before accessing it.
>> >
>> > This function does the sanity check that, the vitual address is a:
>> > 1.   dynamically allocated address (beyond PAGE_OFFSET , but lower
>> > than high_memory, VMALLOC_START, eg)
>> > 2.  besides, the physical address must be direct-mapped(so it would not be a
>> > hole).
>>
>> [Lv Zheng]
>> There is a special case (possibly hackish) on x86_64.
>> x86_64 kernel maps kernel image twice.
>> One is called as high map and the other is called as low map.
>>
>> Since we use __pa() to convert a virtual address,
>> If the virtual address belongs to the high map range, __pa() which takes care of
>> converting high map addresses actually returns a physical address where there
>> should also be low map mappings ready for it.
>> Thus the converted PFN from the result of __pa() will be treated as valid.
>>
>> But this doesn't mean there is a high map for this virtual address.
>> x86_64 kernel drops several pages from high map in cleanup_highmap().
>> So accessing a virtual address that belongs to the holes whose page mappings
>> have been dropped in this function could still result in panic due to no mappings.
>> By enforcing this check, we can avoid such a case.
>> Actually no acpi_object's virtual address will belong to high map range.
>>
>> Thanks and best regards
>> -Lv



-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-17 16:59             ` Andy Lutomirski
@ 2015-12-22  1:03                 ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-22  1:03 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

Hi Andy,
thanks for your review,

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Friday, December 18, 2015 1:00 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
[cut]
> 
> I think that hpa or Borislav [cc'd] could address the memory map details
> better than I could.  However, this functionality seems strange.
> 
> Are these physical addresses or virtual addresses that are being dumped?  
[Yu] They are  virtual addresses to be dumped.
> In  either case, ISTM that using something iike page_is_ram might be a lot
> simpler.
[Yu] if i understand correctly, this API is used to check if the address is a valid 
'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
might treat the latter as valid address?

thanks,
Yu

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-22  1:03                 ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-22  1:03 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1167 bytes --]

Hi Andy,
thanks for your review,

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Friday, December 18, 2015 1:00 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
[cut]
> 
> I think that hpa or Borislav [cc'd] could address the memory map details
> better than I could.  However, this functionality seems strange.
> 
> Are these physical addresses or virtual addresses that are being dumped?  
[Yu] They are  virtual addresses to be dumped.
> In  either case, ISTM that using something iike page_is_ram might be a lot
> simpler.
[Yu] if i understand correctly, this API is used to check if the address is a valid 
'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
might treat the latter as valid address?

thanks,
Yu
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-22  1:03                 ` Chen, Yu C
  (?)
@ 2015-12-22 22:49                 ` Andy Lutomirski
  2015-12-23  3:25                     ` Zheng, Lv
  -1 siblings, 1 reply; 131+ messages in thread
From: Andy Lutomirski @ 2015-12-22 22:49 UTC (permalink / raw)
  To: Chen, Yu C
  Cc: Zheng, Lv, Moore, Robert, Wysocki, Rafael J, Brown, Len,
	Andy Lutomirski, Lv Zheng, linux-kernel, Linux ACPI,
	H. Peter Anvin, Borislav Petkov

On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> Hi Andy,
> thanks for your review,
>
>> -----Original Message-----
>> From: Andy Lutomirski [mailto:luto@amacapital.net]
>> Sent: Friday, December 18, 2015 1:00 AM
>> To: Zheng, Lv
>> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
>> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
>> Anvin; Borislav Petkov
>> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
>>
> [cut]
>>
>> I think that hpa or Borislav [cc'd] could address the memory map details
>> better than I could.  However, this functionality seems strange.
>>
>> Are these physical addresses or virtual addresses that are being dumped?
> [Yu] They are  virtual addresses to be dumped.
>> In  either case, ISTM that using something iike page_is_ram might be a lot
>> simpler.
> [Yu] if i understand correctly, this API is used to check if the address is a valid
> 'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
> might treat the latter as valid address?
>

I'm a bit puzzled as to why this matters, but I have no fundamental
objection to doing it that way.

What's the use case, though?  That is, what goes wrong if the function
just always returns false?

--Andy

> thanks,
> Yu



-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-22 22:49                 ` Andy Lutomirski
@ 2015-12-23  3:25                     ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-23  3:25 UTC (permalink / raw)
  To: Andy Lutomirski, Chen, Yu C
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

Hi, Andy

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> owner@vger.kernel.org] On Behalf Of Andy Lutomirski
> Sent: Wednesday, December 23, 2015 6:49 AM
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> > Hi Andy,
> > thanks for your review,
> >
> >> -----Original Message-----
> >> From: Andy Lutomirski [mailto:luto@amacapital.net]
> >> Sent: Friday, December 18, 2015 1:00 AM
> >> To: Zheng, Lv
> >> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> >> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> >> Anvin; Borislav Petkov
> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable()
> support
> >>
> > [cut]
> >>
> >> I think that hpa or Borislav [cc'd] could address the memory map details
> >> better than I could.  However, this functionality seems strange.
> >>
> >> Are these physical addresses or virtual addresses that are being dumped?
> > [Yu] They are  virtual addresses to be dumped.
> >> In  either case, ISTM that using something iike page_is_ram might be a lot
> >> simpler.
> > [Yu] if i understand correctly, this API is used to check if the address is a valid
> > 'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
> > might treat the latter as valid address?
> >
> 
> I'm a bit puzzled as to why this matters, but I have no fundamental objection to doing it that way.
[Lv Zheng] 
IMO, using page_is_ram() or something similar, the problem is what we need to solve in the current approach still need to be solved:
1. How can we convert a virtual address into a "struct page"?
    There is no kernel API to convert any virtual address into struct page.
    Even there is such a kernel API to convert kmap/vmalloc addresses, we still couldn't use it.
    Because if we want to validate kmap/vmaloc pages, we need 2 APIs rather than 1 API while ACPICA only provides 1 API for this purpose.
    The 2 APIs should be get/put style to ping the page mappings as the mappings other than the direct mappings will not be stationary in the kernel address space.
    Fortunately we needn't take care of the mappings other than the direct mappings (reasons are in the 2nd comment).
    So we still need to use the direct mapping APIs here.
2. How can we ensure the page is a direct mapping page?
    I think Yu should confirm if there is such a common kernel API.
    If there is such an API, we should use it so that we can remove the arch specific stuffs.

> What's the use case, though?
[Lv Zheng] 
Fortunately, currently ACPICA only uses this API to validate if a namespace node, an operand object or a parser object is readable.
See drivers/acpi/acpica/dbdisplay.c and drivers/acpi/acpica/dbcmds.c.

>  That is, what goes wrong if the function just always returns false?
[Lv Zheng] 
1. If it always returns false, then many ACPICA debugger internal object conversion/dump functionalities won't be functioning.
    For example, you can try to type “dump \_SB" in acpidbg shell and it will return an error:
      "Invalid named object at address xxxxxxxxxxxxxxxx"
2. While if this function always returns true (current linux-pm/linux-next merged stuffs), we can see such a result:
      Object (ffffxxxxxxxxxxxx) Pathname: \_SB
          Name : _SB_
          Type : 06 [Device]
          ...
3. But if it always returns true, then there will be another problem:
    User can type an invalid address, for example, "dump 0xFFFFFFFFFFFFFFFF".
    And ACPICA debugger will try to access this invalid virtual address and finally result in a panic.
    So we need to implement acpi_os_readable() to harden the check.

[Lv Zheng]
Let me say more about this patch.
Currently this patch looks wrong.
Though, most of the acpi_object(s) are kmalloced in the kernel heap, as far as I know, at least the namespace root is a statically allocated object in ACPICA.
Maybe "One"/"Ones"/"Zero" operands are all statically allocated objects.

So we need to modify this function to return true for the addresses that belong to .data/.bss sections for x86_64 kernels.
You can confirm this by typing "dump \" in the acpidbg shell, it now returns:
 "Invalid named object at address ffffffff8xxxxxxx".
We'll update it and send it after testing.

Thanks and best regards
-Lv

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-23  3:25                     ` Zheng, Lv
  0 siblings, 0 replies; 131+ messages in thread
From: Zheng, Lv @ 2015-12-23  3:25 UTC (permalink / raw)
  To: Andy Lutomirski, Chen, Yu C
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4540 bytes --]

Hi, Andy

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> owner@vger.kernel.org] On Behalf Of Andy Lutomirski
> Sent: Wednesday, December 23, 2015 6:49 AM
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com> wrote:
> > Hi Andy,
> > thanks for your review,
> >
> >> -----Original Message-----
> >> From: Andy Lutomirski [mailto:luto@amacapital.net]
> >> Sent: Friday, December 18, 2015 1:00 AM
> >> To: Zheng, Lv
> >> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> >> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> >> Anvin; Borislav Petkov
> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable()
> support
> >>
> > [cut]
> >>
> >> I think that hpa or Borislav [cc'd] could address the memory map details
> >> better than I could.  However, this functionality seems strange.
> >>
> >> Are these physical addresses or virtual addresses that are being dumped?
> > [Yu] They are  virtual addresses to be dumped.
> >> In  either case, ISTM that using something iike page_is_ram might be a lot
> >> simpler.
> > [Yu] if i understand correctly, this API is used to check if the address is a valid
> > 'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
> > might treat the latter as valid address?
> >
> 
> I'm a bit puzzled as to why this matters, but I have no fundamental objection to doing it that way.
[Lv Zheng] 
IMO, using page_is_ram() or something similar, the problem is what we need to solve in the current approach still need to be solved:
1. How can we convert a virtual address into a "struct page"?
    There is no kernel API to convert any virtual address into struct page.
    Even there is such a kernel API to convert kmap/vmalloc addresses, we still couldn't use it.
    Because if we want to validate kmap/vmaloc pages, we need 2 APIs rather than 1 API while ACPICA only provides 1 API for this purpose.
    The 2 APIs should be get/put style to ping the page mappings as the mappings other than the direct mappings will not be stationary in the kernel address space.
    Fortunately we needn't take care of the mappings other than the direct mappings (reasons are in the 2nd comment).
    So we still need to use the direct mapping APIs here.
2. How can we ensure the page is a direct mapping page?
    I think Yu should confirm if there is such a common kernel API.
    If there is such an API, we should use it so that we can remove the arch specific stuffs.

> What's the use case, though?
[Lv Zheng] 
Fortunately, currently ACPICA only uses this API to validate if a namespace node, an operand object or a parser object is readable.
See drivers/acpi/acpica/dbdisplay.c and drivers/acpi/acpica/dbcmds.c.

>  That is, what goes wrong if the function just always returns false?
[Lv Zheng] 
1. If it always returns false, then many ACPICA debugger internal object conversion/dump functionalities won't be functioning.
    For example, you can try to type “dump \_SB" in acpidbg shell and it will return an error:
      "Invalid named object at address xxxxxxxxxxxxxxxx"
2. While if this function always returns true (current linux-pm/linux-next merged stuffs), we can see such a result:
      Object (ffffxxxxxxxxxxxx) Pathname: \_SB
          Name : _SB_
          Type : 06 [Device]
          ...
3. But if it always returns true, then there will be another problem:
    User can type an invalid address, for example, "dump 0xFFFFFFFFFFFFFFFF".
    And ACPICA debugger will try to access this invalid virtual address and finally result in a panic.
    So we need to implement acpi_os_readable() to harden the check.

[Lv Zheng]
Let me say more about this patch.
Currently this patch looks wrong.
Though, most of the acpi_object(s) are kmalloced in the kernel heap, as far as I know, at least the namespace root is a statically allocated object in ACPICA.
Maybe "One"/"Ones"/"Zero" operands are all statically allocated objects.

So we need to modify this function to return true for the addresses that belong to .data/.bss sections for x86_64 kernels.
You can confirm this by typing "dump \" in the acpidbg shell, it now returns:
 "Invalid named object at address ffffffff8xxxxxxx".
We'll update it and send it after testing.

Thanks and best regards
-Lv
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-23  3:25                     ` Zheng, Lv
  (?)
@ 2015-12-24  1:40                     ` Andy Lutomirski
  2015-12-24  7:57                         ` Chen, Yu C
  2015-12-24  8:01                         ` Chen, Yu C
  -1 siblings, 2 replies; 131+ messages in thread
From: Andy Lutomirski @ 2015-12-24  1:40 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: Chen, Yu C, Moore, Robert, Wysocki, Rafael J, Brown, Len,
	Andy Lutomirski, Lv Zheng, linux-kernel, Linux ACPI,
	H. Peter Anvin, Borislav Petkov

On Tue, Dec 22, 2015 at 7:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
> Hi, Andy
>
>> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
>> owner@vger.kernel.org] On Behalf Of Andy Lutomirski
>> Sent: Wednesday, December 23, 2015 6:49 AM
>> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
>>
>> On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com> wrote:
>> > Hi Andy,
>> > thanks for your review,
>> >
>> >> -----Original Message-----
>> >> From: Andy Lutomirski [mailto:luto@amacapital.net]
>> >> Sent: Friday, December 18, 2015 1:00 AM
>> >> To: Zheng, Lv
>> >> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
>> >> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
>> >> Anvin; Borislav Petkov
>> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable()
>> support
>> >>
>> > [cut]
>> >>
>> >> I think that hpa or Borislav [cc'd] could address the memory map details
>> >> better than I could.  However, this functionality seems strange.
>> >>
>> >> Are these physical addresses or virtual addresses that are being dumped?
>> > [Yu] They are  virtual addresses to be dumped.
>> >> In  either case, ISTM that using something iike page_is_ram might be a lot
>> >> simpler.
>> > [Yu] if i understand correctly, this API is used to check if the address is a valid
>> > 'kmalloc' style address, but not 'kmap' or 'vmalloc' address, and page_is_ram
>> > might treat the latter as valid address?
>> >
>>
>> I'm a bit puzzled as to why this matters, but I have no fundamental objection to doing it that way.
> [Lv Zheng]
> IMO, using page_is_ram() or something similar, the problem is what we need to solve in the current approach still need to be solved:
> 1. How can we convert a virtual address into a "struct page"?
>     There is no kernel API to convert any virtual address into struct page.
>     Even there is such a kernel API to convert kmap/vmalloc addresses, we still couldn't use it.
>     Because if we want to validate kmap/vmaloc pages, we need 2 APIs rather than 1 API while ACPICA only provides 1 API for this purpose.
>     The 2 APIs should be get/put style to ping the page mappings as the mappings other than the direct mappings will not be stationary in the kernel address space.
>     Fortunately we needn't take care of the mappings other than the direct mappings (reasons are in the 2nd comment).
>     So we still need to use the direct mapping APIs here.
> 2. How can we ensure the page is a direct mapping page?
>     I think Yu should confirm if there is such a common kernel API.
>     If there is such an API, we should use it so that we can remove the arch specific stuffs.
>
>> What's the use case, though?
> [Lv Zheng]
> Fortunately, currently ACPICA only uses this API to validate if a namespace node, an operand object or a parser object is readable.
> See drivers/acpi/acpica/dbdisplay.c and drivers/acpi/acpica/dbcmds.c.
>
>>  That is, what goes wrong if the function just always returns false?
> [Lv Zheng]
> 1. If it always returns false, then many ACPICA debugger internal object conversion/dump functionalities won't be functioning.
>     For example, you can try to type “dump \_SB" in acpidbg shell and it will return an error:
>       "Invalid named object at address xxxxxxxxxxxxxxxx"
> 2. While if this function always returns true (current linux-pm/linux-next merged stuffs), we can see such a result:
>       Object (ffffxxxxxxxxxxxx) Pathname: \_SB
>           Name : _SB_
>           Type : 06 [Device]
>

It seems a bit unfortunate to me that the ACPICA debugger lets
userspace choose what address to dump rather than dumping by pathname,
but given that constraint, I guess this function is needed.

Can you do something like checking virt_addr_valid and then using
virt_to_pfn and page_is_ram?  If that's not enough (e.g. if it doesn't
work for vmalloc addresses and you need those), you could try to do
something like slow_virt_to_phys, but you'd need to do some extra
checks to avoid the BUG in the function.

--Andy

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH] ACPI / debugger: Fix an issue a flag is modified without locking
  2015-11-06  6:46   ` Lv Zheng
@ 2015-12-24  6:16     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-24  6:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

There is one line of code, executed out of locking due to rebase mistakes.
This patch fixes this issue.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpi_dbg.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 381beb2..fa18bd0 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -516,10 +516,10 @@ static int acpi_aml_open(struct inode *inode, struct file *file)
 			ret = -EINVAL;
 			goto err_lock;
 		}
-		acpi_aml_io.flags |= ACPI_AML_OPENED;
 		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");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH] ACPI / debugger: Fix an issue a flag is modified without locking
@ 2015-12-24  6:16     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-24  6:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

There is one line of code, executed out of locking due to rebase mistakes.
This patch fixes this issue.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpi_dbg.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index 381beb2..fa18bd0 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -516,10 +516,10 @@ static int acpi_aml_open(struct inode *inode, struct file *file)
 			ret = -EINVAL;
 			goto err_lock;
 		}
-		acpi_aml_io.flags |= ACPI_AML_OPENED;
 		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");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-24  1:40                     ` Andy Lutomirski
@ 2015-12-24  7:57                         ` Chen, Yu C
  2015-12-24  8:01                         ` Chen, Yu C
  1 sibling, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-24  7:57 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

Hi,Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Thursday, December 24, 2015 9:40 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Dec 22, 2015 at 7:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
[cut]
> 
> It seems a bit unfortunate to me that the ACPICA debugger lets userspace
> choose what address to dump rather than dumping by pathname, but given
> that constraint, I guess this function is needed.
> 
> Can you do something like checking virt_addr_valid and then using
> virt_to_pfn and page_is_ram?  If that's not enough (e.g. if it doesn't work for
> vmalloc addresses and you need those), you could try to do something like
> slow_virt_to_phys, but you'd need to do some extra checks to avoid the
> BUG in the function.
> 
[Yu] This is a  good method,  firstly virt_addr_valid can  exclude the vaddr of vmalloc/kmap
, then slow_virt_to_phys can check if this vaddr has a valid pte physical address, but I guess
we need another non-BUG_on version of slow_virt_to_phys,  I'll try to test with your suggestion,
thanks!
Yu



^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-24  7:57                         ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-24  7:57 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1470 bytes --]

Hi,Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Thursday, December 24, 2015 9:40 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Dec 22, 2015 at 7:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
[cut]
> 
> It seems a bit unfortunate to me that the ACPICA debugger lets userspace
> choose what address to dump rather than dumping by pathname, but given
> that constraint, I guess this function is needed.
> 
> Can you do something like checking virt_addr_valid and then using
> virt_to_pfn and page_is_ram?  If that's not enough (e.g. if it doesn't work for
> vmalloc addresses and you need those), you could try to do something like
> slow_virt_to_phys, but you'd need to do some extra checks to avoid the
> BUG in the function.
> 
[Yu] This is a  good method,  firstly virt_addr_valid can  exclude the vaddr of vmalloc/kmap
, then slow_virt_to_phys can check if this vaddr has a valid pte physical address, but I guess
we need another non-BUG_on version of slow_virt_to_phys,  I'll try to test with your suggestion,
thanks!
Yu


ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
  2015-12-24  1:40                     ` Andy Lutomirski
@ 2015-12-24  8:01                         ` Chen, Yu C
  2015-12-24  8:01                         ` Chen, Yu C
  1 sibling, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-24  8:01 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

(resend for messy code)
Hi, Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Thursday, December 24, 2015 9:40 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Dec 22, 2015 at 7:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
> > Hi, Andy
> >
> >> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> >> owner@vger.kernel.org] On Behalf Of Andy Lutomirski
> >> Sent: Wednesday, December 23, 2015 6:49 AM
> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable()
> >> support
> >>
> >> On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com>
> wrote:
> >> > Hi Andy,
> >> > thanks for your review,
> >> >
> >> >> -----Original Message-----
> >> >> From: Andy Lutomirski [mailto:luto@amacapital.net]
> >> >> Sent: Friday, December 18, 2015 1:00 AM
> >> >> To: Zheng, Lv
> >> >> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> >> >> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H.
> >> >> Peter Anvin; Borislav Petkov
> >> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce
> >> >> acpi_os_readable()
> >> support
> >> >>
> >> > [cut]
> >> >>
> >> >> I think that hpa or Borislav [cc'd] could address the memory map
> >> >> details better than I could.  However, this functionality seems strange.
> >> >>
> >> >> Are these physical addresses or virtual addresses that are being
> dumped?
> >> > [Yu] They are  virtual addresses to be dumped.
> >> >> In  either case, ISTM that using something iike page_is_ram might
> >> >> be a lot simpler.
> >> > [Yu] if i understand correctly, this API is used to check if the
> >> > address is a valid 'kmalloc' style address, but not 'kmap' or
> >> > 'vmalloc' address, and page_is_ram might treat the latter as valid
> address?
> >> >
> >>
> >> I'm a bit puzzled as to why this matters, but I have no fundamental
> objection to doing it that way.
> > [Lv Zheng]
> > IMO, using page_is_ram() or something similar, the problem is what we
> need to solve in the current approach still need to be solved:
> > 1. How can we convert a virtual address into a "struct page"?
> >     There is no kernel API to convert any virtual address into struct page.
> >     Even there is such a kernel API to convert kmap/vmalloc addresses, we
> still couldn't use it.
> >     Because if we want to validate kmap/vmaloc pages, we need 2 APIs
> rather than 1 API while ACPICA only provides 1 API for this purpose.
> >     The 2 APIs should be get/put style to ping the page mappings as the
> mappings other than the direct mappings will not be stationary in the kernel
> address space.
> >     Fortunately we needn't take care of the mappings other than the direct
> mappings (reasons are in the 2nd comment).
> >     So we still need to use the direct mapping APIs here.
> > 2. How can we ensure the page is a direct mapping page?
> >     I think Yu should confirm if there is such a common kernel API.
> >     If there is such an API, we should use it so that we can remove the arch
> specific stuffs.
> >
> >> What's the use case, though?
> > [Lv Zheng]
> > Fortunately, currently ACPICA only uses this API to validate if a namespace
> node, an operand object or a parser object is readable.
> > See drivers/acpi/acpica/dbdisplay.c and drivers/acpi/acpica/dbcmds.c.
> >
> >>  That is, what goes wrong if the function just always returns false?
> > [Lv Zheng]
> > 1. If it always returns false, then many ACPICA debugger internal object
> conversion/dump functionalities won't be functioning.
> >     For example, you can try to type “dump \_SB" in acpidbg shell and it will
> return an error:
> >       "Invalid named object at address xxxxxxxxxxxxxxxx"
> > 2. While if this function always returns true (current linux-pm/linux-next
> merged stuffs), we can see such a result:
> >       Object (ffffxxxxxxxxxxxx) Pathname: \_SB
> >           Name : _SB_
> >           Type : 06 [Device]
> >
> 
> It seems a bit unfortunate to me that the ACPICA debugger lets userspace
> choose what address to dump rather than dumping by pathname, but given
> that constraint, I guess this function is needed.
> 
> Can you do something like checking virt_addr_valid and then using
> virt_to_pfn and page_is_ram?  If that's not enough (e.g. if it doesn't work for
> vmalloc addresses and you need those), you could try to do something like
> slow_virt_to_phys, but you'd need to do some extra checks to avoid the
> BUG in the function.
> 
[Yu] This is a  good method,  firstly virt_addr_valid can  exclude the vaddr of vmalloc/kmap , 
then slow_virt_to_phys can check if this vaddr has a valid pte physical address, 
but I guess we need another non-BUG_on version of slow_virt_to_phys,  
I'll try to test with your suggestion, thanks!
Yu



^ permalink raw reply	[flat|nested] 131+ messages in thread

* RE: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
@ 2015-12-24  8:01                         ` Chen, Yu C
  0 siblings, 0 replies; 131+ messages in thread
From: Chen, Yu C @ 2015-12-24  8:01 UTC (permalink / raw)
  To: Andy Lutomirski, Zheng, Lv
  Cc: Moore, Robert, Wysocki, Rafael J, Brown, Len, Andy Lutomirski,
	Lv Zheng, linux-kernel, Linux ACPI, H. Peter Anvin,
	Borislav Petkov

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 5155 bytes --]

(resend for messy code)
Hi, Andy

> -----Original Message-----
> From: Andy Lutomirski [mailto:luto@amacapital.net]
> Sent: Thursday, December 24, 2015 9:40 AM
> To: Zheng, Lv
> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H. Peter
> Anvin; Borislav Petkov
> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support
> 
> On Tue, Dec 22, 2015 at 7:25 PM, Zheng, Lv <lv.zheng@intel.com> wrote:
> > Hi, Andy
> >
> >> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> >> owner@vger.kernel.org] On Behalf Of Andy Lutomirski
> >> Sent: Wednesday, December 23, 2015 6:49 AM
> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable()
> >> support
> >>
> >> On Mon, Dec 21, 2015 at 5:03 PM, Chen, Yu C <yu.c.chen@intel.com>
> wrote:
> >> > Hi Andy,
> >> > thanks for your review,
> >> >
> >> >> -----Original Message-----
> >> >> From: Andy Lutomirski [mailto:luto@amacapital.net]
> >> >> Sent: Friday, December 18, 2015 1:00 AM
> >> >> To: Zheng, Lv
> >> >> Cc: Chen, Yu C; Moore, Robert; Wysocki, Rafael J; Brown, Len; Andy
> >> >> Lutomirski; Lv Zheng; linux-kernel@vger.kernel.org; Linux ACPI; H.
> >> >> Peter Anvin; Borislav Petkov
> >> >> Subject: Re: [PATCH v4 7/7] ACPI / x86: introduce
> >> >> acpi_os_readable()
> >> support
> >> >>
> >> > [cut]
> >> >>
> >> >> I think that hpa or Borislav [cc'd] could address the memory map
> >> >> details better than I could.  However, this functionality seems strange.
> >> >>
> >> >> Are these physical addresses or virtual addresses that are being
> dumped?
> >> > [Yu] They are  virtual addresses to be dumped.
> >> >> In  either case, ISTM that using something iike page_is_ram might
> >> >> be a lot simpler.
> >> > [Yu] if i understand correctly, this API is used to check if the
> >> > address is a valid 'kmalloc' style address, but not 'kmap' or
> >> > 'vmalloc' address, and page_is_ram might treat the latter as valid
> address?
> >> >
> >>
> >> I'm a bit puzzled as to why this matters, but I have no fundamental
> objection to doing it that way.
> > [Lv Zheng]
> > IMO, using page_is_ram() or something similar, the problem is what we
> need to solve in the current approach still need to be solved:
> > 1. How can we convert a virtual address into a "struct page"?
> >     There is no kernel API to convert any virtual address into struct page.
> >     Even there is such a kernel API to convert kmap/vmalloc addresses, we
> still couldn't use it.
> >     Because if we want to validate kmap/vmaloc pages, we need 2 APIs
> rather than 1 API while ACPICA only provides 1 API for this purpose.
> >     The 2 APIs should be get/put style to ping the page mappings as the
> mappings other than the direct mappings will not be stationary in the kernel
> address space.
> >     Fortunately we needn't take care of the mappings other than the direct
> mappings (reasons are in the 2nd comment).
> >     So we still need to use the direct mapping APIs here.
> > 2. How can we ensure the page is a direct mapping page?
> >     I think Yu should confirm if there is such a common kernel API.
> >     If there is such an API, we should use it so that we can remove the arch
> specific stuffs.
> >
> >> What's the use case, though?
> > [Lv Zheng]
> > Fortunately, currently ACPICA only uses this API to validate if a namespace
> node, an operand object or a parser object is readable.
> > See drivers/acpi/acpica/dbdisplay.c and drivers/acpi/acpica/dbcmds.c.
> >
> >>  That is, what goes wrong if the function just always returns false?
> > [Lv Zheng]
> > 1. If it always returns false, then many ACPICA debugger internal object
> conversion/dump functionalities won't be functioning.
> >     For example, you can try to type “dump \_SB" in acpidbg shell and it will
> return an error:
> >       "Invalid named object at address xxxxxxxxxxxxxxxx"
> > 2. While if this function always returns true (current linux-pm/linux-next
> merged stuffs), we can see such a result:
> >       Object (ffffxxxxxxxxxxxx) Pathname: \_SB
> >           Name : _SB_
> >           Type : 06 [Device]
> >
> 
> It seems a bit unfortunate to me that the ACPICA debugger lets userspace
> choose what address to dump rather than dumping by pathname, but given
> that constraint, I guess this function is needed.
> 
> Can you do something like checking virt_addr_valid and then using
> virt_to_pfn and page_is_ram?  If that's not enough (e.g. if it doesn't work for
> vmalloc addresses and you need those), you could try to do something like
> slow_virt_to_phys, but you'd need to do some extra checks to avoid the
> BUG in the function.
> 
[Yu] This is a  good method,  firstly virt_addr_valid can  exclude the vaddr of vmalloc/kmap , 
then slow_virt_to_phys can check if this vaddr has a valid pte physical address, 
but I guess we need another non-BUG_on version of slow_virt_to_phys,  
I'll try to test with your suggestion, thanks!
Yu


ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 131+ messages in thread

* [PATCH] ACPI / debugger: Fix a redundant mutex unlock issue in acpi_aml_open()
  2015-11-06  6:46   ` Lv Zheng
@ 2015-12-25  3:22     ` Lv Zheng
  -1 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-25  3:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Fix a double mutex_unlock() issue where acpi_initialize_debugger() is
called with the mutex already unlocked.

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpi_dbg.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index fa18bd0..9c31b08 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -514,7 +514,7 @@ static int acpi_aml_open(struct inode *inode, struct file *file)
 		if (ACPI_FAILURE(status)) {
 			pr_err("Failed to initialize debugger.\n");
 			ret = -EINVAL;
-			goto err_lock;
+			goto err_exit;
 		}
 		pr_debug("Debugger thread initialized.\n");
 
@@ -531,6 +531,7 @@ err_lock:
 			acpi_aml_active_reader = NULL;
 	}
 	mutex_unlock(&acpi_aml_io.lock);
+err_exit:
 	return ret;
 }
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 131+ messages in thread

* [PATCH] ACPI / debugger: Fix a redundant mutex unlock issue in acpi_aml_open()
@ 2015-12-25  3:22     ` Lv Zheng
  0 siblings, 0 replies; 131+ messages in thread
From: Lv Zheng @ 2015-12-25  3:22 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Fix a double mutex_unlock() issue where acpi_initialize_debugger() is
called with the mutex already unlocked.

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpi_dbg.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index fa18bd0..9c31b08 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -514,7 +514,7 @@ static int acpi_aml_open(struct inode *inode, struct file *file)
 		if (ACPI_FAILURE(status)) {
 			pr_err("Failed to initialize debugger.\n");
 			ret = -EINVAL;
-			goto err_lock;
+			goto err_exit;
 		}
 		pr_debug("Debugger thread initialized.\n");
 
@@ -531,6 +531,7 @@ err_lock:
 			acpi_aml_active_reader = NULL;
 	}
 	mutex_unlock(&acpi_aml_io.lock);
+err_exit:
 	return ret;
 }
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 131+ messages in thread

end of thread, other threads:[~2015-12-25  3:22 UTC | newest]

Thread overview: 131+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <8c1016ca8a570ba7c7a1c9f0f88d73cd83cea490>
2015-10-19  2:24 ` [PATCH v2 00/14] ACPICA: 20150930 Release Lv Zheng
2015-10-19  2:24   ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 01/14] ACPICA: Remove unnecessary conditional compilation Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 02/14] ACPICA: iASL: Add symbolic operator support for Index() operator Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 03/14] ACPICA: Update exception code for "file not found" error Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 04/14] ACPICA: Debugger: Update mutexes used for multithreaded debugger Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 05/14] ACPICA: Update NFIT table to rename a flags field Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:24   ` [PATCH v2 06/14] ACPICA: Improve typechecking, both compile-time and runtime Lv Zheng
2015-10-19  2:24     ` Lv Zheng
2015-10-19  2:25   ` [PATCH v2 07/14] ACPICA: iASL: General cleanup of the file suffix #defines Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19  2:25   ` [PATCH v2 08/14] ACPICA: Linuxize: Export debugger files to Linux Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19  2:25   ` [PATCH v2 09/14] ACPICA: Debugger: Fix "quit/exit" command by cleaning up user commands termination logic Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19 21:04     ` Rafael J. Wysocki
2015-10-20  2:03       ` Zheng, Lv
2015-10-20  2:03         ` Zheng, Lv
2015-10-20  7:14         ` Zheng, Lv
2015-10-20  7:14           ` Zheng, Lv
2015-10-19  2:25   ` [PATCH v2 10/14] ACPICA: Debugger: Fix "terminate" command by cleaning up subsystem shutdown logic Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19  2:25   ` [PATCH v2 11/14] ACPICA: Debugger: Add thread ID support so that single step mode can only apply to the debugger thread Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19  2:25   ` [PATCH v2 12/14] ACPI: Enable build of AML interpreter debugger Lv Zheng
2015-10-19  2:25     ` Lv Zheng
2015-10-19  2:26   ` [PATCH v2 13/14] ACPICA: Debugger: Fix dead lock issue ocurred in single stepping mode Lv Zheng
2015-10-19  2:26     ` Lv Zheng
2015-10-19  2:26   ` [PATCH v2 14/14] ACPICA: Update version to 20150930 Lv Zheng
2015-10-19  2:26     ` Lv Zheng
2015-11-06  6:46 ` [RFC PATCH v2 0/5] ACPICA / debugger: Add in-kernel AML debugger support Lv Zheng
2015-11-06  6:46   ` Lv Zheng
2015-11-06  6:46   ` [RFC PATCH v2 1/5] ACPICA: Debugger: Remove unnecessary status check Lv Zheng
2015-11-06  6:46     ` Lv Zheng
2015-11-06  6:47   ` [RFC PATCH v2 2/5] ACPICA: Debugger: Convert some mechanisms to OSPM specific Lv Zheng
2015-11-06  6:47     ` Lv Zheng
2015-11-06  6:47   ` [RFC PATCH v2 3/5] ACPI / debugger: Add IO interface to access debugger functionalities Lv Zheng
2015-11-06  6:47     ` Lv Zheng
2015-11-06  6:47   ` [RFC PATCH v2 4/5] tools/power/acpi: Add userspace AML interface support Lv Zheng
2015-11-06  6:47     ` Lv Zheng
2015-11-06  6:47   ` [RFC PATCH v2 5/5] ACPI / debugger: Add module support for ACPI debugger Lv Zheng
2015-11-06  6:47     ` Lv Zheng
2015-11-10  8:21   ` [PATCH v2 0/7] ACPICA / debugger: Add in-kernel AML debugger support Lv Zheng
2015-11-10  8:21     ` Lv Zheng
2015-11-10  8:21     ` [PATCH v2 1/7] ACPICA: Debugger: Remove unnecessary status check Lv Zheng
2015-11-10  8:21       ` Lv Zheng
2015-11-10  8:21     ` [PATCH v2 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific Lv Zheng
2015-11-10  8:21       ` Lv Zheng
2015-11-10  8:21     ` [PATCH v2 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism Lv Zheng
2015-11-10  8:21       ` Lv Zheng
2015-11-10  8:22     ` [PATCH v2 4/7] ACPI / debugger: Add IO interface to access debugger functionalities Lv Zheng
2015-11-10  8:22       ` Lv Zheng
2015-11-10  8:22     ` [PATCH v2 5/7] ACPI / x86: introduce acpi_os_readable() support Lv Zheng
2015-11-10  8:22       ` Lv Zheng
2015-11-10  9:42       ` Chen, Yu C
2015-11-10 10:46         ` Chen, Yu C
2015-11-10 13:04         ` Andy Shevchenko
2015-11-10 13:56           ` Chen, Yu C
2015-11-10 13:56             ` Chen, Yu C
2015-11-11  5:06         ` Zheng, Lv
2015-11-11  5:27           ` Chen, Yu C
2015-11-17  1:49           ` Zheng, Lv
2015-11-10  8:22     ` [PATCH v2 6/7] tools/power/acpi: Add userspace AML interface support Lv Zheng
2015-11-10  8:22       ` Lv Zheng
2015-11-10  8:22     ` [PATCH v2 7/7] ACPI / debugger: Add module support for ACPI debugger Lv Zheng
2015-11-10  8:22       ` Lv Zheng
2015-11-19  6:08   ` [PATCH v3 0/6] ACPICA / debugger: Add in-kernel AML debugger support Lv Zheng
2015-11-19  6:08     ` Lv Zheng
2015-11-19  6:08     ` [PATCH v3 1/6] ACPICA: Debugger: Remove unnecessary status check Lv Zheng
2015-11-19  6:08       ` Lv Zheng
2015-11-19  6:08     ` [PATCH v3 2/6] ACPICA: Debugger: Convert some mechanisms to OSPM specific Lv Zheng
2015-11-19  6:08       ` Lv Zheng
2015-11-19  6:08     ` [PATCH v3 3/6] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism Lv Zheng
2015-11-19  6:08       ` Lv Zheng
2015-11-19  6:08     ` [PATCH v3 4/6] ACPI / debugger: Add IO interface to access debugger functionalities Lv Zheng
2015-11-19  6:08       ` Lv Zheng
2015-11-19  6:08     ` [PATCH v3 5/6] tools/power/acpi: Add userspace AML interface support Lv Zheng
2015-11-19  6:08       ` Lv Zheng
2015-11-19  6:09     ` [PATCH v3 6/6] ACPI / debugger: Add module support for ACPI debugger Lv Zheng
2015-11-19  6:09       ` Lv Zheng
2015-11-19  6:09   ` [PATCH v3] ACPI / x86: introduce acpi_os_readable() support Lv Zheng
2015-11-19  6:09     ` Lv Zheng
2015-12-03  2:40   ` [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support Lv Zheng
2015-12-03  2:40     ` Lv Zheng
2015-12-03  2:42     ` [PATCH v4 1/7] ACPICA: Debugger: Remove unnecessary status check Lv Zheng
2015-12-03  2:42       ` Lv Zheng
2015-12-03  2:42     ` [PATCH v4 2/7] ACPICA: Debugger: Convert some mechanisms to OSPM specific Lv Zheng
2015-12-03  2:42       ` Lv Zheng
2015-12-03  2:42     ` [PATCH v4 3/7] ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism Lv Zheng
2015-12-03  2:42       ` Lv Zheng
2015-12-03  2:43     ` [PATCH v4 4/7] ACPI / debugger: Add IO interface to access debugger functionalities Lv Zheng
2015-12-03  2:43       ` Lv Zheng
2015-12-03 22:27       ` Andy Lutomirski
2015-12-03 23:34         ` Rafael J. Wysocki
2015-12-03  2:43     ` [PATCH v4 5/7] tools/power/acpi: Add userspace AML interface support Lv Zheng
2015-12-03  2:43       ` Lv Zheng
2015-12-03  2:43     ` [PATCH v4 6/7] ACPI / debugger: Add module support for ACPI debugger Lv Zheng
2015-12-03  2:43       ` Lv Zheng
2015-12-03  2:43     ` [PATCH v4 7/7] ACPI / x86: introduce acpi_os_readable() support Lv Zheng
2015-12-03  2:43       ` Lv Zheng
2015-12-14 23:28       ` Andy Lutomirski
2015-12-15  6:13         ` Chen, Yu C
2015-12-15  6:13           ` Chen, Yu C
2015-12-15  8:52           ` Zheng, Lv
2015-12-15  8:52             ` Zheng, Lv
2015-12-16  0:25           ` Zheng, Lv
2015-12-16  0:25             ` Zheng, Lv
2015-12-17 16:59             ` Andy Lutomirski
2015-12-22  1:03               ` Chen, Yu C
2015-12-22  1:03                 ` Chen, Yu C
2015-12-22 22:49                 ` Andy Lutomirski
2015-12-23  3:25                   ` Zheng, Lv
2015-12-23  3:25                     ` Zheng, Lv
2015-12-24  1:40                     ` Andy Lutomirski
2015-12-24  7:57                       ` Chen, Yu C
2015-12-24  7:57                         ` Chen, Yu C
2015-12-24  8:01                       ` Chen, Yu C
2015-12-24  8:01                         ` Chen, Yu C
2015-12-14 23:43       ` Rafael J. Wysocki
2015-12-14 23:44     ` [PATCH v4 0/7] ACPICA / debugger: Add in-kernel AML debugger support Rafael J. Wysocki
2015-12-15  2:55       ` Zheng, Lv
2015-12-15  2:55         ` Zheng, Lv
2015-12-24  6:16   ` [PATCH] ACPI / debugger: Fix an issue a flag is modified without locking Lv Zheng
2015-12-24  6:16     ` Lv Zheng
2015-12-25  3:22   ` [PATCH] ACPI / debugger: Fix a redundant mutex unlock issue in acpi_aml_open() Lv Zheng
2015-12-25  3:22     ` Lv Zheng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.