From f51c50a16720feeaa7ddcbfbc798e2da20918239 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sun, 22 Nov 2015 10:57:52 -0500 Subject: tpm: Move code around in tcgbios.c Move like functions near each other. Reduce forward function declarations. This is only code movement - no code changes. This groups the code into six sections: TPM state tracking, TPM hardware interface, ACPI TCPA table interface, Helper functions, Setup and Measurements, BIOS interface. Signed-off-by: Kevin O'Connor --- src/tcgbios.c | 1377 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 681 insertions(+), 696 deletions(-) (limited to 'src/tcgbios.c') diff --git a/src/tcgbios.c b/src/tcgbios.c index 341ab9d..7877840 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -58,31 +58,9 @@ static const u8 GetCapability_Durations[] = { static u8 evt_separator[] = {0xff,0xff,0xff,0xff}; -#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr) - -/* local function prototypes */ - -static u32 build_and_send_cmd(u8 locty, u32 ordinal, - const u8 *append, u32 append_size, - u8 *resbuffer, u32 return_size, u32 *returnCode, - enum tpmDurationType to_t); -static u32 tpm_calling_int19h(void); -static u32 tpm_add_event_separators(void); -static u32 tpm_start_option_rom_scan(void); -static u32 tpm_smbios_measure(void); - -/* 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); -} - +/**************************************************************** + * TPM state tracking + ****************************************************************/ typedef struct { u8 tpm_probed:1; @@ -108,16 +86,20 @@ typedef struct { u8 * log_area_last_entry; } tpm_state_t; - tpm_state_t tpm_state VARLOW = { .tpm_driver_to_use = TPM_INVALID_DRIVER, }; +static u32 +is_preboot_if_shutdown(void) +{ + return tpm_state.if_shutdown; +} -/******************************************************** - Extensions for TCG-enabled BIOS - *******************************************************/ +/**************************************************************** + * TPM hardware interface + ****************************************************************/ static u32 is_tpm_present(void) @@ -156,31 +138,57 @@ has_working_tpm(void) return tpm_state.tpm_working; } -static void -tpm_set_failure(void) +static u32 +transmit(u8 locty, const struct iovec iovec[], + u8 *respbuffer, u32 *respbufferlen, + enum tpmDurationType to_t) { - u32 returnCode; + u32 rc = 0; + u32 irc; + struct tpm_driver *td; + unsigned int i; - /* we will try to deactivate the TPM now - ignoring all errors */ - build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_CMD_ENABLE, - sizeof(PhysicalPresence_CMD_ENABLE), - NULL, 0, &returnCode, - TPM_DURATION_TYPE_SHORT); + if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER) + return TCG_FATAL_COM_ERROR; - build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_PRESENT, - sizeof(PhysicalPresence_PRESENT), - NULL, 0, &returnCode, - TPM_DURATION_TYPE_SHORT); + td = &tpm_drivers[tpm_state.tpm_driver_to_use]; - build_and_send_cmd(0, TPM_ORD_SetTempDeactivated, - NULL, 0, NULL, 0, &returnCode, - TPM_DURATION_TYPE_SHORT); + irc = td->activate(locty); + if (irc != 0) { + /* tpm could not be activated */ + return TCG_FATAL_COM_ERROR; + } - tpm_state.tpm_working = 0; + 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; } + +/**************************************************************** + * ACPI TCPA table interface + ****************************************************************/ + static struct tcpa_descriptor_rev2 * find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) { @@ -218,7 +226,6 @@ find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) return tcpa; } - static struct tcpa_descriptor_rev2 * find_tcpa_table(void) { @@ -242,7 +249,6 @@ find_tcpa_table(void) return tcpa; } - static u8 * get_lasa_base_ptr(u32 *log_area_minimum_length) { @@ -258,7 +264,6 @@ get_lasa_base_ptr(u32 *log_area_minimum_length) return log_area_start_address; } - /* clear the ACPI log */ static void reset_acpi_log(void) @@ -275,75 +280,72 @@ reset_acpi_log(void) tpm_state.entry_count = 0; } +static void tpm_set_failure(void); /* - initialize the TCPA ACPI subsystem; find the ACPI tables and determine - where the TCPA table is. + * Extend the ACPI log with the given entry by copying the + * entry data into the log. + * Input + * pcpes : Pointer to the event 'header' to be copied into the log + * event : Pointer to the event 'body' to be copied into the log + * event_length: Length of the event array + * entry_count : optional pointer to get the current entry count + * + * Output: + * Returns an error code in case of faiure, 0 in case of success */ -static void -tpm_acpi_init(void) +static u32 +tpm_extend_acpi_log(struct pcpes *pcpes, + const char *event, u32 event_length, + u16 *entry_count) { - tpm_state.if_shutdown = 0; - tpm_state.tpm_probed = 0; - tpm_state.tpm_found = 0; - tpm_state.tpm_working = 0; + u32 size; - if (!has_working_tpm()) { - tpm_state.if_shutdown = 1; - return; - } + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; - reset_acpi_log(); -} + dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n", + tpm_state.log_area_start_address, tpm_state.log_area_next_entry); + if (tpm_state.log_area_next_entry == NULL) { -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; + tpm_set_failure(); - if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER) - return TCG_FATAL_COM_ERROR; + return TCG_PC_LOGOVERFLOW; + } - td = &tpm_drivers[tpm_state.tpm_driver_to_use]; + size = offsetof(struct pcpes, event) + event_length; - irc = td->activate(locty); - if (irc != 0) { - /* tpm could not be activated */ - return TCG_FATAL_COM_ERROR; - } + if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > + tpm_state.log_area_minimum_length) { + dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size); - for (i = 0; iovec[i].length; i++) { - irc = td->senddata(iovec[i].data, - iovec[i].length); - if (irc != 0) - return TCG_FATAL_COM_ERROR; + tpm_set_failure(); + + return TCG_PC_LOGOVERFLOW; } - irc = td->waitdatavalid(); - if (irc != 0) - return TCG_FATAL_COM_ERROR; + pcpes->eventdatasize = event_length; - irc = td->waitrespready(to_t); - if (irc != 0) - return TCG_FATAL_COM_ERROR; + memcpy(tpm_state.log_area_next_entry, pcpes, offsetof(struct pcpes, event)); + memcpy(tpm_state.log_area_next_entry + offsetof(struct pcpes, event), + event, event_length); - irc = td->readresp(respbuffer, - respbufferlen); - if (irc != 0) - return TCG_FATAL_COM_ERROR; + tpm_state.log_area_last_entry = tpm_state.log_area_next_entry; + tpm_state.log_area_next_entry += size; + tpm_state.entry_count++; - td->ready(); + if (entry_count) + *entry_count = tpm_state.entry_count; - return rc; + return 0; } +/**************************************************************** + * Helper functions + ****************************************************************/ + /* * Send a TPM command with the given ordinal. Append the given buffer * containing all data in network byte order to the command (this is @@ -393,6 +395,31 @@ build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size, return 0; } +static void +tpm_set_failure(void) +{ + u32 returnCode; + + /* we will try to deactivate the TPM now - ignoring all errors */ + build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 0, &returnCode, + TPM_DURATION_TYPE_SHORT); + + build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + NULL, 0, &returnCode, + TPM_DURATION_TYPE_SHORT); + + build_and_send_cmd(0, TPM_ORD_SetTempDeactivated, + NULL, 0, NULL, 0, &returnCode, + TPM_DURATION_TYPE_SHORT); + + tpm_state.tpm_working = 0; +} + static u32 determine_timeouts(void) { @@ -458,47 +485,283 @@ err_exit: return TCG_TCG_COMMAND_ERROR; } - static u32 -tpm_startup(void) +pass_through_to_tpm(u8 locty, const u8 *cmd, u32 cmd_length, + u8 *resp, u32 *resp_length) { - u32 rc; - u32 returnCode; + struct iovec iovec[2] = {{ 0 }}; + const u32 *tmp; - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; + if (cmd_length < TPM_REQ_HEADER_SIZE) + return TCG_INVALID_INPUT_PARA; - dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); - rc = build_and_send_cmd(0, TPM_ORD_Startup, - Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), - NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + iovec[0].data = cmd; + tmp = (const u32 *)&((u8 *)iovec[0].data)[2]; + iovec[0].length = cpu_to_be32(*tmp); - dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n", - returnCode); + if (cmd_length != iovec[0].length) + return TCG_INVALID_INPUT_PARA; - if (CONFIG_COREBOOT) { - /* with other firmware on the system the TPM may already have been - * initialized - */ - if (returnCode == TPM_INVALID_POSTINIT) - returnCode = 0; - } + return transmit(locty, iovec, resp, resp_length, + TPM_DURATION_TYPE_LONG /* worst case */); - if (rc || returnCode) - goto err_exit; +} - rc = determine_timeouts(); - if (rc) - goto err_exit; +static u32 +tpm_extend(u8 *hash, u32 pcrindex) +{ + u32 rc; + struct tpm_req_extend tre = { + .tag = cpu_to_be16(TPM_TAG_RQU_CMD), + .totlen = cpu_to_be32(sizeof(tre)), + .ordinal = cpu_to_be32(TPM_ORD_Extend), + .pcrindex = cpu_to_be32(pcrindex), + }; + struct tpm_rsp_extend rsp; + u32 resp_length = sizeof(rsp); - rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0, - NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG); + memcpy(tre.digest, hash, sizeof(tre.digest)); - dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n", - returnCode); + rc = pass_through_to_tpm(0, (u8 *)&tre, sizeof(tre), + (u8 *)&rsp, &resp_length); - if (rc || returnCode) - goto err_exit; + if (rc || resp_length != sizeof(rsp)) + tpm_set_failure(); + + return rc; +} + +static u32 +hash_log_event(const void *hashdata, u32 hashdata_length, + struct pcpes *pcpes, + const char *event, u32 event_length, + u16 *entry_count) +{ + u32 rc = 0; + + if (pcpes->pcrindex >= 24) + return TCG_INVALID_INPUT_PARA; + + if (hashdata) { + rc = sha1(hashdata, hashdata_length, pcpes->digest); + if (rc) + return rc; + } + + return tpm_extend_acpi_log(pcpes, event, event_length, entry_count); +} + +static u32 +hash_log_extend_event(const void *hashdata, u32 hashdata_length, + struct pcpes *pcpes, + const char *event, u32 event_length, + u32 pcrindex, u16 *entry_count) +{ + u32 rc; + + rc = hash_log_event(hashdata, hashdata_length, pcpes, + event, event_length, entry_count); + if (rc) + return rc; + + return tpm_extend(pcpes->digest, pcrindex); +} + +/* + * 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 section on 'Event Types' + * event : pointer to info (e.g., string) to be added to log as-is + * event_length: length of the event + * hashdata : pointer to the data to be hashed + * hashdata_length: length of the data to be hashed + */ +static u32 +tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, + const char *event, u32 event_length, + const u8 *hashdata, u32 hashdata_length) +{ + struct pcpes pcpes = { + .pcrindex = pcrindex, + .eventtype = event_type, + }; + u16 entry_count; + + return hash_log_extend_event(hashdata, hashdata_length, &pcpes, + event, event_length, pcrindex, + &entry_count); +} + + +/**************************************************************** + * Setup and Measurements + ****************************************************************/ + +/* + * Add a measurement to the list of measurements + * pcrIndex : PCR to be extended + * event_type : type of event; specs section on 'Event Types' + * data : additional parameter; used as parameter for + * 'action index' + */ +static u32 +tpm_add_measurement(u32 pcrIndex, + u16 event_type, + const char *string) +{ + u32 rc; + u32 len; + + switch (event_type) { + case EV_SEPARATOR: + len = sizeof(evt_separator); + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + (char *)NULL, 0, + (u8 *)evt_separator, len); + break; + + case EV_ACTION: + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + string, strlen(string), + (u8 *)string, strlen(string)); + break; + + default: + rc = TCG_INVALID_INPUT_PARA; + } + + return rc; +} + +static u32 +tpm_calling_int19h(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(4, EV_ACTION, + "Calling INT 19h"); +} + +/* + * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events' + */ +static u32 +tpm_add_event_separators(void) +{ + u32 rc; + u32 pcrIndex = 0; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + while (pcrIndex <= 7) { + rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL); + if (rc) + break; + pcrIndex ++; + } + + return rc; +} + +/* + * Add measurement to the log about option rom scan + */ +static u32 +tpm_start_option_rom_scan(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(2, EV_ACTION, + "Start Option ROM Scan"); +} + +static u32 +tpm_smbios_measure(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc; + struct pcctes pcctes = { + .eventid = 1, + .eventdatasize = SHA1_BUFSIZE, + }; + struct smbios_entry_point *sep = SMBiosAddr; + + dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep); + + if (!sep) + return 0; + + rc = sha1((const u8 *)sep->structure_table_address, + sep->structure_table_length, pcctes.digest); + if (rc) + return rc; + + return tpm_add_measurement_to_log(1, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} + +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(0, TPM_ORD_Startup, + Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), + NULL, 0, &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 = determine_timeouts(); + if (rc) + goto err_exit; + + rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0, + NULL, 0, &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(3, TSC_ORD_ResetEstablishmentBit, NULL, 0, NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); @@ -528,6 +791,25 @@ err_exit: return TCG_TCG_COMMAND_ERROR; } +/* + 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(); +} void tpm_setup(void) @@ -542,7 +824,6 @@ tpm_setup(void) tpm_startup(); } - void tpm_prepboot(void) { @@ -586,275 +867,221 @@ err_exit: } /* - * Extend the ACPI log with the given entry by copying the - * entry data into the log. - * Input - * pcpes : Pointer to the event 'header' to be copied into the log - * event : Pointer to the event 'body' to be copied into the log - * event_length: Length of the event array - * entry_count : optional pointer to get the current entry count - * - * Output: - * Returns an error code in case of faiure, 0 in case of success + * Add measurement to the log about an option rom */ -static u32 -tpm_extend_acpi_log(struct pcpes *pcpes, - const char *event, u32 event_length, - u16 *entry_count) +u32 +tpm_option_rom(const void *addr, u32 len) { - u32 size; + if (!CONFIG_TCGBIOS) + return 0; if (!has_working_tpm()) return TCG_GENERAL_ERROR; - dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n", - tpm_state.log_area_start_address, tpm_state.log_area_next_entry); - - if (tpm_state.log_area_next_entry == NULL) { + u32 rc; + struct pcctes_romex pcctes = { + .eventid = 7, + .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE, + }; - tpm_set_failure(); + rc = sha1((const u8 *)addr, len, pcctes.digest); + if (rc) + return rc; - return TCG_PC_LOGOVERFLOW; - } + return tpm_add_measurement_to_log(2, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} - size = offsetof(struct pcpes, event) + event_length; +/* + * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to + * the list of measurements. + */ +static u32 +tpm_add_bootdevice(u32 bootcd, u32 bootdrv) +{ + const char *string; - if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > - tpm_state.log_area_minimum_length) { - dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size); + if (!CONFIG_TCGBIOS) + return 0; - tpm_set_failure(); + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; - return TCG_PC_LOGOVERFLOW; - } + switch (bootcd) { + case 0: + switch (bootdrv) { + case 0: + string = "Booting BCV device 00h (Floppy)"; + break; - pcpes->eventdatasize = event_length; + case 0x80: + string = "Booting BCV device 80h (HDD)"; + break; - memcpy(tpm_state.log_area_next_entry, pcpes, offsetof(struct pcpes, event)); - memcpy(tpm_state.log_area_next_entry + offsetof(struct pcpes, event), - event, event_length); + default: + string = "Booting unknown device"; + break; + } - tpm_state.log_area_last_entry = tpm_state.log_area_next_entry; - tpm_state.log_area_next_entry += size; - tpm_state.entry_count++; + break; - if (entry_count) - *entry_count = tpm_state.entry_count; + default: + string = "Booting from CD ROM device"; + } - return 0; + return tpm_add_measurement_to_log(4, EV_ACTION, + string, strlen(string), + (u8 *)string, strlen(string)); } - +/* + * Add a measurement related to Initial Program Loader to the log. + * Creates two log entries. + * + * Input parameter: + * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito + * addr : address where the IP data are located + * length : IP data length in bytes + */ static u32 -is_preboot_if_shutdown(void) +tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length) { - return tpm_state.if_shutdown; -} + u32 rc; + const char *string; + switch (bootcd) { + case IPL_EL_TORITO_1: + /* specs: see section 'El Torito' */ + string = "EL TORITO IPL"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, length); + break; -static u32 -shutdown_preboot_interface(void) -{ - u32 rc = 0; + case IPL_EL_TORITO_2: + /* specs: see section 'El Torito' */ + string = "BOOT CATALOG"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr, length); + break; - if (!is_preboot_if_shutdown()) { - tpm_state.if_shutdown = 1; - } else { - rc = TCG_INTERFACE_SHUTDOWN; + default: + /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */ + /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */ + string = "MBR"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, 0x1b8); + + if (rc) + break; + + /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */ + string = "MBR PARTITION_TABLE"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr + 0x1b8, 0x48); } return rc; } -static u32 -pass_through_to_tpm(u8 locty, const u8 *cmd, u32 cmd_length, - u8 *resp, u32 *resp_length) +u32 +tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length) { - struct iovec iovec[2] = {{ 0 }}; - const u32 *tmp; - - if (cmd_length < TPM_REQ_HEADER_SIZE) - return TCG_INVALID_INPUT_PARA; - - iovec[0].data = cmd; - tmp = (const u32 *)&((u8 *)iovec[0].data)[2]; - iovec[0].length = cpu_to_be32(*tmp); + if (!CONFIG_TCGBIOS) + return 0; - if (cmd_length != iovec[0].length) - return TCG_INVALID_INPUT_PARA; + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; - return transmit(locty, iovec, resp, resp_length, - TPM_DURATION_TYPE_LONG /* worst case */); + u32 rc = tpm_add_bootdevice(0, bootdrv); + if (rc) + return rc; + return tpm_ipl(IPL_BCV, addr, length); } -static u32 -pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto) +u32 +tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length) { - u32 rc = 0; - u32 resbuflen = 0; - struct tpm_req_header *trh; + if (!CONFIG_TCGBIOS) + return 0; - if (is_preboot_if_shutdown()) { - rc = TCG_INTERFACE_SHUTDOWN; - goto err_exit; - } + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; - trh = (struct tpm_req_header *)pttti->tpmopin; + u32 rc = tpm_add_bootdevice(1, bootdrv); + if (rc) + return rc; - if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE || - pttti->opblength < sizeof(struct pttto) || - be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) { - rc = TCG_INVALID_INPUT_PARA; - goto err_exit; - } + return tpm_ipl(IPL_EL_TORITO_1, addr, length); +} - resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout); +u32 +tpm_add_cdrom_catalog(const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; - rc = pass_through_to_tpm(0, pttti->tpmopin, - pttti->ipblength - offsetof(struct pttti, tpmopin), - pttto->tpmopout, &resbuflen); + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + u32 rc = tpm_add_bootdevice(1, 0); if (rc) - goto err_exit; - - pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen; - pttto->reserved = 0; - -err_exit: - if (rc != 0) { - pttto->opblength = 4; - pttto->reserved = 0; - } + return rc; - return rc; + return tpm_ipl(IPL_EL_TORITO_2, addr, length); } - -static u32 -tpm_extend(u8 *hash, u32 pcrindex) +void +tpm_s3_resume(void) { u32 rc; - struct tpm_req_extend tre = { - .tag = cpu_to_be16(TPM_TAG_RQU_CMD), - .totlen = cpu_to_be32(sizeof(tre)), - .ordinal = cpu_to_be32(TPM_ORD_Extend), - .pcrindex = cpu_to_be32(pcrindex), - }; - struct tpm_rsp_extend rsp; - u32 resp_length = sizeof(rsp); + u32 returnCode; - memcpy(tre.digest, hash, sizeof(tre.digest)); + if (!CONFIG_TCGBIOS) + return; - rc = pass_through_to_tpm(0, (u8 *)&tre, sizeof(tre), - (u8 *)&rsp, &resp_length); + if (!has_working_tpm()) + return; - if (rc || resp_length != sizeof(rsp)) - tpm_set_failure(); + dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n"); - return rc; -} + rc = build_and_send_cmd(0, TPM_ORD_Startup, + Startup_ST_STATE, sizeof(Startup_ST_STATE), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n", + returnCode); -static u32 -hash_all_int(const struct hai *hai, u8 *hash) -{ - if (is_preboot_if_shutdown() != 0) - return TCG_INTERFACE_SHUTDOWN; - - if (hai->ipblength != sizeof(struct hai) || - hai->hashdataptr == 0 || - hai->hashdatalen == 0 || - hai->algorithmid != TPM_ALG_SHA) - return TCG_INVALID_INPUT_PARA; - - return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash); -} - -static u32 -hash_log_event(const void *hashdata, u32 hashdata_length, - struct pcpes *pcpes, - const char *event, u32 event_length, - u16 *entry_count) -{ - u32 rc = 0; - - if (pcpes->pcrindex >= 24) - return TCG_INVALID_INPUT_PARA; - - if (hashdata) { - rc = sha1(hashdata, hashdata_length, pcpes->digest); - if (rc) - return rc; - } - - return tpm_extend_acpi_log(pcpes, event, event_length, entry_count); -} - -static u32 -hash_log_event_int(const struct hlei *hlei, struct hleo *hleo) -{ - u32 rc = 0; - u16 size; - struct pcpes *pcpes; - u16 entry_count; - - if (is_preboot_if_shutdown() != 0) { - rc = TCG_INTERFACE_SHUTDOWN; - goto err_exit; - } - - size = hlei->ipblength; - if (size != sizeof(*hlei)) { - rc = TCG_INVALID_INPUT_PARA; + if (rc || returnCode) goto err_exit; - } - pcpes = (struct pcpes *)hlei->logdataptr; + return; - if (pcpes->pcrindex >= 24 || - pcpes->pcrindex != hlei->pcrindex || - pcpes->eventtype != hlei->logeventtype || - hlei->logdatalen != - offsetof(struct pcpes, event) + pcpes->eventdatasize) { - rc = TCG_INVALID_INPUT_PARA; - goto err_exit; - } +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); - rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen, - pcpes, (char *)&pcpes->event, pcpes->eventdatasize, - &entry_count); - if (rc) - goto err_exit; + tpm_set_failure(); +} - /* updating the log was fine */ - hleo->opblength = sizeof(struct hleo); - hleo->reserved = 0; - hleo->eventnumber = entry_count; -err_exit: - if (rc != 0) { - hleo->opblength = 2; - hleo->reserved = 0; - } +/**************************************************************** + * BIOS interface + ****************************************************************/ - return rc; +static inline void *input_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->es, regs->di); } -static u32 -hash_log_extend_event(const void *hashdata, u32 hashdata_length, - struct pcpes *pcpes, - const char *event, u32 event_length, - u32 pcrindex, u16 *entry_count) +static inline void *output_buf32(struct bregs *regs) { - u32 rc; - - rc = hash_log_event(hashdata, hashdata_length, pcpes, - event, event_length, entry_count); - if (rc) - return rc; - - return tpm_extend(pcpes->digest, pcrindex); + return MAKE_FLATPTR(regs->ds, regs->si); } static u32 @@ -926,6 +1153,126 @@ err_exit: } +static u32 +pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto) +{ + u32 rc = 0; + u32 resbuflen = 0; + struct tpm_req_header *trh; + + if (is_preboot_if_shutdown()) { + rc = TCG_INTERFACE_SHUTDOWN; + goto err_exit; + } + + trh = (struct tpm_req_header *)pttti->tpmopin; + + if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE || + pttti->opblength < sizeof(struct pttto) || + be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout); + + rc = pass_through_to_tpm(0, pttti->tpmopin, + pttti->ipblength - offsetof(struct pttti, tpmopin), + pttto->tpmopout, &resbuflen); + + if (rc) + goto err_exit; + + pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen; + pttto->reserved = 0; + +err_exit: + if (rc != 0) { + pttto->opblength = 4; + pttto->reserved = 0; + } + + return rc; +} + +static u32 +shutdown_preboot_interface(void) +{ + u32 rc = 0; + + if (!is_preboot_if_shutdown()) { + tpm_state.if_shutdown = 1; + } else { + rc = TCG_INTERFACE_SHUTDOWN; + } + + return rc; +} + +static u32 +hash_log_event_int(const struct hlei *hlei, struct hleo *hleo) +{ + u32 rc = 0; + u16 size; + struct pcpes *pcpes; + u16 entry_count; + + if (is_preboot_if_shutdown() != 0) { + rc = TCG_INTERFACE_SHUTDOWN; + goto err_exit; + } + + size = hlei->ipblength; + if (size != sizeof(*hlei)) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + pcpes = (struct pcpes *)hlei->logdataptr; + + if (pcpes->pcrindex >= 24 || + pcpes->pcrindex != hlei->pcrindex || + pcpes->eventtype != hlei->logeventtype || + hlei->logdatalen != + offsetof(struct pcpes, event) + pcpes->eventdatasize) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + rc = hash_log_event(hlei->hashdataptr, hlei->hashdatalen, + pcpes, (char *)&pcpes->event, pcpes->eventdatasize, + &entry_count); + if (rc) + goto err_exit; + + /* updating the log was fine */ + hleo->opblength = sizeof(struct hleo); + hleo->reserved = 0; + hleo->eventnumber = entry_count; + +err_exit: + if (rc != 0) { + hleo->opblength = 2; + hleo->reserved = 0; + } + + return rc; +} + +static u32 +hash_all_int(const struct hai *hai, u8 *hash) +{ + if (is_preboot_if_shutdown() != 0) + return TCG_INTERFACE_SHUTDOWN; + + if (hai->ipblength != sizeof(struct hai) || + hai->hashdataptr == 0 || + hai->hashdatalen == 0 || + hai->algorithmid != TPM_ALG_SHA) + return TCG_INVALID_INPUT_PARA; + + return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash); +} static u32 tss_int(struct ti *ti, struct to *to) @@ -944,7 +1291,6 @@ tss_int(struct ti *ti, struct to *to) return rc; } - static u32 compact_hash_log_extend_event_int(u8 *buffer, u32 info, @@ -975,7 +1321,6 @@ compact_hash_log_extend_event_int(u8 *buffer, return rc; } - void VISIBLE32FLAT tpm_interrupt_handler32(struct bregs *regs) { @@ -1053,363 +1398,3 @@ tpm_interrupt_handler32(struct bregs *regs) return; } - -/* - * 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 section on 'Event Types' - * event : pointer to info (e.g., string) to be added to log as-is - * event_length: length of the event - * hashdata : pointer to the data to be hashed - * hashdata_length: length of the data to be hashed - */ -static u32 -tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, - const char *event, u32 event_length, - const u8 *hashdata, u32 hashdata_length) -{ - struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = event_type, - }; - u16 entry_count; - - return hash_log_extend_event(hashdata, hashdata_length, &pcpes, - event, event_length, pcrindex, - &entry_count); -} - - -/* - * Add a measurement to the list of measurements - * pcrIndex : PCR to be extended - * event_type : type of event; specs section on 'Event Types' - * data : additional parameter; used as parameter for - * 'action index' - */ -static u32 -tpm_add_measurement(u32 pcrIndex, - u16 event_type, - const char *string) -{ - u32 rc; - u32 len; - - switch (event_type) { - case EV_SEPARATOR: - len = sizeof(evt_separator); - rc = tpm_add_measurement_to_log(pcrIndex, event_type, - (char *)NULL, 0, - (u8 *)evt_separator, len); - break; - - case EV_ACTION: - rc = tpm_add_measurement_to_log(pcrIndex, event_type, - string, strlen(string), - (u8 *)string, strlen(string)); - break; - - default: - rc = TCG_INVALID_INPUT_PARA; - } - - return rc; -} - - -static u32 -tpm_calling_int19h(void) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - return tpm_add_measurement(4, EV_ACTION, - "Calling INT 19h"); -} - -/* - * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events' - */ -static u32 -tpm_add_event_separators(void) -{ - u32 rc; - u32 pcrIndex = 0; - - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - while (pcrIndex <= 7) { - rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL); - if (rc) - break; - pcrIndex ++; - } - - return rc; -} - - -/* - * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to - * the list of measurements. - */ -static u32 -tpm_add_bootdevice(u32 bootcd, u32 bootdrv) -{ - const char *string; - - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - switch (bootcd) { - case 0: - switch (bootdrv) { - case 0: - string = "Booting BCV device 00h (Floppy)"; - break; - - case 0x80: - string = "Booting BCV device 80h (HDD)"; - break; - - default: - string = "Booting unknown device"; - break; - } - - break; - - default: - string = "Booting from CD ROM device"; - } - - return tpm_add_measurement_to_log(4, EV_ACTION, - string, strlen(string), - (u8 *)string, strlen(string)); -} - - -/* - * Add measurement to the log about option rom scan - */ -static u32 -tpm_start_option_rom_scan(void) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - return tpm_add_measurement(2, EV_ACTION, - "Start Option ROM Scan"); -} - - -/* - * Add measurement to the log about an option rom - */ -u32 -tpm_option_rom(const void *addr, u32 len) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - u32 rc; - struct pcctes_romex pcctes = { - .eventid = 7, - .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE, - }; - - rc = sha1((const u8 *)addr, len, pcctes.digest); - if (rc) - return rc; - - return tpm_add_measurement_to_log(2, - EV_EVENT_TAG, - (const char *)&pcctes, sizeof(pcctes), - (u8 *)&pcctes, sizeof(pcctes)); -} - - -static u32 -tpm_smbios_measure(void) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - u32 rc; - struct pcctes pcctes = { - .eventid = 1, - .eventdatasize = SHA1_BUFSIZE, - }; - struct smbios_entry_point *sep = SMBiosAddr; - - dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep); - - if (!sep) - return 0; - - rc = sha1((const u8 *)sep->structure_table_address, - sep->structure_table_length, pcctes.digest); - if (rc) - return rc; - - return tpm_add_measurement_to_log(1, - EV_EVENT_TAG, - (const char *)&pcctes, sizeof(pcctes), - (u8 *)&pcctes, sizeof(pcctes)); -} - - -/* - * Add a measurement related to Initial Program Loader to the log. - * Creates two log entries. - * - * Input parameter: - * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito - * addr : address where the IP data are located - * length : IP data length in bytes - */ -static u32 -tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length) -{ - u32 rc; - const char *string; - - switch (bootcd) { - case IPL_EL_TORITO_1: - /* specs: see section 'El Torito' */ - string = "EL TORITO IPL"; - rc = tpm_add_measurement_to_log(4, EV_IPL, - string, strlen(string), - addr, length); - break; - - case IPL_EL_TORITO_2: - /* specs: see section 'El Torito' */ - string = "BOOT CATALOG"; - rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, - string, strlen(string), - addr, length); - break; - - default: - /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */ - /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */ - string = "MBR"; - rc = tpm_add_measurement_to_log(4, EV_IPL, - string, strlen(string), - addr, 0x1b8); - - if (rc) - break; - - /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */ - string = "MBR PARTITION_TABLE"; - rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, - string, strlen(string), - addr + 0x1b8, 0x48); - } - - return rc; -} - -u32 -tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - u32 rc = tpm_add_bootdevice(0, bootdrv); - if (rc) - return rc; - - return tpm_ipl(IPL_BCV, addr, length); -} - -u32 -tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - u32 rc = tpm_add_bootdevice(1, bootdrv); - if (rc) - return rc; - - return tpm_ipl(IPL_EL_TORITO_1, addr, length); -} - -u32 -tpm_add_cdrom_catalog(const u8 *addr, u32 length) -{ - if (!CONFIG_TCGBIOS) - return 0; - - if (!has_working_tpm()) - return TCG_GENERAL_ERROR; - - u32 rc = tpm_add_bootdevice(1, 0); - if (rc) - return rc; - - return tpm_ipl(IPL_EL_TORITO_2, addr, length); -} - -void -tpm_s3_resume(void) -{ - u32 rc; - u32 returnCode; - - if (!CONFIG_TCGBIOS) - return; - - if (!has_working_tpm()) - return; - - dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n"); - - rc = build_and_send_cmd(0, TPM_ORD_Startup, - Startup_ST_STATE, sizeof(Startup_ST_STATE), - NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); - - dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n", - returnCode); - - if (rc || returnCode) - goto err_exit; - - return; - -err_exit: - dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); - - tpm_set_failure(); -} -- cgit v1.1