linux/drivers/char/tpm/eventlog/efi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2017 Google
   4 *
   5 * Authors:
   6 *      Thiebaud Weksteen <tweek@google.com>
   7 */
   8
   9#include <linux/efi.h>
  10#include <linux/tpm_eventlog.h>
  11
  12#include "../tpm.h"
  13#include "common.h"
  14
  15/* read binary bios log from EFI configuration table */
  16int tpm_read_log_efi(struct tpm_chip *chip)
  17{
  18
  19        struct efi_tcg2_final_events_table *final_tbl = NULL;
  20        int final_events_log_size = efi_tpm_final_log_size;
  21        struct linux_efi_tpm_eventlog *log_tbl;
  22        struct tpm_bios_log *log;
  23        u32 log_size;
  24        u8 tpm_log_version;
  25        void *tmp;
  26        int ret;
  27
  28        if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
  29                return -ENODEV;
  30
  31        if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
  32                return -ENODEV;
  33
  34        log = &chip->log;
  35
  36        log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB);
  37        if (!log_tbl) {
  38                pr_err("Could not map UEFI TPM log table !\n");
  39                return -ENOMEM;
  40        }
  41
  42        log_size = log_tbl->size;
  43        memunmap(log_tbl);
  44
  45        if (!log_size) {
  46                pr_warn("UEFI TPM log area empty\n");
  47                return -EIO;
  48        }
  49
  50        log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
  51                           MEMREMAP_WB);
  52        if (!log_tbl) {
  53                pr_err("Could not map UEFI TPM log table payload!\n");
  54                return -ENOMEM;
  55        }
  56
  57        /* malloc EventLog space */
  58        log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
  59        if (!log->bios_event_log) {
  60                ret = -ENOMEM;
  61                goto out;
  62        }
  63
  64        log->bios_event_log_end = log->bios_event_log + log_size;
  65        tpm_log_version = log_tbl->version;
  66
  67        ret = tpm_log_version;
  68
  69        if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
  70            final_events_log_size == 0 ||
  71            tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
  72                goto out;
  73
  74        final_tbl = memremap(efi.tpm_final_log,
  75                             sizeof(*final_tbl) + final_events_log_size,
  76                             MEMREMAP_WB);
  77        if (!final_tbl) {
  78                pr_err("Could not map UEFI TPM final log\n");
  79                kfree(log->bios_event_log);
  80                ret = -ENOMEM;
  81                goto out;
  82        }
  83
  84        /*
  85         * The 'final events log' size excludes the 'final events preboot log'
  86         * at its beginning.
  87         */
  88        final_events_log_size -= log_tbl->final_events_preboot_size;
  89
  90        /*
  91         * Allocate memory for the 'combined log' where we will append the
  92         * 'final events log' to.
  93         */
  94        tmp = krealloc(log->bios_event_log,
  95                       log_size + final_events_log_size,
  96                       GFP_KERNEL);
  97        if (!tmp) {
  98                kfree(log->bios_event_log);
  99                ret = -ENOMEM;
 100                goto out;
 101        }
 102
 103        log->bios_event_log = tmp;
 104
 105        /*
 106         * Append any of the 'final events log' that didn't also end up in the
 107         * 'main log'. Events can be logged in both if events are generated
 108         * between GetEventLog() and ExitBootServices().
 109         */
 110        memcpy((void *)log->bios_event_log + log_size,
 111               final_tbl->events + log_tbl->final_events_preboot_size,
 112               final_events_log_size);
 113        /*
 114         * The size of the 'combined log' is the size of the 'main log' plus
 115         * the size of the 'final events log'.
 116         */
 117        log->bios_event_log_end = log->bios_event_log +
 118                log_size + final_events_log_size;
 119
 120out:
 121        memunmap(final_tbl);
 122        memunmap(log_tbl);
 123        return ret;
 124}
 125