18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Google, Inc. 48c2ecf20Sopenharmony_ci * Thiebaud Weksteen <tweek@google.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define TPM_MEMREMAP(start, size) early_memremap(start, size) 88c2ecf20Sopenharmony_ci#define TPM_MEMUNMAP(start, size) early_memunmap(start, size) 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <asm/early_ioremap.h> 118c2ecf20Sopenharmony_ci#include <linux/efi.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/memblock.h> 148c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint efi_tpm_final_log_size; 178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(efi_tpm_final_log_size); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int __init tpm2_calc_event_log_size(void *data, int count, void *size_info) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct tcg_pcr_event2_head *header; 228c2ecf20Sopenharmony_ci int event_size, size = 0; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci while (count > 0) { 258c2ecf20Sopenharmony_ci header = data + size; 268c2ecf20Sopenharmony_ci event_size = __calc_tpm2_event_size(header, size_info, true); 278c2ecf20Sopenharmony_ci if (event_size == 0) 288c2ecf20Sopenharmony_ci return -1; 298c2ecf20Sopenharmony_ci size += event_size; 308c2ecf20Sopenharmony_ci count--; 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return size; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Reserve the memory associated with the TPM Event Log configuration table. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ciint __init efi_tpm_eventlog_init(void) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct linux_efi_tpm_eventlog *log_tbl; 428c2ecf20Sopenharmony_ci struct efi_tcg2_final_events_table *final_tbl; 438c2ecf20Sopenharmony_ci int tbl_size; 448c2ecf20Sopenharmony_ci int ret = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) { 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * We can't calculate the size of the final events without the 498c2ecf20Sopenharmony_ci * first entry in the TPM log, so bail here. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); 558c2ecf20Sopenharmony_ci if (!log_tbl) { 568c2ecf20Sopenharmony_ci pr_err("Failed to map TPM Event Log table @ 0x%lx\n", 578c2ecf20Sopenharmony_ci efi.tpm_log); 588c2ecf20Sopenharmony_ci efi.tpm_log = EFI_INVALID_TABLE_ADDR; 598c2ecf20Sopenharmony_ci return -ENOMEM; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci tbl_size = sizeof(*log_tbl) + log_tbl->size; 638c2ecf20Sopenharmony_ci memblock_reserve(efi.tpm_log, tbl_size); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) { 668c2ecf20Sopenharmony_ci pr_info("TPM Final Events table not present\n"); 678c2ecf20Sopenharmony_ci goto out; 688c2ecf20Sopenharmony_ci } else if (log_tbl->version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { 698c2ecf20Sopenharmony_ci pr_warn(FW_BUG "TPM Final Events table invalid\n"); 708c2ecf20Sopenharmony_ci goto out; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!final_tbl) { 768c2ecf20Sopenharmony_ci pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n", 778c2ecf20Sopenharmony_ci efi.tpm_final_log); 788c2ecf20Sopenharmony_ci efi.tpm_final_log = EFI_INVALID_TABLE_ADDR; 798c2ecf20Sopenharmony_ci ret = -ENOMEM; 808c2ecf20Sopenharmony_ci goto out; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci tbl_size = 0; 848c2ecf20Sopenharmony_ci if (final_tbl->nr_events != 0) { 858c2ecf20Sopenharmony_ci void *events = (void *)efi.tpm_final_log 868c2ecf20Sopenharmony_ci + sizeof(final_tbl->version) 878c2ecf20Sopenharmony_ci + sizeof(final_tbl->nr_events); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci tbl_size = tpm2_calc_event_log_size(events, 908c2ecf20Sopenharmony_ci final_tbl->nr_events, 918c2ecf20Sopenharmony_ci log_tbl->log); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (tbl_size < 0) { 958c2ecf20Sopenharmony_ci pr_err(FW_BUG "Failed to parse event in TPM Final Events Log\n"); 968c2ecf20Sopenharmony_ci ret = -EINVAL; 978c2ecf20Sopenharmony_ci goto out_calc; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci memblock_reserve(efi.tpm_final_log, 1018c2ecf20Sopenharmony_ci tbl_size + sizeof(*final_tbl)); 1028c2ecf20Sopenharmony_ci efi_tpm_final_log_size = tbl_size; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciout_calc: 1058c2ecf20Sopenharmony_ci early_memunmap(final_tbl, sizeof(*final_tbl)); 1068c2ecf20Sopenharmony_ciout: 1078c2ecf20Sopenharmony_ci early_memunmap(log_tbl, sizeof(*log_tbl)); 1088c2ecf20Sopenharmony_ci return ret; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 111