mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.5 KiB
160 lines
3.5 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright (C) 2005 IBM Corporation |
|
* |
|
* Authors: |
|
* Seiji Munetoh <[email protected]> |
|
* Stefan Berger <[email protected]> |
|
* Reiner Sailer <[email protected]> |
|
* Kylene Hall <[email protected]> |
|
* Nayna Jain <[email protected]> |
|
* |
|
* Maintained by: <[email protected]> |
|
* |
|
* Access to the event log extended by the TCG BIOS of PC platform |
|
*/ |
|
|
|
#include <linux/seq_file.h> |
|
#include <linux/fs.h> |
|
#include <linux/security.h> |
|
#include <linux/module.h> |
|
#include <linux/slab.h> |
|
#include <linux/acpi.h> |
|
#include <linux/tpm_eventlog.h> |
|
|
|
#include "../tpm.h" |
|
#include "common.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; |
|
}; |
|
}; |
|
|
|
/* Check that the given log is indeed a TPM2 log. */ |
|
static bool tpm_is_tpm2_log(void *bios_event_log, u64 len) |
|
{ |
|
struct tcg_efi_specid_event_head *efispecid; |
|
struct tcg_pcr_event *event_header; |
|
int n; |
|
|
|
if (len < sizeof(*event_header)) |
|
return false; |
|
len -= sizeof(*event_header); |
|
event_header = bios_event_log; |
|
|
|
if (len < sizeof(*efispecid)) |
|
return false; |
|
efispecid = (struct tcg_efi_specid_event_head *)event_header->event; |
|
|
|
n = memcmp(efispecid->signature, TCG_SPECID_SIG, |
|
sizeof(TCG_SPECID_SIG)); |
|
return n == 0; |
|
} |
|
|
|
/* 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; |
|
struct acpi_table_tpm2 *tbl; |
|
struct acpi_tpm2_phy *tpm2_phy; |
|
int format; |
|
int ret; |
|
|
|
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; |
|
|
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
|
status = acpi_get_table("TPM2", 1, |
|
(struct acpi_table_header **)&tbl); |
|
if (ACPI_FAILURE(status)) |
|
return -ENODEV; |
|
|
|
if (tbl->header.length < |
|
sizeof(*tbl) + sizeof(struct acpi_tpm2_phy)) |
|
return -ENODEV; |
|
|
|
tpm2_phy = (void *)tbl + sizeof(*tbl); |
|
len = tpm2_phy->log_area_minimum_length; |
|
|
|
start = tpm2_phy->log_area_start_address; |
|
if (!start || !len) |
|
return -ENODEV; |
|
|
|
format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; |
|
} else { |
|
/* 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; |
|
} |
|
|
|
format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; |
|
} |
|
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; |
|
|
|
ret = -EIO; |
|
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); |
|
|
|
if (chip->flags & TPM_CHIP_FLAG_TPM2 && |
|
!tpm_is_tpm2_log(log->bios_event_log, len)) { |
|
/* try EFI log next */ |
|
ret = -ENODEV; |
|
goto err; |
|
} |
|
|
|
return format; |
|
|
|
err: |
|
kfree(log->bios_event_log); |
|
log->bios_event_log = NULL; |
|
return ret; |
|
|
|
}
|
|
|