From 0bfb23746052168620c5b52f49d8a47c3bb022fa Mon Sep 17 00:00:00 2001 From: Thiebaud Weksteen Date: Thu, 12 Apr 2018 12:13:48 +0200 Subject: tpm: Move eventlog files to a subdirectory Signed-off-by: Thiebaud Weksteen Suggested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/Makefile | 8 +- drivers/char/tpm/eventlog/acpi.c | 112 +++++++++ drivers/char/tpm/eventlog/efi.c | 66 +++++ drivers/char/tpm/eventlog/of.c | 82 ++++++ drivers/char/tpm/eventlog/tpm1.c | 476 +++++++++++++++++++++++++++++++++++ drivers/char/tpm/eventlog/tpm2.c | 209 +++++++++++++++ drivers/char/tpm/tpm1_eventlog.c | 476 ----------------------------------- drivers/char/tpm/tpm2_eventlog.c | 209 --------------- drivers/char/tpm/tpm_eventlog_acpi.c | 112 --------- drivers/char/tpm/tpm_eventlog_efi.c | 66 ----- drivers/char/tpm/tpm_eventlog_of.c | 82 ------ 11 files changed, 949 insertions(+), 949 deletions(-) create mode 100644 drivers/char/tpm/eventlog/acpi.c create mode 100644 drivers/char/tpm/eventlog/efi.c create mode 100644 drivers/char/tpm/eventlog/of.c create mode 100644 drivers/char/tpm/eventlog/tpm1.c create mode 100644 drivers/char/tpm/eventlog/tpm2.c delete mode 100644 drivers/char/tpm/tpm1_eventlog.c delete mode 100644 drivers/char/tpm/tpm2_eventlog.c delete mode 100644 drivers/char/tpm/tpm_eventlog_acpi.c delete mode 100644 drivers/char/tpm/tpm_eventlog_efi.c delete mode 100644 drivers/char/tpm/tpm_eventlog_of.c (limited to 'drivers') diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index acd758381c58b..5dcf5bd35a3d2 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -4,11 +4,11 @@ # obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ - tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \ + tpm-dev-common.o tpmrm-dev.o eventlog/tpm1.o eventlog/tpm2.o \ tpm2-space.o -tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o -tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o -tpm-$(CONFIG_OF) += tpm_eventlog_of.o +tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o +tpm-$(CONFIG_EFI) += eventlog/efi.o +tpm-$(CONFIG_OF) += eventlog/of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c new file mode 100644 index 0000000000000..8476be2e95263 --- /dev/null +++ b/drivers/char/tpm/eventlog/acpi.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2005 IBM Corporation + * + * Authors: + * Seiji Munetoh + * Stefan Berger + * Reiner Sailer + * Kylene Hall + * Nayna Jain + * + * Maintained by: + * + * Access to the event log extended by the TCG BIOS of PC platform + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../tpm.h" + +struct acpi_tcpa { + struct acpi_table_header hdr; + u16 platform_class; + union { + struct client_hdr { + u32 log_max_len __packed; + u64 log_start_addr __packed; + } client; + struct server_hdr { + u16 reserved; + u64 log_max_len __packed; + u64 log_start_addr __packed; + } server; + }; +}; + +/* read binary bios log */ +int tpm_read_log_acpi(struct tpm_chip *chip) +{ + struct acpi_tcpa *buff; + acpi_status status; + void __iomem *virt; + u64 len, start; + struct tpm_bios_log *log; + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return -ENODEV; + + log = &chip->log; + + /* Unfortuntely ACPI does not associate the event log with a specific + * TPM, like PPI. Thus all ACPI TPMs will read the same log. + */ + if (!chip->acpi_dev_handle) + return -ENODEV; + + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ + status = acpi_get_table(ACPI_SIG_TCPA, 1, + (struct acpi_table_header **)&buff); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + switch(buff->platform_class) { + case BIOS_SERVER: + len = buff->server.log_max_len; + start = buff->server.log_start_addr; + break; + case BIOS_CLIENT: + default: + len = buff->client.log_max_len; + start = buff->client.log_start_addr; + break; + } + if (!len) { + dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); + return -EIO; + } + + /* malloc EventLog space */ + log->bios_event_log = kmalloc(len, GFP_KERNEL); + if (!log->bios_event_log) + return -ENOMEM; + + log->bios_event_log_end = log->bios_event_log + len; + + virt = acpi_os_map_iomem(start, len); + if (!virt) + goto err; + + memcpy_fromio(log->bios_event_log, virt, len); + + acpi_os_unmap_iomem(virt, len); + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + +err: + kfree(log->bios_event_log); + log->bios_event_log = NULL; + return -EIO; + +} diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c new file mode 100644 index 0000000000000..e1593c5271a47 --- /dev/null +++ b/drivers/char/tpm/eventlog/efi.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 Google + * + * Authors: + * Thiebaud Weksteen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +#include "../tpm.h" + +/* read binary bios log from EFI configuration table */ +int tpm_read_log_efi(struct tpm_chip *chip) +{ + + struct linux_efi_tpm_eventlog *log_tbl; + struct tpm_bios_log *log; + u32 log_size; + u8 tpm_log_version; + + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) + return -ENODEV; + + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) + return -ENODEV; + + log = &chip->log; + + log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB); + if (!log_tbl) { + pr_err("Could not map UEFI TPM log table !\n"); + return -ENOMEM; + } + + log_size = log_tbl->size; + memunmap(log_tbl); + + log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size, + MEMREMAP_WB); + if (!log_tbl) { + pr_err("Could not map UEFI TPM log table payload!\n"); + return -ENOMEM; + } + + /* malloc EventLog space */ + log->bios_event_log = kmalloc(log_size, GFP_KERNEL); + if (!log->bios_event_log) + goto err_memunmap; + memcpy(log->bios_event_log, log_tbl->log, log_size); + log->bios_event_log_end = log->bios_event_log + log_size; + + tpm_log_version = log_tbl->version; + memunmap(log_tbl); + return tpm_log_version; + +err_memunmap: + memunmap(log_tbl); + return -ENOMEM; +} diff --git a/drivers/char/tpm/eventlog/of.c b/drivers/char/tpm/eventlog/of.c new file mode 100644 index 0000000000000..e1ec532298f02 --- /dev/null +++ b/drivers/char/tpm/eventlog/of.c @@ -0,0 +1,82 @@ +/* + * Copyright 2012 IBM Corporation + * + * Author: Ashley Lai + * Nayna Jain + * + * Maintained by: + * + * Read the event log created by the firmware on PPC64 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include + +#include "../tpm.h" + +int tpm_read_log_of(struct tpm_chip *chip) +{ + struct device_node *np; + const u32 *sizep; + const u64 *basep; + struct tpm_bios_log *log; + u32 size; + u64 base; + + log = &chip->log; + if (chip->dev.parent && chip->dev.parent->of_node) + np = chip->dev.parent->of_node; + else + return -ENODEV; + + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + + sizep = of_get_property(np, "linux,sml-size", NULL); + basep = of_get_property(np, "linux,sml-base", NULL); + if (sizep == NULL && basep == NULL) + return -ENODEV; + if (sizep == NULL || basep == NULL) + return -EIO; + + /* + * For both vtpm/tpm, firmware has log addr and log size in big + * endian format. But in case of vtpm, there is a method called + * sml-handover which is run during kernel init even before + * device tree is setup. This sml-handover function takes care + * of endianness and writes to sml-base and sml-size in little + * endian format. For this reason, vtpm doesn't need conversion + * but physical tpm needs the conversion. + */ + if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) { + size = be32_to_cpup((__force __be32 *)sizep); + base = be64_to_cpup((__force __be64 *)basep); + } else { + size = *sizep; + base = *basep; + } + + if (size == 0) { + dev_warn(&chip->dev, "%s: Event log area empty\n", __func__); + return -EIO; + } + + log->bios_event_log = kmalloc(size, GFP_KERNEL); + if (!log->bios_event_log) + return -ENOMEM; + + log->bios_event_log_end = log->bios_event_log + size; + + memcpy(log->bios_event_log, __va(base), size); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; +} diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c new file mode 100644 index 0000000000000..d6aea3ca950ec --- /dev/null +++ b/drivers/char/tpm/eventlog/tpm1.c @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2005, 2012 IBM Corporation + * + * Authors: + * Kent Yoder + * Seiji Munetoh + * Stefan Berger + * Reiner Sailer + * Kylene Hall + * Nayna Jain + * + * Maintained by: + * + * Access to the event log created by a system's firmware / BIOS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../tpm.h" + + +static const char* tcpa_event_type_strings[] = { + "PREBOOT", + "POST CODE", + "", + "NO ACTION", + "SEPARATOR", + "ACTION", + "EVENT TAG", + "S-CRTM Contents", + "S-CRTM Version", + "CPU Microcode", + "Platform Config Flags", + "Table of Devices", + "Compact Hash", + "IPL", + "IPL Partition Data", + "Non-Host Code", + "Non-Host Config", + "Non-Host Info" +}; + +static const char* tcpa_pc_event_id_strings[] = { + "", + "SMBIOS", + "BIS Certificate", + "POST BIOS ", + "ESCD ", + "CMOS", + "NVRAM", + "Option ROM", + "Option ROM config", + "", + "Option ROM microcode ", + "S-CRTM Version", + "S-CRTM Contents ", + "POST Contents ", + "Table of Devices", +}; + +/* returns pointer to start of pos. entry of tcg log */ +static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + loff_t i; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcpa_event *event; + u32 converted_event_size; + u32 converted_event_type; + + + /* read over *pos measurements */ + for (i = 0; i < *pos; i++) { + event = addr; + + converted_event_size = + do_endian_conversion(event->event_size); + converted_event_type = + do_endian_conversion(event->event_type); + + if ((addr + sizeof(struct tcpa_event)) < limit) { + if ((converted_event_type == 0) && + (converted_event_size == 0)) + return NULL; + addr += (sizeof(struct tcpa_event) + + converted_event_size); + } + } + + /* now check if current entry is valid */ + if ((addr + sizeof(struct tcpa_event)) >= limit) + return NULL; + + event = addr; + + converted_event_size = do_endian_conversion(event->event_size); + converted_event_type = do_endian_conversion(event->event_type); + + if (((converted_event_type == 0) && (converted_event_size == 0)) + || ((addr + sizeof(struct tcpa_event) + converted_event_size) + >= limit)) + return NULL; + + return addr; +} + +static void *tpm_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcpa_event *event = v; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *limit = log->bios_event_log_end; + u32 converted_event_size; + u32 converted_event_type; + + converted_event_size = do_endian_conversion(event->event_size); + + v += sizeof(struct tcpa_event) + converted_event_size; + + /* now check if current entry is valid */ + if ((v + sizeof(struct tcpa_event)) >= limit) + return NULL; + + event = v; + + converted_event_size = do_endian_conversion(event->event_size); + converted_event_type = do_endian_conversion(event->event_type); + + if (((converted_event_type == 0) && (converted_event_size == 0)) || + ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int get_event_name(char *dest, struct tcpa_event *event, + unsigned char * event_entry) +{ + const char *name = ""; + /* 41 so there is room for 40 data and 1 nul */ + char data[41] = ""; + int i, n_len = 0, d_len = 0; + struct tcpa_pc_event *pc_event; + + switch (do_endian_conversion(event->event_type)) { + case PREBOOT: + case POST_CODE: + case UNUSED: + case NO_ACTION: + case SCRTM_CONTENTS: + case SCRTM_VERSION: + case CPU_MICROCODE: + case PLATFORM_CONFIG_FLAGS: + case TABLE_OF_DEVICES: + case COMPACT_HASH: + case IPL: + case IPL_PARTITION_DATA: + case NONHOST_CODE: + case NONHOST_CONFIG: + case NONHOST_INFO: + name = tcpa_event_type_strings[do_endian_conversion + (event->event_type)]; + n_len = strlen(name); + break; + case SEPARATOR: + case ACTION: + if (MAX_TEXT_EVENT > + do_endian_conversion(event->event_size)) { + name = event_entry; + n_len = do_endian_conversion(event->event_size); + } + break; + case EVENT_TAG: + pc_event = (struct tcpa_pc_event *)event_entry; + + /* ToDo Row data -> Base64 */ + + switch (do_endian_conversion(pc_event->event_id)) { + case SMBIOS: + case BIS_CERT: + case CMOS: + case NVRAM: + case OPTION_ROM_EXEC: + case OPTION_ROM_CONFIG: + case S_CRTM_VERSION: + name = tcpa_pc_event_id_strings[do_endian_conversion + (pc_event->event_id)]; + n_len = strlen(name); + break; + /* hash data */ + case POST_BIOS_ROM: + case ESCD: + case OPTION_ROM_MICROCODE: + case S_CRTM_CONTENTS: + case POST_CONTENTS: + name = tcpa_pc_event_id_strings[do_endian_conversion + (pc_event->event_id)]; + n_len = strlen(name); + for (i = 0; i < 20; i++) + d_len += sprintf(&data[2*i], "%02x", + pc_event->event_data[i]); + break; + default: + break; + } + default: + break; + } + + return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", + n_len, name, d_len, data); + +} + +static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + struct tcpa_event *event = v; + struct tcpa_event temp_event; + char *temp_ptr; + int i; + + memcpy(&temp_event, event, sizeof(struct tcpa_event)); + + /* convert raw integers for endianness */ + temp_event.pcr_index = do_endian_conversion(event->pcr_index); + temp_event.event_type = do_endian_conversion(event->event_type); + temp_event.event_size = do_endian_conversion(event->event_size); + + temp_ptr = (char *) &temp_event; + + for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++) + seq_putc(m, temp_ptr[i]); + + temp_ptr = (char *) v; + + for (i = (sizeof(struct tcpa_event) - 1); + i < (sizeof(struct tcpa_event) + temp_event.event_size); i++) + seq_putc(m, temp_ptr[i]); + + return 0; + +} + +static int tpm_bios_measurements_release(struct inode *inode, + struct file *file) +{ + struct seq_file *seq = (struct seq_file *)file->private_data; + struct tpm_chip *chip = (struct tpm_chip *)seq->private; + + put_device(&chip->dev); + + return seq_release(inode, file); +} + +static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) +{ + int len = 0; + char *eventname; + struct tcpa_event *event = v; + unsigned char *event_entry = + (unsigned char *)(v + sizeof(struct tcpa_event)); + + eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); + if (!eventname) { + printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", + __func__); + return -EFAULT; + } + + /* 1st: PCR */ + seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index)); + + /* 2nd: SHA1 */ + seq_printf(m, "%20phN", event->pcr_value); + + /* 3rd: event type identifier */ + seq_printf(m, " %02x", do_endian_conversion(event->event_type)); + + len += get_event_name(eventname, event, event_entry); + + /* 4th: eventname <= max + \'0' delimiter */ + seq_printf(m, " %s\n", eventname); + + kfree(eventname); + return 0; +} + +static const struct seq_operations tpm_ascii_b_measurements_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_ascii_bios_measurements_show, +}; + +static const struct seq_operations tpm_binary_b_measurements_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_binary_bios_measurements_show, +}; + +static int tpm_bios_measurements_open(struct inode *inode, + struct file *file) +{ + int err; + struct seq_file *seq; + struct tpm_chip_seqops *chip_seqops; + const struct seq_operations *seqops; + struct tpm_chip *chip; + + inode_lock(inode); + if (!inode->i_private) { + inode_unlock(inode); + return -ENODEV; + } + chip_seqops = (struct tpm_chip_seqops *)inode->i_private; + seqops = chip_seqops->seqops; + chip = chip_seqops->chip; + get_device(&chip->dev); + inode_unlock(inode); + + /* now register seq file */ + err = seq_open(file, seqops); + if (!err) { + seq = file->private_data; + seq->private = chip; + } + + return err; +} + +static const struct file_operations tpm_bios_measurements_ops = { + .owner = THIS_MODULE, + .open = tpm_bios_measurements_open, + .read = seq_read, + .llseek = seq_lseek, + .release = tpm_bios_measurements_release, +}; + +static int tpm_read_log(struct tpm_chip *chip) +{ + int rc; + + if (chip->log.bios_event_log != NULL) { + dev_dbg(&chip->dev, + "%s: ERROR - event log already initialized\n", + __func__); + return -EFAULT; + } + + rc = tpm_read_log_acpi(chip); + if (rc != -ENODEV) + return rc; + + rc = tpm_read_log_efi(chip); + if (rc != -ENODEV) + return rc; + + return tpm_read_log_of(chip); +} + +/* + * tpm_bios_log_setup() - Read the event log from the firmware + * @chip: TPM chip to use. + * + * If an event log is found then the securityfs files are setup to + * export it to userspace, otherwise nothing is done. + * + * Returns -ENODEV if the firmware has no event log or securityfs is not + * supported. + */ +int tpm_bios_log_setup(struct tpm_chip *chip) +{ + const char *name = dev_name(&chip->dev); + unsigned int cnt; + int log_version; + int rc = 0; + + rc = tpm_read_log(chip); + if (rc < 0) + return rc; + log_version = rc; + + cnt = 0; + chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); + /* NOTE: securityfs_create_dir can return ENODEV if securityfs is + * compiled out. The caller should ignore the ENODEV return code. + */ + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; + + chip->bin_log_seqops.chip = chip; + if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + chip->bin_log_seqops.seqops = + &tpm2_binary_b_measurements_seqops; + else + chip->bin_log_seqops.seqops = + &tpm_binary_b_measurements_seqops; + + + chip->bios_dir[cnt] = + securityfs_create_file("binary_bios_measurements", + 0440, chip->bios_dir[0], + (void *)&chip->bin_log_seqops, + &tpm_bios_measurements_ops); + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; + + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + + chip->ascii_log_seqops.chip = chip; + chip->ascii_log_seqops.seqops = + &tpm_ascii_b_measurements_seqops; + + chip->bios_dir[cnt] = + securityfs_create_file("ascii_bios_measurements", + 0440, chip->bios_dir[0], + (void *)&chip->ascii_log_seqops, + &tpm_bios_measurements_ops); + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; + } + + return 0; + +err: + rc = PTR_ERR(chip->bios_dir[cnt]); + chip->bios_dir[cnt] = NULL; + tpm_bios_log_teardown(chip); + return rc; +} + +void tpm_bios_log_teardown(struct tpm_chip *chip) +{ + int i; + struct inode *inode; + + /* securityfs_remove currently doesn't take care of handling sync + * between removal and opening of pseudo files. To handle this, a + * workaround is added by making i_private = NULL here during removal + * and to check it during open(), both within inode_lock()/unlock(). + * This design ensures that open() either safely gets kref or fails. + */ + for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { + if (chip->bios_dir[i]) { + inode = d_inode(chip->bios_dir[i]); + inode_lock(inode); + inode->i_private = NULL; + inode_unlock(inode); + securityfs_remove(chip->bios_dir[i]); + } + } +} diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c new file mode 100644 index 0000000000000..f0723fa9ae144 --- /dev/null +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2016 IBM Corporation + * + * Authors: + * Nayna Jain + * + * Access to TPM 2.0 event log as written by Firmware. + * It assumes that writer of event log has followed TCG Specification + * for Family "2.0" and written the event data in little endian. + * With that, it doesn't need any endian conversion for structure + * content. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "../tpm.h" + +/* + * calc_tpm2_event_size() - calculate the event size, where event + * is an entry in the TPM 2.0 event log. The event is of type Crypto + * Agile Log Entry Format as defined in TCG EFI Protocol Specification + * Family "2.0". + + * @event: event whose size is to be calculated. + * @event_header: the first event in the event log. + * + * Returns size of the event. If it is an invalid event, returns 0. + */ +static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, + struct tcg_pcr_event *event_header) +{ + struct tcg_efi_specid_event *efispecid; + struct tcg_event_field *event_field; + void *marker; + void *marker_start; + u32 halg_size; + size_t size; + u16 halg; + int i; + int j; + + marker = event; + marker_start = marker; + marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) + + sizeof(event->count); + + efispecid = (struct tcg_efi_specid_event *)event_header->event; + + /* Check if event is malformed. */ + if (event->count > efispecid->num_algs) + return 0; + + for (i = 0; i < event->count; i++) { + halg_size = sizeof(event->digests[i].alg_id); + memcpy(&halg, marker, halg_size); + marker = marker + halg_size; + for (j = 0; j < efispecid->num_algs; j++) { + if (halg == efispecid->digest_sizes[j].alg_id) { + marker += + efispecid->digest_sizes[j].digest_size; + break; + } + } + /* Algorithm without known length. Such event is unparseable. */ + if (j == efispecid->num_algs) + return 0; + } + + event_field = (struct tcg_event_field *)marker; + marker = marker + sizeof(event_field->event_size) + + event_field->event_size; + size = marker - marker_start; + + if ((event->event_type == 0) && (event_field->event_size == 0)) + return 0; + + return size; +} + +static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2 *event; + size_t size; + int i; + + event_header = addr; + size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) + + event_header->event_size; + + if (*pos == 0) { + if (addr + size < limit) { + if ((event_header->event_type == 0) && + (event_header->event_size == 0)) + return NULL; + return SEQ_START_TOKEN; + } + } + + if (*pos > 0) { + addr += size; + event = addr; + size = calc_tpm2_event_size(event, event_header); + if ((addr + size >= limit) || (size == 0)) + return NULL; + } + + for (i = 0; i < (*pos - 1); i++) { + event = addr; + size = calc_tpm2_event_size(event, event_header); + + if ((addr + size >= limit) || (size == 0)) + return NULL; + addr += size; + } + + return addr; +} + +static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2 *event; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *limit = log->bios_event_log_end; + size_t event_size; + void *marker; + + event_header = log->bios_event_log; + + if (v == SEQ_START_TOKEN) { + event_size = sizeof(struct tcg_pcr_event) - + sizeof(event_header->event) + event_header->event_size; + marker = event_header; + } else { + event = v; + event_size = calc_tpm2_event_size(event, event_header); + if (event_size == 0) + return NULL; + marker = event; + } + + marker = marker + event_size; + if (marker >= limit) + return NULL; + v = marker; + event = v; + + event_size = calc_tpm2_event_size(event, event_header); + if (((v + event_size) >= limit) || (event_size == 0)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + struct tcg_pcr_event *event_header = log->bios_event_log; + struct tcg_pcr_event2 *event = v; + void *temp_ptr; + size_t size; + + if (v == SEQ_START_TOKEN) { + size = sizeof(struct tcg_pcr_event) - + sizeof(event_header->event) + event_header->event_size; + + temp_ptr = event_header; + + if (size > 0) + seq_write(m, temp_ptr, size); + } else { + size = calc_tpm2_event_size(event, event_header); + temp_ptr = event; + if (size > 0) + seq_write(m, temp_ptr, size); + } + + return 0; +} + +const struct seq_operations tpm2_binary_b_measurements_seqops = { + .start = tpm2_bios_measurements_start, + .next = tpm2_bios_measurements_next, + .stop = tpm2_bios_measurements_stop, + .show = tpm2_binary_bios_measurements_show, +}; diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c deleted file mode 100644 index add798bd69d0f..0000000000000 --- a/drivers/char/tpm/tpm1_eventlog.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (C) 2005, 2012 IBM Corporation - * - * Authors: - * Kent Yoder - * Seiji Munetoh - * Stefan Berger - * Reiner Sailer - * Kylene Hall - * Nayna Jain - * - * Maintained by: - * - * Access to the event log created by a system's firmware / BIOS - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "tpm.h" - - -static const char* tcpa_event_type_strings[] = { - "PREBOOT", - "POST CODE", - "", - "NO ACTION", - "SEPARATOR", - "ACTION", - "EVENT TAG", - "S-CRTM Contents", - "S-CRTM Version", - "CPU Microcode", - "Platform Config Flags", - "Table of Devices", - "Compact Hash", - "IPL", - "IPL Partition Data", - "Non-Host Code", - "Non-Host Config", - "Non-Host Info" -}; - -static const char* tcpa_pc_event_id_strings[] = { - "", - "SMBIOS", - "BIS Certificate", - "POST BIOS ", - "ESCD ", - "CMOS", - "NVRAM", - "Option ROM", - "Option ROM config", - "", - "Option ROM microcode ", - "S-CRTM Version", - "S-CRTM Contents ", - "POST Contents ", - "Table of Devices", -}; - -/* returns pointer to start of pos. entry of tcg log */ -static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) -{ - loff_t i; - struct tpm_chip *chip = m->private; - struct tpm_bios_log *log = &chip->log; - void *addr = log->bios_event_log; - void *limit = log->bios_event_log_end; - struct tcpa_event *event; - u32 converted_event_size; - u32 converted_event_type; - - - /* read over *pos measurements */ - for (i = 0; i < *pos; i++) { - event = addr; - - converted_event_size = - do_endian_conversion(event->event_size); - converted_event_type = - do_endian_conversion(event->event_type); - - if ((addr + sizeof(struct tcpa_event)) < limit) { - if ((converted_event_type == 0) && - (converted_event_size == 0)) - return NULL; - addr += (sizeof(struct tcpa_event) + - converted_event_size); - } - } - - /* now check if current entry is valid */ - if ((addr + sizeof(struct tcpa_event)) >= limit) - return NULL; - - event = addr; - - converted_event_size = do_endian_conversion(event->event_size); - converted_event_type = do_endian_conversion(event->event_type); - - if (((converted_event_type == 0) && (converted_event_size == 0)) - || ((addr + sizeof(struct tcpa_event) + converted_event_size) - >= limit)) - return NULL; - - return addr; -} - -static void *tpm_bios_measurements_next(struct seq_file *m, void *v, - loff_t *pos) -{ - struct tcpa_event *event = v; - struct tpm_chip *chip = m->private; - struct tpm_bios_log *log = &chip->log; - void *limit = log->bios_event_log_end; - u32 converted_event_size; - u32 converted_event_type; - - converted_event_size = do_endian_conversion(event->event_size); - - v += sizeof(struct tcpa_event) + converted_event_size; - - /* now check if current entry is valid */ - if ((v + sizeof(struct tcpa_event)) >= limit) - return NULL; - - event = v; - - converted_event_size = do_endian_conversion(event->event_size); - converted_event_type = do_endian_conversion(event->event_type); - - if (((converted_event_type == 0) && (converted_event_size == 0)) || - ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit)) - return NULL; - - (*pos)++; - return v; -} - -static void tpm_bios_measurements_stop(struct seq_file *m, void *v) -{ -} - -static int get_event_name(char *dest, struct tcpa_event *event, - unsigned char * event_entry) -{ - const char *name = ""; - /* 41 so there is room for 40 data and 1 nul */ - char data[41] = ""; - int i, n_len = 0, d_len = 0; - struct tcpa_pc_event *pc_event; - - switch (do_endian_conversion(event->event_type)) { - case PREBOOT: - case POST_CODE: - case UNUSED: - case NO_ACTION: - case SCRTM_CONTENTS: - case SCRTM_VERSION: - case CPU_MICROCODE: - case PLATFORM_CONFIG_FLAGS: - case TABLE_OF_DEVICES: - case COMPACT_HASH: - case IPL: - case IPL_PARTITION_DATA: - case NONHOST_CODE: - case NONHOST_CONFIG: - case NONHOST_INFO: - name = tcpa_event_type_strings[do_endian_conversion - (event->event_type)]; - n_len = strlen(name); - break; - case SEPARATOR: - case ACTION: - if (MAX_TEXT_EVENT > - do_endian_conversion(event->event_size)) { - name = event_entry; - n_len = do_endian_conversion(event->event_size); - } - break; - case EVENT_TAG: - pc_event = (struct tcpa_pc_event *)event_entry; - - /* ToDo Row data -> Base64 */ - - switch (do_endian_conversion(pc_event->event_id)) { - case SMBIOS: - case BIS_CERT: - case CMOS: - case NVRAM: - case OPTION_ROM_EXEC: - case OPTION_ROM_CONFIG: - case S_CRTM_VERSION: - name = tcpa_pc_event_id_strings[do_endian_conversion - (pc_event->event_id)]; - n_len = strlen(name); - break; - /* hash data */ - case POST_BIOS_ROM: - case ESCD: - case OPTION_ROM_MICROCODE: - case S_CRTM_CONTENTS: - case POST_CONTENTS: - name = tcpa_pc_event_id_strings[do_endian_conversion - (pc_event->event_id)]; - n_len = strlen(name); - for (i = 0; i < 20; i++) - d_len += sprintf(&data[2*i], "%02x", - pc_event->event_data[i]); - break; - default: - break; - } - default: - break; - } - - return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", - n_len, name, d_len, data); - -} - -static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) -{ - struct tcpa_event *event = v; - struct tcpa_event temp_event; - char *temp_ptr; - int i; - - memcpy(&temp_event, event, sizeof(struct tcpa_event)); - - /* convert raw integers for endianness */ - temp_event.pcr_index = do_endian_conversion(event->pcr_index); - temp_event.event_type = do_endian_conversion(event->event_type); - temp_event.event_size = do_endian_conversion(event->event_size); - - temp_ptr = (char *) &temp_event; - - for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++) - seq_putc(m, temp_ptr[i]); - - temp_ptr = (char *) v; - - for (i = (sizeof(struct tcpa_event) - 1); - i < (sizeof(struct tcpa_event) + temp_event.event_size); i++) - seq_putc(m, temp_ptr[i]); - - return 0; - -} - -static int tpm_bios_measurements_release(struct inode *inode, - struct file *file) -{ - struct seq_file *seq = (struct seq_file *)file->private_data; - struct tpm_chip *chip = (struct tpm_chip *)seq->private; - - put_device(&chip->dev); - - return seq_release(inode, file); -} - -static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) -{ - int len = 0; - char *eventname; - struct tcpa_event *event = v; - unsigned char *event_entry = - (unsigned char *)(v + sizeof(struct tcpa_event)); - - eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); - if (!eventname) { - printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", - __func__); - return -EFAULT; - } - - /* 1st: PCR */ - seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index)); - - /* 2nd: SHA1 */ - seq_printf(m, "%20phN", event->pcr_value); - - /* 3rd: event type identifier */ - seq_printf(m, " %02x", do_endian_conversion(event->event_type)); - - len += get_event_name(eventname, event, event_entry); - - /* 4th: eventname <= max + \'0' delimiter */ - seq_printf(m, " %s\n", eventname); - - kfree(eventname); - return 0; -} - -static const struct seq_operations tpm_ascii_b_measurements_seqops = { - .start = tpm_bios_measurements_start, - .next = tpm_bios_measurements_next, - .stop = tpm_bios_measurements_stop, - .show = tpm_ascii_bios_measurements_show, -}; - -static const struct seq_operations tpm_binary_b_measurements_seqops = { - .start = tpm_bios_measurements_start, - .next = tpm_bios_measurements_next, - .stop = tpm_bios_measurements_stop, - .show = tpm_binary_bios_measurements_show, -}; - -static int tpm_bios_measurements_open(struct inode *inode, - struct file *file) -{ - int err; - struct seq_file *seq; - struct tpm_chip_seqops *chip_seqops; - const struct seq_operations *seqops; - struct tpm_chip *chip; - - inode_lock(inode); - if (!inode->i_private) { - inode_unlock(inode); - return -ENODEV; - } - chip_seqops = (struct tpm_chip_seqops *)inode->i_private; - seqops = chip_seqops->seqops; - chip = chip_seqops->chip; - get_device(&chip->dev); - inode_unlock(inode); - - /* now register seq file */ - err = seq_open(file, seqops); - if (!err) { - seq = file->private_data; - seq->private = chip; - } - - return err; -} - -static const struct file_operations tpm_bios_measurements_ops = { - .owner = THIS_MODULE, - .open = tpm_bios_measurements_open, - .read = seq_read, - .llseek = seq_lseek, - .release = tpm_bios_measurements_release, -}; - -static int tpm_read_log(struct tpm_chip *chip) -{ - int rc; - - if (chip->log.bios_event_log != NULL) { - dev_dbg(&chip->dev, - "%s: ERROR - event log already initialized\n", - __func__); - return -EFAULT; - } - - rc = tpm_read_log_acpi(chip); - if (rc != -ENODEV) - return rc; - - rc = tpm_read_log_efi(chip); - if (rc != -ENODEV) - return rc; - - return tpm_read_log_of(chip); -} - -/* - * tpm_bios_log_setup() - Read the event log from the firmware - * @chip: TPM chip to use. - * - * If an event log is found then the securityfs files are setup to - * export it to userspace, otherwise nothing is done. - * - * Returns -ENODEV if the firmware has no event log or securityfs is not - * supported. - */ -int tpm_bios_log_setup(struct tpm_chip *chip) -{ - const char *name = dev_name(&chip->dev); - unsigned int cnt; - int log_version; - int rc = 0; - - rc = tpm_read_log(chip); - if (rc < 0) - return rc; - log_version = rc; - - cnt = 0; - chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); - /* NOTE: securityfs_create_dir can return ENODEV if securityfs is - * compiled out. The caller should ignore the ENODEV return code. - */ - if (IS_ERR(chip->bios_dir[cnt])) - goto err; - cnt++; - - chip->bin_log_seqops.chip = chip; - if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) - chip->bin_log_seqops.seqops = - &tpm2_binary_b_measurements_seqops; - else - chip->bin_log_seqops.seqops = - &tpm_binary_b_measurements_seqops; - - - chip->bios_dir[cnt] = - securityfs_create_file("binary_bios_measurements", - 0440, chip->bios_dir[0], - (void *)&chip->bin_log_seqops, - &tpm_bios_measurements_ops); - if (IS_ERR(chip->bios_dir[cnt])) - goto err; - cnt++; - - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - - chip->ascii_log_seqops.chip = chip; - chip->ascii_log_seqops.seqops = - &tpm_ascii_b_measurements_seqops; - - chip->bios_dir[cnt] = - securityfs_create_file("ascii_bios_measurements", - 0440, chip->bios_dir[0], - (void *)&chip->ascii_log_seqops, - &tpm_bios_measurements_ops); - if (IS_ERR(chip->bios_dir[cnt])) - goto err; - cnt++; - } - - return 0; - -err: - rc = PTR_ERR(chip->bios_dir[cnt]); - chip->bios_dir[cnt] = NULL; - tpm_bios_log_teardown(chip); - return rc; -} - -void tpm_bios_log_teardown(struct tpm_chip *chip) -{ - int i; - struct inode *inode; - - /* securityfs_remove currently doesn't take care of handling sync - * between removal and opening of pseudo files. To handle this, a - * workaround is added by making i_private = NULL here during removal - * and to check it during open(), both within inode_lock()/unlock(). - * This design ensures that open() either safely gets kref or fails. - */ - for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { - if (chip->bios_dir[i]) { - inode = d_inode(chip->bios_dir[i]); - inode_lock(inode); - inode->i_private = NULL; - inode_unlock(inode); - securityfs_remove(chip->bios_dir[i]); - } - } -} diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c deleted file mode 100644 index 1ce4411292ba9..0000000000000 --- a/drivers/char/tpm/tpm2_eventlog.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2016 IBM Corporation - * - * Authors: - * Nayna Jain - * - * Access to TPM 2.0 event log as written by Firmware. - * It assumes that writer of event log has followed TCG Specification - * for Family "2.0" and written the event data in little endian. - * With that, it doesn't need any endian conversion for structure - * content. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include "tpm.h" - -/* - * calc_tpm2_event_size() - calculate the event size, where event - * is an entry in the TPM 2.0 event log. The event is of type Crypto - * Agile Log Entry Format as defined in TCG EFI Protocol Specification - * Family "2.0". - - * @event: event whose size is to be calculated. - * @event_header: the first event in the event log. - * - * Returns size of the event. If it is an invalid event, returns 0. - */ -static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, - struct tcg_pcr_event *event_header) -{ - struct tcg_efi_specid_event *efispecid; - struct tcg_event_field *event_field; - void *marker; - void *marker_start; - u32 halg_size; - size_t size; - u16 halg; - int i; - int j; - - marker = event; - marker_start = marker; - marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) - + sizeof(event->count); - - efispecid = (struct tcg_efi_specid_event *)event_header->event; - - /* Check if event is malformed. */ - if (event->count > efispecid->num_algs) - return 0; - - for (i = 0; i < event->count; i++) { - halg_size = sizeof(event->digests[i].alg_id); - memcpy(&halg, marker, halg_size); - marker = marker + halg_size; - for (j = 0; j < efispecid->num_algs; j++) { - if (halg == efispecid->digest_sizes[j].alg_id) { - marker += - efispecid->digest_sizes[j].digest_size; - break; - } - } - /* Algorithm without known length. Such event is unparseable. */ - if (j == efispecid->num_algs) - return 0; - } - - event_field = (struct tcg_event_field *)marker; - marker = marker + sizeof(event_field->event_size) - + event_field->event_size; - size = marker - marker_start; - - if ((event->event_type == 0) && (event_field->event_size == 0)) - return 0; - - return size; -} - -static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) -{ - struct tpm_chip *chip = m->private; - struct tpm_bios_log *log = &chip->log; - void *addr = log->bios_event_log; - void *limit = log->bios_event_log_end; - struct tcg_pcr_event *event_header; - struct tcg_pcr_event2 *event; - size_t size; - int i; - - event_header = addr; - size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) - + event_header->event_size; - - if (*pos == 0) { - if (addr + size < limit) { - if ((event_header->event_type == 0) && - (event_header->event_size == 0)) - return NULL; - return SEQ_START_TOKEN; - } - } - - if (*pos > 0) { - addr += size; - event = addr; - size = calc_tpm2_event_size(event, event_header); - if ((addr + size >= limit) || (size == 0)) - return NULL; - } - - for (i = 0; i < (*pos - 1); i++) { - event = addr; - size = calc_tpm2_event_size(event, event_header); - - if ((addr + size >= limit) || (size == 0)) - return NULL; - addr += size; - } - - return addr; -} - -static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, - loff_t *pos) -{ - struct tcg_pcr_event *event_header; - struct tcg_pcr_event2 *event; - struct tpm_chip *chip = m->private; - struct tpm_bios_log *log = &chip->log; - void *limit = log->bios_event_log_end; - size_t event_size; - void *marker; - - event_header = log->bios_event_log; - - if (v == SEQ_START_TOKEN) { - event_size = sizeof(struct tcg_pcr_event) - - sizeof(event_header->event) + event_header->event_size; - marker = event_header; - } else { - event = v; - event_size = calc_tpm2_event_size(event, event_header); - if (event_size == 0) - return NULL; - marker = event; - } - - marker = marker + event_size; - if (marker >= limit) - return NULL; - v = marker; - event = v; - - event_size = calc_tpm2_event_size(event, event_header); - if (((v + event_size) >= limit) || (event_size == 0)) - return NULL; - - (*pos)++; - return v; -} - -static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) -{ -} - -static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) -{ - struct tpm_chip *chip = m->private; - struct tpm_bios_log *log = &chip->log; - struct tcg_pcr_event *event_header = log->bios_event_log; - struct tcg_pcr_event2 *event = v; - void *temp_ptr; - size_t size; - - if (v == SEQ_START_TOKEN) { - size = sizeof(struct tcg_pcr_event) - - sizeof(event_header->event) + event_header->event_size; - - temp_ptr = event_header; - - if (size > 0) - seq_write(m, temp_ptr, size); - } else { - size = calc_tpm2_event_size(event, event_header); - temp_ptr = event; - if (size > 0) - seq_write(m, temp_ptr, size); - } - - return 0; -} - -const struct seq_operations tpm2_binary_b_measurements_seqops = { - .start = tpm2_bios_measurements_start, - .next = tpm2_bios_measurements_next, - .stop = tpm2_bios_measurements_stop, - .show = tpm2_binary_bios_measurements_show, -}; diff --git a/drivers/char/tpm/tpm_eventlog_acpi.c b/drivers/char/tpm/tpm_eventlog_acpi.c deleted file mode 100644 index 66f19e93c216c..0000000000000 --- a/drivers/char/tpm/tpm_eventlog_acpi.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2005 IBM Corporation - * - * Authors: - * Seiji Munetoh - * Stefan Berger - * Reiner Sailer - * Kylene Hall - * Nayna Jain - * - * Maintained by: - * - * Access to the event log extended by the TCG BIOS of PC platform - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "tpm.h" - -struct acpi_tcpa { - struct acpi_table_header hdr; - u16 platform_class; - union { - struct client_hdr { - u32 log_max_len __packed; - u64 log_start_addr __packed; - } client; - struct server_hdr { - u16 reserved; - u64 log_max_len __packed; - u64 log_start_addr __packed; - } server; - }; -}; - -/* read binary bios log */ -int tpm_read_log_acpi(struct tpm_chip *chip) -{ - struct acpi_tcpa *buff; - acpi_status status; - void __iomem *virt; - u64 len, start; - struct tpm_bios_log *log; - - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return -ENODEV; - - log = &chip->log; - - /* Unfortuntely ACPI does not associate the event log with a specific - * TPM, like PPI. Thus all ACPI TPMs will read the same log. - */ - if (!chip->acpi_dev_handle) - return -ENODEV; - - /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ - status = acpi_get_table(ACPI_SIG_TCPA, 1, - (struct acpi_table_header **)&buff); - - if (ACPI_FAILURE(status)) - return -ENODEV; - - switch(buff->platform_class) { - case BIOS_SERVER: - len = buff->server.log_max_len; - start = buff->server.log_start_addr; - break; - case BIOS_CLIENT: - default: - len = buff->client.log_max_len; - start = buff->client.log_start_addr; - break; - } - if (!len) { - dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); - return -EIO; - } - - /* malloc EventLog space */ - log->bios_event_log = kmalloc(len, GFP_KERNEL); - if (!log->bios_event_log) - return -ENOMEM; - - log->bios_event_log_end = log->bios_event_log + len; - - virt = acpi_os_map_iomem(start, len); - if (!virt) - goto err; - - memcpy_fromio(log->bios_event_log, virt, len); - - acpi_os_unmap_iomem(virt, len); - return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; - -err: - kfree(log->bios_event_log); - log->bios_event_log = NULL; - return -EIO; - -} diff --git a/drivers/char/tpm/tpm_eventlog_efi.c b/drivers/char/tpm/tpm_eventlog_efi.c deleted file mode 100644 index e3f9ffd341d23..0000000000000 --- a/drivers/char/tpm/tpm_eventlog_efi.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2017 Google - * - * Authors: - * Thiebaud Weksteen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include - -#include "tpm.h" - -/* read binary bios log from EFI configuration table */ -int tpm_read_log_efi(struct tpm_chip *chip) -{ - - struct linux_efi_tpm_eventlog *log_tbl; - struct tpm_bios_log *log; - u32 log_size; - u8 tpm_log_version; - - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) - return -ENODEV; - - if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) - return -ENODEV; - - log = &chip->log; - - log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB); - if (!log_tbl) { - pr_err("Could not map UEFI TPM log table !\n"); - return -ENOMEM; - } - - log_size = log_tbl->size; - memunmap(log_tbl); - - log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size, - MEMREMAP_WB); - if (!log_tbl) { - pr_err("Could not map UEFI TPM log table payload!\n"); - return -ENOMEM; - } - - /* malloc EventLog space */ - log->bios_event_log = kmalloc(log_size, GFP_KERNEL); - if (!log->bios_event_log) - goto err_memunmap; - memcpy(log->bios_event_log, log_tbl->log, log_size); - log->bios_event_log_end = log->bios_event_log + log_size; - - tpm_log_version = log_tbl->version; - memunmap(log_tbl); - return tpm_log_version; - -err_memunmap: - memunmap(log_tbl); - return -ENOMEM; -} diff --git a/drivers/char/tpm/tpm_eventlog_of.c b/drivers/char/tpm/tpm_eventlog_of.c deleted file mode 100644 index ea0f16f19d73b..0000000000000 --- a/drivers/char/tpm/tpm_eventlog_of.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2012 IBM Corporation - * - * Author: Ashley Lai - * Nayna Jain - * - * Maintained by: - * - * Read the event log created by the firmware on PPC64 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include - -#include "tpm.h" - -int tpm_read_log_of(struct tpm_chip *chip) -{ - struct device_node *np; - const u32 *sizep; - const u64 *basep; - struct tpm_bios_log *log; - u32 size; - u64 base; - - log = &chip->log; - if (chip->dev.parent && chip->dev.parent->of_node) - np = chip->dev.parent->of_node; - else - return -ENODEV; - - if (of_property_read_bool(np, "powered-while-suspended")) - chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; - - sizep = of_get_property(np, "linux,sml-size", NULL); - basep = of_get_property(np, "linux,sml-base", NULL); - if (sizep == NULL && basep == NULL) - return -ENODEV; - if (sizep == NULL || basep == NULL) - return -EIO; - - /* - * For both vtpm/tpm, firmware has log addr and log size in big - * endian format. But in case of vtpm, there is a method called - * sml-handover which is run during kernel init even before - * device tree is setup. This sml-handover function takes care - * of endianness and writes to sml-base and sml-size in little - * endian format. For this reason, vtpm doesn't need conversion - * but physical tpm needs the conversion. - */ - if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) { - size = be32_to_cpup((__force __be32 *)sizep); - base = be64_to_cpup((__force __be64 *)basep); - } else { - size = *sizep; - base = *basep; - } - - if (size == 0) { - dev_warn(&chip->dev, "%s: Event log area empty\n", __func__); - return -EIO; - } - - log->bios_event_log = kmalloc(size, GFP_KERNEL); - if (!log->bios_event_log) - return -ENOMEM; - - log->bios_event_log_end = log->bios_event_log + size; - - memcpy(log->bios_event_log, __va(base), size); - - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; - return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; -} -- cgit v1.2.3