2013-04-27 07:05:41

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 0/5] TXT driver

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


2013-04-27 07:05:45

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 2/5] driver: provide sysfs interfaces to access TXT config space

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 <[email protected]>
Signed-off-by: Xiaoyan Zhang <[email protected]>
Signed-off-by: Gang Wei <[email protected]>
---
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

2013-04-27 07:05:52

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 5/5] driver: provide sysfs interfaces to access TXT heap

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 <[email protected]>
Signed-off-by: Xiaoyan Zhang <[email protected]>
Signed-off-by: Gang Wei <[email protected]>
---
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

2013-04-27 07:05:49

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 4/5] driver: provide sysfs interfaces to access SMX parameter

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 <[email protected]>
Signed-off-by: Xiaoyan Zhang <[email protected]>
Signed-off-by: Gang Wei <[email protected]>
---
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

2013-04-27 07:06:32

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 3/5] driver: provide sysfs interfaces to access TXT log

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

Signed-off-by: Qiaowei Ren <[email protected]>
Signed-off-by: Xiaoyan Zhang <[email protected]>
Signed-off-by: Gang Wei <[email protected]>
---
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

2013-04-27 07:06:50

by Ren Qiaowei

[permalink] [raw]
Subject: [PATCH 1/5] driver: add TXT driver in kernel

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 <[email protected]>
Signed-off-by: Xiaoyan Zhang <[email protected]>
Signed-off-by: Gang Wei <[email protected]>
---
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

2013-04-27 13:14:49

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 1/5] driver: add TXT driver in kernel

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 <[email protected]>
> Signed-off-by: Xiaoyan Zhang <[email protected]>
> Signed-off-by: Gang Wei <[email protected]>
> ---
> 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

2013-04-27 13:17:19

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 3/5] driver: provide sysfs interfaces to access TXT log

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

2013-04-29 14:01:58

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 3/5] driver: provide sysfs interfaces to access TXT log

On Mon, Apr 29, 2013 at 04:47:41PM +0300, Andy Johnson wrote:
> Hello
> ??
> >Oh, and NEVER use "raw" kobjects, by doing that, you know you are >doing
> something wrong in a driver.
>
> May I ask a short question ?what do you mean by ?"raw" kobjects? do you mean
> that?
>
> struct kobject *log_kobj;
>
> is a local variable inside a method and thus this is not?
>
> ok?

I mean "a driver should almost never touch a 'struct kobject' directly,
or define it as a variable to be used."

Use the driver core (i.e. 'struct device' and friends), and not 'struct
kobject'.

thanks,

greg k-h