diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | src/Kconfig | 7 | ||||
-rw-r--r-- | src/config.h | 1 | ||||
-rw-r--r-- | src/hw/tpm_drivers.c | 33 | ||||
-rw-r--r-- | src/post.c | 7 | ||||
-rw-r--r-- | src/resume.c | 3 | ||||
-rw-r--r-- | src/std/acpi.h | 20 | ||||
-rw-r--r-- | src/tcgbios.c | 572 | ||||
-rw-r--r-- | src/tcgbios.h | 386 |
9 files changed, 1032 insertions, 2 deletions
@@ -38,11 +38,12 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c SRC16=$(SRCBOTH) SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ - pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \ + pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c \ hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \ fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \ - fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c + fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \ + hw/tpm_drivers.c SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c DIRS=src src/hw src/fw vgasrc diff --git a/src/Kconfig b/src/Kconfig index 45ca59c..19f4db1 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -421,6 +421,13 @@ menu "BIOS interfaces" modified by programs. However, some old DOS high memory managers may require the UMB region to be read-only. + config TCGBIOS + depends on S3_RESUME + bool "TPM support and TCG BIOS extensions" + default y + help + Provide TPM support along with TCG BIOS extensions + endmenu menu "BIOS Tables" diff --git a/src/config.h b/src/config.h index 6da067d..4bfebe8 100644 --- a/src/config.h +++ b/src/config.h @@ -104,5 +104,6 @@ #define DEBUG_unimplemented 2 #define DEBUG_invalid 3 #define DEBUG_thread 2 +#define DEBUG_tcg 20 #endif // config.h diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index ea602e8..444eac3 100644 --- a/src/hw/tpm_drivers.c +++ b/src/hw/tpm_drivers.c @@ -35,6 +35,9 @@ static u32 tpm_default_to[4]; /* if device is not there, return '0', '1' otherwise */ static u32 tis_probe(void) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID)); @@ -46,6 +49,9 @@ static u32 tis_probe(void) static u32 tis_init(void) { + if (!CONFIG_TCGBIOS) + return 1; + writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0); if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) { @@ -68,6 +74,9 @@ static u32 tis_init(void) static void set_timeouts(u32 timeouts[4], u32 durations[3]) { + if (!CONFIG_TCGBIOS) + return; + u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts; u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations; @@ -80,6 +89,9 @@ static void set_timeouts(u32 timeouts[4], u32 durations[3]) static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 1; while (time > 0) { @@ -96,6 +108,9 @@ static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect) static u32 tis_activate(u8 locty) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u8 acc; int l; @@ -124,6 +139,9 @@ static u32 tis_activate(u8 locty) static u32 tis_find_active_locality(void) { + if (!CONFIG_TCGBIOS) + return 0; + u8 locty; for (locty = 0; locty <= 4; locty++) { @@ -139,6 +157,9 @@ static u32 tis_find_active_locality(void) static u32 tis_ready(void) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u8 locty = tis_find_active_locality(); u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B]; @@ -152,6 +173,9 @@ static u32 tis_ready(void) static u32 tis_senddata(const u8 *const data, u32 len) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u32 offset = 0; u32 end = 0; @@ -191,6 +215,9 @@ static u32 tis_senddata(const u8 *const data, u32 len) static u32 tis_readresp(u8 *buffer, u32 *len) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u32 offset = 0; u32 sts; @@ -213,6 +240,9 @@ static u32 tis_readresp(u8 *buffer, u32 *len) static u32 tis_waitdatavalid(void) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u8 locty = tis_find_active_locality(); u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C]; @@ -225,6 +255,9 @@ static u32 tis_waitdatavalid(void) static u32 tis_waitrespready(enum tpmDurationType to_t) { + if (!CONFIG_TCGBIOS) + return 0; + u32 rc = 0; u8 locty = tis_find_active_locality(); u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t]; @@ -28,6 +28,7 @@ #include "output.h" // dprintf #include "string.h" // memset #include "util.h" // kbd_init +#include "tcgbios.h" // tpm_* /**************************************************************** @@ -220,6 +221,9 @@ maininit(void) if (threads_during_optionroms()) device_hardware_setup(); + // Initialize TPM + tpm_start(); + // Run vga option rom vgarom_setup(); @@ -236,6 +240,9 @@ maininit(void) interactive_bootmenu(); wait_threads(); + // Change TPM phys. presence state befor leaving BIOS + tpm_leave_bios(); + // Prepare for boot. prepareboot(); diff --git a/src/resume.c b/src/resume.c index 1903174..a5465d8 100644 --- a/src/resume.c +++ b/src/resume.c @@ -16,6 +16,7 @@ #include "std/bda.h" // struct bios_data_area_s #include "string.h" // memset #include "util.h" // dma_setup +#include "tcgbios.h" // tpm_s3_resume // Handler for post calls that look like a resume. void VISIBLE16 @@ -99,6 +100,8 @@ s3_resume(void) pci_resume(); + /* resume TPM before we may measure option roms */ + tpm_s3_resume(); s3_resume_vga(); make_bios_readonly(); diff --git a/src/std/acpi.h b/src/std/acpi.h index e0d9516..b672bbe 100644 --- a/src/std/acpi.h +++ b/src/std/acpi.h @@ -294,4 +294,24 @@ struct acpi_table_mcfg { struct acpi_mcfg_allocation allocation[0]; } PACKED; + +struct rsdt_descriptor { + ACPI_TABLE_HEADER_DEF + u32 entry[1]; +} PACKED; + +#define TCPA_SIGNATURE 0x41504354 +struct tcpa_descriptor_rev2 +{ + ACPI_TABLE_HEADER_DEF + u16 platform_class; + u32 log_area_minimum_length; + u64 log_area_start_address; +} PACKED; + +/* TCPA ACPI definitions */ +#define TCPA_ACPI_CLASS_CLIENT 0 +#define TCPA_ACPI_CLASS_SERVER 1 + + #endif // acpi.h diff --git a/src/tcgbios.c b/src/tcgbios.c new file mode 100644 index 0000000..73ff1f3 --- /dev/null +++ b/src/tcgbios.c @@ -0,0 +1,572 @@ +// 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 +// +// Copyright (C) 2006-2011, 2014 IBM Corporation +// +// Authors: +// Stefan Berger <stefanb@linux.vnet.ibm.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +#include "config.h" + +#include "types.h" +#include "byteorder.h" // cpu_to_* +#include "hw/tpm_drivers.h" // tpm_drivers[] +#include "farptr.h" // MAKE_FLATPTR +#include "string.h" // checksum +#include "tcgbios.h"// tpm_*, prototypes +#include "util.h" // printf, get_keystroke +#include "output.h" // dprintf +#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor +#include "bregs.h" // struct bregs + + +static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; +static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; + +static const u8 PhysicalPresence_CMD_ENABLE[2] = { 0x00, 0x20 }; +static const u8 PhysicalPresence_CMD_DISABLE[2] = { 0x01, 0x00 }; +static const u8 PhysicalPresence_PRESENT[2] = { 0x00, 0x08 }; +static const u8 PhysicalPresence_NOT_PRESENT_LOCK[2] = { 0x00, 0x14 }; + +static const u8 CommandFlag_FALSE[1] = { 0x00 }; +static const u8 CommandFlag_TRUE[1] = { 0x01 }; + +static const u8 GetCapability_Permanent_Flags[12] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x08 +}; + +static const u8 GetCapability_OwnerAuth[12] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x11 +}; + +static const u8 GetCapability_Timeouts[] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x15 +}; + +static const u8 GetCapability_Durations[] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x20 +}; + + +#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr) + + +/* helper functions */ + +static inline void *input_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->es, regs->di); +} + +static inline void *output_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->ds, regs->si); +} + + +typedef struct { + u8 tpm_probed:1; + u8 tpm_found:1; + u8 tpm_working:1; + u8 if_shutdown:1; + u8 tpm_driver_to_use:4; +} tpm_state_t; + + +static tpm_state_t tpm_state = { + .tpm_driver_to_use = TPM_INVALID_DRIVER, +}; + + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + + +static u32 +is_tpm_present(void) +{ + u32 rc = 0; + unsigned int i; + + for (i = 0; i < TPM_NUM_DRIVERS; i++) { + struct tpm_driver *td = &tpm_drivers[i]; + if (td->probe() != 0) { + td->init(); + tpm_state.tpm_driver_to_use = i; + rc = 1; + break; + } + } + + return rc; +} + +static void +probe_tpm(void) +{ + if (!tpm_state.tpm_probed) { + tpm_state.tpm_probed = 1; + tpm_state.tpm_found = (is_tpm_present() != 0); + tpm_state.tpm_working = tpm_state.tpm_found; + } +} + +static int +has_working_tpm(void) +{ + probe_tpm(); + + return tpm_state.tpm_working; +} + +static struct tcpa_descriptor_rev2 * +find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) +{ + u32 ctr = 0; + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdt_descriptor *rsdt; + u32 length; + u16 off; + + rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address; + if (!rsdt) + return NULL; + + length = rsdt->length; + off = offsetof(struct rsdt_descriptor, entry); + + while ((off + sizeof(rsdt->entry[0])) <= length) { + /* try all pointers to structures */ + tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr]; + + /* valid TCPA ACPI table ? */ + if (tcpa->signature == TCPA_SIGNATURE && + checksum((u8 *)tcpa, tcpa->length) == 0) + break; + + tcpa = NULL; + off += sizeof(rsdt->entry[0]); + ctr++; + } + + return tcpa; +} + + +static struct tcpa_descriptor_rev2 * +find_tcpa_table(void) +{ + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdp_descriptor *rsdp = RsdpAddr; + + if (rsdp) + tcpa = find_tcpa_by_rsdp(rsdp); + else + tpm_state.if_shutdown = 1; + + if (!rsdp) + dprintf(DEBUG_tcg, + "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n"); + else if (!tcpa) + dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n"); + + return tcpa; +} + + +static u8 * +get_lasa_base_ptr(u32 *log_area_minimum_length) +{ + u8 *log_area_start_address = 0; + struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table(); + + if (tcpa) { + log_area_start_address = (u8 *)(long)tcpa->log_area_start_address; + if (log_area_minimum_length) + *log_area_minimum_length = tcpa->log_area_minimum_length; + } + + return log_area_start_address; +} + + +/* clear the ACPI log */ +static void +reset_acpi_log(void) +{ + u32 log_area_minimum_length; + u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length); + + if (log_area_start_address) + memset(log_area_start_address, 0x0, log_area_minimum_length); +} + + +/* + initialize the TCPA ACPI subsystem; find the ACPI tables and determine + where the TCPA table is. + */ +static void +tpm_acpi_init(void) +{ + tpm_state.if_shutdown = 0; + tpm_state.tpm_probed = 0; + tpm_state.tpm_found = 0; + tpm_state.tpm_working = 0; + + if (!has_working_tpm()) { + tpm_state.if_shutdown = 1; + return; + } + + reset_acpi_log(); +} + + +static u32 +transmit(u8 locty, const struct iovec iovec[], + u8 *respbuffer, u32 *respbufferlen, + enum tpmDurationType to_t) +{ + u32 rc = 0; + u32 irc; + struct tpm_driver *td; + unsigned int i; + + if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER) + return TCG_FATAL_COM_ERROR; + + td = &tpm_drivers[tpm_state.tpm_driver_to_use]; + + irc = td->activate(locty); + if (irc != 0) { + /* tpm could not be activated */ + return TCG_FATAL_COM_ERROR; + } + + for (i = 0; iovec[i].length; i++) { + irc = td->senddata(iovec[i].data, + iovec[i].length); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + } + + irc = td->waitdatavalid(); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->waitrespready(to_t); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->readresp(respbuffer, + respbufferlen); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + td->ready(); + + return rc; +} + + +/* + * Send a TPM command with the given ordinal. Append the given buffer + * containing all data in network byte order to the command (this is + * the custom part per command) and expect a response of the given size. + * If a buffer is provided, the response will be copied into it. + */ +static u32 +build_and_send_cmd_od(u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode, + const u8 *otherdata, u32 otherdata_size, + enum tpmDurationType to_t) +{ +#define MAX_APPEND_SIZE 12 +#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags) + u32 rc; + u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE]; + u8 obuffer[MAX_RESPONSE_SIZE]; + struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer; + struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer; + u8 locty = 0; + struct iovec iovec[3]; + u32 obuffer_len = sizeof(obuffer); + u32 idx = 1; + + if (append_size > MAX_APPEND_SIZE || + return_size > MAX_RESPONSE_SIZE) { + dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big."); + return TCG_FIRMWARE_ERROR; + } + + iovec[0].data = trqh; + iovec[0].length = TPM_REQ_HEADER_SIZE + append_size; + + if (otherdata) { + iovec[1].data = (void *)otherdata; + iovec[1].length = otherdata_size; + idx = 2; + } + + iovec[idx].data = NULL; + iovec[idx].length = 0; + + memset(ibuffer, 0x0, sizeof(ibuffer)); + memset(obuffer, 0x0, sizeof(obuffer)); + + trqh->tag = cpu_to_be16(0xc1); + trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size + otherdata_size); + trqh->ordinal = cpu_to_be32(ordinal); + + if (append_size) + memcpy((char *)trqh + sizeof(*trqh), + append, append_size); + + rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t); + if (rc) + return rc; + + *returnCode = be32_to_cpu(trsh->errcode); + + if (resbuffer) + memcpy(resbuffer, trsh, return_size); + + return 0; +} + + +static u32 +build_and_send_cmd(u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode, + enum tpmDurationType to_t) +{ + return build_and_send_cmd_od(ordinal, append, append_size, + resbuffer, return_size, returnCode, + NULL, 0, to_t); +} + + +static u32 +determine_timeouts(void) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_timeouts timeouts; + struct tpm_res_getcap_durations durations; + struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use]; + u32 i; + + rc = build_and_send_cmd(TPM_ORD_GetCapability, + GetCapability_Timeouts, + sizeof(GetCapability_Timeouts), + (u8 *)&timeouts, + sizeof(struct tpm_res_getcap_timeouts), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)" + " = 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_GetCapability, + GetCapability_Durations, + sizeof(GetCapability_Durations), + (u8 *)&durations, + sizeof(struct tpm_res_getcap_durations), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)" + " = 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + for (i = 0; i < 3; i++) + durations.durations[i] = be32_to_cpu(durations.durations[i]); + + for (i = 0; i < 4; i++) + timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]); + + dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n", + timeouts.timeouts[0], + timeouts.timeouts[1], + timeouts.timeouts[2], + timeouts.timeouts[3]); + + dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n", + durations.durations[0], + durations.durations[1], + durations.durations[2]); + + + td->set_timeouts(timeouts.timeouts, durations.durations); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +tpm_startup(void) +{ + u32 rc; + u32 returnCode; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); + rc = build_and_send_cmd(TPM_ORD_Startup, + Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n", + returnCode); + + if (CONFIG_COREBOOT) { + /* with other firmware on the system the TPM may already have been + * initialized + */ + if (returnCode == TPM_INVALID_POSTINIT) + returnCode = 0; + } + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_SelfTestFull, NULL, 0, + NULL, 10, &returnCode, TPM_DURATION_TYPE_LONG); + + dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n", + returnCode); + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TSC_ORD_ResetEstablishmentBit, NULL, 0, + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n", + returnCode); + + if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY)) + goto err_exit; + + rc = determine_timeouts(); + if (rc) + goto err_exit; + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +u32 +tpm_start(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + tpm_acpi_init(); + + return tpm_startup(); +} + + +u32 +tpm_leave_bios(void) +{ + u32 rc; + u32 returnCode; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_NOT_PRESENT_LOCK, + sizeof(PhysicalPresence_NOT_PRESENT_LOCK), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + if (rc || returnCode) + goto err_exit; + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +u32 +tpm_s3_resume(void) +{ + u32 rc; + u32 returnCode; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n"); + + rc = build_and_send_cmd(TPM_ORD_Startup, + Startup_ST_STATE, sizeof(Startup_ST_STATE), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n", + returnCode); + + if (rc || returnCode) + goto err_exit; + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} diff --git a/src/tcgbios.h b/src/tcgbios.h new file mode 100644 index 0000000..c6abd2c --- /dev/null +++ b/src/tcgbios.h @@ -0,0 +1,386 @@ +#ifndef TCGBIOS_H +#define TCGBIOS_H + +#include "types.h" + +#define TCG_MAGIC 0x41504354L + +/* Define for section 12.3 */ +#define TCG_PC_OK 0x0 +#define TCG_PC_TPMERROR 0x1 +#define TCG_PC_LOGOVERFLOW 0x2 +#define TCG_PC_UNSUPPORTED 0x3 + +#define TPM_ALG_SHA 0x4 + +#define TCG_MAGIC 0x41504354L +#define TCG_VERSION_MAJOR 1 +#define TCG_VERSION_MINOR 2 + +#define TPM_OK 0x0 +#define TPM_RET_BASE 0x1 +#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0) +#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1) +#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2) +#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3) +#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4) +#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5) +#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6) +#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7) +#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8) +#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9) +#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa) +#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb) +#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc) +#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd) +#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe) +#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf) +#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10) +#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11) +#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12) +#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13) +#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14) +#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15) +#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16) +#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17) +#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18) +#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19) +#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20) +//define TCG_PC_UNSUPPORTED (TPM_RET_BASE + 0x21) +#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22) +#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23) + + +#define TPM_INVALID_ADR_REQUEST TCG_INVALID_ADR_REQUEST +#define TPM_IS_LOCKED TCG_TPM_IS_LOCKED +#define TPM_INVALID_DEVICE_ID TCG_INVALID_DEVICE_ID +#define TPM_INVALID_VENDOR_ID TCG_INVALID_VENDOR_ID +//define TPM_RESERVED_REG_INVALID +#define TPM_FIRMWARE_ERROR TCG_FIRMWARE_ERROR +#define TPM_UNABLE_TO_OPEN TCG_UNABLE_TO_OPEN +#define TPM_UNABLE_TO_CLOSE TCG_UNABLE_TO_CLOSE +#define TPM_INVALID_RESPONSE TCG_INVALID_RESPONSE +#define TPM_RESPONSE_TIMEOUT TCG_RESPONSE_TIMEOUT +#define TPM_INVALID_ACCESS_REQUEST TCG_INVALID_ACCESS_REQUEST +#define TPM_TRANSFER_ABORT TCG_TRANSFER_ABORT +#define TPM_GENERAL_ERROR TCG_GENERAL_ERROR + + +#define TPM_ORD_SelfTestFull 0x00000050 +#define TPM_ORD_ForceClear 0x0000005d +#define TPM_ORD_GetCapability 0x00000065 +#define TPM_ORD_PhysicalEnable 0x0000006f +#define TPM_ORD_PhysicalDisable 0x00000070 +#define TPM_ORD_SetOwnerInstall 0x00000071 +#define TPM_ORD_PhysicalSetDeactivated 0x00000072 +#define TPM_ORD_Startup 0x00000099 +#define TPM_ORD_PhysicalPresence 0x4000000a +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_SHA1Start 0x000000a0 +#define TPM_ORD_SHA1Update 0x000000a1 +#define TPM_ORD_SHA1Complete 0x000000a2 +#define TSC_ORD_ResetEstablishmentBit 0x4000000b + + +#define TPM_ST_CLEAR 0x1 +#define TPM_ST_STATE 0x2 +#define TPM_ST_DEACTIVATED 0x3 + + +/* TPM command error codes */ +#define TPM_INVALID_POSTINIT 0x26 +#define TPM_BAD_LOCALITY 0x3d + + +/* interrupt identifiers (al register) */ +enum irq_ids { + TCG_StatusCheck = 0, + TCG_HashLogExtendEvent = 1, + TCG_PassThroughToTPM = 2, + TCG_ShutdownPreBootInterface = 3, + TCG_HashLogEvent = 4, + TCG_HashAll = 5, + TCG_TSS = 6, + TCG_CompactHashLogExtendEvent = 7, +}; + +/* event types: 10.4.1 / table 11 */ +#define EV_POST_CODE 1 +#define EV_SEPARATOR 4 +#define EV_ACTION 5 +#define EV_EVENT_TAG 6 +#define EV_COMPACT_HASH 12 +#define EV_IPL 13 +#define EV_IPL_PARTITION_DATA 14 + + +#define STATUS_FLAG_SHUTDOWN (1 << 0) + +#define SHA1_BUFSIZE 20 + + +struct iovec +{ + size_t length; + void *data; +}; + + +/* Input and Output blocks for the TCG BIOS commands */ + +struct hleei_short +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleei_long +{ + u16 ipblength; + u16 reserved; + void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 reserved2; + void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleeo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct pttti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tpmopin[0]; +} PACKED; + + +struct pttto +{ + u16 opblength; + u16 reserved; + u8 tpmopout[0]; +}; + + +struct hlei +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 logeventtype; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; +} PACKED; + + +struct hai +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 algorithmid; +} PACKED; + + +struct ti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tssoperandin[0]; +} PACKED; + + +struct to +{ + u16 opblength; + u16 reserved; + u8 tssoperandout[0]; +} PACKED; + + +struct pcpes +{ + u32 pcrindex; + u32 eventtype; + u8 digest[SHA1_BUFSIZE]; + u32 eventdatasize; + u32 event; +} PACKED; + + +/* 10.4.2.1 */ +struct pcctes +{ + u32 eventid; + u32 eventdatasize; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + +/* 10.4.2.1 w/ 10.4.2.2.1 embedded */ +struct pcctes_romex +{ + u32 eventid; + u32 eventdatasize; + u16 reserved; + u16 pfa; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +#define TPM_REQ_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 ordinal; + +#define TPM_REQ_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +#define TPM_RSP_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 errcode; + +#define TPM_RSP_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +struct tpm_req_header { + TPM_REQ_HEADER; +} PACKED; + + +struct tpm_rsp_header { + TPM_RSP_HEADER; +} PACKED; + + +struct tpm_req_extend { + TPM_REQ_HEADER + u32 pcrindex; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_rsp_extend { + TPM_RSP_HEADER + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_req_getcap_perm_flags { + TPM_REQ_HEADER + u32 capArea; + u32 subCapSize; + u32 subCap; +} PACKED; + + +struct tpm_permanent_flags { + u16 tag; + u8 flags[20]; +} PACKED; + + +enum permFlagsIndex { + PERM_FLAG_IDX_DISABLE = 0, + PERM_FLAG_IDX_OWNERSHIP, + PERM_FLAG_IDX_DEACTIVATED, + PERM_FLAG_IDX_READPUBEK, + PERM_FLAG_IDX_DISABLEOWNERCLEAR, + PERM_FLAG_IDX_ALLOW_MAINTENANCE, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE, +}; + + +struct tpm_res_getcap_perm_flags { + TPM_RSP_HEADER + u32 size; + struct tpm_permanent_flags perm_flags; +} PACKED; + + +struct tpm_res_getcap_ownerauth { + TPM_RSP_HEADER + u32 size; + u8 flag; +} PACKED; + + +struct tpm_res_getcap_timeouts { + TPM_RSP_HEADER + u32 size; + u32 timeouts[4]; +} PACKED; + + +struct tpm_res_getcap_durations { + TPM_RSP_HEADER + u32 size; + u32 durations[3]; +} PACKED; + + +struct tpm_res_sha1start { + TPM_RSP_HEADER + u32 max_num_bytes; +} PACKED; + + +struct tpm_res_sha1complete { + TPM_RSP_HEADER + u8 hash[20]; +} PACKED; + +struct pttti_extend { + struct pttti pttti; + struct tpm_req_extend req; +} PACKED; + + +struct pttto_extend { + struct pttto pttto; + struct tpm_rsp_extend rsp; +} PACKED; + + +enum ipltype { + IPL_BCV = 0, + IPL_EL_TORITO_1, + IPL_EL_TORITO_2 +}; + + +u32 tpm_start(void); +u32 tpm_leave_bios(void); +u32 tpm_s3_resume(void); + +#endif /* TCGBIOS_H */ |