📄 tcgbios.c
字号:
/* * Implementation of the TCG BIOS extension according to the specification * described in * https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) IBM Corporation, 2006 * * Author: Stefan Berger <stefanb@us.ibm.com> */#include "rombios_compat.h"#include "tpm_drivers.h"#include "util.h"#include "tcgbios.h"#include "32bitprotos.h"/* local structure and variables */struct ptti_cust { uint16_t ipblength; uint16_t reserved; uint16_t opblength; uint16_t reserved2; uint8_t tpmoperandin[18];} __attribute__((packed));struct ptti_cust CMD_TPM_Startup_0x01_IPB = { 0x8+0xc, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x01 },};struct ptti_cust CMD_TSC_PhysicalPresence_0x20_IPB = { 0x8+0xc, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x20 },};struct ptti_cust CMD_TSC_PhysicalPresence_0x08_IPB = { 0x8+0xc, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x08 },};struct ptti_cust CMD_TSC_PhysicalPresence_0x100_IPB = { 0x8+0xc, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x01, 0x00 },};struct ptti_cust CMD_TSC_PhysicalPresence_0x10_IPB = { 0x8+0xc, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x10 },};struct ptti_cust CMD_TPM_PhysicalEnable_IPB = { 0x8+0xa, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x6f },};struct ptti_cust CMD_TPM_PhysicalSetDeactivated_0x00_IPB = { 0x8+0xb, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x72, 0x00 }};struct ptti_cust CMD_TPM_SHA1Start_IPB = { 0x8+0xa, 0x00, 4+10, 0x00, { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa0 },};struct ptti_cust CMD_TPM_GetCap_Version_IPB = { 0x8+0x12, 0x00, 4+18, 0x00, {0x00, 0xc1, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 },};struct ptti_cust *TCG_CommandList[] = { &CMD_TPM_Startup_0x01_IPB, &CMD_TSC_PhysicalPresence_0x20_IPB, &CMD_TSC_PhysicalPresence_0x08_IPB, &CMD_TSC_PhysicalPresence_0x100_IPB, &CMD_TSC_PhysicalPresence_0x10_IPB, &CMD_TPM_PhysicalEnable_IPB, &CMD_TPM_PhysicalSetDeactivated_0x00_IPB, &CMD_TPM_SHA1Start_IPB,};/* local function prototypes */static void sha1(const unsigned char *data, uint32_t length, unsigned char *hash);static uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx);static uint32_t HashAll32(struct hai *hai, unsigned char *hash, uint32_t magic, uint32_t ecx, uint32_t edx);static uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, struct hleeo *hleeo, uint32_t magic, uint32_t ecx, uint32_t edx);static uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, uint32_t ebx, uint32_t ecx, uint32_t edx);static uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto, uint32_t magic, uint32_t ecx, uint32_t edx);static uint32_t MA_Transmit(unsigned char *cmdbuffer, unsigned char *respbuffer, uint32_t respbufferlen);static unsigned char *tcpa_get_lasa_last_ptr(void);static unsigned char *tcpa_get_lasa_base_ptr(void);static void tcpa_reset_acpi_log(void);static uint32_t tcpa_get_laml(void);extern struct tpm_driver tpm_drivers[];/* utility functions */static inline uint32_t bswap(uint32_t a){ return ( ( a >> 24 ) & 0x000000ff) | ( ( a >> 8 ) & 0x0000ff00) | ( ( a << 8 ) & 0x00ff0000) | ( ( a << 24 ) & 0xff000000);}/******************************************************** Extensions for TCG-enabled BIOS *******************************************************/typedef struct { struct acpi_20_tcpa_clisrv *tcpa_ptr; unsigned char *lasa_last_ptr; uint16_t entry_count; uint16_t flags;} tcpa_acpi_t;static tcpa_acpi_t tcpa_acpi;/* low level driver implementation */static int tpm_driver_to_use = TPM_INVALID_DRIVER;staticuint32_t MA_IsTPMPresent(void){ uint32_t rc = 0; unsigned int i; for (i = 0; i < TPM_NUM_DRIVERS; i++) { struct tpm_driver *td = &tpm_drivers[i]; if (td->probe(td->baseaddr) != 0) { tpm_driver_to_use = i; rc = 1; break; } } return rc;}staticuint32_t MA_InitTPM(uint16_t startupcode){ uint32_t rc = 0; /* low-level initialize the TPM */ unsigned char command[sizeof(CMD_TPM_Startup_0x01_IPB.tpmoperandin)]; unsigned char response[10]; uint32_t response_size = sizeof(response); memcpy(command, CMD_TPM_Startup_0x01_IPB.tpmoperandin, sizeof(CMD_TPM_Startup_0x01_IPB.tpmoperandin)); command[10] = (startupcode >> 8) & 0xff; command[11] = (startupcode >> 0) & 0xff; rc = MA_Transmit(command, response, response_size); return rc;}staticuint32_t MA_Transmit(unsigned char *cmdbuffer, unsigned char *respbuffer, uint32_t respbufferlen){ uint32_t rc = 0; uint32_t irc; struct tpm_driver *td; if (tpm_driver_to_use == TPM_INVALID_DRIVER) return TCG_FATAL_COM_ERROR; td = &tpm_drivers[tpm_driver_to_use]; if (rc == 0) { irc = td->activate(td->baseaddr); if (irc == 0) { /* tpm could not be activated */ rc = TCG_FATAL_COM_ERROR; } } if (rc == 0) { uint32_t *tmp = (uint32_t *)&cmdbuffer[2]; uint32_t len = bswap(*tmp); irc = td->senddata(td->baseaddr, cmdbuffer, len); if (irc != 0) { rc = TCG_FATAL_COM_ERROR; } } if (rc == 0) { irc = td->waitdatavalid(td->baseaddr); if (irc != 0) { rc = TCG_FATAL_COM_ERROR; } } if (rc == 0) { irc = td->waitrespready(td->baseaddr, 2000); if (irc != 0) { rc = TCG_FATAL_COM_ERROR; } } if (rc == 0) { irc = td->readresp(td->baseaddr, respbuffer, respbufferlen); if (irc != 0) { rc = TCG_FATAL_COM_ERROR; } } if (rc == 0) { irc = td->ready(td->baseaddr); } return rc;}staticuint8_t acpi_validate_entry(struct acpi_header *hdr){ uint8_t sum = 0; unsigned int length = hdr->length; unsigned int ctr; unsigned char *addr = (unsigned char *)hdr; for (ctr = 0; ctr < length; ctr++) sum += addr[ctr]; return sum;}void tcpa_acpi_init(void){ struct acpi_20_rsdt *rsdt; struct acpi_20_tcpa_clisrv *tcpa = (void *)0; struct acpi_20_rsdp *rsdp; uint32_t length; uint16_t off; int found = 0; if (MA_IsTPMPresent() == 0) return; rsdp = find_rsdp(); if (rsdp) { uint32_t ctr = 0; /* get RSDT from RSDP */ rsdt = (struct acpi_20_rsdt *)rsdp->rsdt_address; length = rsdt->header.length; off = 36; while ((off + 3) < length) { /* try all pointers to structures */ tcpa = (struct acpi_20_tcpa_clisrv *)rsdt->entry[ctr]; /* valid TCPA ACPI table ? */ if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature && acpi_validate_entry(&tcpa->header) == 0) { found = 1; break; } off += 4; ctr++; } } if (found == 0) { printf("TCPA ACPI was NOT found!\n"); tcpa = 0; } tcpa_acpi.tcpa_ptr = tcpa; tcpa_acpi.lasa_last_ptr = 0; tcpa_acpi.entry_count = 0; tcpa_acpi.flags = 0; tcpa_reset_acpi_log();}/* clear the ACPI log */static void tcpa_reset_acpi_log(void){ unsigned char *lasa = tcpa_get_lasa_base_ptr(); if (lasa) memset(lasa, 0x0, tcpa_get_laml());}uint32_t tcpa_extend_acpi_log(uint32_t entry_ptr){ uint32_t res = 0; unsigned char *lasa_last = tcpa_get_lasa_last_ptr(); unsigned char *lasa_base = tcpa_get_lasa_base_ptr(); uint32_t size; uint16_t entry_count = tcpa_acpi.entry_count; struct pcpes *pcpes = (struct pcpes *)entry_ptr; if (lasa_last == 0) { lasa_last = lasa_base; } else { struct pcpes *pcpes = (struct pcpes *)lasa_last; /* skip the last entry in the log */ size = pcpes->eventdatasize; size += 32; lasa_last += size; } if (lasa_last == 0) { res = ((uint32_t)TCG_PC_LOGOVERFLOW << 16); } if (res == 0) { uint32_t laml = tcpa_get_laml(); size = pcpes->eventdatasize; size += 32; if ((lasa_last + size - lasa_base) > laml) { res = (TCG_PC_LOGOVERFLOW << 16); } } if (res == 0) { /* copy the log entry into the ACPI log */ memcpy((char *)lasa_last, (char *)entry_ptr, size); /* * update the pointers and entry counter that were modified * due to the new entry in the log */ tcpa_acpi.lasa_last_ptr = lasa_last; entry_count++; tcpa_acpi.entry_count = entry_count; res = entry_count; } return res;}staticunsigned char *tcpa_get_lasa_last_ptr(void){ return tcpa_acpi.lasa_last_ptr;}staticunsigned char *tcpa_get_lasa_base_ptr(void){ unsigned char *lasa = 0; struct acpi_20_tcpa_clisrv *tcpa = tcpa_acpi.tcpa_ptr; if (tcpa != 0) { uint32_t class = tcpa->platform_class; if (class == TCPA_ACPI_CLASS_CLIENT) { /* client type */ lasa = (unsigned char *)(long)tcpa->u.client.lasa; } else if (class == TCPA_ACPI_CLASS_SERVER) { /* server type */ lasa = (unsigned char *)(long)tcpa->u.server.lasa; } } return lasa;}staticuint32_t tcpa_get_laml(void){ uint32_t laml = 0; struct acpi_20_tcpa_clisrv *tcpa = tcpa_acpi.tcpa_ptr; if (tcpa != 0) { uint32_t class = tcpa->platform_class; if (class == TCPA_ACPI_CLASS_CLIENT) { /* client type */ laml = tcpa->u.client.laml; } else if (class == TCPA_ACPI_CLASS_SERVER) { laml = tcpa->u.server.laml; } } return laml;}/* * Add a measurement to the log; the data at data_seg:data/length are * appended to the TCG_PCClientPCREventStruct * * Input parameters: * pcrIndex : which PCR to extend * event_type : type of event; specs 10.4.1 * event_id : (unused) * data : pointer to the data (i.e., string) to be added to the log * length : length of the data */static uint16_ttcpa_add_measurement_to_log(uint32_t pcrIndex, uint32_t event_type, uint32_t event_id, const char *data_ptr, uint32_t length){ uint32_t rc = 0; struct hleei_short hleei; struct hleeo hleeo; uint8_t _pcpes[32+400]; struct pcpes *pcpes = (struct pcpes *)_pcpes; uint8_t *data = (uint8_t *)data_ptr; if (length < sizeof(_pcpes)-32) { memset(pcpes, 0x0, 32); pcpes->pcrindex = pcrIndex; pcpes->eventtype = event_type; pcpes->eventdatasize = length; memcpy(&_pcpes[32], data, length); hleei.ipblength = 0x18; hleei.reserved = 0x0; hleei.hashdataptr = (uint32_t)&_pcpes[32]; hleei.hashdatalen = length; hleei.pcrindex = pcrIndex; hleei.logdataptr = (uint32_t)_pcpes; hleei.logdatalen = length + 32; rc = HashLogExtendEvent32(&hleei, &hleeo, TCG_MAGIC, 0x0, 0x0); } else { rc = (TCG_PC_TPMERROR | ((uint32_t)TCG_GENERAL_ERROR << 16)); } return rc;}staticuint16_t tcpa_add_pcpes_to_log(struct pcpes *pcpes){ uint32_t rc = 0; struct hleei_short hleei; struct hleeo hleeo; hleei.ipblength = 0x18; hleei.reserved = 0x0; hleei.hashdataptr = 0; hleei.hashdatalen = 0; hleei.pcrindex = pcpes->pcrindex; hleei.logdataptr = (uint32_t)pcpes; hleei.logdatalen = sizeof(pcpes); rc = HashLogExtendEvent32(&hleei, &hleeo, TCG_MAGIC, 0x0, 0x0); return rc;}/* * Add a measurement to the log; further description of the data * that are to be hashed are NOT appended to the TCG_PCClientPCREventStruc. * Input parameters: * pcrIndex : PCR to extend * event_type : type of event; specs 10.4.1 * ptr : 32 bit pointer to the data to be hashed * length : length of the data to be hashed * * Returns lower 16 bit of return code of TCG_HashLogExtendEvent. '0' means * success, otherwise an error is indicated. */staticuint16_t tcpa_add_measurement_to_log_simple(uint32_t pcrIndex, uint16_t event_type, uint8_t *ptr, uint32_t length){ uint32_t rc = 0; struct hleei_short hleei; struct hleeo hleeo; struct pcpes pcpes;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -