cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acpi.c (3631B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2005 IBM Corporation
      4 *
      5 * Authors:
      6 *	Seiji Munetoh <munetoh@jp.ibm.com>
      7 *	Stefan Berger <stefanb@us.ibm.com>
      8 *	Reiner Sailer <sailer@watson.ibm.com>
      9 *	Kylene Hall <kjhall@us.ibm.com>
     10 *	Nayna Jain <nayna@linux.vnet.ibm.com>
     11 *
     12 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
     13 *
     14 * Access to the event log extended by the TCG BIOS of PC platform
     15 */
     16
     17#include <linux/seq_file.h>
     18#include <linux/fs.h>
     19#include <linux/security.h>
     20#include <linux/module.h>
     21#include <linux/slab.h>
     22#include <linux/acpi.h>
     23#include <linux/tpm_eventlog.h>
     24
     25#include "../tpm.h"
     26#include "common.h"
     27
     28struct acpi_tcpa {
     29	struct acpi_table_header hdr;
     30	u16 platform_class;
     31	union {
     32		struct client_hdr {
     33			u32 log_max_len __packed;
     34			u64 log_start_addr __packed;
     35		} client;
     36		struct server_hdr {
     37			u16 reserved;
     38			u64 log_max_len __packed;
     39			u64 log_start_addr __packed;
     40		} server;
     41	};
     42};
     43
     44/* Check that the given log is indeed a TPM2 log. */
     45static bool tpm_is_tpm2_log(void *bios_event_log, u64 len)
     46{
     47	struct tcg_efi_specid_event_head *efispecid;
     48	struct tcg_pcr_event *event_header;
     49	int n;
     50
     51	if (len < sizeof(*event_header))
     52		return false;
     53	len -= sizeof(*event_header);
     54	event_header = bios_event_log;
     55
     56	if (len < sizeof(*efispecid))
     57		return false;
     58	efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
     59
     60	n = memcmp(efispecid->signature, TCG_SPECID_SIG,
     61		   sizeof(TCG_SPECID_SIG));
     62	return n == 0;
     63}
     64
     65/* read binary bios log */
     66int tpm_read_log_acpi(struct tpm_chip *chip)
     67{
     68	struct acpi_tcpa *buff;
     69	acpi_status status;
     70	void __iomem *virt;
     71	u64 len, start;
     72	struct tpm_bios_log *log;
     73	struct acpi_table_tpm2 *tbl;
     74	struct acpi_tpm2_phy *tpm2_phy;
     75	int format;
     76	int ret;
     77
     78	log = &chip->log;
     79
     80	/* Unfortuntely ACPI does not associate the event log with a specific
     81	 * TPM, like PPI. Thus all ACPI TPMs will read the same log.
     82	 */
     83	if (!chip->acpi_dev_handle)
     84		return -ENODEV;
     85
     86	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
     87		status = acpi_get_table("TPM2", 1,
     88					(struct acpi_table_header **)&tbl);
     89		if (ACPI_FAILURE(status))
     90			return -ENODEV;
     91
     92		if (tbl->header.length <
     93				sizeof(*tbl) + sizeof(struct acpi_tpm2_phy))
     94			return -ENODEV;
     95
     96		tpm2_phy = (void *)tbl + sizeof(*tbl);
     97		len = tpm2_phy->log_area_minimum_length;
     98
     99		start = tpm2_phy->log_area_start_address;
    100		if (!start || !len)
    101			return -ENODEV;
    102
    103		format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
    104	} else {
    105		/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
    106		status = acpi_get_table(ACPI_SIG_TCPA, 1,
    107					(struct acpi_table_header **)&buff);
    108		if (ACPI_FAILURE(status))
    109			return -ENODEV;
    110
    111		switch (buff->platform_class) {
    112		case BIOS_SERVER:
    113			len = buff->server.log_max_len;
    114			start = buff->server.log_start_addr;
    115			break;
    116		case BIOS_CLIENT:
    117		default:
    118			len = buff->client.log_max_len;
    119			start = buff->client.log_start_addr;
    120			break;
    121		}
    122
    123		format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
    124	}
    125	if (!len) {
    126		dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__);
    127		return -EIO;
    128	}
    129
    130	/* malloc EventLog space */
    131	log->bios_event_log = kmalloc(len, GFP_KERNEL);
    132	if (!log->bios_event_log)
    133		return -ENOMEM;
    134
    135	log->bios_event_log_end = log->bios_event_log + len;
    136
    137	ret = -EIO;
    138	virt = acpi_os_map_iomem(start, len);
    139	if (!virt)
    140		goto err;
    141
    142	memcpy_fromio(log->bios_event_log, virt, len);
    143
    144	acpi_os_unmap_iomem(virt, len);
    145
    146	if (chip->flags & TPM_CHIP_FLAG_TPM2 &&
    147	    !tpm_is_tpm2_log(log->bios_event_log, len)) {
    148		/* try EFI log next */
    149		ret = -ENODEV;
    150		goto err;
    151	}
    152
    153	return format;
    154
    155err:
    156	kfree(log->bios_event_log);
    157	log->bios_event_log = NULL;
    158	return ret;
    159
    160}