Index: seabios/src/post.c
===================================================================
--- seabios.orig/src/post.c
+++ seabios/src/post.c
@@ -197,6 +197,9 @@ init_hw(void)
 void VISIBLE32FLAT
 startBoot(void)
 {
+    tcpa_calling_int19h();
+    tcpa_add_event_separators();
+
     // Clear low-memory allocations (required by PMM spec).
     memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
 
@@ -254,6 +257,7 @@ maininit(void)
     // Initialize tpm (after acpi tables were written)
     tcpa_acpi_init();
     tcpa_startup();
+    tcpa_smbios_measure();
 
     // Run vga option rom
     vga_setup();
Index: seabios/src/optionroms.c
===================================================================
--- seabios.orig/src/optionroms.c
+++ seabios/src/optionroms.c
@@ -14,6 +14,7 @@
 #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
 #include "boot.h" // IPL
 #include "paravirt.h" // qemu_cfg_*
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -136,6 +137,7 @@ is_valid_rom(struct rom_header *rom)
         if (EnforceChecksum)
             return 0;
     }
+    tcpa_option_rom(rom, len);
     return 1;
 }
 
@@ -399,6 +401,8 @@ optionrom_setup(void)
     memset(sources, 0, sizeof(sources));
     u32 post_vga = RomEnd;
 
+    tcpa_start_option_rom_scan();
+
     if (CONFIG_OPTIONROMS_DEPLOYED) {
         // Option roms are already deployed on the system.
         u32 pos = RomEnd;
Index: seabios/src/boot.c
===================================================================
--- seabios.orig/src/boot.c
+++ seabios/src/boot.c
@@ -547,6 +547,10 @@ boot_disk(u8 bootdrv, int checksig)
         }
     }
 
+    tcpa_add_bootdevice(0, bootdrv);
+    /* specs: 8.2.3 steps 4 and 5 */
+    tcpa_ipl(IPL_BCV, MAKE_FLATPTR(bootseg, 0), 512);
+
     /* Canonicalize bootseg:bootip */
     u16 bootip = (bootseg & 0x0fff) << 4;
     bootseg &= 0xf000;
@@ -571,6 +575,11 @@ boot_cdrom(struct drive_s *drive_g)
     u16 ebda_seg = get_ebda_seg();
     u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
     u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
+
+    tcpa_add_bootdevice(1, bootdrv);
+    /* specs: 8.2.5.6 */
+    tcpa_ipl(IPL_EL_TORITO_1, MAKE_FLATPTR(bootseg, 0), 512);
+
     /* Canonicalize bootseg:bootip */
     u16 bootip = (bootseg & 0x0fff) << 4;
     bootseg &= 0xf000;
@@ -634,6 +643,8 @@ do_boot(u16 seq_nr)
         break;
     }
 
+    tcpa_returned_via_int18h();
+
     // Boot failed: invoke the boot recovery function
     struct bregs br;
     memset(&br, 0, sizeof(br));
Index: seabios/src/cdrom.c
===================================================================
--- seabios.orig/src/cdrom.c
+++ seabios/src/cdrom.c
@@ -11,6 +11,7 @@
 #include "biosvar.h" // GET_EBDA
 #include "ata.h" // ATA_CMD_REQUEST_SENSE
 #include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -291,6 +292,11 @@ cdrom_boot(struct drive_s *drive_g)
     if (buffer[0x20] != 0x88)
         return 11; // Bootable
 
+    /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
+    /* measure 2048 bytes (one sector) */
+    tcpa_add_bootdevice(1, 0);
+    tcpa_ipl(IPL_EL_TORITO_2, MAKE_FLATPTR(GET_SEG(SS), buffer), 2048);
+
     u16 ebda_seg = get_ebda_seg();
     u8 media = buffer[0x21];
     SET_EBDA2(ebda_seg, cdemu.media, media);
@@ -317,6 +323,10 @@ cdrom_boot(struct drive_s *drive_g)
     if (ret)
         return 12;
 
+    /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
+    /* measure 1st 512 bytes */
+    tcpa_ipl(IPL_EL_TORITO_1, MAKE_FLATPTR(boot_segment, 0), 512);
+
     if (media == 0) {
         // No emulation requested - return success.
         SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -16,6 +16,7 @@
 #include "tcgbios.h"// tcpa_*, prototypes
 #include "acpi.h"  // RSDP_SIGNATURE, rsdt_descriptor
 #include "sha1.h"  // sha1
+#include "smbios.h" // get_smbios_entry_point
 
 
 static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR };
@@ -49,6 +50,8 @@ static const u8 GetCapability_Durations[
     0x00, 0x00, 0x01, 0x20
 };
 
+static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
+
 
 #define RSDP_CAST(ptr)   ((struct rsdp_descriptor *)ptr)
 
@@ -1090,4 +1093,360 @@ tcpa_interrupt_handler32(struct bregs *r
 }
 
 
+/*
+ * Add a measurement to the log; the data at data_seg:data/length are
+ * appended to the TCG_PCClientPCREventStruct
+ *
+ * Input parameters:
+ *  pcrIndex   : which PCR to extend
+ *  event_type : type of event; specs 10.4.1
+ *  data       : pointer to the data (i.e., string) to be added to the log
+ *  length     : length of the data
+ */
+static u32
+tcpa_add_measurement_to_log(u32 pcrIndex,
+                            u32 event_type,
+                            const char *data, u32 length)
+{
+    u32 rc = 0;
+    struct hleeo hleeo;
+    u8 _pcpes[offsetof(struct pcpes, event) + 400];
+    struct pcpes *pcpes = (struct pcpes *)_pcpes;
+
+    if (length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
+
+        pcpes->pcrindex      = pcrIndex;
+        pcpes->eventtype     = event_type;
+        memset(&pcpes->digest, 0x0, sizeof(pcpes->digest));
+        pcpes->eventdatasize = length;
+        memcpy(&pcpes->event, data, length);
+
+        struct hleei_short hleei = {
+            .ipblength   = sizeof(hleei),
+            .hashdataptr = &pcpes->event,
+            .hashdatalen = length,
+            .pcrindex    = pcrIndex,
+            .logdataptr  = _pcpes,
+            .logdatalen  = length + offsetof(struct pcpes, event),
+        };
+
+        rc = hash_log_extend_event(&hleei, &hleeo);
+    } else {
+        rc = TCG_GENERAL_ERROR;
+    }
+
+    return rc;
+}
+
+
+/*
+ * Add a measurement to the log; further description of the data
+ * that are to be hashed are NOT appended to the TCG_PCClientPCREventStruc.
+ * Input parameters:
+ *  pcrIndex   : PCR to extend
+ *  event_type : type of event; specs 10.4.1
+ *  ptr        : 32 bit pointer to the data to be hashed
+ *  length     : length of the data to be hashed
+ *
+ * Returns lower 16 bit of return code of TCG_HashLogExtendEvent. '0' means
+ * success, otherwise an error is indicated.
+ */
+static u32
+tcpa_add_measurement_to_log_simple(u32 pcrIndex,
+                                   u16 event_type,
+                                   const u8 *ptr, u32 length)
+{
+    struct hleeo hleeo;
+    struct pcpes pcpes = {
+        .pcrindex = pcrIndex,
+        .eventtype = event_type,
+        /* specs: 10.4.1, EV_IPL eventfield should not contain the code.*/
+        .eventdatasize = 0,
+        .event = 0,
+    };
+    struct hleei_short hleei = {
+        .ipblength   = sizeof(hleei),
+        .hashdataptr = ptr,
+        .hashdatalen = length,
+        .pcrindex    = pcrIndex,
+        .logdataptr  = &pcpes,
+        .logdatalen  = offsetof(struct pcpes, event),
+    };
+
+    return hash_log_extend_event(&hleei, &hleeo);
+}
+
+
+/*
+ * Add a measurement to the list of measurements
+ * pcrIndex   : PCR to be extended
+ * event_type : type of event; specs 10.4.1
+ * data       : additional parameter; used as parameter for 10.4.3
+ *              'action index'
+ */
+static u32
+tcpa_add_measurement(u32 pcrIndex,
+                     u16 event_type,
+                     const char *string)
+{
+    u32 rc;
+
+    switch (event_type) {
+    case EV_SEPARATOR:
+        rc = tcpa_add_measurement_to_log_simple(pcrIndex,
+                                                event_type,
+                                                (u8 *)evt_separator,
+                                                4);
+        break;
+
+    case EV_ACTION:
+        rc = tcpa_add_measurement_to_log(pcrIndex,
+                                         event_type,
+                                         string,
+                                         strlen(string));
+        break;
+
+    default:
+        rc = TCG_INVALID_INPUT_PARA;
+    }
+
+    return rc;
+}
+
+
+u32
+tcpa_calling_int19h(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (!has_working_tpm())
+        return TCG_GENERAL_ERROR;
+
+    return tcpa_add_measurement(4, EV_ACTION,
+                                "Calling INT 19h");
+}
+
+
+u32
+tcpa_returned_via_int18h(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (!has_working_tpm())
+        return TCG_GENERAL_ERROR;
+
+    return tcpa_add_measurement(4, EV_ACTION,
+                                "Return via INT 18h");
+}
+
+
+/*
+ * Add event separators for PCRs 0 to 7; specs 8.2.3
+ */
+u32
+tcpa_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 = tcpa_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.
+ */
+u32
+tcpa_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 tcpa_add_measurement_to_log(4, EV_ACTION,
+                                       string, strlen(string));
+}
+
+
+/*
+ * Add measurement to the log about option rom scan
+ * 10.4.3 : action 14
+ */
+u32
+tcpa_start_option_rom_scan(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (!has_working_tpm())
+        return TCG_GENERAL_ERROR;
+
+    return tcpa_add_measurement(2, EV_ACTION,
+                                "Start Option ROM Scan");
+}
+
+
+/*
+ * Add measurement to the log about an option rom
+ */
+u32
+tcpa_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, /* 10.4.2.3.7 */
+        .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
+    };
+
+    rc = sha1((const u8 *)addr, len, pcctes.digest);
+    if (rc)
+        return rc;
+
+    return tcpa_add_measurement_to_log(2,
+                                       EV_EVENT_TAG,
+                                       (const char *)&pcctes,
+                                       sizeof(pcctes));
+}
+
+
+u32
+tcpa_smbios_measure(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (!has_working_tpm())
+        return TCG_GENERAL_ERROR;
+
+    u32 rc;
+    struct pcctes pcctes = {
+        .eventid = 1, /* 10.4.2.3.1 */
+        .eventdatasize = SHA1_BUFSIZE,
+    };
+    struct smbios_entry_point *sep = get_smbios_entry_point();
+
+    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 tcpa_add_measurement_to_log(1,
+                                       EV_EVENT_TAG,
+                                       (const char *)&pcctes,
+                                       sizeof(pcctes));
+}
+
+
+/*
+ * Add a measurement to the log in support of 8.2.5.3
+ * 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
+ */
+u32
+tcpa_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
+{
+    u32 rc;
+
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (!has_working_tpm())
+        return TCG_GENERAL_ERROR;
+
+    switch (bootcd) {
+    case IPL_EL_TORITO_1:
+        /* specs: 8.2.5.6 El Torito */
+        rc = tcpa_add_measurement_to_log_simple(4,
+                                                EV_IPL,
+                                                addr,
+                                                length);
+        break;
+
+    case IPL_EL_TORITO_2:
+        /* specs: 8.2.5.6 El Torito */
+        rc = tcpa_add_measurement_to_log_simple(5,
+                                                EV_IPL_PARTITION_DATA,
+                                                addr,
+                                                length);
+        break;
+
+    default:
+        /* specs: 8.2.5.3 */
+        /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+        rc = tcpa_add_measurement_to_log_simple(4,
+                                                EV_IPL,
+                                                addr,
+                                                0x1b8);
+
+        if (rc)
+            break;
+
+        /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+        rc = tcpa_add_measurement_to_log_simple(5,
+                                                EV_IPL_PARTITION_DATA,
+                                                addr + 0x1b8,
+                                                0x48);
+    }
+
+    return rc;
+}
+
+
 
Index: seabios/src/smbios.c
===================================================================
--- seabios.orig/src/smbios.c
+++ seabios/src/smbios.c
@@ -10,6 +10,8 @@
 #include "paravirt.h" // qemu_cfg_smbios_load_field
 #include "smbios.h" // struct smbios_entry_point
 
+static struct smbios_entry_point *smbios_ep;
+
 static void
 smbios_entry_point_init(u16 max_structure_size,
                         u16 structure_table_length,
@@ -30,6 +32,7 @@ smbios_entry_point_init(u16 max_structur
         free(finaltable);
         return;
     }
+    smbios_ep = ep;
     memcpy(finaltable, structure_table_address, structure_table_length);
 
     memcpy(ep->anchor_string, "_SM_", 4);
@@ -519,3 +522,12 @@ smbios_init(void)
     smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
     free(start);
 }
+
+struct smbios_entry_point *
+get_smbios_entry_point(void)
+{
+    if (!smbios_ep || memcmp(smbios_ep->anchor_string, "_SM_", 4) != 0)
+        return 0;
+
+    return smbios_ep;
+}
Index: seabios/src/smbios.h
===================================================================
--- seabios.orig/src/smbios.h
+++ seabios/src/smbios.h
@@ -3,6 +3,7 @@
 
 // smbios.c
 void smbios_init(void);
+struct smbios_entry_point *get_smbios_entry_point();
 
 /* SMBIOS entry point -- must be written to a 16-bit aligned address
    between 0xf0000 and 0xfffff.
Index: seabios/src/tcgbios.h
===================================================================
--- seabios.orig/src/tcgbios.h
+++ seabios/src/tcgbios.h
@@ -382,6 +382,14 @@ int has_working_tpm(void);
 u32 tcpa_startup(void);
 u32 tcpa_leave_bios(void);
 u32 tcpa_s3_resume(void);
+u32 tcpa_calling_int19h(void);
+u32 tcpa_returned_via_int18h(void);
+u32 tcpa_add_bootdevice(u32 bootcd, u32 bootdrv);
+u32 tcpa_add_event_separators(void);
+u32 tcpa_ipl(enum ipltype bootcd, const u8 *addr, u32 count);
+u32 tcpa_start_option_rom_scan(void);
+u32 tcpa_option_rom(const void *addr, u32 len);
+u32 tcpa_smbios_measure(void);
 
 
 #endif /* TCGBIOS_H */
