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

From: Qiaowei Ren
Date: Sat Apr 27 2013 - 03:05:56 EST


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

Signed-off-by: Qiaowei Ren <qiaowei.ren@xxxxxxxxx>
Signed-off-by: Xiaoyan Zhang <xiaoyan.zhang@xxxxxxxxx>
Signed-off-by: Gang Wei <gang.wei@xxxxxxxxx>
---
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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/