162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Google 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Thiebaud Weksteen <tweek@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/efi.h> 1162306a36Sopenharmony_ci#include <linux/tpm_eventlog.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "../tpm.h" 1462306a36Sopenharmony_ci#include "common.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* read binary bios log from EFI configuration table */ 1762306a36Sopenharmony_ciint tpm_read_log_efi(struct tpm_chip *chip) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci struct efi_tcg2_final_events_table *final_tbl = NULL; 2162306a36Sopenharmony_ci int final_events_log_size = efi_tpm_final_log_size; 2262306a36Sopenharmony_ci struct linux_efi_tpm_eventlog *log_tbl; 2362306a36Sopenharmony_ci struct tpm_bios_log *log; 2462306a36Sopenharmony_ci u32 log_size; 2562306a36Sopenharmony_ci u8 tpm_log_version; 2662306a36Sopenharmony_ci void *tmp; 2762306a36Sopenharmony_ci int ret; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) 3062306a36Sopenharmony_ci return -ENODEV; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) 3362306a36Sopenharmony_ci return -ENODEV; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci log = &chip->log; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB); 3862306a36Sopenharmony_ci if (!log_tbl) { 3962306a36Sopenharmony_ci pr_err("Could not map UEFI TPM log table !\n"); 4062306a36Sopenharmony_ci return -ENOMEM; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci log_size = log_tbl->size; 4462306a36Sopenharmony_ci memunmap(log_tbl); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!log_size) { 4762306a36Sopenharmony_ci pr_warn("UEFI TPM log area empty\n"); 4862306a36Sopenharmony_ci return -EIO; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size, 5262306a36Sopenharmony_ci MEMREMAP_WB); 5362306a36Sopenharmony_ci if (!log_tbl) { 5462306a36Sopenharmony_ci pr_err("Could not map UEFI TPM log table payload!\n"); 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* malloc EventLog space */ 5962306a36Sopenharmony_ci log->bios_event_log = devm_kmemdup(&chip->dev, log_tbl->log, log_size, GFP_KERNEL); 6062306a36Sopenharmony_ci if (!log->bios_event_log) { 6162306a36Sopenharmony_ci ret = -ENOMEM; 6262306a36Sopenharmony_ci goto out; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci log->bios_event_log_end = log->bios_event_log + log_size; 6662306a36Sopenharmony_ci tpm_log_version = log_tbl->version; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ret = tpm_log_version; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || 7162306a36Sopenharmony_ci final_events_log_size == 0 || 7262306a36Sopenharmony_ci tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) 7362306a36Sopenharmony_ci goto out; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci final_tbl = memremap(efi.tpm_final_log, 7662306a36Sopenharmony_ci sizeof(*final_tbl) + final_events_log_size, 7762306a36Sopenharmony_ci MEMREMAP_WB); 7862306a36Sopenharmony_ci if (!final_tbl) { 7962306a36Sopenharmony_ci pr_err("Could not map UEFI TPM final log\n"); 8062306a36Sopenharmony_ci devm_kfree(&chip->dev, log->bios_event_log); 8162306a36Sopenharmony_ci ret = -ENOMEM; 8262306a36Sopenharmony_ci goto out; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * The 'final events log' size excludes the 'final events preboot log' 8762306a36Sopenharmony_ci * at its beginning. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci final_events_log_size -= log_tbl->final_events_preboot_size; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Allocate memory for the 'combined log' where we will append the 9362306a36Sopenharmony_ci * 'final events log' to. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci tmp = devm_krealloc(&chip->dev, log->bios_event_log, 9662306a36Sopenharmony_ci log_size + final_events_log_size, 9762306a36Sopenharmony_ci GFP_KERNEL); 9862306a36Sopenharmony_ci if (!tmp) { 9962306a36Sopenharmony_ci devm_kfree(&chip->dev, log->bios_event_log); 10062306a36Sopenharmony_ci ret = -ENOMEM; 10162306a36Sopenharmony_ci goto out; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci log->bios_event_log = tmp; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * Append any of the 'final events log' that didn't also end up in the 10862306a36Sopenharmony_ci * 'main log'. Events can be logged in both if events are generated 10962306a36Sopenharmony_ci * between GetEventLog() and ExitBootServices(). 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci memcpy((void *)log->bios_event_log + log_size, 11262306a36Sopenharmony_ci final_tbl->events + log_tbl->final_events_preboot_size, 11362306a36Sopenharmony_ci final_events_log_size); 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * The size of the 'combined log' is the size of the 'main log' plus 11662306a36Sopenharmony_ci * the size of the 'final events log'. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci log->bios_event_log_end = log->bios_event_log + 11962306a36Sopenharmony_ci log_size + final_events_log_size; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciout: 12262306a36Sopenharmony_ci memunmap(final_tbl); 12362306a36Sopenharmony_ci memunmap(log_tbl); 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci} 126