public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 1/5] driver: add TXT driver in kernel
  2013-04-27 14:56 ` [PATCH 1/5] driver: add TXT driver in kernel Qiaowei Ren
@ 2013-04-27 13:14   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 8+ messages in thread
From: Greg Kroah-Hartman @ 2013-04-27 13:14 UTC (permalink / raw)
  To: Qiaowei Ren
  Cc: Arnd Bergmann, Richard L Maliszewski, Shane Wang, Gang Wei,
	linux-kernel, Xiaoyan Zhang

On Sat, Apr 27, 2013 at 10:56:16PM +0800, Qiaowei Ren wrote:
> TXT driver is expected to be a better tool to access below resources:
> TXT config space, TXT heap, TXT log and SMX parameter.

You are adding new sysfs files, so that means you need to add
Documentation/ABI files as well.  Please respin this series with those
added so we have a hint as to how this driver is interacting with
userspace.

> Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
> Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
> Signed-off-by: Gang Wei <gang.wei@intel.com>
> ---
>  drivers/char/Kconfig         |    2 ++
>  drivers/char/Makefile        |    1 +
>  drivers/char/txt/Kconfig     |   18 ++++++++++++++++++
>  drivers/char/txt/Makefile    |    5 +++++
>  drivers/char/txt/txt-sysfs.c |   41 +++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 67 insertions(+)
>  create mode 100644 drivers/char/txt/Kconfig
>  create mode 100644 drivers/char/txt/Makefile
>  create mode 100644 drivers/char/txt/txt-sysfs.c
> 
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 3bb6fa3..9309e89 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -565,6 +565,8 @@ config UV_MMTIMER
>  
>  source "drivers/char/tpm/Kconfig"
>  
> +source "drivers/char/txt/Kconfig"
> +
>  config TELCLOCK
>  	tristate "Telecom clock driver for ATCA SBC"
>  	depends on X86
> diff --git a/drivers/char/Makefile b/drivers/char/Makefile
> index 7ff1d0d..301d5b4 100644
> --- a/drivers/char/Makefile
> +++ b/drivers/char/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_PCMCIA)		+= pcmcia/
>  
>  obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
>  obj-$(CONFIG_TCG_TPM)		+= tpm/
> +obj-$(CONFIG_TXT)		+= txt/
>  
>  obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
>  
> diff --git a/drivers/char/txt/Kconfig b/drivers/char/txt/Kconfig
> new file mode 100644
> index 0000000..2e57ef6
> --- /dev/null
> +++ b/drivers/char/txt/Kconfig
> @@ -0,0 +1,18 @@
> +#
> +# intel TXT driver configuration
> +#
> +
> +config INTEL_TXT_DRIVER
> +       tristate "INTEL TXT sysfs driver"

Why isn't this a drivers/platform/x86/ driver?

> +       default m
> +       depends on INTEL_TXT
> +       select SECURITYFS

Or even better yet, a drivers/security/ driver?

> +       ---help---
> +         TXT Driver is expected to be a better tool to access below resources:
> +           - TXT config space
> +           - TXT heap
> +           - Tboot log mem
> +           - SMX parameter
> +
> +         To compile this driver as a module, choose M here; the module will be
> +         called txt.
> diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
> new file mode 100644
> index 0000000..3148bb8
> --- /dev/null
> +++ b/drivers/char/txt/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the intel TXT drivers.
> +#
> +obj-$(CONFIG_TXT) += txt.o
> +txt-y := txt-sysfs.o
> diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
> new file mode 100644
> index 0000000..c56bfe3
> --- /dev/null
> +++ b/drivers/char/txt/txt-sysfs.c
> @@ -0,0 +1,41 @@
> +/*
> + * txt-sysfs.c
> + *
> + * This module is expected to be a better tool to access below resources
> + *   - TXT config space
> + *   - TXT heap
> + *   - Tboot log mem
> + *   - SMX parameter
> + *
> + * Data is currently found below
> + *   /sys/devices/platform/txt/...
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/sysfs.h>
> +
> +#define DEV_NAME "txt"

That's a _very_ generic name.

> +struct platform_device *pdev;

That's a _very_ generic global variable you just created.  Don't.

> +static int __init txt_sysfs_init(void)
> +{
> +	pdev = platform_device_register_simple(DEV_NAME, -1, NULL, 0);
> +	if (IS_ERR(pdev))
> +		return PTR_ERR(pdev);
> +
> +	pr_info("Loading TXT module successfully\n");

We don't care that your driver was loaded, don't be noisy.

> +	return 0;
> +}
> +
> +static void __exit txt_sysfs_exit(void)
> +{
> +	platform_device_unregister(pdev);
> +	pr_info("Unloading TXT module successfully\n");

Same thing here.

Also, isn't there a module_platform_driver() macro you can use intead?

thanks,

greg k-h

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

* Re: [PATCH 3/5] driver: provide sysfs interfaces to access TXT log
  2013-04-27 14:56 ` [PATCH 3/5] driver: provide sysfs interfaces to access TXT log Qiaowei Ren
@ 2013-04-27 13:17   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 8+ messages in thread
From: Greg Kroah-Hartman @ 2013-04-27 13:17 UTC (permalink / raw)
  To: Qiaowei Ren
  Cc: Arnd Bergmann, Richard L Maliszewski, Shane Wang, Gang Wei,
	linux-kernel, Xiaoyan Zhang

On Sat, Apr 27, 2013 at 10:56:18PM +0800, Qiaowei Ren wrote:
> +ssize_t sysfs_create_log(struct kobject *parent)
> +{
> +	struct kobject *log_kobj;
> +	int retval;
> +
> +	log_kobj = kobject_create_and_add("log", parent);
> +	if (!log_kobj)
> +		return -ENOMEM;
> +
> +	retval = sysfs_create_group(log_kobj, &log_attr_grp);
> +	if (retval)
> +		kobject_put(log_kobj);
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(sysfs_create_log);

Seriously?  That's what you are calling this function?

{sigh}

Please, go get this patch series reviewed by other, experienced, Intel
developers, before you send it out again.  There's loads of things wrong
with this series, and they can help you out much easier, and nicer, than
I'm going to be here.

Oh, and NEVER use "raw" kobjects, by doing that, you know you are doing
something wrong in a driver.

greg k-h

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

* [PATCH 0/5] TXT driver
@ 2013-04-27 14:56 Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 1/5] driver: add TXT driver in kernel Qiaowei Ren
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren

This module is expected to be a better tool to access below resources
  - TXT config space
  - TXT heap
  - Tboot log mem
  - SMX parameter

Intel TXT (Trusted Execution Technology) will provide higher assurance
of system configuration and initial state as well as data reset
protection. It also helps solve real end user concerns about having
confidence that their hardware is running the VMM or kernel that
it was configured with, especially since they may be responsible for
providing such assurances to VMs and services running on it.

See <http://www.intel.com/technology/security/> for more information
about Intel(R) TXT.

Intel TXT configuration registers are a subset of chipset registers.
These chipset registers that interact with SMX are accessed from two
regions of memory, which represent the public and private configuration
spaces, by system software using memory read/write protocols.

Intel TXT Heap memory is a region of physically contiguous memory
which is set aside by BIOS for the use of Intel TXT hardware and
software.

With this module, it will be easier to access TXT/tboot related
information/logs.

Qiaowei Ren (5):
  driver: add TXT driver in kernel
  driver: provide sysfs interfaces to access TXT config space
  driver: provide sysfs interfaces to access TXT log
  driver: provide sysfs interfaces to access SMX parameter
  driver: provide sysfs interfaces to access TXT heap

 drivers/char/Kconfig             |    2 +
 drivers/char/Makefile            |    1 +
 drivers/char/txt/Kconfig         |   18 +
 drivers/char/txt/Makefile        |    5 +
 drivers/char/txt/txt-config.c    | 1041 ++++++++++++++++++++++++
 drivers/char/txt/txt-config.h    |  138 ++++
 drivers/char/txt/txt-heap.c      | 1616 ++++++++++++++++++++++++++++++++++++++
 drivers/char/txt/txt-heap.h      |  338 ++++++++
 drivers/char/txt/txt-log.c       |  140 ++++
 drivers/char/txt/txt-log.h       |   27 +
 drivers/char/txt/txt-parameter.c |  261 ++++++
 drivers/char/txt/txt-parameter.h |   40 +
 drivers/char/txt/txt-sysfs.c     |   68 ++
 13 files changed, 3695 insertions(+)
 create mode 100644 drivers/char/txt/Kconfig
 create mode 100644 drivers/char/txt/Makefile
 create mode 100644 drivers/char/txt/txt-config.c
 create mode 100644 drivers/char/txt/txt-config.h
 create mode 100644 drivers/char/txt/txt-heap.c
 create mode 100644 drivers/char/txt/txt-heap.h
 create mode 100644 drivers/char/txt/txt-log.c
 create mode 100644 drivers/char/txt/txt-log.h
 create mode 100644 drivers/char/txt/txt-parameter.c
 create mode 100644 drivers/char/txt/txt-parameter.h
 create mode 100644 drivers/char/txt/txt-sysfs.c

-- 
1.7.9.5


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

* [PATCH 1/5] driver: add TXT driver in kernel
  2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
@ 2013-04-27 14:56 ` Qiaowei Ren
  2013-04-27 13:14   ` Greg Kroah-Hartman
  2013-04-27 14:56 ` [PATCH 2/5] driver: provide sysfs interfaces to access TXT config space Qiaowei Ren
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren, Xiaoyan Zhang

TXT driver is expected to be a better tool to access below resources:
TXT config space, TXT heap, TXT log and SMX parameter.

Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
 drivers/char/Kconfig         |    2 ++
 drivers/char/Makefile        |    1 +
 drivers/char/txt/Kconfig     |   18 ++++++++++++++++++
 drivers/char/txt/Makefile    |    5 +++++
 drivers/char/txt/txt-sysfs.c |   41 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 67 insertions(+)
 create mode 100644 drivers/char/txt/Kconfig
 create mode 100644 drivers/char/txt/Makefile
 create mode 100644 drivers/char/txt/txt-sysfs.c

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 3bb6fa3..9309e89 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -565,6 +565,8 @@ config UV_MMTIMER
 
 source "drivers/char/tpm/Kconfig"
 
+source "drivers/char/txt/Kconfig"
+
 config TELCLOCK
 	tristate "Telecom clock driver for ATCA SBC"
 	depends on X86
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7ff1d0d..301d5b4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_PCMCIA)		+= pcmcia/
 
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)		+= tpm/
+obj-$(CONFIG_TXT)		+= txt/
 
 obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
 
diff --git a/drivers/char/txt/Kconfig b/drivers/char/txt/Kconfig
new file mode 100644
index 0000000..2e57ef6
--- /dev/null
+++ b/drivers/char/txt/Kconfig
@@ -0,0 +1,18 @@
+#
+# intel TXT driver configuration
+#
+
+config INTEL_TXT_DRIVER
+       tristate "INTEL TXT sysfs driver"
+       default m
+       depends on INTEL_TXT
+       select SECURITYFS
+       ---help---
+         TXT Driver is expected to be a better tool to access below resources:
+           - TXT config space
+           - TXT heap
+           - Tboot log mem
+           - SMX parameter
+
+         To compile this driver as a module, choose M here; the module will be
+         called txt.
diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
new file mode 100644
index 0000000..3148bb8
--- /dev/null
+++ b/drivers/char/txt/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the intel TXT drivers.
+#
+obj-$(CONFIG_TXT) += txt.o
+txt-y := txt-sysfs.o
diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
new file mode 100644
index 0000000..c56bfe3
--- /dev/null
+++ b/drivers/char/txt/txt-sysfs.c
@@ -0,0 +1,41 @@
+/*
+ * txt-sysfs.c
+ *
+ * This module is expected to be a better tool to access below resources
+ *   - TXT config space
+ *   - TXT heap
+ *   - Tboot log mem
+ *   - SMX parameter
+ *
+ * Data is currently found below
+ *   /sys/devices/platform/txt/...
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#define DEV_NAME "txt"
+struct platform_device *pdev;
+
+static int __init txt_sysfs_init(void)
+{
+	pdev = platform_device_register_simple(DEV_NAME, -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	pr_info("Loading TXT module successfully\n");
+	return 0;
+}
+
+static void __exit txt_sysfs_exit(void)
+{
+	platform_device_unregister(pdev);
+	pr_info("Unloading TXT module successfully\n");
+}
+
+module_init(txt_sysfs_init);
+module_exit(txt_sysfs_exit);
+
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH 2/5] driver: provide sysfs interfaces to access TXT config space
  2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 1/5] driver: add TXT driver in kernel Qiaowei Ren
@ 2013-04-27 14:56 ` Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 3/5] driver: provide sysfs interfaces to access TXT log Qiaowei Ren
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren, Xiaoyan Zhang

These interfaces are located in /sys/devices/platform/txt/config,
and including totally 37 files, providing access to Intel TXT
configuration registers.

Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
 drivers/char/txt/Makefile     |    2 +-
 drivers/char/txt/txt-config.c | 1041 +++++++++++++++++++++++++++++++++++++++++
 drivers/char/txt/txt-config.h |  138 ++++++
 drivers/char/txt/txt-sysfs.c  |   12 +
 4 files changed, 1192 insertions(+), 1 deletion(-)
 create mode 100644 drivers/char/txt/txt-config.c
 create mode 100644 drivers/char/txt/txt-config.h

diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
index 3148bb8..3db5a6f 100644
--- a/drivers/char/txt/Makefile
+++ b/drivers/char/txt/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the intel TXT drivers.
 #
 obj-$(CONFIG_TXT) += txt.o
-txt-y := txt-sysfs.o
+txt-y := txt-sysfs.o txt-config.o
diff --git a/drivers/char/txt/txt-config.c b/drivers/char/txt/txt-config.c
new file mode 100644
index 0000000..75c7fac
--- /dev/null
+++ b/drivers/char/txt/txt-config.c
@@ -0,0 +1,1041 @@
+/*
+ * txt-config.c
+ *
+ * Totally 37 sysfs files with owner root, each related with a register.
+ *
+ * Intel TXT configuration registers are a subset of chipset registers.
+ * These registers are mapped into two regions of memory, representing
+ * the public and private configuration spaces.
+ *
+ * STS_raw		-r--r--r--	ERRORCODE		-rw-rw-r--
+ * STS_senter_done	-r--r--r--	STS_sexit_done		-r--r--r--
+ * STS_mem_config_lock	-r--r--r--	STS_private_open	-r--r--r--
+ * STS_locality_1_open	-r--r--r--	STS_locality_2_open	-r--r--r--
+ * ESTS_raw		-r--r--r--	ESTS_txt_reset		-r--r--r--
+ * E2STS_raw		-r--r--r--	E2STS_secrets		-rw-rw-r--
+ * VER_FSBIF		-r--r--r--	VER_QPIIF		-r--r--r--
+ * DIDVID_raw		-r--r--r--	DIDVID_vendor_id	-r--r--r--
+ * DIDVID_device_id	-r--r--r--	DIDVID_revision_id	-r--r--r--
+ * SINIT_BASE		-rw-rw-r--	SINIT_SIZE		-rw-rw-r--
+ * HEAP_BASE		-rw-rw-r--	HEAP_SIZE		-rw-rw-r--
+ * PUBLIC_KEY		-r--r--r--	MLE_JOIN		-rw-rw-r--
+ * DPR_raw		-rw-rw-r--	DPR_lock		-rw-rw-r--
+ * DPR_top		-rw-rw-r--	DPR_size		-rw-rw-r--
+ * CMD_RESET		--w--w----	CMD_CLOSE_PRIVATE	--w--w----
+ * CMD_SECRETS		--w--w----	CMD_NO_SECRETS		--w--w----
+ * CMD_OPEN_LOCALITY1	--w--w----	CMD_OPEN_LOCALITY2	--w--w----
+ * CMD_CLOSE_LOCALITY1	--w--w----	CMD_CLOSE_LOCALITY2	--w--w----
+ * CMD_UNLOCK_MEM_CONFIG	--w--w----
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/io.h>
+#include <linux/stat.h>
+
+#include "txt-config.h"
+
+static ssize_t print_hex(char *buf, void *start, size_t len)
+{
+	char *str = buf;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		str += scnprintf(str, PAGE_SIZE, "%02x ", *(uint8_t *)start);
+		start++;
+		if ((i + 1) % 16 == 0)
+			str += scnprintf(str, PAGE_SIZE, "\n");
+	}
+
+	return str - buf;
+}
+
+static ssize_t show_config(char *buf, u32 offset)
+{
+	void __iomem *config;
+	int retval;
+
+	config = ioremap_nocache(TXT_PUB_CONFIG_REGS_BASE,
+				 TXT_CONFIG_REGS_SIZE);
+	if (config == NULL)
+		return -ENOMEM;
+
+	switch (offset) {
+	case off_STS_raw:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08llx\n", sts._raw);
+		break;
+	}
+
+	case off_STS_senter_done:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n", sts.senter_done_sts);
+		break;
+	}
+
+	case off_STS_sexit_done:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n", sts.sexit_done_sts);
+		break;
+	}
+
+	case off_STS_mem_config_lock:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       sts.mem_config_lock_sts);
+		break;
+	}
+
+	case off_STS_private_open:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       sts.private_open_sts);
+		break;
+	}
+
+	case off_STS_locality_1_open:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       sts.locality_1_open_sts);
+		break;
+	}
+
+	case off_STS_locality_2_open:
+	{
+		txt_sts_t sts;
+
+		sts._raw = read_txt_config_reg(config, TXTCR_STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       sts.locality_2_open_sts);
+		break;
+	}
+
+	case off_ERRORCODE:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08llx\n",
+			       read_txt_config_reg(config, TXTCR_ERRORCODE));
+		break;
+
+	case off_ESTS_raw:
+	{
+		txt_ests_t ests;
+
+		ests._raw = read_txt_config_reg(config, TXTCR_ESTS);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%02llx\n", ests._raw);
+		break;
+	}
+
+	case off_ESTS_txt_reset:
+	{
+		txt_ests_t ests;
+
+		ests._raw = read_txt_config_reg(config, TXTCR_ESTS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n", ests.txt_reset_sts);
+		break;
+	}
+
+	case off_E2STS_raw:
+	{
+		txt_e2sts_t e2sts;
+
+		e2sts._raw = read_txt_config_reg(config, TXTCR_E2STS);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%016llx\n", e2sts._raw);
+		break;
+	}
+
+	case off_E2STS_secrets:
+	{
+		txt_e2sts_t e2sts;
+
+		e2sts._raw = read_txt_config_reg(config, TXTCR_E2STS);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n", e2sts.secrets_sts);
+		break;
+	}
+
+	case off_VER_FSBIF:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%016llx\n",
+			       read_txt_config_reg(config, TXTCR_VER_FSBIF));
+		break;
+
+	case off_VER_QPIIF:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%016llx\n",
+			       read_txt_config_reg(config, TXTCR_VER_QPIIF));
+		break;
+
+	case off_DIDVID_raw:
+	{
+		txt_didvid_t didvid;
+
+		didvid._raw = read_txt_config_reg(config, TXTCR_DIDVID);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%016llx\n", didvid._raw);
+		break;
+	}
+
+	case off_DIDVID_vendor_id:
+	{
+		txt_didvid_t didvid;
+
+		didvid._raw = read_txt_config_reg(config, TXTCR_DIDVID);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%x\n", didvid.vendor_id);
+		break;
+	}
+
+	case off_DIDVID_device_id:
+	{
+		txt_didvid_t didvid;
+
+		didvid._raw = read_txt_config_reg(config, TXTCR_DIDVID);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%x\n", didvid.device_id);
+		break;
+	}
+
+	case off_DIDVID_revision_id:
+	{
+		txt_didvid_t didvid;
+
+		didvid._raw = read_txt_config_reg(config, TXTCR_DIDVID);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%x\n",
+				didvid.revision_id);
+		break;
+	}
+
+	case off_SINIT_BASE:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08llx\n",
+			       read_txt_config_reg(config, TXTCR_SINIT_BASE));
+		break;
+
+	case off_SINIT_SIZE:
+		retval = scnprintf(buf, PAGE_SIZE, "%lluB (0x%llx)\n",
+			       read_txt_config_reg(config, TXTCR_SINIT_SIZE),
+			       read_txt_config_reg(config, TXTCR_SINIT_SIZE));
+		break;
+
+	case off_HEAP_BASE:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08llx\n",
+			       read_txt_config_reg(config, TXTCR_HEAP_BASE));
+		break;
+
+	case off_HEAP_SIZE:
+		retval = scnprintf(buf, PAGE_SIZE, "%lluB (0x%llx)\n",
+			       read_txt_config_reg(config, TXTCR_HEAP_SIZE),
+			       read_txt_config_reg(config, TXTCR_HEAP_SIZE));
+		break;
+
+	case off_PUBLIC_KEY:
+	{
+		uint8_t key[256/8];
+		unsigned int i = 0;
+
+		do {
+			*(uint64_t *)&key[i] = read_txt_config_reg(config,
+						TXTCR_PUBLIC_KEY + i);
+			i += sizeof(uint64_t);
+		} while (i < sizeof(key));
+
+		retval = print_hex(buf, key, sizeof(key));
+		break;
+	}
+
+	case off_MLE_JOIN:
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08llx\n",
+			       read_txt_config_reg(config, TXTCR_MLE_JOIN));
+		break;
+
+	case off_DPR_raw:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%016llx\n", dpr._raw);
+		break;
+	}
+
+	case off_DPR_lock:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		retval = scnprintf(buf, PAGE_SIZE, "%d\n", dpr.lock);
+		break;
+	}
+
+	case off_DPR_top:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		retval = scnprintf(buf, PAGE_SIZE, "0x%08x\n", dpr.top << 20);
+		break;
+	}
+
+	case off_DPR_size:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		retval = scnprintf(buf, PAGE_SIZE, "%uMB (%uB)\n",
+			       dpr.size, dpr.size*1024*1024);
+		break;
+	}
+
+	default:
+		retval = -EINVAL;
+	}
+
+	iounmap(config);
+	return retval;
+}
+
+static ssize_t store_pub_config(const char *buf, u32 offset)
+{
+	void __iomem *config;
+	long value;
+
+	config = ioremap_nocache(TXT_PUB_CONFIG_REGS_BASE,
+				 TXT_CONFIG_REGS_SIZE);
+	if (config == NULL)
+		return -ENOMEM;
+
+	if (kstrtol(buf, 0, &value))
+		return -EINVAL;
+
+	switch (offset) {
+	case off_SINIT_BASE:
+		write_txt_config_reg(config, TXTCR_SINIT_BASE, value);
+		break;
+
+	case off_SINIT_SIZE:
+		write_txt_config_reg(config, TXTCR_SINIT_SIZE, value);
+		break;
+
+	case off_HEAP_BASE:
+		write_txt_config_reg(config, TXTCR_HEAP_BASE, value);
+		break;
+
+	case off_HEAP_SIZE:
+		write_txt_config_reg(config, TXTCR_HEAP_SIZE, value);
+		break;
+
+	case off_MLE_JOIN:
+		write_txt_config_reg(config, TXTCR_MLE_JOIN, value);
+		break;
+
+	case off_DPR_raw:
+		write_txt_config_reg(config, TXTCR_DPR, value);
+		break;
+
+	case off_DPR_lock:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		dpr.lock = value;
+
+		write_txt_config_reg(config, TXTCR_DPR, dpr._raw);
+		break;
+	}
+
+	case off_DPR_top:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		dpr.top = value;
+
+		write_txt_config_reg(config, TXTCR_DPR, dpr._raw);
+		break;
+	}
+
+	case off_DPR_size:
+	{
+		txt_dpr_t dpr;
+
+		dpr._raw = read_txt_config_reg(config, TXTCR_DPR);
+		dpr.size = value;
+
+		write_txt_config_reg(config, TXTCR_DPR, dpr._raw);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	iounmap(config);
+	return 0;
+}
+
+static ssize_t store_priv_config(const char *buf, u32 offset)
+{
+	void __iomem *config;
+	long value;
+	int retval = 0;
+
+	config = ioremap_nocache(TXT_PRIV_CONFIG_REGS_BASE,
+				 TXT_CONFIG_REGS_SIZE);
+	if (config == NULL)
+		return -ENOMEM;
+
+	if (kstrtol(buf, 0, &value))
+		return -EINVAL;
+
+	if (offset != off_ERRORCODE && offset != off_E2STS_secrets) {
+		if (value != 0 && value != 1) {
+			retval = -EINVAL;
+			goto out;
+		}
+	}
+
+	switch (offset) {
+	case off_ERRORCODE:
+		write_txt_config_reg(config, TXTCR_ERRORCODE, value);
+		break;
+
+	case off_E2STS_secrets:
+		write_txt_config_reg(config, TXTCR_E2STS, value);
+		break;
+
+	case off_CMD_RESET:
+		write_txt_config_reg(config, TXTCR_CMD_RESET, value);
+		break;
+
+	case off_CMD_CLOSE_PRIVATE:
+		write_txt_config_reg(config, TXTCR_CMD_CLOSE_PRIVATE, value);
+		break;
+
+	case off_CMD_SECRETS:
+		write_txt_config_reg(config, TXTCR_CMD_SECRETS, value);
+		break;
+
+	case off_CMD_NO_SECRETS:
+		write_txt_config_reg(config, TXTCR_CMD_NO_SECRETS, value);
+		break;
+
+	case off_CMD_OPEN_LOCALITY1:
+		write_txt_config_reg(config, TXTCR_CMD_OPEN_LOCALITY1, value);
+		break;
+
+	case off_CMD_OPEN_LOCALITY2:
+		write_txt_config_reg(config, TXTCR_CMD_OPEN_LOCALITY2, value);
+		break;
+
+	case off_CMD_CLOSE_LOCALITY1:
+		write_txt_config_reg(config, TXTCR_CMD_CLOSE_LOCALITY1,
+				     value);
+		break;
+
+	case off_CMD_CLOSE_LOCALITY2:
+		write_txt_config_reg(config, TXTCR_CMD_CLOSE_LOCALITY2,
+				     value);
+		break;
+
+	case off_CMD_UNLOCK_MEM_CONFIG:
+		write_txt_config_reg(config, TXTCR_CMD_UNLOCK_MEM_CONFIG,
+				     value);
+		break;
+
+	default:
+		retval = -EINVAL;
+	}
+
+out:
+	iounmap(config);
+	return retval;
+}
+
+static ssize_t txt_show_STS_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_config(buf, off_STS_raw);
+}
+static DEVICE_ATTR(STS_raw, S_IRUGO, txt_show_STS_raw, NULL);
+
+static ssize_t txt_show_STS_senter_done(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return show_config(buf, off_STS_senter_done);
+}
+static DEVICE_ATTR(STS_senter_done, S_IRUGO, txt_show_STS_senter_done, NULL);
+
+static ssize_t txt_show_STS_sexit_done(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	return show_config(buf, off_STS_sexit_done);
+}
+static DEVICE_ATTR(STS_sexit_done, S_IRUGO, txt_show_STS_sexit_done, NULL);
+
+static ssize_t txt_show_STS_mem_config_lock(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return show_config(buf, off_STS_mem_config_lock);
+}
+static DEVICE_ATTR(STS_mem_config_lock, S_IRUGO,
+		   txt_show_STS_mem_config_lock, NULL);
+
+static ssize_t txt_show_STS_private_open(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return show_config(buf, off_STS_private_open);
+}
+static DEVICE_ATTR(STS_private_open, S_IRUGO,
+		   txt_show_STS_private_open, NULL);
+
+static ssize_t txt_show_STS_locality_1_open(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return show_config(buf, off_STS_locality_1_open);
+}
+static DEVICE_ATTR(STS_locality_1_open, S_IRUGO,
+		   txt_show_STS_locality_1_open, NULL);
+
+static ssize_t txt_show_STS_locality_2_open(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return show_config(buf, off_STS_locality_2_open);
+}
+static DEVICE_ATTR(STS_locality_2_open, S_IRUGO,
+		   txt_show_STS_locality_2_open, NULL);
+
+static ssize_t txt_show_ERRORCODE(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	return show_config(buf, off_ERRORCODE);
+}
+
+static ssize_t txt_store_ERRORCODE(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_ERRORCODE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(ERRORCODE, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_ERRORCODE, txt_store_ERRORCODE);
+
+static ssize_t txt_show_ESTS_raw(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return show_config(buf, off_ESTS_raw);
+}
+static DEVICE_ATTR(ESTS_raw, S_IRUGO, txt_show_ESTS_raw, NULL);
+
+static ssize_t txt_show_ESTS_txt_reset(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	return show_config(buf, off_ESTS_txt_reset);
+}
+static DEVICE_ATTR(ESTS_txt_reset, S_IRUGO, txt_show_ESTS_txt_reset, NULL);
+
+static ssize_t txt_show_E2STS_raw(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	return show_config(buf, off_E2STS_raw);
+}
+static DEVICE_ATTR(E2STS_raw, S_IRUGO, txt_show_E2STS_raw, NULL);
+
+static ssize_t txt_show_E2STS_secrets(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_config(buf, off_E2STS_secrets);
+}
+
+static ssize_t txt_store_E2STS_secrets(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_E2STS_secrets);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(E2STS_secrets, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_E2STS_secrets, txt_store_E2STS_secrets);
+
+static ssize_t txt_show_VER_FSBIF(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	return show_config(buf, off_VER_FSBIF);
+}
+static DEVICE_ATTR(VER_FSBIF, S_IRUGO, txt_show_VER_FSBIF, NULL);
+
+static ssize_t txt_show_VER_QPIIF(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_config(buf, off_VER_QPIIF);
+}
+static DEVICE_ATTR(VER_QPIIF, S_IRUGO, txt_show_VER_QPIIF, NULL);
+
+static ssize_t txt_show_DIDVID_raw(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return show_config(buf, off_DIDVID_raw);
+}
+static DEVICE_ATTR(DIDVID_raw, S_IRUGO, txt_show_DIDVID_raw, NULL);
+
+static ssize_t txt_show_DIDVID_vendor_id(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return show_config(buf, off_DIDVID_vendor_id);
+}
+static DEVICE_ATTR(DIDVID_vendor_id, S_IRUGO,
+		   txt_show_DIDVID_vendor_id, NULL);
+
+static ssize_t txt_show_DIDVID_device_id(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return show_config(buf, off_DIDVID_device_id);
+}
+static DEVICE_ATTR(DIDVID_device_id, S_IRUGO,
+		   txt_show_DIDVID_device_id, NULL);
+
+static ssize_t txt_show_DIDVID_revision_id(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	return show_config(buf, off_DIDVID_revision_id);
+}
+static DEVICE_ATTR(DIDVID_revision_id, S_IRUGO,
+		   txt_show_DIDVID_revision_id, NULL);
+
+static ssize_t txt_show_SINIT_BASE(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_config(buf, off_SINIT_BASE);
+}
+
+static ssize_t txt_store_SINIT_BASE(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_SINIT_BASE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(SINIT_BASE, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_SINIT_BASE, txt_store_SINIT_BASE);
+
+static ssize_t txt_show_SINIT_SIZE(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_config(buf, off_SINIT_SIZE);
+}
+
+static ssize_t txt_store_SINIT_SIZE(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_SINIT_SIZE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(SINIT_SIZE, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_SINIT_SIZE, txt_store_SINIT_SIZE);
+
+static ssize_t txt_show_HEAP_BASE(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_config(buf, off_HEAP_BASE);
+}
+
+static ssize_t txt_store_HEAP_BASE(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_HEAP_BASE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(HEAP_BASE, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_HEAP_BASE, txt_store_HEAP_BASE);
+
+static ssize_t txt_show_HEAP_SIZE(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_config(buf, off_HEAP_SIZE);
+}
+
+static ssize_t txt_store_HEAP_SIZE(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_HEAP_SIZE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(HEAP_SIZE, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_HEAP_SIZE, txt_store_HEAP_SIZE);
+
+static ssize_t txt_show_PUBLIC_KEY(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_config(buf, off_PUBLIC_KEY);
+}
+static DEVICE_ATTR(PUBLIC_KEY, S_IRUGO, txt_show_PUBLIC_KEY, NULL);
+
+static ssize_t txt_show_MLE_JOIN(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_config(buf, off_MLE_JOIN);
+}
+
+static ssize_t txt_store_MLE_JOIN(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_MLE_JOIN);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(MLE_JOIN, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_MLE_JOIN, txt_store_MLE_JOIN);
+
+static ssize_t txt_show_DPR_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_config(buf, off_DPR_raw);
+}
+
+static ssize_t txt_store_DPR_raw(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_DPR_raw);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(DPR_raw, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_DPR_raw, txt_store_DPR_raw);
+
+static ssize_t txt_show_DPR_lock(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_config(buf, off_DPR_lock);
+}
+
+static ssize_t txt_store_DPR_lock(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_DPR_lock);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(DPR_lock, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_DPR_lock, txt_store_DPR_lock);
+
+static ssize_t txt_show_DPR_top(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_config(buf, off_DPR_top);
+}
+
+static ssize_t txt_store_DPR_top(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_DPR_top);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(DPR_top, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_DPR_top, txt_store_DPR_top);
+
+static ssize_t txt_show_DPR_size(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_config(buf, off_DPR_size);
+}
+
+static ssize_t txt_store_DPR_size(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_pub_config(buf, off_DPR_size);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(DPR_size, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_DPR_size, txt_store_DPR_size);
+
+static ssize_t txt_store_CMD_RESET(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_RESET);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_RESET, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_RESET);
+
+static ssize_t txt_store_CMD_CLOSE_PRIVATE(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_CLOSE_PRIVATE);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_CLOSE_PRIVATE, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_CLOSE_PRIVATE);
+
+static ssize_t txt_store_CMD_SECRETS(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_SECRETS);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_SECRETS, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_SECRETS);
+
+static ssize_t txt_store_CMD_NO_SECRETS(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_NO_SECRETS);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_NO_SECRETS, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_NO_SECRETS);
+
+static ssize_t txt_store_CMD_OPEN_LOCALITY1(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_OPEN_LOCALITY1);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_OPEN_LOCALITY1, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_OPEN_LOCALITY1);
+
+static ssize_t txt_store_CMD_OPEN_LOCALITY2(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_OPEN_LOCALITY2);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_OPEN_LOCALITY2, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_OPEN_LOCALITY2);
+
+static ssize_t txt_store_CMD_CLOSE_LOCALITY1(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_CLOSE_LOCALITY1);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_CLOSE_LOCALITY1, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_CLOSE_LOCALITY1);
+
+static ssize_t txt_store_CMD_CLOSE_LOCALITY2(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_CLOSE_LOCALITY2);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_CLOSE_LOCALITY2, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_CLOSE_LOCALITY2);
+
+static ssize_t txt_store_CMD_UNLOCK_MEM_CONFIG(struct device *dev,
+					       struct device_attribute *attr,
+					       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = store_priv_config(buf, off_CMD_UNLOCK_MEM_CONFIG);
+	if (!ret)
+		return count;
+
+	return ret;
+}
+static DEVICE_ATTR(CMD_UNLOCK_MEM_CONFIG, S_IWUSR | S_IWGRP,
+		   NULL, txt_store_CMD_UNLOCK_MEM_CONFIG);
+
+static struct attribute *config_attrs[] = {
+	&dev_attr_STS_raw.attr,
+	&dev_attr_STS_senter_done.attr,
+	&dev_attr_STS_sexit_done.attr,
+	&dev_attr_STS_mem_config_lock.attr,
+	&dev_attr_STS_private_open.attr,
+	&dev_attr_STS_locality_1_open.attr,
+	&dev_attr_STS_locality_2_open.attr,
+	&dev_attr_ERRORCODE.attr,
+	&dev_attr_ESTS_raw.attr,
+	&dev_attr_ESTS_txt_reset.attr,
+	&dev_attr_E2STS_raw.attr,
+	&dev_attr_E2STS_secrets.attr,
+	&dev_attr_VER_FSBIF.attr,
+	&dev_attr_VER_QPIIF.attr,
+	&dev_attr_DIDVID_raw.attr,
+	&dev_attr_DIDVID_vendor_id.attr,
+	&dev_attr_DIDVID_device_id.attr,
+	&dev_attr_DIDVID_revision_id.attr,
+	&dev_attr_SINIT_BASE.attr,
+	&dev_attr_SINIT_SIZE.attr,
+	&dev_attr_HEAP_BASE.attr,
+	&dev_attr_HEAP_SIZE.attr,
+	&dev_attr_PUBLIC_KEY.attr,
+	&dev_attr_MLE_JOIN.attr,
+	&dev_attr_DPR_raw.attr,
+	&dev_attr_DPR_lock.attr,
+	&dev_attr_DPR_top.attr,
+	&dev_attr_DPR_size.attr,
+	&dev_attr_CMD_RESET.attr,
+	&dev_attr_CMD_CLOSE_PRIVATE.attr,
+	&dev_attr_CMD_SECRETS.attr,
+	&dev_attr_CMD_NO_SECRETS.attr,
+	&dev_attr_CMD_OPEN_LOCALITY1.attr,
+	&dev_attr_CMD_OPEN_LOCALITY2.attr,
+	&dev_attr_CMD_CLOSE_LOCALITY1.attr,
+	&dev_attr_CMD_CLOSE_LOCALITY2.attr,
+	&dev_attr_CMD_UNLOCK_MEM_CONFIG.attr,
+	NULL,
+};
+
+static struct attribute_group config_attr_grp = {
+	.attrs = config_attrs
+};
+
+ssize_t sysfs_create_config(struct kobject *parent)
+{
+	struct kobject *config_kobj;
+	int retval;
+
+	config_kobj = kobject_create_and_add("config", parent);
+	if (!config_kobj)
+		return -ENOMEM;
+
+	retval = sysfs_create_group(config_kobj, &config_attr_grp);
+	if (retval)
+		kobject_put(config_kobj);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_config);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/char/txt/txt-config.h b/drivers/char/txt/txt-config.h
new file mode 100644
index 0000000..015bd13
--- /dev/null
+++ b/drivers/char/txt/txt-config.h
@@ -0,0 +1,138 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#define TXT_PUB_CONFIG_REGS_BASE	0xfed30000
+#define TXT_PRIV_CONFIG_REGS_BASE	0xfed20000
+#define TXT_CONFIG_REGS_SIZE		0x10000
+
+#define TXTCR_STS			0x0000
+#define TXTCR_ESTS			0x0008
+#define TXTCR_ERRORCODE			0x0030
+#define TXTCR_CMD_RESET			0x0038
+#define TXTCR_CMD_CLOSE_PRIVATE		0x0048
+#define TXTCR_VER_FSBIF			0x0100
+#define TXTCR_DIDVID			0x0110
+#define TXTCR_VER_QPIIF			0x0200
+#define TXTCR_CMD_UNLOCK_MEM_CONFIG	0x0218
+#define TXTCR_SINIT_BASE		0x0270
+#define TXTCR_SINIT_SIZE		0x0278
+#define TXTCR_MLE_JOIN			0x0290
+#define TXTCR_HEAP_BASE			0x0300
+#define TXTCR_HEAP_SIZE			0x0308
+#define TXTCR_MSEG_BASE			0x0310
+#define TXTCR_MSEG_SIZE			0x0318
+#define TXTCR_DPR			0x0330
+#define TXTCR_CMD_OPEN_LOCALITY1	0x0380
+#define TXTCR_CMD_CLOSE_LOCALITY1	0x0388
+#define TXTCR_CMD_OPEN_LOCALITY2	0x0390
+#define TXTCR_CMD_CLOSE_LOCALITY2	0x0398
+#define TXTCR_PUBLIC_KEY		0x0400
+#define TXTCR_CMD_SECRETS		0x08e0
+#define TXTCR_CMD_NO_SECRETS		0x08e8
+#define TXTCR_E2STS			0x08f0
+
+#define off_STS_raw			1
+#define off_STS_senter_done		2
+#define off_STS_sexit_done		3
+#define off_STS_mem_config_lock		4
+#define off_STS_private_open		5
+#define off_STS_locality_1_open		6
+#define off_STS_locality_2_open		7
+#define off_ERRORCODE			8
+#define off_ESTS_raw			9
+#define off_ESTS_txt_reset		10
+#define off_E2STS_raw			11
+#define off_E2STS_secrets		12
+#define off_VER_FSBIF			13
+#define off_VER_QPIIF			14
+#define off_DIDVID_raw			15
+#define off_DIDVID_vendor_id		16
+#define off_DIDVID_device_id		17
+#define off_DIDVID_revision_id		18
+#define off_SINIT_BASE			19
+#define off_SINIT_SIZE			20
+#define off_HEAP_BASE			21
+#define off_HEAP_SIZE			22
+#define off_PUBLIC_KEY			23
+#define off_MLE_JOIN			24
+#define off_DPR_raw			25
+#define off_DPR_lock			26
+#define off_DPR_top			27
+#define off_DPR_size			28
+#define off_CMD_RESET			29
+#define off_CMD_CLOSE_PRIVATE		30
+#define off_CMD_SECRETS			31
+#define off_CMD_NO_SECRETS		32
+#define off_CMD_OPEN_LOCALITY1		33
+#define off_CMD_OPEN_LOCALITY2		34
+#define off_CMD_CLOSE_LOCALITY1		35
+#define off_CMD_CLOSE_LOCALITY2		36
+#define off_CMD_UNLOCK_MEM_CONFIG	37
+
+typedef union txt_ests {
+	uint64_t _raw;
+	struct {
+		uint64_t txt_reset_sts:1;
+	};
+} txt_ests_t;
+
+typedef union txt_e2sts {
+	uint64_t _raw;
+	struct {
+		uint64_t reserved:1;
+		uint64_t secrets_sts:1;
+	};
+} txt_e2sts_t;
+
+typedef union txt_sts {
+	uint64_t _raw;
+	struct {
+		uint64_t senter_done_sts:1;
+		uint64_t sexit_done_sts:1;
+		uint64_t reserved1:4;
+		uint64_t mem_config_lock_sts:1;
+		uint64_t private_open_sts:1;
+		uint64_t reserved2:7;
+		uint64_t locality_1_open_sts:1;
+		uint64_t locality_2_open_sts:1;
+	};
+} txt_sts_t;
+
+typedef union txt_divid {
+	uint64_t _raw;
+	struct {
+		uint16_t vendor_id;
+		uint16_t device_id;
+		uint16_t revision_id;
+		uint16_t reserved;
+	};
+} txt_didvid_t;
+
+typedef union txt_dpr {
+	uint64_t _raw;
+	struct {
+		uint64_t lock:1;
+		uint64_t reserved1:3;
+		uint64_t size:8;
+		uint64_t reserved2:8;
+		uint64_t top:12;
+		uint64_t reserved3:32;
+	};
+} txt_dpr_t;
+
+static inline uint64_t
+read_txt_config_reg(void *config_regs_base, uint32_t reg)
+{
+	return readq(config_regs_base + reg);
+}
+
+static inline void
+write_txt_config_reg(void *config_regs_base, uint32_t reg, uint64_t val)
+{
+	writeq(val, config_regs_base + reg);
+}
+
+extern ssize_t sysfs_create_config(struct kobject *parent);
+
+#endif /* __CONFIG_H__ */
+
diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
index c56bfe3..99d42d0 100644
--- a/drivers/char/txt/txt-sysfs.c
+++ b/drivers/char/txt/txt-sysfs.c
@@ -16,17 +16,29 @@
 #include <linux/platform_device.h>
 #include <linux/sysfs.h>
 
+#include "txt-config.h"
+
 #define DEV_NAME "txt"
 struct platform_device *pdev;
 
 static int __init txt_sysfs_init(void)
 {
+	int retval;
+
 	pdev = platform_device_register_simple(DEV_NAME, -1, NULL, 0);
 	if (IS_ERR(pdev))
 		return PTR_ERR(pdev);
 
+	retval = sysfs_create_config(&pdev->dev.kobj);
+	if (retval)
+		goto err;
+
 	pr_info("Loading TXT module successfully\n");
 	return 0;
+
+err:
+	platform_device_unregister(pdev);
+	return retval;
 }
 
 static void __exit txt_sysfs_exit(void)
-- 
1.7.9.5


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

* [PATCH 3/5] driver: provide sysfs interfaces to access TXT log
  2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 1/5] driver: add TXT driver in kernel Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 2/5] driver: provide sysfs interfaces to access TXT config space Qiaowei Ren
@ 2013-04-27 14:56 ` Qiaowei Ren
  2013-04-27 13:17   ` Greg Kroah-Hartman
  2013-04-27 14:56 ` [PATCH 4/5] driver: provide sysfs interfaces to access SMX parameter Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 5/5] driver: provide sysfs interfaces to access TXT heap Qiaowei Ren
  4 siblings, 1 reply; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren, Xiaoyan Zhang

These interfaces are located in /sys/devices/platform/txt/log/.

Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
 drivers/char/txt/Makefile    |    2 +-
 drivers/char/txt/txt-log.c   |  140 ++++++++++++++++++++++++++++++++++++++++++
 drivers/char/txt/txt-log.h   |   27 ++++++++
 drivers/char/txt/txt-sysfs.c |    5 ++
 4 files changed, 173 insertions(+), 1 deletion(-)
 create mode 100644 drivers/char/txt/txt-log.c
 create mode 100644 drivers/char/txt/txt-log.h

diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
index 3db5a6f..fcb0e81 100644
--- a/drivers/char/txt/Makefile
+++ b/drivers/char/txt/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the intel TXT drivers.
 #
 obj-$(CONFIG_TXT) += txt.o
-txt-y := txt-sysfs.o txt-config.o
+txt-y := txt-sysfs.o txt-config.o txt-log.o
diff --git a/drivers/char/txt/txt-log.c b/drivers/char/txt/txt-log.c
new file mode 100644
index 0000000..10f3918
--- /dev/null
+++ b/drivers/char/txt/txt-log.c
@@ -0,0 +1,140 @@
+/*
+ * txt-log.c
+ *
+ * - log/
+ *   log_header	 -r--r--r-- ; output log header, including max_size and
+ *			      curr_pos.
+ *   block	 -r--r--r-- ; output pure log in block style, 1 page size.
+ *   block_index -rw-rw-r-- ; the block index for output.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/io.h>
+#include <linux/stat.h>
+
+#include "txt-log.h"
+
+static u32 log_block_index;
+
+static int are_uuids_equal(const struct uuid *uuid1,
+			   const struct uuid *uuid2)
+{
+	return (memcmp(uuid1, uuid2, sizeof(*uuid1)) == 0) ? 1 : 0;
+}
+
+static struct tboot_log *get_log(void)
+{
+	struct tboot_log *log;
+
+	log = (struct tboot_log *)ioremap_nocache(TBOOT_SERIAL_LOG_ADDR,
+						    TBOOT_SERIAL_LOG_SIZE);
+	if (!log)
+		return NULL;
+
+	if (!are_uuids_equal(&(log->uuid),
+			     &((struct uuid)TBOOT_LOG_UUID))) {
+		iounmap(log);
+		return NULL;
+	}
+
+	return log;
+}
+
+ssize_t txt_show_log_header(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	struct tboot_log *log;
+	int ret;
+
+	log = get_log();
+	if (!log)
+		return -EFAULT;
+
+	ret = scnprintf(buf, PAGE_SIZE, "max_size: %x\ncurr_pos: %x\n",
+		       log->max_size, log->curr_pos);
+
+	iounmap(log);
+	return ret;
+}
+static DEVICE_ATTR(log_header, S_IRUGO, txt_show_log_header, NULL);
+
+ssize_t txt_show_block(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct tboot_log *log;
+	char *block;
+	int ret;
+
+	log = get_log();
+	if (!log)
+		return -EFAULT;
+
+	block = log->buf + log_block_index * PAGE_SIZE;
+	ret = scnprintf(buf, PAGE_SIZE, "%s\n", block);
+
+	iounmap(log);
+	return ret;
+}
+static DEVICE_ATTR(block, S_IRUGO, txt_show_block, NULL);
+
+ssize_t txt_show_block_index(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d\n", log_block_index);
+}
+
+ssize_t txt_store_block_index(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	u32 index;
+	struct tboot_log *log;
+
+	log = get_log();
+	if (!log)
+		return -EFAULT;
+
+	sscanf(buf, "%d", &index);
+	if (index > log->curr_pos / PAGE_SIZE)
+		return -EINVAL;
+	log_block_index = index;
+
+	iounmap(log);
+	return count;
+}
+static DEVICE_ATTR(block_index, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_block_index, txt_store_block_index);
+
+static struct attribute *log_attrs[] = {
+	&dev_attr_log_header.attr,
+	&dev_attr_block.attr,
+	&dev_attr_block_index.attr,
+	NULL,
+};
+
+static struct attribute_group log_attr_grp = {
+	.attrs = log_attrs
+};
+
+ssize_t sysfs_create_log(struct kobject *parent)
+{
+	struct kobject *log_kobj;
+	int retval;
+
+	log_kobj = kobject_create_and_add("log", parent);
+	if (!log_kobj)
+		return -ENOMEM;
+
+	retval = sysfs_create_group(log_kobj, &log_attr_grp);
+	if (retval)
+		kobject_put(log_kobj);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_log);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/char/txt/txt-log.h b/drivers/char/txt/txt-log.h
new file mode 100644
index 0000000..580d71c
--- /dev/null
+++ b/drivers/char/txt/txt-log.h
@@ -0,0 +1,27 @@
+#ifndef __LOG_H__
+#define __LOG_H__
+
+struct uuid {
+	uint32_t data1;
+	uint16_t data2;
+	uint16_t data3;
+	uint16_t data4;
+	uint8_t  data5[6];
+} __packed;
+
+struct tboot_log {
+	struct uuid   uuid;
+	uint32_t      max_size;
+	uint32_t      curr_pos;
+	char          buf[];
+};
+
+#define TBOOT_LOG_UUID		{0xc0192526, 0x6b30, 0x4db4, 0x844c, \
+				{0xa3, 0xe9, 0x53, 0xb8, 0x81, 0x74} }
+#define TBOOT_SERIAL_LOG_ADDR	0x60000
+#define TBOOT_SERIAL_LOG_SIZE	0x08000
+
+extern ssize_t sysfs_create_log(struct kobject *parent);
+
+#endif /* __LOG_H__ */
+
diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
index 99d42d0..e945586 100644
--- a/drivers/char/txt/txt-sysfs.c
+++ b/drivers/char/txt/txt-sysfs.c
@@ -17,6 +17,7 @@
 #include <linux/sysfs.h>
 
 #include "txt-config.h"
+#include "txt-log.h"
 
 #define DEV_NAME "txt"
 struct platform_device *pdev;
@@ -33,6 +34,10 @@ static int __init txt_sysfs_init(void)
 	if (retval)
 		goto err;
 
+	retval = sysfs_create_log(&pdev->dev.kobj);
+	if (retval)
+		goto err;
+
 	pr_info("Loading TXT module successfully\n");
 	return 0;
 
-- 
1.7.9.5


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

* [PATCH 4/5] driver: provide sysfs interfaces to access SMX parameter
  2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
                   ` (2 preceding siblings ...)
  2013-04-27 14:56 ` [PATCH 3/5] driver: provide sysfs interfaces to access TXT log Qiaowei Ren
@ 2013-04-27 14:56 ` Qiaowei Ren
  2013-04-27 14:56 ` [PATCH 5/5] driver: provide sysfs interfaces to access TXT heap Qiaowei Ren
  4 siblings, 0 replies; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren, Xiaoyan Zhang

These interfaces are located in /sys/devices/platform/txt/parameter/,
showing specific parameter information for SMX features supported by
the processor.

Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
 drivers/char/txt/Makefile        |    2 +-
 drivers/char/txt/txt-parameter.c |  261 ++++++++++++++++++++++++++++++++++++++
 drivers/char/txt/txt-parameter.h |   40 ++++++
 drivers/char/txt/txt-sysfs.c     |    5 +
 4 files changed, 307 insertions(+), 1 deletion(-)
 create mode 100644 drivers/char/txt/txt-parameter.c
 create mode 100644 drivers/char/txt/txt-parameter.h

diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
index fcb0e81..be73add 100644
--- a/drivers/char/txt/Makefile
+++ b/drivers/char/txt/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the intel TXT drivers.
 #
 obj-$(CONFIG_TXT) += txt.o
-txt-y := txt-sysfs.o txt-config.o txt-log.o
+txt-y := txt-sysfs.o txt-config.o txt-log.o txt-parameter.o
diff --git a/drivers/char/txt/txt-parameter.c b/drivers/char/txt/txt-parameter.c
new file mode 100644
index 0000000..6e2600d
--- /dev/null
+++ b/drivers/char/txt/txt-parameter.c
@@ -0,0 +1,261 @@
+/*
+ * txt-parameter.c
+ *
+ * specific parameter information for SMX features supported by the processor.
+ *
+ *   n_versions		-r--r--r--;
+ *   acm_max_size	-r--r--r--;
+ *   acm_mem_types	-r--r--r--;
+ *   senter_controls	-r--r--r--;
+ *   proc_based_scrtm	-r--r--r--;
+ *   preserve_mce	-r--r--r--;
+ *   acm_version_index	-rw-rw-r--; desginate which acm_version will be output
+ *   acm_version	-r--r--r--;
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include "txt-parameter.h"
+
+static u32 acm_version_index;
+
+static void __getsec_parameters(uint32_t index, int *param_type,
+				uint32_t *peax, uint32_t *pebx,
+				uint32_t *pecx)
+{
+	uint32_t eax = 0, ebx = 0, ecx = 0;
+
+	__asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+			      : "=a"(eax), "=b"(ebx), "=c"(ecx)
+			      : "a"(IA32_GETSEC_PARAMETERS), "b"(index));
+
+	*param_type = eax & 0x1f;
+	*peax = eax;
+	*pebx = ebx;
+	*pecx = ecx;
+}
+
+static bool get_parameters(struct getsec_parameters *params)
+{
+	uint32_t index, eax, ebx, ecx;
+	int param_type;
+
+	write_cr4(read_cr4() | CR4_SMXE);
+
+	memset(params, 0, sizeof(struct getsec_parameters));
+	params->acm_max_size = DEF_ACM_MAX_SIZE;
+	params->acm_mem_types = DEF_ACM_MEM_TYPES;
+	params->senter_controls = DEF_SENTER_CTRLS;
+	params->proc_based_scrtm = false;
+	params->preserve_mce = false;
+
+	index = 0;
+	do {
+		__getsec_parameters(index++, &param_type, &eax, &ebx, &ecx);
+
+		switch (param_type) {
+		case 1:
+			if (params->n_versions == MAX_SUPPORTED_ACM_VERSIONS)
+				continue;
+			params->acm_versions[params->n_versions].mask = ebx;
+			params->acm_versions[params->n_versions].version = ecx;
+			params->n_versions++;
+			break;
+
+		case 2:
+			params->acm_max_size = eax & 0xffffffe0;
+			break;
+
+		case 3:
+			params->acm_mem_types = eax & 0xffffffe0;
+			break;
+
+		case 4:
+			params->senter_controls = (eax & 0x00007fff) >> 8;
+			break;
+
+		case 5:
+			params->proc_based_scrtm =
+				(eax & 0x00000020) ? true : false;
+			params->preserve_mce =
+				(eax & 0x00000040) ? true : false;
+			break;
+
+		default:
+			param_type = 0;
+			break;
+		}
+	} while (param_type != 0);
+
+	if (params->n_versions == 0) {
+		params->acm_versions[0].mask = DEF_ACM_VER_MASK;
+		params->acm_versions[0].version = DEF_ACM_VER_SUPPORTED;
+		params->n_versions = 1;
+	}
+
+	return true;
+}
+
+static ssize_t show_param(char *buf, u32 index)
+{
+	struct getsec_parameters params;
+
+	if (!get_parameters(&params))
+		return -EPERM;
+
+	switch (index) {
+	case off_n_versions:
+		return scnprintf(buf, PAGE_SIZE, "%d\n",
+				params.n_versions);
+
+	case off_acm_max_size:
+		return scnprintf(buf, PAGE_SIZE, "%u\n",
+				 params.acm_max_size);
+
+	case off_acm_mem_types:
+		return scnprintf(buf, PAGE_SIZE, "%u\n",
+				 params.acm_mem_types);
+
+	case off_senter_controls:
+		return scnprintf(buf, PAGE_SIZE, "%u\n",
+				 params.senter_controls);
+
+	case off_proc_based_scrtm:
+		return scnprintf(buf, PAGE_SIZE, "%d\n",
+				 params.proc_based_scrtm);
+
+	case off_preserve_mce:
+		return scnprintf(buf, PAGE_SIZE, "%d\n",
+				 params.preserve_mce);
+
+	case off_acm_version:
+		return scnprintf(buf, PAGE_SIZE,
+			"mask: %u\nversion: %u\n",
+			params.acm_versions[acm_version_index].mask,
+			params.acm_versions[acm_version_index].version);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+ssize_t txt_show_param_nversions(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_param(buf, off_n_versions);
+}
+static DEVICE_ATTR(n_versions, S_IRUGO, txt_show_param_nversions, NULL);
+
+ssize_t txt_show_param_acmmaxsize(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_param(buf, off_acm_max_size);
+}
+static DEVICE_ATTR(acm_max_size, S_IRUGO, txt_show_param_acmmaxsize, NULL);
+
+ssize_t txt_show_param_acmmemtypes(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_param(buf, off_acm_mem_types);
+}
+static DEVICE_ATTR(acm_mem_types, S_IRUGO, txt_show_param_acmmemtypes, NULL);
+
+ssize_t txt_show_param_senter(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	return show_param(buf, off_senter_controls);
+}
+static DEVICE_ATTR(senter_controls, S_IRUGO, txt_show_param_senter, NULL);
+
+ssize_t txt_show_param_proc(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	return show_param(buf, off_proc_based_scrtm);
+}
+static DEVICE_ATTR(proc_based_scrtm, S_IRUGO, txt_show_param_proc, NULL);
+
+ssize_t txt_show_param_preserve(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_param(buf, off_preserve_mce);
+}
+static DEVICE_ATTR(preserve_mce, S_IRUGO, txt_show_param_preserve, NULL);
+
+ssize_t txt_show_param_acmvindex(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d\n", acm_version_index);
+}
+
+ssize_t txt_store_param_acmvindex(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	u32 index;
+	struct getsec_parameters params;
+
+	sscanf(buf, "%d", &index);
+
+	if (!get_parameters(&params))
+		return -EPERM;
+
+	if (index >= params.n_versions)
+		return -EINVAL;
+
+	acm_version_index = index;
+
+	return count;
+}
+static DEVICE_ATTR(acm_version_index, S_IRUGO | S_IWUSR | S_IWGRP,
+		   txt_show_param_acmvindex, txt_store_param_acmvindex);
+
+ssize_t txt_show_param_acmversion(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_param(buf, off_acm_version);
+}
+static DEVICE_ATTR(acm_version, S_IRUGO, txt_show_param_acmversion, NULL);
+
+static struct attribute *param_attrs[] = {
+	&dev_attr_n_versions.attr,
+	&dev_attr_acm_max_size.attr,
+	&dev_attr_acm_mem_types.attr,
+	&dev_attr_senter_controls.attr,
+	&dev_attr_proc_based_scrtm.attr,
+	&dev_attr_preserve_mce.attr,
+	&dev_attr_acm_version_index.attr,
+	&dev_attr_acm_version.attr,
+	NULL,
+};
+
+static struct attribute_group param_attr_grp = {
+	.attrs = param_attrs
+};
+
+ssize_t sysfs_create_parameter(struct kobject *parent)
+{
+	struct kobject *param_kobj;
+	int retval;
+
+	param_kobj = kobject_create_and_add("parameter", parent);
+	if (!param_kobj)
+		return -ENOMEM;
+
+	retval = sysfs_create_group(param_kobj, &param_attr_grp);
+	if (retval)
+		kobject_put(param_kobj);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_parameter);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/char/txt/txt-parameter.h b/drivers/char/txt/txt-parameter.h
new file mode 100644
index 0000000..d5ff6d6
--- /dev/null
+++ b/drivers/char/txt/txt-parameter.h
@@ -0,0 +1,40 @@
+#ifndef __PARAMETER_H__
+#define __PARAMETER_H__
+
+#define CR4_SMXE 0x00004000
+#define MAX_SUPPORTED_ACM_VERSIONS 16
+
+#define DEF_ACM_MAX_SIZE	0x8000
+#define DEF_ACM_VER_MASK	0xffffffff
+#define DEF_ACM_VER_SUPPORTED	0x00
+#define DEF_ACM_MEM_TYPES	0x0100
+#define DEF_SENTER_CTRLS	0x00
+
+#define IA32_GETSEC_OPCODE	".byte 0x0f,0x37"
+#define IA32_GETSEC_PARAMETERS	6
+
+#define off_n_versions		1
+#define off_acm_max_size	2
+#define off_acm_mem_types	3
+#define off_senter_controls	4
+#define off_proc_based_scrtm	5
+#define off_preserve_mce	6
+#define off_acm_version		7
+
+typedef struct getsec_parameters {
+	struct {
+		uint32_t mask;
+		uint32_t version;
+	} acm_versions[MAX_SUPPORTED_ACM_VERSIONS];
+	int n_versions;
+	uint32_t acm_max_size;
+	uint32_t acm_mem_types;
+	uint32_t senter_controls;
+	bool proc_based_scrtm;
+	bool preserve_mce;
+} getsec_parameters_t;
+
+extern ssize_t sysfs_create_parameter(struct kobject *parent);
+
+#endif /* __PARAMETER_H__ */
+
diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
index e945586..7b092bd 100644
--- a/drivers/char/txt/txt-sysfs.c
+++ b/drivers/char/txt/txt-sysfs.c
@@ -18,6 +18,7 @@
 
 #include "txt-config.h"
 #include "txt-log.h"
+#include "txt-parameter.h"
 
 #define DEV_NAME "txt"
 struct platform_device *pdev;
@@ -38,6 +39,10 @@ static int __init txt_sysfs_init(void)
 	if (retval)
 		goto err;
 
+	retval = sysfs_create_parameter(&pdev->dev.kobj);
+	if (retval)
+		goto err;
+
 	pr_info("Loading TXT module successfully\n");
 	return 0;
 
-- 
1.7.9.5


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

* [PATCH 5/5] driver: provide sysfs interfaces to access TXT heap
  2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
                   ` (3 preceding siblings ...)
  2013-04-27 14:56 ` [PATCH 4/5] driver: provide sysfs interfaces to access SMX parameter Qiaowei Ren
@ 2013-04-27 14:56 ` Qiaowei Ren
  4 siblings, 0 replies; 8+ messages in thread
From: Qiaowei Ren @ 2013-04-27 14:56 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman
  Cc: Richard L Maliszewski, Shane Wang, Gang Wei, linux-kernel,
	Qiaowei Ren, Xiaoyan Zhang

These interfaces are located in /sys/devices/platform/txt/heap/.
There are one file binary_heap displaying the whole heap information
in binary, and four subfolders displaying detailed heap information.

Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
 drivers/char/txt/Makefile    |    2 +-
 drivers/char/txt/txt-heap.c  | 1616 ++++++++++++++++++++++++++++++++++++++++++
 drivers/char/txt/txt-heap.h  |  338 +++++++++
 drivers/char/txt/txt-sysfs.c |    5 +
 4 files changed, 1960 insertions(+), 1 deletion(-)
 create mode 100644 drivers/char/txt/txt-heap.c
 create mode 100644 drivers/char/txt/txt-heap.h

diff --git a/drivers/char/txt/Makefile b/drivers/char/txt/Makefile
index be73add..4e972df 100644
--- a/drivers/char/txt/Makefile
+++ b/drivers/char/txt/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the intel TXT drivers.
 #
 obj-$(CONFIG_TXT) += txt.o
-txt-y := txt-sysfs.o txt-config.o txt-log.o txt-parameter.o
+txt-y := txt-sysfs.o txt-config.o txt-log.o txt-parameter.o txt-heap.o
diff --git a/drivers/char/txt/txt-heap.c b/drivers/char/txt/txt-heap.c
new file mode 100644
index 0000000..e47018d
--- /dev/null
+++ b/drivers/char/txt/txt-heap.c
@@ -0,0 +1,1616 @@
+/*
+ * txt-heap.c
+ *
+ * binary_heap, -r--r--r--; output all raw binary heap data.
+ * 4 subfolders, indicating 4 kinds of data in heap, in which every file
+ * is one data field bios_data, os_mle_data, os_sinit_data, sinit_mle_data
+ *
+ * Data is currently found below
+ *   /sys/devices/platform/txt/heap/...
+ *
+ *   - bios_data/
+ *     bios_data_raw		-r--r--r-- ;
+ *     bios_data_version	-r--r--r-- ;
+ *     bios_sinit_size		-r--r--r-- ;
+ *     lcp_pd_base		-r--r--r-- ;
+ *     lcp_pd_size		-r--r--r-- ;
+ *     num_logical_procs	-r--r--r-- ;
+ *     flags			-r--r--r-- ;
+ *
+ *   - Dynamically create extended data elements subfolders:
+ *     bios_spec_ver_elt/
+ *	 major, minor, ver
+ *     acm_elt/
+ *	 num_acms, acm_addrs
+ *     custom_elt/
+ *	 size, uuid
+ *     event_log_elt/
+ *	 event_log_size, event_log_addr, event_log_container, events
+ *
+ *   - os_mle_data/
+ *     os_mle_data_raw		-r--r--r-- ;
+ *     os_mle_data_version	-r--r--r-- ;
+ *     mbi			-r--r--r-- ;
+ *
+ *   - os_sinit_data/
+ *     os_sinit_data_raw	-r--r--r-- ;
+ *     os_sinit_data_version	-r--r--r-- ;
+ *     mle_ptab			-r--r--r-- ;
+ *     mle_size			-r--r--r-- ;
+ *     mle_hdr_base		-r--r--r-- ;
+ *     vtd_pmr_lo_base		-r--r--r-- ;
+ *     vtd_pmr_lo_size		-r--r--r-- ;
+ *     vtd_pmr_hi_base		-r--r--r-- ;
+ *     vtd_pmr_hi_size		-r--r--r-- ;
+ *     lcp_po_base		-r--r--r-- ;
+ *     lcp_po_size		-r--r--r-- ;
+ *     caps_raw			-r--r--r-- ;
+ *     caps_rlp_wake_getsec	-r--r--r-- ;
+ *     caps_rlp_wake_monitor	-r--r--r-- ;
+ *     caps_ecx_pgtbl		-r--r--r-- ;
+ *     caps_pcr_map_no_legacy	-r--r--r-- ;
+ *     caps_pcr_map_da		-r--r--r-- ;
+ *     efi_rsdt_ptr		-r--r--r-- ;
+ *     ext_data_element same with that in bios_data
+ *
+ *   - sinit_mle_data/
+ *     sinit_mle_data_raw	-r--r--r-- ;
+ *     sinit_mle_data_version	-r--r--r-- ;
+ *     bios_acm_id		-r--r--r-- ;
+ *     edx_senter_flags		-r--r--r-- ;
+ *     mseg_valid		-r--r--r-- ;
+ *     sinit_hash		-r--r--r-- ;
+ *     mle_hash			-r--r--r-- ;
+ *     stm_hash			-r--r--r-- ;
+ *     lcp_policy_hash		-r--r--r-- ;
+ *     lcp_policy_control	-r--r--r-- ;
+ *     rlp_wakeup_addr		-r--r--r-- ;
+ *     num_mdrs			-r--r--r-- ;
+ *     mdrs_off			-r--r--r-- ;
+ *     num_vtd_dmars		-r--r--r-- ;
+ *     vtd_dmars_off		-r--r--r-- ;
+ *     sinit_mdrs		-r--r--r-- ;
+ *     proc_scrtm_status	-r--r--r-- ;
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include "txt-config.h"
+#include "txt-log.h"
+#include "txt-heap.h"
+
+static uint64_t txt_heap_size;
+
+static ssize_t print_hash(char *buf, uint8_t *hash)
+{
+	int i;
+	void *start;
+	char *str = buf;
+
+	if (hash == NULL)
+		return -EINVAL;
+
+	start = hash;
+	for (i = 0; i < SHA1_LENGTH; i++, start++)
+		str += scnprintf(str, PAGE_SIZE, "%02x ", *(uint8_t *)start);
+
+	str += scnprintf(str, PAGE_SIZE, "\n");
+	return str - buf;
+}
+
+static ssize_t print_hex(char *buf, char *prefix, void *ptr, size_t size)
+{
+	size_t i;
+	char *str = buf;
+
+	for (i = 0; i < size; i++) {
+		if (i % 16 == 0 && prefix != NULL)
+			str += scnprintf(str, PAGE_SIZE, "\n%s", prefix);
+		str += scnprintf(str, PAGE_SIZE, "%02x ", *(uint8_t *)ptr++);
+	}
+
+	str += scnprintf(str, PAGE_SIZE, "\n");
+	return str - buf;
+}
+
+static void *get_txt_heap(void)
+{
+	void __iomem *config;
+	void __iomem *heap;
+	uint64_t base, size;
+
+	config = ioremap_nocache(TXT_PUB_CONFIG_REGS_BASE,
+				 TXT_CONFIG_REGS_SIZE);
+	if (!config)
+		return NULL;
+
+	base = read_txt_config_reg(config, TXTCR_HEAP_BASE);
+	size = read_txt_config_reg(config, TXTCR_HEAP_SIZE);
+
+	iounmap(config);
+
+	if (base == 0 || size == 0)
+		return NULL;
+
+	heap = ioremap_nocache(base, size);
+	if (!heap)
+		return NULL;
+
+	txt_heap_size = size;
+
+	return heap;
+}
+
+/*
+ * extended data elements
+ */
+
+/* HEAP_BIOS_SPEC_VER_ELEMENT */
+static ssize_t print_bios_elt(char *buf, struct heap_ext_data_element *elt,
+			      u32 offset)
+{
+	struct heap_bios_spec_ver_elt *bios_elt;
+
+	while (elt->type != HEAP_EXTDATA_TYPE_END &&
+	       elt->type != HEAP_EXTDATA_TYPE_BIOS_SPEC_VER)
+		elt = (void *)elt + elt->size;
+
+	if (elt->type == HEAP_EXTDATA_TYPE_END)
+		return -EFAULT;
+
+	bios_elt = (struct heap_bios_spec_ver_elt *)elt->data;
+
+	switch (offset) {
+	case off_bios_elt_major:
+		return scnprintf(buf, PAGE_SIZE, "0x%x\n",
+				 bios_elt->spec_ver_major);
+
+	case off_bios_elt_minor:
+		return scnprintf(buf, PAGE_SIZE, "0x%x\n",
+				 bios_elt->spec_ver_minor);
+
+	case off_bios_elt_rev:
+		return scnprintf(buf, PAGE_SIZE, "0x%x\n",
+				 bios_elt->spec_ver_rev);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/* HEAP_ACM_ELEMENT */
+static ssize_t print_acm_elt(char *buf, struct heap_ext_data_element *elt,
+			     u32 offset)
+{
+	struct heap_acm_elt *acm_elt;
+
+	while (elt->type != HEAP_EXTDATA_TYPE_END &&
+	       elt->type != HEAP_EXTDATA_TYPE_ACM)
+		elt = (void *)elt + elt->size;
+
+	if (elt->type == HEAP_EXTDATA_TYPE_END)
+		return -EFAULT;
+
+	acm_elt = (struct heap_acm_elt *)elt->data;
+
+	switch (offset) {
+	case off_acm_elt_num_acms:
+		return scnprintf(buf, PAGE_SIZE, "%u\n", acm_elt->num_acms);
+
+	case off_acm_elt_acm_addrs:
+	{
+		char *str = buf;
+		u32 i;
+
+		for (i = 0; i < acm_elt->num_acms; i++)
+			str += scnprintf(str, PAGE_SIZE,
+					 "acm_addrs[%u]: 0x%llx\n",
+					 i, acm_elt->acm_addrs[i]);
+
+		return str - buf;
+	}
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/* HEAP_CUSTOM_ELEMENT */
+static ssize_t print_custom_elt(char *buf, struct heap_ext_data_element *elt,
+				u32 offset)
+{
+	struct heap_custom_elt *custom_elt;
+
+	while (elt->type != HEAP_EXTDATA_TYPE_END &&
+	       elt->type != HEAP_EXTDATA_TYPE_CUSTOM)
+		elt = (void *)elt + elt->size;
+
+	if (elt->type == HEAP_EXTDATA_TYPE_END)
+		return -EFAULT;
+
+	custom_elt = (struct heap_custom_elt *)elt->data;
+
+	switch (offset) {
+	case off_custom_elt_size:
+		return scnprintf(buf, PAGE_SIZE, "%u\n", elt->size);
+
+	case off_custom_elt_uuid:
+	{
+		struct uuid *uuid;
+
+		uuid = &custom_elt->uuid;
+
+		return scnprintf(buf, PAGE_SIZE,
+				 "{0x%08x, 0x%04x, 0x%04x, 0x%04x,\n{0x%02x"
+				 ",0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}",
+				 uuid->data1, (uint32_t)uuid->data2,
+				 (uint32_t)uuid->data3, (uint32_t)uuid->data4,
+				 (uint32_t)uuid->data5[0],
+				 (uint32_t)uuid->data5[1],
+				 (uint32_t)uuid->data5[2],
+				 (uint32_t)uuid->data5[3],
+				 (uint32_t)uuid->data5[4],
+				 (uint32_t)uuid->data5[5]);
+	}
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/* HEAP_EVENT_LOG_POINTER_ELEMENT */
+static ssize_t print_event(char *buf, struct tpm12_pcr_event *evt)
+{
+	char *str = buf;
+
+	str += scnprintf(str, PAGE_SIZE, "Event:\n");
+	str += scnprintf(str, PAGE_SIZE, "  PCRIndex: %u\n", evt->pcr_index);
+	str += scnprintf(str, PAGE_SIZE, "      Type: 0x%x\n", evt->type);
+	str += scnprintf(str, PAGE_SIZE, "    Digest: ");
+	str += print_hash(str, evt->digest);
+	str += scnprintf(str, PAGE_SIZE, "      Data: %u bytes",
+			 evt->data_size);
+	str += print_hex(str, "      ", evt->data, evt->data_size);
+
+	return str - buf;
+}
+
+static ssize_t print_event_elt(char *buf, struct heap_ext_data_element *elt,
+			       u32 offset)
+{
+	struct heap_event_log_ptr_elt *elog_elt;
+	struct event_log_container *elog_con;
+	void *elog_con_base;
+	char *str = buf;
+	int ret;
+
+	while (elt->type != HEAP_EXTDATA_TYPE_END &&
+	       elt->type != HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR)
+		elt = (void *)elt + elt->size;
+
+	if (elt->type == HEAP_EXTDATA_TYPE_END)
+		return -EFAULT;
+
+	elog_elt = (struct heap_event_log_ptr_elt *)elt->data;
+
+	elog_con_base = ioremap_nocache(elog_elt->event_log_phys_addr,
+					MAX_EVENT_LOG_SIZE);
+	if (elog_con_base == NULL)
+		return -ENOMEM;
+
+	elog_con = (struct event_log_container *)elog_con_base;
+
+	switch (offset) {
+	case off_event_elt_size:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n", elt->size);
+		break;
+
+	case off_event_elt_addr:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       elog_elt->event_log_phys_addr);
+		break;
+
+	case off_event_elt_container:
+		ret = scnprintf(buf, PAGE_SIZE,
+			       "Signature: %s\nContainerVer: %u.%u\n"
+			       "PCREventVer: %u.%u\nSize: %u\n"
+			       "EventOffset: [%u,%u)\n",
+			       elog_con->signature,
+			       elog_con->container_ver_major,
+			       elog_con->container_ver_minor,
+			       elog_con->pcr_event_ver_major,
+			       elog_con->pcr_event_ver_minor,
+			       elog_con->size,
+			       elog_con->pcr_events_offset,
+			       elog_con->next_event_offset);
+		break;
+
+	case off_event_elt_events:
+	{
+		struct tpm12_pcr_event *cur, *next;
+
+		cur = (struct tpm12_pcr_event *)
+			((void *)elog_con + elog_con->pcr_events_offset);
+		next = (struct tpm12_pcr_event *)
+			((void *)elog_con + elog_con->next_event_offset);
+		while (cur < next) {
+			str += print_event(str, cur);
+			cur = (void *)cur + sizeof(*cur) + cur->data_size;
+		}
+		ret = str - buf;
+
+		break;
+	}
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iounmap(elog_con_base);
+	return ret;
+}
+
+static struct attribute_group bios_spec_ver_elt_attr_grp;
+static struct attribute_group acm_elt_attr_grp;
+static struct attribute_group custom_elt_attr_grp;
+static struct attribute_group event_elt_attr_grp;
+
+static ssize_t sysfs_create_ext_data_elt(struct kobject *parent,
+					 struct heap_ext_data_element elts[])
+{
+	struct heap_ext_data_element *elt = elts;
+	int ret = 0;
+
+	while (elt->type != HEAP_EXTDATA_TYPE_END) {
+
+		switch (elt->type) {
+		case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER:
+		{
+			struct kobject *bios_spec_ver_elt_kobj;
+
+			bios_spec_ver_elt_kobj = kobject_create_and_add(
+					"bios_spec_ver_elt", parent);
+			if (!bios_spec_ver_elt_kobj)
+				return -ENOMEM;
+
+			ret = sysfs_create_group(bios_spec_ver_elt_kobj,
+						&bios_spec_ver_elt_attr_grp);
+			if (ret)
+				return ret;
+
+			break;
+		}
+
+		case HEAP_EXTDATA_TYPE_ACM:
+		{
+			struct kobject *acm_elt_kobj;
+
+			acm_elt_kobj = kobject_create_and_add(
+					"acm_elt", parent);
+			if (!acm_elt_kobj)
+				return -ENOMEM;
+
+			ret = sysfs_create_group(acm_elt_kobj,
+						&acm_elt_attr_grp);
+			if (ret)
+				return ret;
+
+			break;
+		}
+
+		case HEAP_EXTDATA_TYPE_CUSTOM:
+		{
+			struct kobject *custom_elt_kobj;
+
+			custom_elt_kobj = kobject_create_and_add(
+					"custom_elt", parent);
+			if (!custom_elt_kobj)
+				return -ENOMEM;
+
+			ret = sysfs_create_group(custom_elt_kobj,
+						&custom_elt_attr_grp);
+			if (ret)
+				return ret;
+
+			break;
+		}
+
+		case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+		{
+			struct kobject *event_log_ptr_elt_kobj;
+
+			event_log_ptr_elt_kobj = kobject_create_and_add(
+					"event_log_elt", parent);
+			if (!event_log_ptr_elt_kobj)
+				return -ENOMEM;
+
+			ret = sysfs_create_group(event_log_ptr_elt_kobj,
+						&event_elt_attr_grp);
+			if (ret)
+				return ret;
+
+			break;
+		}
+
+		default:
+			return -EINVAL;
+		}
+
+		elt = (void *)elt + elt->size;
+	}
+
+	return ret;
+}
+
+/*
+ * BIOS Data Format
+ */
+
+static ssize_t show_bios_data(char *buf, u32 offset)
+{
+	void *heap = NULL;
+	struct bios_data *bios_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	bios_data = get_bios_data_start(heap);
+
+	switch (offset) {
+	case off_bios_data_raw:
+		ret = scnprintf(buf, PAGE_SIZE, "@0x%p, 0x%llx\n", bios_data,
+			       *((uint64_t *)bios_data - 1));
+		break;
+
+	case off_bios_data_version:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n", bios_data->version);
+		break;
+
+	case off_bios_sinit_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%x (%u)\n",
+			       bios_data->bios_sinit_size,
+			       bios_data->bios_sinit_size);
+		break;
+
+	case off_lcp_pd_base:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       bios_data->lcp_pd_base);
+		break;
+
+	case off_lcp_pd_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx (%llu)\n",
+			       bios_data->lcp_pd_size,
+			       bios_data->lcp_pd_size);
+		break;
+
+	case off_num_logical_procs:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			       bios_data->num_logical_procs);
+		break;
+
+	case off_flags:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%08llx\n",
+			       bios_data->flags);
+		break;
+
+	case off_bios_elt_major:
+	case off_bios_elt_minor:
+	case off_bios_elt_rev:
+		ret = print_bios_elt(buf, bios_data->ext_data_elts, offset);
+		break;
+
+	case off_acm_elt_num_acms:
+	case off_acm_elt_acm_addrs_index:
+	case off_acm_elt_acm_addrs:
+		ret = print_acm_elt(buf, bios_data->ext_data_elts, offset);
+		break;
+
+	case off_custom_elt_size:
+	case off_custom_elt_uuid:
+		ret = print_custom_elt(buf, bios_data->ext_data_elts, offset);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iounmap(heap);
+	return ret;
+}
+
+static ssize_t show_bios_spec_ver_elt_major(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return show_bios_data(buf, off_bios_elt_major);
+}
+static DEVICE_ATTR(major, S_IRUGO, show_bios_spec_ver_elt_major, NULL);
+
+static ssize_t show_bios_spec_ver_elt_minor(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return show_bios_data(buf, off_bios_elt_minor);
+}
+static DEVICE_ATTR(minor, S_IRUGO, show_bios_spec_ver_elt_minor, NULL);
+
+static ssize_t show_bios_spec_ver_elt_rev(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	return show_bios_data(buf, off_bios_elt_rev);
+}
+static DEVICE_ATTR(rev, S_IRUGO, show_bios_spec_ver_elt_rev, NULL);
+
+static struct attribute *bios_spec_ver_elt_attr[] = {
+	&dev_attr_major.attr,
+	&dev_attr_minor.attr,
+	&dev_attr_rev.attr,
+	NULL,
+};
+
+static struct attribute_group bios_spec_ver_elt_attr_grp = {
+	.attrs = bios_spec_ver_elt_attr
+};
+static ssize_t show_acm_elt_num_acms(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	return show_bios_data(buf, off_acm_elt_num_acms);
+}
+static DEVICE_ATTR(num_acms, S_IRUGO, show_acm_elt_num_acms, NULL);
+
+static ssize_t show_acm_elt_acm_addrs(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_bios_data(buf, off_acm_elt_acm_addrs);
+}
+static DEVICE_ATTR(acm_addrs, S_IRUGO, show_acm_elt_acm_addrs, NULL);
+
+static struct attribute *acm_elt_attr[] = {
+	&dev_attr_num_acms.attr,
+	&dev_attr_acm_addrs.attr,
+	NULL,
+};
+static struct attribute_group acm_elt_attr_grp = {
+	.attrs = acm_elt_attr
+};
+
+static ssize_t show_custom_elt_size(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_bios_data(buf, off_custom_elt_size);
+}
+static DEVICE_ATTR(size, S_IRUGO, show_custom_elt_size, NULL);
+
+static ssize_t show_custom_elt_uuid(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_bios_data(buf, off_custom_elt_uuid);
+}
+static DEVICE_ATTR(uuid, S_IRUGO, show_custom_elt_uuid, NULL);
+
+static struct attribute *custom_elt_attr[] = {
+	&dev_attr_size.attr,
+	&dev_attr_uuid.attr,
+	NULL,
+};
+static struct attribute_group custom_elt_attr_grp = {
+	.attrs = custom_elt_attr
+};
+
+static ssize_t show_bios_data_raw(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_bios_data(buf, off_bios_data_raw);
+}
+static DEVICE_ATTR(bios_data_raw, S_IRUGO, show_bios_data_raw, NULL);
+
+static ssize_t show_bios_data_version(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_bios_data(buf, off_bios_data_version);
+}
+static DEVICE_ATTR(bios_data_version, S_IRUGO, show_bios_data_version, NULL);
+
+static ssize_t show_bios_sinit_size(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_bios_data(buf, off_bios_sinit_size);
+}
+static DEVICE_ATTR(bios_sinit_size, S_IRUGO, show_bios_sinit_size, NULL);
+
+static ssize_t show_lcp_pd_base(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_bios_data(buf, off_lcp_pd_base);
+}
+static DEVICE_ATTR(lcp_pd_base, S_IRUGO, show_lcp_pd_base, NULL);
+
+static ssize_t show_lcp_pd_size(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_bios_data(buf, off_lcp_pd_size);
+}
+static DEVICE_ATTR(lcp_pd_size, S_IRUGO, show_lcp_pd_size, NULL);
+
+static ssize_t show_num_logical_procs(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_bios_data(buf, off_num_logical_procs);
+}
+static DEVICE_ATTR(num_logical_procs, S_IRUGO, show_num_logical_procs, NULL);
+
+static ssize_t show_flags(struct device *dev,
+			  struct device_attribute *attr,
+			  char *buf)
+{
+	return show_bios_data(buf, off_flags);
+}
+static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
+static struct attribute *bios_data_attr[] = {
+	&dev_attr_bios_data_raw.attr,
+	&dev_attr_bios_data_version.attr,
+	&dev_attr_bios_sinit_size.attr,
+	&dev_attr_lcp_pd_base.attr,
+	&dev_attr_lcp_pd_size.attr,
+	&dev_attr_num_logical_procs.attr,
+	NULL,
+};
+
+static struct attribute_group bios_data_attr_grp = {
+	.attrs = bios_data_attr
+};
+
+static ssize_t sysfs_create_bios_data(struct kobject *parent)
+{
+	struct kobject *bios_data_kobj;
+	void *heap;
+	struct bios_data *bios_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	bios_data = get_bios_data_start(heap);
+
+	bios_data_kobj = kobject_create_and_add("bios_data", parent);
+	if (!bios_data_kobj) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sysfs_create_group(bios_data_kobj, &bios_data_attr_grp);
+	if (ret)
+		goto err;
+
+	if (bios_data->version >= 3) {
+		ret = sysfs_create_file(bios_data_kobj, &dev_attr_flags.attr);
+		if (ret)
+			goto err;
+	}
+
+	if (bios_data->version >= 4) {
+		ret = sysfs_create_ext_data_elt(bios_data_kobj,
+						bios_data->ext_data_elts);
+		if (ret)
+			goto err;
+	}
+
+	ret = 0;
+
+err:
+	iounmap(heap);
+	return ret;
+}
+
+/*
+ * OS to MLE Data Format
+ */
+
+static ssize_t show_os_mle_data(char *buf, u32 offset)
+{
+	void *heap;
+	struct os_mle_data *os_mle_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	os_mle_data = get_os_mle_data_start(heap);
+
+	switch (offset) {
+	case off_os_mle_raw:
+		ret = scnprintf(buf, PAGE_SIZE, "@0x%p, 0x%llx\n", os_mle_data,
+			       *((uint64_t *)os_mle_data - 1));
+		break;
+
+	case off_os_mle_version:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n", os_mle_data->version);
+		break;
+
+	case off_mbi:
+		ret = scnprintf(buf, PAGE_SIZE, "%p\n", os_mle_data->mbi);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iounmap(heap);
+	return ret;
+}
+
+static ssize_t show_os_mle_data_raw(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_mle_data(buf, off_os_mle_raw);
+}
+static DEVICE_ATTR(os_mle_data_raw, S_IRUGO, show_os_mle_data_raw, NULL);
+
+static ssize_t show_os_mle_data_version(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return show_os_mle_data(buf, off_os_mle_version);
+}
+static DEVICE_ATTR(os_mle_data_version, S_IRUGO,
+		   show_os_mle_data_version, NULL);
+
+static ssize_t show_mbi(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return show_os_mle_data(buf, off_mbi);
+}
+static DEVICE_ATTR(mbi, S_IRUGO, show_mbi, NULL);
+
+static struct attribute *os_mle_attr[] = {
+	&dev_attr_os_mle_data_raw.attr,
+	&dev_attr_os_mle_data_version.attr,
+	&dev_attr_mbi.attr,
+	NULL,
+};
+
+static struct attribute_group os_mle_attr_grp = {
+	.attrs = os_mle_attr
+};
+
+static ssize_t sysfs_create_os_mle_data(struct kobject *parent)
+{
+	struct kobject *os_mle_data;
+	int ret;
+
+	os_mle_data = kobject_create_and_add("os_mle_data", parent);
+	if (!os_mle_data)
+		return -ENOMEM;
+
+	ret = sysfs_create_group(os_mle_data, &os_mle_attr_grp);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * OS to SINIT Data Format
+ */
+
+static ssize_t show_os_sinit_data(char *buf, u32 offset)
+{
+	void *heap = NULL;
+	struct os_sinit_data *os_sinit_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	os_sinit_data = get_os_sinit_data_start(heap);
+
+	switch (offset) {
+	case off_os_sinit_raw:
+		ret = scnprintf(buf, PAGE_SIZE, "@0x%p, 0x%llx\n",
+			       os_sinit_data,
+			       *((uint64_t *)os_sinit_data - 1));
+		break;
+
+	case off_os_sinit_version:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			       os_sinit_data->version);
+		break;
+
+	case off_mle_ptab:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->mle_ptab);
+		break;
+
+	case off_mle_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx, %llu\n",
+			       os_sinit_data->mle_size,
+			       os_sinit_data->mle_size);
+		break;
+
+	case off_mle_hdr_base:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->mle_hdr_base);
+		break;
+
+	case off_vtd_pmr_lo_base:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->vtd_pmr_lo_base);
+		break;
+
+	case off_vtd_pmr_lo_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->vtd_pmr_lo_size);
+		break;
+
+	case off_vtd_pmr_hi_base:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->vtd_pmr_hi_base);
+		break;
+
+	case off_vtd_pmr_hi_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->vtd_pmr_hi_size);
+		break;
+
+	case off_lcp_po_base:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->lcp_po_base);
+		break;
+
+	case off_lcp_po_size:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx (%llu)\n",
+			       os_sinit_data->lcp_po_size,
+			       os_sinit_data->lcp_po_size);
+		break;
+
+	case off_caps_raw:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+			       os_sinit_data->capabilities._raw);
+		break;
+
+	case off_caps_rlp_wake_getsec:
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       os_sinit_data->capabilities.rlp_wake_getsec);
+		break;
+
+	case off_caps_rlp_wake_monitor:
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       os_sinit_data->capabilities.rlp_wake_monitor);
+		break;
+
+	case off_caps_ecx_pgtbl:
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       os_sinit_data->capabilities.ecx_pgtbl);
+		break;
+
+	case off_caps_pcr_map_no_legacy:
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       os_sinit_data->capabilities.pcr_map_no_legacy);
+		break;
+
+	case off_caps_pcr_map_da:
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n",
+			       os_sinit_data->capabilities.pcr_map_da);
+		break;
+
+	case off_efi_rsdt_ptr:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       os_sinit_data->efi_rsdt_ptr);
+		break;
+
+	case off_event_elt_size:
+	case off_event_elt_addr:
+	case off_event_elt_container:
+	case off_event_elt_events:
+		ret = print_event_elt(buf, os_sinit_data->ext_data_elts,
+				     offset);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iounmap(heap);
+	return ret;
+}
+
+static ssize_t show_event_elt_size(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_os_sinit_data(buf, off_event_elt_size);
+}
+static DEVICE_ATTR(event_log_size, S_IRUGO, show_event_elt_size, NULL);
+
+static ssize_t show_event_elt_addr(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_os_sinit_data(buf, off_event_elt_addr);
+}
+static DEVICE_ATTR(event_log_addr, S_IRUGO, show_event_elt_addr, NULL);
+
+static ssize_t show_event_elt_container(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return show_os_sinit_data(buf, off_event_elt_container);
+}
+static DEVICE_ATTR(event_log_container, S_IRUGO,
+		   show_event_elt_container, NULL);
+
+static ssize_t show_event_elt_events(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	return show_os_sinit_data(buf, off_event_elt_events);
+}
+static DEVICE_ATTR(events, S_IRUGO, show_event_elt_events, NULL);
+
+static struct attribute *event_elt_attr[] = {
+	&dev_attr_event_log_size.attr,
+	&dev_attr_event_log_addr.attr,
+	&dev_attr_event_log_container.attr,
+	&dev_attr_events.attr,
+	NULL,
+};
+
+static struct attribute_group event_elt_attr_grp = {
+	.attrs = event_elt_attr
+};
+
+static ssize_t show_os_sinit_data_raw(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_os_sinit_data(buf, off_os_sinit_raw);
+}
+static DEVICE_ATTR(os_sinit_data_raw, S_IRUGO, show_os_sinit_data_raw, NULL);
+
+static ssize_t show_os_sinit_data_version(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	return show_os_sinit_data(buf, off_os_sinit_version);
+}
+static DEVICE_ATTR(os_sinit_data_version, S_IRUGO,
+		   show_os_sinit_data_version, NULL);
+
+static ssize_t show_mle_ptab(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_os_sinit_data(buf, off_mle_ptab);
+}
+static DEVICE_ATTR(mle_ptab, S_IRUGO, show_mle_ptab, NULL);
+
+static ssize_t show_mle_size(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_os_sinit_data(buf, off_mle_size);
+}
+static DEVICE_ATTR(mle_size, S_IRUGO, show_mle_size, NULL);
+
+static ssize_t show_mle_hdr_base(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_os_sinit_data(buf, off_mle_hdr_base);
+}
+static DEVICE_ATTR(mle_hdr_base, S_IRUGO, show_mle_hdr_base, NULL);
+
+static ssize_t show_vtd_pmr_lo_base(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_sinit_data(buf, off_vtd_pmr_lo_base);
+}
+static DEVICE_ATTR(vtd_pmr_lo_base, S_IRUGO, show_vtd_pmr_lo_base, NULL);
+
+static ssize_t show_vtd_pmr_lo_size(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_sinit_data(buf, off_vtd_pmr_lo_size);
+}
+static DEVICE_ATTR(vtd_pmr_lo_size, S_IRUGO, show_vtd_pmr_lo_size, NULL);
+
+static ssize_t show_vtd_pmr_hi_base(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_sinit_data(buf, off_vtd_pmr_hi_base);
+}
+static DEVICE_ATTR(vtd_pmr_hi_base, S_IRUGO, show_vtd_pmr_hi_base, NULL);
+
+static ssize_t show_vtd_pmr_hi_size(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_sinit_data(buf, off_vtd_pmr_hi_size);
+}
+static DEVICE_ATTR(vtd_pmr_hi_size, S_IRUGO, show_vtd_pmr_hi_size, NULL);
+
+static ssize_t show_lcp_po_base(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_os_sinit_data(buf, off_lcp_po_base);
+}
+static DEVICE_ATTR(lcp_po_base, S_IRUGO, show_lcp_po_base, NULL);
+
+static ssize_t show_lcp_po_size(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_os_sinit_data(buf, off_lcp_po_size);
+}
+static DEVICE_ATTR(lcp_po_size, S_IRUGO, show_lcp_po_size, NULL);
+
+static ssize_t show_caps_raw(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_raw);
+}
+static DEVICE_ATTR(caps_raw, S_IRUGO, show_caps_raw, NULL);
+
+static ssize_t show_caps_rlp_wake_getsec(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_rlp_wake_getsec);
+}
+static DEVICE_ATTR(caps_rlp_wake_getsec, S_IRUGO,
+		   show_caps_rlp_wake_getsec, NULL);
+
+static ssize_t show_caps_rlp_wake_monitor(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_rlp_wake_monitor);
+}
+static DEVICE_ATTR(caps_rlp_wake_monitor, S_IRUGO,
+		   show_caps_rlp_wake_monitor, NULL);
+
+static ssize_t show_caps_ecx_pgtbl(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_ecx_pgtbl);
+}
+static DEVICE_ATTR(caps_ecx_pgtbl, S_IRUGO, show_caps_ecx_pgtbl, NULL);
+
+static ssize_t show_caps_pcr_map_no_legacy(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_pcr_map_no_legacy);
+}
+static DEVICE_ATTR(caps_pcr_map_no_legacy, S_IRUGO,
+		   show_caps_pcr_map_no_legacy, NULL);
+
+static ssize_t show_caps_pcr_map_da(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_os_sinit_data(buf, off_caps_pcr_map_da);
+}
+static DEVICE_ATTR(caps_pcr_map_da, S_IRUGO,
+		   show_caps_pcr_map_da, NULL);
+
+static ssize_t show_efi_rsdt_ptr(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return show_os_sinit_data(buf, off_efi_rsdt_ptr);
+}
+static DEVICE_ATTR(efi_rsdt_ptr, S_IRUGO, show_efi_rsdt_ptr, NULL);
+
+static struct attribute *os_sinit_attr[] = {
+	&dev_attr_os_sinit_data_raw.attr,
+	&dev_attr_os_sinit_data_version.attr,
+	&dev_attr_mle_ptab.attr,
+	&dev_attr_mle_size.attr,
+	&dev_attr_mle_hdr_base.attr,
+	&dev_attr_vtd_pmr_lo_base.attr,
+	&dev_attr_vtd_pmr_lo_size.attr,
+	&dev_attr_vtd_pmr_hi_base.attr,
+	&dev_attr_vtd_pmr_hi_size.attr,
+	&dev_attr_lcp_po_base.attr,
+	&dev_attr_lcp_po_size.attr,
+	&dev_attr_caps_raw.attr,
+	&dev_attr_caps_rlp_wake_getsec.attr,
+	&dev_attr_caps_rlp_wake_monitor.attr,
+	&dev_attr_caps_ecx_pgtbl.attr,
+	&dev_attr_caps_pcr_map_no_legacy.attr,
+	&dev_attr_caps_pcr_map_da.attr,
+	NULL,
+};
+
+static struct attribute_group os_sinit_attr_grp = {
+	.attrs = os_sinit_attr
+};
+
+static ssize_t sysfs_create_os_sinit_data(struct kobject *parent)
+{
+	struct kobject *os_sinit_data_kobj;
+	void *heap;
+	struct os_sinit_data *os_sinit_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	os_sinit_data = get_os_sinit_data_start(heap);
+
+	os_sinit_data_kobj = kobject_create_and_add("os_sinit_data", parent);
+	if (!os_sinit_data_kobj) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sysfs_create_group(os_sinit_data_kobj, &os_sinit_attr_grp);
+	if (ret)
+		goto err;
+
+	if (os_sinit_data->version >= 5) {
+		ret = sysfs_create_file(os_sinit_data_kobj,
+				       &dev_attr_efi_rsdt_ptr.attr);
+		if (ret)
+			goto err;
+	}
+
+	if (os_sinit_data->version >= 6) {
+		ret = sysfs_create_ext_data_elt(os_sinit_data_kobj,
+					       os_sinit_data->ext_data_elts);
+		if (ret)
+			goto err;
+	}
+
+	ret = 0;
+
+err:
+	iounmap(heap);
+	return ret;
+}
+
+/*
+ * SINIT to MLE Data Format
+ */
+
+static ssize_t print_sinit_mdrs(char *buf, struct sinit_mdr mdrs[],
+				uint32_t num)
+{
+	static const char * const mem_types[] = {
+		"GOOD",
+		"SMRAM OVERLAY",
+		"SMRAM NON-OVERLAY",
+		"PCIE EXTENDED CONFIG",
+		"PROTECTED"
+	};
+	uint32_t i;
+	char *str = buf;
+
+	for (i = 0; i < num; i++) {
+		str += scnprintf(str, PAGE_SIZE, "%016llx - %016llx ",
+				 mdrs[i].base, mdrs[i].base + mdrs[i].length);
+		if (mdrs[i].mem_type < sizeof(mem_types)/sizeof(mem_types[0]))
+			str += scnprintf(str, PAGE_SIZE, "(%s)\n",
+					 mem_types[mdrs[i].mem_type]);
+		else
+			str += scnprintf(str, PAGE_SIZE, "(%d)\n",
+					 (int)mdrs[i].mem_type);
+	}
+
+	return str - buf;
+}
+
+static ssize_t show_sinit_mle_data(char *buf, u32 offset)
+{
+	void *heap;
+	struct sinit_mle_data *sinit_mle_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	sinit_mle_data = get_sinit_mle_data_start(heap);
+
+	switch (offset) {
+	case off_sinit_mle_raw:
+		ret = scnprintf(buf, PAGE_SIZE, "@0x%p, 0x%llx\n",
+			       sinit_mle_data,
+			       *((uint64_t *)sinit_mle_data - 1));
+		break;
+
+	case off_sinit_mle_version:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			       sinit_mle_data->version);
+		break;
+
+	case off_bios_acm_id:
+		ret = print_hash(buf, sinit_mle_data->bios_acm_id);
+		break;
+
+	case off_edx_senter_flags:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+			       sinit_mle_data->edx_senter_flags);
+		break;
+
+	case off_mseg_valid:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
+			       sinit_mle_data->mseg_valid);
+		break;
+
+	case off_sinit_hash:
+		ret = print_hash(buf, sinit_mle_data->sinit_hash);
+		break;
+
+	case off_mle_hash:
+		ret = print_hash(buf, sinit_mle_data->mle_hash);
+		break;
+
+	case off_stm_hash:
+		ret = print_hash(buf, sinit_mle_data->stm_hash);
+		break;
+
+	case off_lcp_policy_hash:
+		ret = print_hash(buf, sinit_mle_data->lcp_policy_hash);
+		break;
+
+	case off_lcp_policy_control:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+			       sinit_mle_data->lcp_policy_control);
+		break;
+
+	case off_rlp_wakeup_addr:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%x\n",
+			       sinit_mle_data->rlp_wakeup_addr);
+		break;
+
+	case off_num_mdrs:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			       sinit_mle_data->num_mdrs);
+		break;
+
+	case off_mdrs_off:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%x\n",
+			       sinit_mle_data->mdrs_off);
+		break;
+
+	case off_num_vtd_dmars:
+		ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			       sinit_mle_data->num_vtd_dmars);
+		break;
+
+	case off_vtd_dmars_off:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%x\n",
+			       sinit_mle_data->vtd_dmars_off);
+		break;
+
+	case off_sinit_mdrs:
+	{
+		struct sinit_mdr *mdrs;
+
+		mdrs = (struct sinit_mdr *)(((void *)sinit_mle_data -
+					     sizeof(uint64_t)) +
+					    sinit_mle_data->mdrs_off);
+		ret = print_sinit_mdrs(buf, mdrs, sinit_mle_data->num_mdrs);
+
+		break;
+	}
+
+	case off_proc_scrtm_status:
+		ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+			       sinit_mle_data->proc_scrtm_status);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	iounmap(heap);
+	return ret;
+}
+
+static ssize_t show_sinit_mle_data_raw(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	return show_sinit_mle_data(buf, off_sinit_mle_raw);
+}
+static DEVICE_ATTR(sinit_mle_data_raw, S_IRUGO,
+		   show_sinit_mle_data_raw, NULL);
+
+static ssize_t show_sinit_mle_data_version(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	return show_sinit_mle_data(buf, off_sinit_mle_version);
+}
+static DEVICE_ATTR(sinit_mle_data_version, S_IRUGO,
+		   show_sinit_mle_data_version, NULL);
+
+static ssize_t show_bios_acm_id(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return show_sinit_mle_data(buf, off_bios_acm_id);
+}
+static DEVICE_ATTR(bios_acm_id, S_IRUGO, show_bios_acm_id, NULL);
+
+static ssize_t show_edx_senter_flags(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	return show_sinit_mle_data(buf, off_edx_senter_flags);
+}
+static DEVICE_ATTR(edx_senter_flags, S_IRUGO, show_edx_senter_flags, NULL);
+
+static ssize_t show_mseg_valid(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	return show_sinit_mle_data(buf, off_mseg_valid);
+}
+static DEVICE_ATTR(mseg_valid, S_IRUGO, show_mseg_valid, NULL);
+
+static ssize_t show_sinit_hash(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	return show_sinit_mle_data(buf, off_sinit_hash);
+}
+static DEVICE_ATTR(sinit_hash, S_IRUGO, show_sinit_hash, NULL);
+
+static ssize_t show_mle_hash(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_sinit_mle_data(buf, off_mle_hash);
+}
+static DEVICE_ATTR(mle_hash, S_IRUGO, show_mle_hash, NULL);
+
+static ssize_t show_stm_hash(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return show_sinit_mle_data(buf, off_stm_hash);
+}
+static DEVICE_ATTR(stm_hash, S_IRUGO, show_stm_hash, NULL);
+
+static ssize_t show_lcp_policy_hash(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_sinit_mle_data(buf, off_lcp_policy_hash);
+}
+static DEVICE_ATTR(lcp_policy_hash, S_IRUGO, show_lcp_policy_hash, NULL);
+
+static ssize_t show_lcp_policy_control(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	return show_sinit_mle_data(buf, off_lcp_policy_control);
+}
+static DEVICE_ATTR(lcp_policy_control, S_IRUGO,
+		   show_lcp_policy_control, NULL);
+
+static ssize_t show_rlp_wakeup_addr(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return show_sinit_mle_data(buf, off_rlp_wakeup_addr);
+}
+static DEVICE_ATTR(rlp_wakeup_addr, S_IRUGO, show_rlp_wakeup_addr, NULL);
+
+static ssize_t show_num_mdrs(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_sinit_mle_data(buf, off_num_mdrs);
+}
+static DEVICE_ATTR(num_mdrs, S_IRUGO, show_num_mdrs, NULL);
+
+static ssize_t show_mdrs_off(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	return show_sinit_mle_data(buf, off_mdrs_off);
+}
+static DEVICE_ATTR(mdrs_off, S_IRUGO, show_mdrs_off, NULL);
+
+static ssize_t show_num_vtd_dmars(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_sinit_mle_data(buf, off_num_vtd_dmars);
+}
+static DEVICE_ATTR(num_vtd_dmars, S_IRUGO, show_num_vtd_dmars, NULL);
+
+static ssize_t show_vtd_dmars_off(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	return show_sinit_mle_data(buf, off_vtd_dmars_off);
+}
+static DEVICE_ATTR(vtd_dmars_off, S_IRUGO, show_vtd_dmars_off, NULL);
+
+static ssize_t show_sinit_mdrs(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return show_sinit_mle_data(buf, off_sinit_mdrs);
+}
+static DEVICE_ATTR(sinit_mdrs, S_IRUGO, show_sinit_mdrs, NULL);
+
+static ssize_t show_proc_scrtm_status(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return show_sinit_mle_data(buf, off_proc_scrtm_status);
+}
+static DEVICE_ATTR(proc_scrtm_status, S_IRUGO, show_proc_scrtm_status, NULL);
+
+static struct attribute *sinit_mle_attr[] = {
+	&dev_attr_sinit_mle_data_raw.attr,
+	&dev_attr_sinit_mle_data_version.attr,
+	&dev_attr_bios_acm_id.attr,
+	&dev_attr_edx_senter_flags.attr,
+	&dev_attr_mseg_valid.attr,
+	&dev_attr_sinit_hash.attr,
+	&dev_attr_mle_hash.attr,
+	&dev_attr_stm_hash.attr,
+	&dev_attr_lcp_policy_hash.attr,
+	&dev_attr_lcp_policy_control.attr,
+	&dev_attr_rlp_wakeup_addr.attr,
+	&dev_attr_num_mdrs.attr,
+	&dev_attr_mdrs_off.attr,
+	&dev_attr_num_vtd_dmars.attr,
+	&dev_attr_vtd_dmars_off.attr,
+	&dev_attr_sinit_mdrs.attr,
+	NULL,
+};
+
+static struct attribute_group sinit_mle_attr_grp = {
+	.attrs = sinit_mle_attr
+};
+
+static ssize_t sysfs_create_sinit_mle_data(struct kobject *parent)
+{
+	struct kobject *sinit_mle_data_kobj;
+	void *heap;
+	struct sinit_mle_data *sinit_mle_data;
+	int ret;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	sinit_mle_data = get_sinit_mle_data_start(heap);
+
+	sinit_mle_data_kobj = kobject_create_and_add("sinit_mle_data", parent);
+	if (!sinit_mle_data_kobj) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sysfs_create_group(sinit_mle_data_kobj, &sinit_mle_attr_grp);
+	if (ret)
+		goto err;
+
+	if (sinit_mle_data->version >= 8) {
+		ret = sysfs_create_file(sinit_mle_data_kobj,
+				       &dev_attr_proc_scrtm_status.attr);
+		if (ret)
+			goto err;
+	}
+
+	ret = 0;
+
+err:
+	iounmap(heap);
+	return ret;
+}
+
+/*
+ * Raw Binary Data in Heap Memory
+ */
+
+static ssize_t txt_show_binary_heap(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr, char *buf,
+				    loff_t off, size_t count)
+{
+	void *heap;
+
+	heap = get_txt_heap();
+	if (!heap)
+		return -ENOMEM;
+
+	if (off >= txt_heap_size) {
+		count = 0;
+	} else {
+		if (off + count > txt_heap_size)
+			count = txt_heap_size - off;
+		memcpy_fromio(buf, heap + off, count);
+	}
+
+	iounmap(heap);
+	return count;
+}
+
+static struct bin_attribute heap_bin_attr = {
+	.attr = {
+		.name = "binary_heap",
+		.mode = S_IRUGO,
+	},
+	.size = PAGE_SIZE,
+	.read = txt_show_binary_heap,
+};
+
+ssize_t sysfs_create_heap(struct kobject *parent)
+{
+	struct kobject *heap_kobj;
+	int retval;
+	void *base;
+
+	base = get_txt_heap();
+	if (!base || txt_heap_size == 0)
+		return -ENOMEM;
+
+	heap_bin_attr.size = txt_heap_size;
+	iounmap(base);
+
+	heap_kobj = kobject_create_and_add("heap", parent);
+	if (!heap_kobj)
+		return -ENOMEM;
+
+	retval = sysfs_create_bin_file(heap_kobj, &heap_bin_attr);
+	if (retval)
+		return retval;
+
+	retval = sysfs_create_bios_data(heap_kobj);
+	if (retval)
+		return retval;
+
+	retval = sysfs_create_os_mle_data(heap_kobj);
+	if (retval)
+		return retval;
+
+	retval = sysfs_create_os_sinit_data(heap_kobj);
+	if (retval)
+		return retval;
+
+	retval = sysfs_create_sinit_mle_data(heap_kobj);
+	if (retval)
+		return retval;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_heap);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/char/txt/txt-heap.h b/drivers/char/txt/txt-heap.h
new file mode 100644
index 0000000..b354948
--- /dev/null
+++ b/drivers/char/txt/txt-heap.h
@@ -0,0 +1,338 @@
+#ifndef __HEAP_H__
+#define __HEAP_H__
+
+#define off_bios_data_raw		101
+#define off_bios_data_version		102
+#define off_bios_sinit_size		103
+#define off_lcp_pd_base			104
+#define off_lcp_pd_size			105
+#define off_num_logical_procs		106
+#define off_flags			107
+
+#define off_os_mle_raw			201
+#define off_os_mle_version		202
+#define off_mbi				203
+
+#define off_os_sinit_raw		301
+#define off_os_sinit_version		302
+#define off_mle_ptab			303
+#define off_mle_size			304
+#define off_mle_hdr_base		305
+#define off_vtd_pmr_lo_base		306
+#define off_vtd_pmr_lo_size		307
+#define off_vtd_pmr_hi_base		308
+#define off_vtd_pmr_hi_size		309
+#define off_lcp_po_base			310
+#define off_lcp_po_size			311
+#define off_caps_raw			312
+#define off_caps_rlp_wake_getsec	313
+#define off_caps_rlp_wake_monitor	314
+#define off_caps_ecx_pgtbl		315
+#define off_caps_pcr_map_no_legacy	316
+#define off_caps_pcr_map_da		317
+#define off_efi_rsdt_ptr		318
+
+#define off_sinit_mle_raw		401
+#define off_sinit_mle_version		402
+#define off_bios_acm_id			403
+#define off_edx_senter_flags		404
+#define off_mseg_valid			405
+#define off_sinit_hash			406
+#define off_mle_hash			407
+#define off_stm_hash			408
+#define off_lcp_policy_hash		409
+#define off_lcp_policy_control		410
+#define off_rlp_wakeup_addr		411
+#define off_num_mdrs			412
+#define off_mdrs_off			413
+#define off_num_vtd_dmars		414
+#define off_vtd_dmars_off		415
+#define off_sinit_mdrs			416
+#define off_proc_scrtm_status		417
+
+#define off_bios_elt_major		501
+#define off_bios_elt_minor		502
+#define off_bios_elt_rev		503
+#define off_acm_elt_num_acms		504
+#define off_acm_elt_acm_addrs_index	505
+#define off_acm_elt_acm_addrs		506
+#define off_custom_elt_size		507
+#define off_custom_elt_uuid		508
+#define off_event_elt_size		509
+#define off_event_elt_addr		510
+#define off_event_elt_container		511
+#define off_event_elt_events		512
+
+#define SHA1_LENGTH 20
+
+/*
+ * Extensible TXT heap data structure
+ */
+struct heap_ext_data_element {
+	uint32_t type;
+	uint32_t size;
+	uint8_t  data[];
+} __packed;
+
+/*
+ * HEAP_END_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_END			0
+
+/*
+ * HEAP_BIOS_SPEC_VER_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER		1
+
+struct heap_bios_spec_ver_elt {
+	uint16_t spec_ver_major;
+	uint16_t spec_ver_minor;
+	uint16_t spec_ver_rev;
+} __packed;
+
+/*
+ * HEAP_ACM_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_ACM			2
+
+struct heap_acm_elt {
+	uint32_t num_acms;
+	uint64_t acm_addrs[];
+} __packed;
+
+/*
+ * HEAP_CUSTOM_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_CUSTOM		4
+
+struct heap_custom_elt {
+	struct uuid uuid;
+	uint8_t     data[];
+} __packed;
+
+/*
+ * HEAP_EVENT_LOG_POINTER_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR	5
+
+struct heap_event_log_ptr_elt {
+	uint64_t event_log_phys_addr;
+} __packed;
+
+struct tpm12_pcr_event {
+	uint32_t pcr_index;
+	uint32_t type;
+	uint8_t  digest[SHA1_LENGTH];
+	uint32_t data_size;
+	uint8_t  data[];
+} __packed;
+
+struct event_log_container {
+	uint8_t  signature[20];
+	uint8_t  reserved[12];
+	uint8_t  container_ver_major;
+	uint8_t  container_ver_minor;
+	uint8_t  pcr_event_ver_major;
+	uint8_t  pcr_event_ver_minor;
+	uint32_t size;
+	uint32_t pcr_events_offset;
+	uint32_t next_event_offset;
+	struct tpm12_pcr_event pcr_events[];
+} __packed;
+
+/*
+ * data-passing structures contained in TXT heap:
+ *   - BIOS
+ *   - OS/loader to MLE
+ *   - OS/loader to SINIT
+ *   - SINIT to MLE
+ */
+
+/*
+ * BIOS structure
+ */
+struct bios_data {
+	uint32_t version;
+	uint32_t bios_sinit_size;
+	uint64_t lcp_pd_base;
+	uint64_t lcp_pd_size;
+	uint32_t num_logical_procs;
+	/* versions >= 3 */
+	uint64_t flags;
+	/* versions >= 4 */
+	struct heap_ext_data_element ext_data_elts[];
+} __packed;
+
+/*
+ * OS/loader to MLE structure
+ */
+#define MAX_LCP_PO_DATA_SIZE (64*1024)
+#define MAX_EVENT_LOG_SIZE   (4*1024)
+
+struct os_mle_data {
+	uint32_t version;
+	uint8_t  saved_mtrr_state;
+	uint8_t  *mbi;
+	uint32_t saved_misc_enable_msr;
+	uint8_t  lcp_po_data[MAX_LCP_PO_DATA_SIZE];
+	uint8_t  event_log_buffer[MAX_EVENT_LOG_SIZE];
+} __packed;
+
+/*
+ * SINIT/MLE capabilities
+ */
+union txt_caps {
+	uint32_t _raw;
+	struct {
+		uint32_t rlp_wake_getsec:1;
+		uint32_t rlp_wake_monitor:1;
+		uint32_t ecx_pgtbl:1;
+		uint32_t reserved1:1;
+		uint32_t pcr_map_no_legacy:1;
+		uint32_t pcr_map_da:1;
+		uint32_t reserved2:26;
+	};
+};
+
+/*
+ * OS/loader to SINIT structure
+ */
+struct os_sinit_data {
+	uint32_t version;
+	uint32_t reserved;
+	uint64_t mle_ptab;
+	uint64_t mle_size;
+	uint64_t mle_hdr_base;
+	uint64_t vtd_pmr_lo_base;
+	uint64_t vtd_pmr_lo_size;
+	uint64_t vtd_pmr_hi_base;
+	uint64_t vtd_pmr_hi_size;
+	uint64_t lcp_po_base;
+	uint64_t lcp_po_size;
+	union txt_caps capabilities;
+	/* versions >= 5 */
+	uint64_t    efi_rsdt_ptr;
+	/* versions >= 6 */
+	struct heap_ext_data_element  ext_data_elts[];
+} __packed;
+
+struct sinit_mdr {
+	uint64_t base;
+	uint64_t length;
+	uint8_t  mem_type;
+	uint8_t  reserved[7];
+} __packed;
+
+/*
+ * SINIT to MLE structure
+ */
+struct sinit_mle_data {
+	uint32_t version;
+	uint8_t  bios_acm_id[SHA1_LENGTH];
+	uint32_t edx_senter_flags;
+	uint64_t mseg_valid;
+	uint8_t  sinit_hash[SHA1_LENGTH];
+	uint8_t  mle_hash[SHA1_LENGTH];
+	uint8_t  stm_hash[SHA1_LENGTH];
+	uint8_t  lcp_policy_hash[SHA1_LENGTH];
+	uint32_t lcp_policy_control;
+	uint32_t rlp_wakeup_addr;
+	uint32_t reserved;
+	uint32_t num_mdrs;
+	uint32_t mdrs_off;
+	uint32_t num_vtd_dmars;
+	uint32_t vtd_dmars_off;
+	/* versions >= 8 */
+	uint32_t proc_scrtm_status;
+} __packed;
+
+/*
+ * TXT field accessor fns
+ */
+
+/*
+ * offset                 length                      field
+ * ------                 ------                      -----
+ *  0                     8                          bios_data_size
+ *  8                     bios_data_size - 8         bios_data
+ *
+ *  bios_data_size        8                          os_mle_data_size
+ *  bios_data_size +      os_mle_data_size - 8       os_mle_data
+ *   8
+ *
+ *  bios_data_size +      8                          os_sinit_data_size
+ *   os_mle_data_size
+ *  bios_data_size +      os_sinit_data_size - 8     os_sinit_data
+ *   os_mle_data_size +
+ *   8
+ *
+ *  bios_data_size +      8                          sinit_mle_data_size
+ *   os_mle_data_size +
+ *   os_sinit_data_size
+ *  bios_data_size +      sinit_mle_data_size - 8    sinit_mle_data
+ *   os_mle_data_size +
+ *   os_sinit_data_size +
+ *   8
+ */
+
+static inline uint64_t
+get_bios_data_size(const void *heap)
+{
+	return *(uint64_t *)heap;
+}
+
+static inline struct bios_data *
+get_bios_data_start(const void *heap)
+{
+	return (struct bios_data *)((char *)heap + sizeof(uint64_t));
+}
+
+static inline uint64_t
+get_os_mle_data_size(const void *heap)
+{
+	return *(uint64_t *)(heap + get_bios_data_size(heap));
+}
+
+static inline struct os_mle_data *
+get_os_mle_data_start(const void *heap)
+{
+	return (struct os_mle_data *)(heap + get_bios_data_size(heap) +
+				      sizeof(uint64_t));
+}
+
+static inline uint64_t
+get_os_sinit_data_size(const void *heap)
+{
+	return *(uint64_t *)(heap + get_bios_data_size(heap) +
+			     get_os_mle_data_size(heap));
+}
+
+static inline struct os_sinit_data *
+get_os_sinit_data_start(const void *heap)
+{
+	return (struct os_sinit_data *)(heap + get_bios_data_size(heap) +
+					get_os_mle_data_size(heap) +
+					sizeof(uint64_t));
+}
+
+static inline uint64_t
+get_sinit_mle_data_size(const void *heap)
+{
+	return *(uint64_t *)(heap + get_bios_data_size(heap) +
+			     get_os_mle_data_size(heap) +
+			     get_os_sinit_data_size(heap));
+}
+
+static inline struct sinit_mle_data *
+get_sinit_mle_data_start(const void *heap)
+{
+	return (struct sinit_mle_data *)(heap + get_bios_data_size(heap) +
+					 get_os_mle_data_size(heap) +
+					 get_os_sinit_data_size(heap) +
+					 sizeof(uint64_t));
+}
+
+extern ssize_t sysfs_create_heap(struct kobject *parent);
+
+#endif /* __HEAP_H__ */
+
diff --git a/drivers/char/txt/txt-sysfs.c b/drivers/char/txt/txt-sysfs.c
index 7b092bd..341e0eb 100644
--- a/drivers/char/txt/txt-sysfs.c
+++ b/drivers/char/txt/txt-sysfs.c
@@ -19,6 +19,7 @@
 #include "txt-config.h"
 #include "txt-log.h"
 #include "txt-parameter.h"
+#include "txt-heap.h"
 
 #define DEV_NAME "txt"
 struct platform_device *pdev;
@@ -43,6 +44,10 @@ static int __init txt_sysfs_init(void)
 	if (retval)
 		goto err;
 
+	retval = sysfs_create_heap(&pdev->dev.kobj);
+	if (retval)
+		goto err;
+
 	pr_info("Loading TXT module successfully\n");
 	return 0;
 
-- 
1.7.9.5


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

end of thread, other threads:[~2013-04-27 13:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-27 14:56 [PATCH 0/5] TXT driver Qiaowei Ren
2013-04-27 14:56 ` [PATCH 1/5] driver: add TXT driver in kernel Qiaowei Ren
2013-04-27 13:14   ` Greg Kroah-Hartman
2013-04-27 14:56 ` [PATCH 2/5] driver: provide sysfs interfaces to access TXT config space Qiaowei Ren
2013-04-27 14:56 ` [PATCH 3/5] driver: provide sysfs interfaces to access TXT log Qiaowei Ren
2013-04-27 13:17   ` Greg Kroah-Hartman
2013-04-27 14:56 ` [PATCH 4/5] driver: provide sysfs interfaces to access SMX parameter Qiaowei Ren
2013-04-27 14:56 ` [PATCH 5/5] driver: provide sysfs interfaces to access TXT heap Qiaowei Ren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox