[PATCH 2/4] driver: provide sysfs interfaces to access TXT config space

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Signed-off-by: Qiaowei Ren <qiaowei.ren@xxxxxxxxx>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@xxxxxxxxx>
Signed-off-by: Gang Wei <gang.wei@xxxxxxxxx>
---
 Documentation/ABI/testing/sysfs-platform-intel-txt |  309 ++++++
 drivers/platform/x86/intel_txt/Makefile            |    2 +-
 drivers/platform/x86/intel_txt/txt-config.c        | 1032 ++++++++++++++++++++
 drivers/platform/x86/intel_txt/txt-config.h        |  138 +++
 drivers/platform/x86/intel_txt/txt-sysfs.c         |   12 +
 5 files changed, 1492 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-txt
 create mode 100644 drivers/platform/x86/intel_txt/txt-config.c
 create mode 100644 drivers/platform/x86/intel_txt/txt-config.h

diff --git a/Documentation/ABI/testing/sysfs-platform-intel-txt b/Documentation/ABI/testing/sysfs-platform-intel-txt
new file mode 100644
index 0000000..fa20a9f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-intel-txt
@@ -0,0 +1,309 @@
+What:		/sys/devices/platform/intel_txt/config/
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	The config/ directory exposes Intel TXT configuration
+		registers. These registers are a subset of chipset registers.
+		They are mapped into two regions of memory, representing the
+		public and private configuration spaces.
+
+		Registers in the private space can only be accessed after a
+		measured environment has been established and before the
+		TXT.CMD.CLOSE-PRIVATE command has been issued. The public space
+		registers are available before, during and after a measured
+		environment launch. All registers are available within both
+		spaces, though with different permissions.
+
+What:		/sys/devices/platform/intel_txt/config/STS_raw
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.STS is the general status register. This read-only register
+		is used by AC modules and the MLE to get the status of various
+		Intel TXT features.
+
+What:		/sys/devices/platform/intel_txt/config/STS_enter_done
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	The chipset sets SENTER.DONE.STS status bit when it sees all
+		of the threads have done an TXT.CYC.SENTER-ACK.
+
+What:		/sys/devices/platform/intel_txt/config/STS_sexit_done
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	SEXIT.DONE.STS status bit is set when all of the bits in the
+		TXT.THREADS.JOIN register are clear. Thus, this bit will be
+		set immediately after reset.
+
+What:		/sys/devices/platform/intel_txt/config/STS_mem_config_lock
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	MEM-CONFIG-LOCK.STS status bit will be set to 1 when the memory
+		configuration has been locked. Cleared by
+		TXT.CMD.UNLOCK.MEMCONFIG or by a system reset.
+
+What:		/sys/devices/platform/intel_txt/config/STS_private_open
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	PRIVATE-OPEN.STS status bit will be set to 1 when
+		TXT.CMD.OPEN-PRIVATE is performed. Cleared by
+		TXT.CMD.CLOSE-PRIVATE or by a system reset.
+
+What:		/sys/devices/platform/intel_txt/config/STS_locality_1_open
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.LOCALITY1.OPEN.STS status bit is set when the
+		TXT.CMD.OPEN.LOCALITY1 command is seen by the chipset.
+		It is cleared on reset or when TXT.CMD.CLOSE.LOCALITY1 is seen.
+
+What:		/sys/devices/platform/intel_txt/config/STS_locality_2_open
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.LOCALITY2.OPEN.STS status bit is set when either the
+		TXT.CMD.OPEN.LOCALITY2 command or the TXT.CMD.OPEN.PRIVATE
+		is seen by the chipset. It is cleared on reset, when either
+		TXT.CMD.CLOSE.LOCALITY2 or TXT.CMD.CLOSE.PRIVATE is seen,
+		and by the GETSEC[SEXIT] instruction.
+
+What:		/sys/devices/platform/intel_txt/config/ESTS_raw
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.ESTS is the error status register which contains status
+		information associated with various error conditions. The
+		contents of this read-only register are preserved across
+		soft resets.
+
+What:		/sys/devices/platform/intel_txt/config/ESTS_intel_txt_reset
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT_RESET.STS bit is set to '1' to indicate that an event
+		occurred which may prevent the proper use of TXT (possibly
+		including a TXT reset).
+
+What:		/sys/devices/platform/intel_txt/config/ERRORCODE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.ERRORCODE register holds the Intel TXT shutdown error code.
+		A soft reset does not clear the contents of this register;
+		a hard reset/power cycle will clear the contents. This was
+		formerly labeled the TXT.CRASH register.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_RESET
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	A write to TXT.CMD.RESET register causes a system reset.
+		This is performed by the processor as part of an Intel TXT
+		shutdown, after writing to the TXT.ERRORCODE register.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_CLOSE_PRIVATE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	A write to TXT.CMD.CLOSE-PRIVATE register causes the Intel
+		TXT-capable chipset private configuration space to be locked.
+		Locality 2 will also be closed. Once locked, conventional
+		memory read/write operations can no longer be used to access
+		these registers. The private configuration space can only be
+		opened for the MLE by successfully executing GETSEC[SENTER].
+
+What:		/sys/devices/platform/intel_txt/config/VER_FSBIF
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.VER.FSBIF register identifies whether the chipset is
+		debug or release fused.
+
+What:		/sys/devices/platform/intel_txt/config/DIDVID_raw
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.DIDVID register contains the vendor, device, and revision
+		IDs for the memory controller or chipset.
+
+What:		/sys/devices/platform/intel_txt/config/DIDVID_vendor_id
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Vendor ID.
+
+What:		/sys/devices/platform/intel_txt/config/DIDVID_device_id
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Device ID.
+
+What:		/sys/devices/platform/intel_txt/config/DIDVID_revision_id
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Revision ID.
+
+What:		/sys/devices/platform/intel_txt/config/VER_QPIIF
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.VER.QPIIF register identifies whether the memory
+		controller or chipset is debug or release fused.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_UNLOCK_MEM_CONFIG
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	When TXT.CMD.UNLOCK-MEM-CONFIG command is invoked, the
+		chipset unlocks all memory configuration registers.
+
+What:		/sys/devices/platform/intel_txt/config/SINIT_BASE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.SINIT.BASE register contains the physical base address
+		of the memory region set aside by the BIOS for loading an
+		SINIT AC module. If BIOS has provided an SINIT AC module,
+		it will be located at this address. System software that
+		provides an SINIT AC module must store it to this location.
+
+What:		/sys/devices/platform/intel_txt/config/SINIT_SIZE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.SINIT.SIZE register contains the size (in bytes) of
+		the memory region set aside by the BIOS for loading an
+		SINIT AC module. This register is initialized by the BIOS.
+
+What:		/sys/devices/platform/intel_txt/config/MLE_JOIN
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Holds a physical address pointer to the base of the join
+		data structure used to initialize RLPs in response to
+		GETSEC[WAKEUP].
+
+What:		/sys/devices/platform/intel_txt/config/HEAP_BASE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.HEAP.BASE register contains the physical base address
+		of the Intel TXT Heap memory region. The BIOS initializes
+		this register.
+
+What:		/sys/devices/platform/intel_txt/config/HEAP_SIZE
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.HEAP.SIZE register contains the size (in bytes) of the
+		Intel TXT Heap memory region. The BIOS initializes this
+		register.
+
+What:		/sys/devices/platform/intel_txt/config/DPR_raw
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	TXT.DPR register defines the DMA Protected Range of memory
+		in which the TXT heap and SINIT region are located.
+
+What:		/sys/devices/platform/intel_txt/config/DPR_lock
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Bits 19:0 are locked down in this register when this Lock
+		bit is set.
+
+What:		/sys/devices/platform/intel_txt/config/DPR_top
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Top address + 1 of DPR.
+
+What:		/sys/devices/platform/intel_txt/config/DPR_size
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	This is the size of memory, in MB, that will be protected from
+		DMA accesses. A value of 0x00 in this field means no additional
+		memory is protected.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_OPEN_LOCALITY1
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.OPEN.LOCALITY1 register "opens" the
+		TPM locality 1 address range, enabling decoding by the chipset
+		and thus access to the TPM.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_CLOSE_LOCALITY1
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.CLOSE.LOCALITY1 register "closes" the
+		TPM locality 1 address range, disabling decoding by the chipset
+		and thus access to the TPM.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_OPEN_LOCALITY2
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.OPEN.LOCALITY2 register "opens" the
+		TPM locality 2 address range, enabling decoding by the chipset
+		and thus access to the TPM.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_CLOSE_LOCALITY2
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.CLOSE.LOCALITY2 register "closes" the
+		TPM locality 2 address range, disabling decoding by the chipset
+		and thus access to the TPM.
+
+What:		/sys/devices/platform/intel_txt/config/PUBLIC_KEY
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	This read-only TXT.PUBLIC.KEY register contains the hash of
+		the public key used for the verification of AC Modules.
+		The size, hash algorithm, and value are specific to the memory
+		controller or chipset.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_SECRETS
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.SECRETS register indicates to the
+		chipset that there are secrets in memory. The chipset tracks
+		this fact with a sticky bit. If the platform reboots with this
+		sticky bit set the BIOS AC module (or BIOS on multiprocessor
+		TXT systems) will scrub memory. The chipset also uses this
+		bit to detect invalid sleep state transitions. If software
+		tries to transition to S3, S4, or S5 while secrets are in
+		memory then the chipset will reset the system.
+
+What:		/sys/devices/platform/intel_txt/config/CMD_NO_SECRETS
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	Writing to this TXT.CMD.NO-SECRETS register indicates there
+		are no secrets in memory.
+
+What:		/sys/devices/platform/intel_txt/config/E2STS_raw
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	This TXT.E2STS register is used to read the status associated
+		with various errors that might be detected.
+
+What:		/sys/devices/platform/intel_txt/config/E2STS_secrets
+Date:		May 2013
+KernelVersion:	3.9
+Contact:	"Qiaowei Ren" <qiaowei.ren@xxxxxxxxx>
+Description:	0 = Chipset acknowledges that no secrets are in memory.
+		1 = Chipset believes that secrets are in memory and will
+		provide reset protection.
diff --git a/drivers/platform/x86/intel_txt/Makefile b/drivers/platform/x86/intel_txt/Makefile
index a130308..8d5258e 100644
--- a/drivers/platform/x86/intel_txt/Makefile
+++ b/drivers/platform/x86/intel_txt/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the intel TXT drivers.
 #
 obj-$(CONFIG_INTEL_TXT_DRIVER) += intel_txt.o
-intel_txt-y := txt-sysfs.o
+intel_txt-y := txt-sysfs.o txt-config.o
diff --git a/drivers/platform/x86/intel_txt/txt-config.c b/drivers/platform/x86/intel_txt/txt-config.c
new file mode 100644
index 0000000..34311a2
--- /dev/null
+++ b/drivers/platform/x86/intel_txt/txt-config.c
@@ -0,0 +1,1032 @@
+/*
+ * 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 = {
+	.name = "config",
+	.attrs = config_attrs
+};
+
+int sysfs_create_config(struct kobject *parent)
+{
+	return sysfs_create_group(parent, &config_attr_grp);
+}
+EXPORT_SYMBOL_GPL(sysfs_create_config);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/platform/x86/intel_txt/txt-config.h b/drivers/platform/x86/intel_txt/txt-config.h
new file mode 100644
index 0000000..d88cc83
--- /dev/null
+++ b/drivers/platform/x86/intel_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 int sysfs_create_config(struct kobject *parent);
+
+#endif /* __CONFIG_H__ */
+
diff --git a/drivers/platform/x86/intel_txt/txt-sysfs.c b/drivers/platform/x86/intel_txt/txt-sysfs.c
index 96efe87..28cc8a2 100644
--- a/drivers/platform/x86/intel_txt/txt-sysfs.c
+++ b/drivers/platform/x86/intel_txt/txt-sysfs.c
@@ -15,16 +15,28 @@
 #include <linux/platform_device.h>
 #include <linux/sysfs.h>
 
+#include "txt-config.h"
+
 #define DEV_NAME "intel_txt"
 static struct platform_device *txt_pdev;
 
 static int __init txt_sysfs_init(void)
 {
+	int retval;
+
 	txt_pdev = platform_device_register_simple(DEV_NAME, -1, NULL, 0);
 	if (IS_ERR(txt_pdev))
 		return PTR_ERR(txt_pdev);
 
+	retval = sysfs_create_config(&txt_pdev->dev.kobj);
+	if (retval)
+		goto err;
+
 	return 0;
+
+err:
+	platform_device_unregister(txt_pdev);
+	return retval;
 }
 
 static void __exit txt_sysfs_exit(void)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux