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;
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)
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)
{
return tcpa;
}
-
static struct tcpa_descriptor_rev2 *
find_tcpa_table(void)
{
return tcpa;
}
-
static u8 *
get_lasa_base_ptr(u32 *log_area_minimum_length)
{
return log_area_start_address;
}
-
/* clear the ACPI log */
static void
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
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)
{
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);
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)
tpm_startup();
}
-
void
tpm_prepboot(void)
{
}
/*
- * 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
}
+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)
return rc;
}
-
static u32
compact_hash_log_extend_event_int(u8 *buffer,
u32 info,
return rc;
}
-
void VISIBLE32FLAT
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();
-}