All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
@ 2006-12-07 22:04 Stefan Berger
  2006-12-08  9:24 ` Keir Fraser
  0 siblings, 1 reply; 8+ messages in thread
From: Stefan Berger @ 2006-12-07 22:04 UTC (permalink / raw)
  To: Xen-devel

[-- Attachment #1: Type: text/plain, Size: 760 bytes --]

This patch adds an implementation of the TCG BIOS extensions to the
Bochs BIOS and enables logging of boot measurements using the previously
implemented support for TCPA ACPI tables. A low-level driver for a TPM
TIS device and an Atmel device is provided.

The implemented specification is described here:

https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf

I added a #define 'BX_TCGBIOS' to rombios.c that enables or disables
these extensions. It's currently disabled so none of the code is
compiled into the BIOS.

The implementation passes the tests implemented in a newer version of
trusted grub (available through the trousers project on sourceforge).

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>


[-- Attachment #2: bios_tcg.diff --]
[-- Type: text/x-patch, Size: 124286 bytes --]

Index: root/xen-unstable.hg/tools/firmware/rombios/Makefile
===================================================================
--- root.orig/xen-unstable.hg/tools/firmware/rombios/Makefile
+++ root/xen-unstable.hg/tools/firmware/rombios/Makefile
@@ -12,7 +12,7 @@ clean:
 	rm -f  rombios*.txt rombios*.sym usage biossums
 	rm -f  BIOS-bochs-*
 
-BIOS-bochs-latest: rombios.c biossums
+BIOS-bochs-latest: rombios.c biossums tcgbios.c tcgbios.h tpm_tis.c tpm_atmel.c
 	gcc -DBX_SMP_PROCESSORS=1 -E -P $< > _rombios_.c
 	bcc -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
 	sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
Index: root/xen-unstable.hg/tools/firmware/rombios/rombios.c
===================================================================
--- root.orig/xen-unstable.hg/tools/firmware/rombios/rombios.c
+++ root/xen-unstable.hg/tools/firmware/rombios/rombios.c
@@ -154,6 +154,10 @@
 #define BX_USE_ATADRV    1
 #define BX_ELTORITO_BOOT 1
 
+#define BX_TCGBIOS       0              /* main switch for TCG BIOS ext. */
+#define BX_TCGBIOS_PHYSICAL_PRESENCE 0
+#define BX_TCGBIOS_SHA1_NO_HARDWARE 1   /* faster in SW than with TPM */
+
 #define BX_MAX_ATA_INTERFACES   4
 #define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
 
@@ -638,6 +642,10 @@ typedef struct {
 
 #define BiosData ((bios_data_t  *) 0)
 
+#if BX_TCGBIOS
+#include "tcgbios.h"
+#endif
+
 #if BX_USE_ATADRV
   typedef struct {
     Bit16u heads;      // # heads
@@ -745,6 +753,9 @@ typedef struct {
     cdemu_t cdemu;
 #endif // BX_ELTORITO_BOOT
 
+#if BX_TCGBIOS
+    tcpa_t  tcpa;
+#endif
     } ebda_data_t;
   
   #define EbdaData ((ebda_data_t *) 0)
@@ -1844,6 +1855,9 @@ print_bios_banner()
 {
   printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
   printf("%s %s\n", bios_cvs_version_string, bios_date_string);
+#if BX_TCGBIOS
+  printf("TCG-enabled BIOS.\n");
+#endif
   printf("\n");
 }
 
@@ -7603,6 +7617,23 @@ Bit8u bseqnr;
   if((bootseq&0x20)==0) bootdrv=0x80;
 #endif // BX_ELTORITO_BOOT
 
+#if BX_TCGBIOS
+  if (1) {
+    char *string;
+    if (bootcd == 0) {
+      if (bootdrv == 0x00) {
+        string = "Booting BCV Device 00h (Floppy)";
+      } else {
+        string = "Booting BCV Device 80h (HDD)";
+      }
+    } else {
+      string = "Booting from CD ROM";
+    }
+    tcpa_add_measurement_to_log(4L, 5, 0L, get_CS(), string,
+                                strlen(get_CS(), string));
+  }
+#endif
+
 #if BX_ELTORITO_BOOT
   // We have to boot from cd
   if (bootcd != 0) {
@@ -7674,6 +7705,10 @@ ASM_END
       }
     }
   
+#if BX_TCGBIOS
+  tcpa_ipl(bootseg);               /* specs: 8.2.3 steps 4 and 5 */
+#endif
+
 #if BX_ELTORITO_BOOT
   // Print out the boot string
   print_boot_device(bootcd, bootdrv);
@@ -7885,6 +7920,10 @@ int1a_function(regs, ds, iret_addr)
     }
 }
 
+#if BX_TCGBIOS
+#include "tcgbios.c"
+#endif
+
   void
 int70_function(regs, ds, iret_addr)
   pusha_regs_t regs; // regs pushed from PUSHA instruction
@@ -9400,6 +9439,9 @@ rom_scan:
   ;;   2         ROM length in 512-byte blocks
   ;;   3         ROM initialization entry point (FAR CALL)
 
+#if BX_TCGBIOS
+  call _tcpa_start_option_rom_scan    /* specs: 3.2.3.3 + 10.4.3 */
+#endif
   mov  cx, #0xc000
 rom_scan_loop:
   mov  ds, cx
@@ -9418,6 +9460,17 @@ rom_scan_loop:
   add  al, #0x04
 block_count_rounded:
 
+#if BX_TCGBIOS
+  push ax
+  push ds
+  mov ax, #0x0000
+  mov ds, ax
+  push cx       ;; segment where option rom is located at
+  call _tcpa_option_rom                   /* specs: 3.2.3.3 */
+  pop cx        ;; pop segement
+  pop ds
+  pop ax
+#endif
   xor  bx, bx   ;; Restore DS back to 0000:
   mov  ds, bx
   push ax       ;; Save AX
@@ -9683,6 +9736,11 @@ post_default_ints:
   in   al, 0x71
   mov  0x0410, ax
 
+#if BX_TCGBIOS
+  call _tcpa_acpi_init
+  call _tcpa_initialize_tpm
+  call _tcpa_wake_event     /* specs: 3.2.3.7 */
+#endif
 
   ;; Parallel setup
   SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
@@ -9803,9 +9861,16 @@ post_default_ints:
   ;;
 #endif // BX_ELTORITO_BOOT
  
+#if BX_TCGBIOS
+  call _tcpa_calling_int19h          /* specs: 8.2.3 step 1 */
+  call _tcpa_add_event_separators    /* specs: 8.2.3 step 2 */
+#endif
   int  #0x19
   //JMP_EP(0x0064) ; INT 19h location
 
+#if BX_TCGBIOS
+  call _tcpa_returned_int19h         /* specs: 8.2.3 step 3/7 */
+#endif
 
 .org 0xe2c3 ; NMI Handler Entry Point
 nmi:
@@ -10288,6 +10353,21 @@ db 0x00    ;; base  23:16
 ;----------
 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
 int1a_handler:
+#if BX_TCGBIOS
+  cmp  ah, #0xbb
+  jne  no_tcg
+  pushf
+  push ds
+  push es
+  pushad
+  call _int1a_function32
+  popad
+  pop es
+  pop ds
+  popf
+  iret
+no_tcg:
+#endif
 #if BX_PCIBIOS
   cmp  ah, #0xb1
   jne  int1a_normal
Index: root/xen-unstable.hg/tools/firmware/rombios/tcgbios.c
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/firmware/rombios/tcgbios.c
@@ -0,0 +1,4232 @@
+/*
+ * Implementation of the TCG BIOS extension according to the specification
+ * described in
+ * https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+
+/*
+ * Note: A mixture of 16bit real-mode code and 32 bit protected mode code
+ *       has been implemented. All functions ending in '32' assume that they
+ *       will be called in 32bit protected mode. 32 bit mode needs to
+ *       be supported here since some of the pointers to data areas are
+ *       outside the real mode-reachable area. The specs suggest big
+ *       real-mode, but that won't work without emulation.
+ *
+ * Note: The extended BIOS data area (EBDA) is used to store some TCG ACPI
+ *       specific information as well as hold certain register values
+ *       (ss,cs,ds,es,MSW(esp)) during the execution in protected mode. The
+ *       EBDA has been used since it provides a well-defined memory area
+ *       and no application should touch it.
+ */
+#include "tcgbios.h"
+
+/* which TPM interface to use */
+#define TPM_TYPE  TPM_TIS
+
+#define SEGMENT_OFFSET  0xf0000
+#define REAL_MODE_CODE_SEGMENT  0xf000
+
+#define START_PM_CODE  USE32
+#define END_PM_CODE    USE16
+
+/* the segment where the ACPI data is to be found */
+#define ACPI_SEGMENT    0xe000
+
+    ASM_START
+
+MACRO Calc32FromSegOff
+    ; Calculate a 32 bit address from segment:offset
+    ;
+    ; this is done in an order such that ss:sp can be used also
+    ; as parameters and sp does not change due to the 'push'
+    xor ?1, ?1			;clear destination reg
+    mov ?2, ?4			;mov offset to 16 bit dest. reg
+    push ?5			;pop@1; save contents of scratch reg.
+    xor ?5, ?5			;clear scratch register
+    mov ?6, ?3			;segment to 16 bit scratch
+    rol ?5, #4			;adjust 32 bit scratch for segment
+    add ?1, ?5			;from final address
+    pop ?5			;@1
+MEND
+
+   ASM_END
+
+#if TPM_TYPE == TPM_ATMEL
+#include "tpm_atmel.c"
+#endif
+#if TPM_TYPE == TPM_TIS
+#include "tpm_tis.c"
+#endif
+
+/*
+ * Utility functions to read/write from/to 32-bit addresses - to be used by
+ * 'C' code.
+ */
+
+/* read a byte from a 32 bit physical address */
+Bit8u
+read_byte32(addr)
+  Bit32u addr;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push ebx				;pop@2
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov ebx, 4[bp]			; addr
+    mov al, [ebx]			; val = *(char *)addr;
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebx				;@2
+    pop bp				;@1
+    ASM_END
+}
+
+
+/*
+   read a 32bit value from a 32 bit (physical) address
+   return value in dx and ax: value = (register dx << 16) | register ax
+ */
+Bit32u
+read_dword32(addr)
+    Bit32u addr;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push ebx				;pop@2
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov ebx, 4[bp]			; addr
+    mov ax, [ebx]			; lo(val)=*(uint16_t *)addr
+    inc ebx				; addr+=1
+    inc ebx				; addr+=1
+    mov dx, [ebx]			; hi(val)=*(uint16_t *)addr
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebx				;@2
+    pop bp				;@1
+    ASM_END
+}
+
+/* write a byte to a 32 bit (physical) address */
+void
+write_byte32(addr, val)
+    Bit32u addr;
+    Bit8u val;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push ebx				;pop@2
+    push ax				;pop@3
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov ebx, 4[bp]			; addr
+    mov al, 8[bp]			; val
+    mov [ebx], al			; *(char *)addr = val
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ax				;@3
+    pop ebx				;@2
+    pop bp				;@1
+
+    ASM_END
+}
+
+/* copy bytes in  32 bit (physical) address space */
+void
+memcpy32(des, src, n)
+    Bit32u des;
+    Bit32u src;
+    Bit16u n;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push ebx				;pop@2
+    push edx				;pop@3
+    push ecx				;pop@4
+    push ax				;pop@5
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    xor ecx, ecx
+
+    mov ebx,  #4[bp]			; dest
+    mov edx,  #8[bp]			; src
+    mov cx,  #12[bp]			; n
+
+memcpy32_loop:
+    dec ecx
+    cmp ecx, #0
+    jl memcpy32_end
+    mov al, [edx+ecx]
+    mov [ebx+ecx], al
+    jmp memcpy32_loop
+
+memcpy32_end:
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ax				;@5
+    pop ecx				;@4
+    pop edx				;@3
+    pop ebx				;@2
+    pop bp				;@1
+
+    ret
+    ASM_END
+}
+
+
+/*
+ * Two often-used functions
+ */
+Bit16u
+read_word_from_ebda(offset)
+    Bit16u offset;
+{
+	Bit16u ebda_seg = read_word(0x0040, 0x000E);
+	return read_word(ebda_seg, offset);
+}
+
+Bit32u
+read_dword_from_ebda(offset)
+    Bit16u offset;
+{
+	Bit16u ebda_seg = read_word(0x0040, 0x000E);
+	return read_dword(ebda_seg, offset);
+}
+
+#if BX_TCGBIOS_SHA1_NO_HARDWARE
+/*******************************************************************
+  Calculation of SHA1 without the TPM but only in SW
+
+  See: RFC3174, Wikipedia's SHA1 alogrithm description
+ ******************************************************************/
+typedef struct _sha1_ctx {
+	Bit32u h[5];
+} sha1_ctx;
+
+#if 0
+void sha1_dump(ctx_seg, ctx)
+  Bit16u ctx_seg;
+  sha1_ctx *ctx;
+{
+	Bit8u i;
+	for (i = 0; i < 5; i ++) {
+		Bit32u d = read_dword(ctx_seg, &ctx->h[i]);
+		printf("h[%d] = ",i);
+		printf("0x%x",(Bit16u)(d>>16));
+		printf("%x\n",(Bit16u)d);
+	}
+}
+#endif
+
+
+Bit32u rol(val, rol)
+  Bit32u val;
+  Bit16u rol;
+{
+	return (val << rol) | (val >> (32 - rol));
+}
+
+/* missing implementation of xor in bcc! */
+Bit32u xor(val1, val2)
+  Bit32u val1;
+  Bit32u val2;
+{
+	ASM_START
+	push bp
+	mov bp, sp
+
+	mov ax, #4[bp]		; lo
+	xor ax, #8[bp]
+	mov dx, #6[bp]		; hi
+	xor dx, #10[bp]
+
+	pop bp
+	ret
+	ASM_END
+}
+
+/* change endianess */
+Bit32u bswap(val)
+  Bit32u val;
+{
+	ASM_START
+	push bp
+	mov bp, sp
+
+	mov dx, #4[bp]
+	rol dx, #8
+	mov ax, #6[bp]
+	rol ax, #8
+
+	pop bp
+	ret
+	ASM_END
+}
+
+static Bit32u ko[4] = { 0x5a827999L,
+                        0x6ed9eba1L,
+                        0x8f1bbcdcL,
+                        0xca62c1d6L };
+
+void sha1_block(w_seg, ww, ctx_seg, ctx)
+  Bit16u w_seg;
+  Bit16u ww;
+  Bit16u ctx_seg;
+  sha1_ctx *ctx;
+{
+	Bit16u i;
+	Bit32u a,b,c,d,e,f;
+	Bit32u tmp;
+	Bit32u *w = (Bit32u *)ww;
+	Bit16u idx;
+
+	/* change endianess of given data */
+	for (i = 0; i < 16; i++) {
+		tmp = read_dword(w_seg, &w[i]);
+		write_dword(w_seg, &w[i], bswap(tmp));
+	}
+
+	for (i = 16; i <= 79; i++) {
+		tmp = xor(read_dword(w_seg, &w[i-3]),
+		          read_dword(w_seg, &w[i-8]));
+		tmp = xor(tmp, read_dword(w_seg, &w[i-14]));
+		tmp = xor(tmp, read_dword(w_seg, &w[i-16]));
+		tmp = rol(tmp,1);
+		write_dword(w_seg, &w[i], tmp);
+	}
+
+	a = read_dword(ctx_seg, &ctx->h[0]);
+	b = read_dword(ctx_seg, &ctx->h[1]);
+	c = read_dword(ctx_seg, &ctx->h[2]);
+	d = read_dword(ctx_seg, &ctx->h[3]);
+	e = read_dword(ctx_seg, &ctx->h[4]);
+
+	for (i = 0; i <= 79; i++) {
+		if (i <= 19) {
+			f = (b & c) | (xor(b,0xffffffffL) & d);
+			idx = 0;
+		} else if (i <= 39) {
+			f = xor(xor(b, c), d);
+			idx = 1;
+		} else if (i <= 59) {
+			f = (b & c) | (b & d) | (c & d);
+			idx = 2;
+		} else {
+			f = xor(xor(b, c), d);
+			idx = 3;
+		}
+
+		tmp = rol(a, 5) +
+		      f +
+		      e +
+		      read_dword(get_CS(), &ko[idx]) +
+		      read_dword(w_seg, &w[i]);
+		e = d;
+		d = c;
+		c = rol(b, 30);
+		b = a;
+		a = tmp;
+	}
+
+	a += read_dword(ctx_seg, &ctx->h[0]);
+	b += read_dword(ctx_seg, &ctx->h[1]);
+	c += read_dword(ctx_seg, &ctx->h[2]);
+	d += read_dword(ctx_seg, &ctx->h[3]);
+	e += read_dword(ctx_seg, &ctx->h[4]);
+
+	write_dword(ctx_seg, &ctx->h[0], a);
+	write_dword(ctx_seg, &ctx->h[1], b);
+	write_dword(ctx_seg, &ctx->h[2], c);
+	write_dword(ctx_seg, &ctx->h[3], d);
+	write_dword(ctx_seg, &ctx->h[4], e);
+}
+
+void sha1_do(ctx_seg, ctx, data32, length)
+  Bit16u ctx_seg;
+  sha1_ctx *ctx;
+  Bit32u data32;
+  Bit32u length;
+{
+	Bit32u offset;
+	Bit16u ss;
+	Bit32u dst;
+	Bit16u num;
+	Bit32u bits = 0L;
+	Bit8u w[80*4];
+
+	ss = get_SS();
+
+	/* 32 bit destination address of w-array */
+	dst  = ((Bit32u)ss << 4) + (Bit32u)&w[0];
+
+	/* treat data in 64-byte chunks */
+	for (offset = 0L; length - offset >= 64; offset += 64) {
+		/* copy into the 'w' array */
+		memcpy32(dst, data32 + offset, 64);
+		/* hash the block in the 'w' array */
+		sha1_block(ss, w, ctx_seg, ctx);
+		bits += (64 * 8);
+	}
+
+	/* last block with less than 64 bytes */
+	num = length - offset;
+	bits += (num << 3);
+
+	memsetb(ss, w, 0x0, 64);
+	memcpy32(dst, data32 + offset, num);
+	write_byte(ss, &w[num], 0x80);
+
+	if (num >= 56) {
+		/* cannot append number of bits here */
+		sha1_block(ss, w, ctx_seg, ctx);
+		memsetb(ss, w, 0x0, 60);
+	}
+
+	/* write number of bits to end of block */
+	write_dword(ss, &w[60], bswap(bits));
+	sha1_block(ss, w, ctx_seg, ctx);
+
+	/* need to switch result's endianess */
+	for (num = 0; num < 5; num++) {
+		Bit32u tmp = read_dword(ctx_seg, &ctx->h[num]);
+		write_dword(ctx_seg, &ctx->h[num], bswap(tmp));
+	}
+}
+
+/* sha1 initialization constants */
+static Bit32u sha_const[5] = {
+	0x67452301L,
+	0xefcdab89L,
+	0x98badcfeL,
+	0x10325476L,
+	0xc3d2e1f0L
+};
+
+void sha1(data32, length, hash32)
+  Bit32u data32;
+  Bit32u length;
+  Bit32u hash32;
+{
+	sha1_ctx ctx;
+	Bit16u ctx_seg = get_SS();
+
+	memcpyb(ctx_seg, &ctx.h[0], get_CS(), sha_const, 20);
+	sha1_do(ctx_seg, &ctx, data32, length);
+
+	memcpy32(hash32,
+	         (((Bit32u)ctx_seg << 4) + (Bit32u)&ctx),
+	         20);
+}
+
+#if 0
+char test1[4] = "abc";
+
+void sha1_test()
+{
+	Bit32u data32, hash32;
+	Bit16u i;
+	Bit32u hash[5];
+
+	memsetb(get_SS(), hash, 0x0, 20);
+
+	data32 = ((Bit32u)get_CS() << 4) + (Bit32u)test1;
+	hash32 = ((Bit32u)get_SS() << 4) + (Bit32u)hash;
+	sha1(data32, 3L, hash32);
+
+	sha1_dump(get_SS(), hash);
+}
+#endif
+
+#endif
+
+/*******************************************************************
+  Support for TCPA ACPI logging
+ ******************************************************************/
+
+static char rsdp_sig[9] = "RSD PTR ";
+
+/*
+ * Extend the ACPI log with the given entry by copying the
+ * entry data into the log.
+ * Input
+ *  Pointer to the structure to be copied into the log
+ *
+ * Output:
+ *  lower 16 bits of return code contain entry number
+ *  if entry number is '0', then upper 16 bits contain error code.
+ */
+Bit32u tcpa_extend_acpi_log(entry_ptr)
+    Bit32u entry_ptr;
+{
+	Bit32u res = 0L;
+	Bit16u ebda_seg = read_word(0x0040, 0x000E);
+	Bit32u lasa_last = tcpa_get_lasa_last_ptr();
+	Bit32u lasa_base = tcpa_get_lasa_base_ptr();
+	Bit32u size;
+	Bit16u entry_count = read_word (ebda_seg,
+	                                &EbdaData->tcpa.tcpa_acpi.entry_count);
+
+	if (lasa_last == 0L) {
+		lasa_last = lasa_base;
+	} else {
+		/* skip the last entry in the log */
+		size = read_dword32(lasa_last + 28);
+		size += 32;
+		lasa_last = lasa_last + size;
+	}
+
+	if (lasa_last == 0L) {
+		res = TCG_PC_LOGOVERFLOW;
+		res <<= 16;
+	}
+
+	if (res == 0L) {
+		Bit32u tcpa = read_dword(ebda_seg,
+		                         &EbdaData->tcpa.tcpa_acpi.tcpa_ptr);
+		Bit32u laml = read_dword32(tcpa + 0x26);
+		size = read_dword32(entry_ptr + 28);
+		size += 32;
+		if ((lasa_last + size - lasa_base) > laml) {
+			res = TCG_PC_LOGOVERFLOW;
+			res <<= 16;
+		}
+	}
+
+	if (res == 0L) {
+		/* copy the log entry into the ACPI log */
+		memcpy32(lasa_last, entry_ptr, size);
+		/*
+		 * update the pointers and entry counter that were modified
+		 * due to the new entry in the log
+		 */
+		write_dword(ebda_seg,
+		            &EbdaData->tcpa.tcpa_acpi.lasa_last_ptr,
+		            lasa_last);
+		entry_count++;
+		write_word (ebda_seg,
+		            &EbdaData->tcpa.tcpa_acpi.entry_count,
+		            entry_count);
+
+		res = entry_count;
+	}
+	return res;
+}
+
+/*
+ * Determine the length of a null-terminated ASCII string
+ *
+ * Input parameters:
+ *  string_seg  : The segment where the string is located in
+ *  string      : Offset within the segement pointing to the beginning of the
+ *                string
+ *
+ * Returns length of the string excluding the terminating '0' in 'ax'.
+ */
+ Bit16u
+strlen(string_seg, string)
+    Bit16u string_seg;
+    Bit16u string;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push si				;pop@2
+    push bx				;pop@3
+    push ds				;pop@4
+    xor bx,bx
+    xor ax,ax
+
+    mov si, 2+2+2[bp]
+    mov ds, 2+2[bp]
+strlen_loop_0:
+    seg ds
+    cmp byte ptr [si+bx], al
+    je strlen_goon_0
+    inc bx
+    jmp strlen_loop_0
+strlen_goon_0:
+    mov ax, bx
+
+    pop ds				;@4
+    pop bx				;@3
+    pop si				;@2
+    pop bp				;@1
+    ASM_END
+}
+
+/*
+ * Compare two strings given their segments and offsets within the segments.
+ * Compare a maximum of 'n' characters.
+ * Returns '0' if string=string2, a value less than '0' if string1<string2
+ * a value greater than '0' otherwise.
+ */
+Bit8u strncmp(seg1, off1, seg2, off2, n)
+    Bit16u seg1;
+    Bit16u off1;
+    Bit16u seg2;
+    Bit16u off2;
+    Bit16u n;
+{
+	Bit16u ctr;
+	for (ctr = 0; ctr < n; ctr++) {
+		Bit8u c1 = read_byte(seg1, off1 + ctr);
+		Bit8u c2 = read_byte(seg2, off2 + ctr);
+		if (c1 != c2) {
+			return (Bit8u)(c1 - c2);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Validate an ACPI table entry by calculating the sum over the
+ * structure.
+ * If the entry is valid, a '0' will be returned.
+ */
+Bit8u acpi_validate_entry32(addr)
+    Bit32u addr;
+{
+	Bit8u sum = 0;
+	Bit32u length = read_dword32(addr + 4L); /* length of structure */
+	Bit32u ctr;
+
+	for (ctr = 0; ctr < length; ctr++) {
+		sum += read_byte32(addr + ctr);
+	}
+	return sum;
+}
+
+
+/*
+   initialize the TCPA ACPI subsystem; find the ACPI tables and determine
+   where the TCPA table is.
+ */
+void
+tcpa_acpi_init()
+{
+	Bit32u rsdt;
+	Bit32u length;
+	Bit32u tcpa;
+	Bit16u found;
+	Bit16u rsdp_off;
+	Bit16u off;
+	Bit16u ebda_seg;
+	Bit16u ctr;
+
+	/* scan memory in steps of  16 bytes in the ACPI_SEGMENT segment */
+	found = 0;
+	for (rsdp_off = 0; rsdp_off < 0xfff0; rsdp_off += 0x10) {
+		/* check for expected string */
+		if (!strncmp(ACPI_SEGMENT, rsdp_off,
+		             get_CS()    , rsdp_sig, 8)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		/* try to find TCPA APCI table linked to RSDT */
+		found = 0;
+		/* get RSDT from RSDP */
+		rsdt   = read_dword(ACPI_SEGMENT, rsdp_off + 16);
+		/* rsdt may be anywhere in 32bit space */
+		length = read_dword32(rsdt + 4L);
+		off = 36;
+		while ((off + 3) < length) {
+			/* try all pointers to structures */
+			tcpa = read_dword32(rsdt + (Bit32u)off);
+			/* valid TCPA ACPI table ? */
+			if (ACPI_2_0_TCPA_SIGNATURE == read_dword32(tcpa) &&
+			    acpi_validate_entry32(tcpa) == 0) {
+				found = 1;
+				break;
+			}
+			off += 4;
+		}
+	}
+
+	if (!found) {
+		printf("TCPA ACPI was NOT found!\n");
+		tcpa = 0L;
+	}
+
+	/* initialize the TCPA part of the EBDA with our data */
+	ebda_seg = read_word(0x0040, 0x000E);
+	write_dword(ebda_seg,
+	            &EbdaData->tcpa.tcpa_acpi.tcpa_ptr,
+	            tcpa);
+	write_dword(ebda_seg,
+	            &EbdaData->tcpa.tcpa_acpi.lasa_last_ptr,
+	            0L);
+	write_word (ebda_seg,
+	            &EbdaData->tcpa.tcpa_acpi.entry_count,
+	            0);
+}
+
+/* get the address of the last entry in the log */
+Bit32u
+tcpa_get_lasa_last_ptr()
+{
+	return read_dword_from_ebda(&EbdaData->tcpa.tcpa_acpi.lasa_last_ptr);
+}
+
+/* get the pointer to the first entry in the log */
+  Bit32u
+tcpa_get_lasa_base_ptr()
+{
+	Bit32u lasa = 0L;
+	Bit32u tcpa = read_dword_from_ebda(&EbdaData->tcpa.tcpa_acpi.tcpa_ptr);
+	if (tcpa != 0L) {
+		Bit16u tcpa_off = (Bit16u)tcpa;
+		Bit16u class = read_word(ACPI_SEGMENT, tcpa_off + 0x24);
+		if (class == TCPA_ACPI_CLASS_CLIENT) {
+			/* client type */
+			lasa = read_dword(ACPI_SEGMENT, tcpa_off + 0x2a);
+		} else if (class == TCPA_ACPI_CLASS_SERVER) {
+			/* server type */
+			lasa = read_dword(ACPI_SEGMENT, tcpa_off + 0x30);
+		}
+	}
+	return lasa;
+}
+
+/*
+ * Add a measurement to the log; the data at data_seg:data/length are
+ * appended to the TCG_PCClientPCREventStruct
+ *
+ * Input parameters:
+ *  pcrIndex   : which PCR to extend
+ *  event_type : type of event; specs 10.4.1
+ *  event_id   : (unused)
+ *  data_seg   : real mode segement where the data are located
+ *  data       : offset where the data are located
+ *  length     : length of the data
+ */
+Bit16u
+tcpa_add_measurement_to_log(pcrIndex,
+                            event_type,
+                            event_id,
+                            data_seg,
+                            data,
+                            length)
+    Bit32u pcrIndex;
+    Bit16u event_type;
+    Bit32u event_id;
+    Bit16u data_seg;
+    Bit16u data;
+    Bit16u length;
+{
+    ASM_START
+    push bp				;pop@1
+    mov bp, sp
+    push ecx				;pop@2
+    push ebx				;pop@3
+    push edx				;pop@4
+    push si				;pop@5
+    push ds				;pop@6
+    push di				;pop@7
+    push es				;pop@8
+    push fs				;pop@9
+    ; determine length of string
+    xor ebx, ebx
+    mov fs, 2+2+4+2+4[bp]		; data_seg
+    mov si, 2+2+4+2+4+2[bp]		; data
+    mov bx, 2+2+4+2+4+2+2[bp]		; length
+
+    ; create room on the stack for HashLogExtendEvent input and
+    ; output blocks and the TCG_PCClientPCREventStruc
+    ;bx contains size of event in TCG_CPCleintPCREventStruc
+    sub sp, #(0x18+(8+20)+32)		;adjust @10
+    sub sp, bx				;adjust@11
+
+    ; first initialize the TCG_PCClientPCREventStruc (es:di)
+    mov di, sp
+    mov ax, ss
+    mov es, ax
+
+    push eax				;pop@A
+
+    mov eax, 2+2[bp]			;pcrIndex
+    seg es
+    mov 0[di], eax
+
+    mov ax, 2+2+4[bp]			;event_type
+    and eax, #0xffff
+    seg es
+    mov 4[di], eax
+
+    pop eax				;@A
+
+    seg es
+    mov 28[di], ebx			;eventDataSize
+
+    push ebx				;pop@B
+tcpa_add_measurement_to_log_loop_1:
+    dec ebx
+    jl tcpa_add_measurement_to_log_goon_1
+    seg fs
+    mov al, [si+bx]				; copy data to end of
+    seg es
+    mov 32[di+bx], al				; PCClientPCREventStruc
+    jmp tcpa_add_measurement_to_log_loop_1
+
+tcpa_add_measurement_to_log_goon_1:
+    pop ebx					;@B
+
+    ; edx contains 32 bit address of TCG_PCClientPCREventStruc
+    Calc32FromSegOff(edx, dx, es, di, eax, ax)
+
+    ; initialize the HashLogExtentEvent Input Block
+    add di, #32
+    add di, bx
+
+    seg es
+    mov word ptr 0[di], word #0x18		;length
+    seg es
+    mov word ptr 2[di], word #0x0		;reserved
+
+    add edx, #32
+    seg es
+    mov dword ptr 4[di], edx			;data to be hashed
+    sub edx, #32
+    seg es
+    mov dword ptr 8[di], ebx			;length of data
+
+    mov ecx, 2+2[bp]				;pcrIndex
+    seg es
+    mov dword ptr 12[di], ecx
+
+    seg es
+    mov dword ptr 16[di], edx			;TCG_PCClientPCREventStruc
+    add ebx, #32
+    seg es
+    mov dword ptr 20[di], ebx			; total length of structure
+    sub ebx, #32
+
+    ; initialize the pointers to the HashLogExtendEvent Ouptut Block
+    mov si, di
+    mov ax, sp
+    mov ds, ax
+    add si, #0x18
+
+    push eax
+    call TCG_HashLogExtendEvent
+    mov cx, ax
+    pop eax
+
+    mov ax, cx
+
+    add sp, bx					;@11
+    add sp, #(0x18 +(8+20)+32)			;@10
+    pop fs					;@9
+    pop es					;@8
+    pop di					;@7
+    pop ds					;@6
+    pop si					;@5
+    pop edx					;@4
+    pop ebx					;@3
+    pop ecx					;@2
+    pop bp					;@1
+    ASM_END
+}
+
+
+/*
+ * 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.
+ */
+Bit16u
+tcpa_add_measurement_to_log_simple(pcrIndex, event_type, ptr, length)
+    Bit32u pcrIndex;
+    Bit16u event_type;
+    Bit32u ptr;
+    Bit32u length;
+{
+    ASM_START
+    push bp					;pop@1
+    mov bp, sp
+    push ecx					;pop@2
+    push ebx					;pop@3
+    push edx					;pop@4
+    push si					;pop@5
+    push ds					;pop@6
+    push di					;pop@7
+    push es					;pop@8
+
+    ; create room on the stack for HashLogExtendEvent input and
+    ; output blocks and the TCG_PCClientPCREventStruc
+    ;bx contains size of event in TCG_CPCleintPCREventStruc
+    sub sp, #(0x18+(8+20)+32)			;adjust @9
+
+    ; first initialize the TCG_PCClientPCREventstruc
+    mov di, sp
+    mov ax, ss
+    mov es, ax
+
+    push eax					;pop@A
+
+    mov eax, 2+2[bp]				;pcrIndex
+    seg es
+    mov 0[di], eax
+
+    mov ax, 2+2+4[bp]				;event_type
+    and eax, #0xffff
+    seg es
+    mov 4[di], eax
+
+    pop eax					;@A
+
+    mov ecx, 2+2+4+2+4[bp]
+    seg es
+    mov 28[di], ecx				;eventDataSize
+
+    ; edx contains 32 bit address of TCG_PCClientPCREventStruc
+    Calc32FromSegOff(edx, dx, es, di, eax, ax)
+
+    ; initialize the HashLogExtentEvent Input Block
+    add di, #32
+
+    seg es
+    mov word ptr 0[di], word #0x18		;length
+    seg es
+    mov word ptr 2[di], word #0x0		;reserved
+
+    mov ebx, 2+2+4+2[bp]			; data ptr
+    seg es
+    mov dword ptr 4[di], ebx			;data to be hashed
+    seg es
+    mov dword ptr 8[di], ecx			;length of data
+
+    mov ecx, 2+2[bp]				;pcrIndex
+    seg es
+    mov dword ptr 12[di], ecx
+
+    seg es
+    mov dword ptr 16[di], edx			;TCG_PCClientPCREventStruc
+    seg es
+    mov dword ptr 20[di], #32			; total length of structure
+
+    ; initialize the pointers to the HashLogExtendEvent Ouptut Block
+    mov si, di
+    mov ax, sp
+    mov ds, ax
+    add si, #0x18
+
+    push eax
+    call TCG_HashLogExtendEvent
+    mov cx, ax
+    pop eax
+
+    mov ax, cx
+
+    add sp, #(0x18 +(8+20)+32)			;@9
+    pop es					;@8
+    pop di					;@7
+    pop ds					;@6
+    pop si					;@5
+    pop edx					;@4
+    pop ebx					;@3
+    pop ecx					;@2
+    pop bp					;@1
+    ASM_END
+}
+
+
+
+/* table of event types according to 10.4.1 / table 11 */
+static char ev_action[][23] = {
+  /*  0 */ "Calling INT 19h",
+           "Returned INT 19h",
+           "Returned via INT 18h",
+           "",
+           "",
+  /*  5 */ "",
+           "",
+           "",
+           "",
+           "",
+  /* 10 */ "",
+           "",
+           "",
+           "",
+           "Start Option ROM Scan"
+};
+
+static char evt_separator[] = "---------------";
+static char wake_event_1[]    = "Wake Event 1";
+
+/*
+ * 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'
+ */
+  void
+tcpa_add_measurement(pcrIndex, event_type, data)
+    Bit32u pcrIndex;
+    Bit16u event_type;
+    Bit32u data;
+{
+	char *string;
+	Bit16u cs = get_CS();
+
+	switch (event_type) {
+	case EV_SEPARATOR:
+		tcpa_add_measurement_to_log(pcrIndex,
+		                            event_type,
+		                            0L,
+		                            cs,
+		                            evt_separator,
+		                            strlen(cs, evt_separator));
+	break;
+	case EV_ACTION:
+		string = ev_action[data /* event_id */];
+		tcpa_add_measurement_to_log(pcrIndex,
+		                            event_type,
+		                            data,
+		                            cs,
+		                            string,
+		                            strlen(cs, string));
+	break;
+	}
+}
+
+/*
+ * Add measurement to log about call of int 19h
+ */
+ void
+tcpa_calling_int19h()
+{
+	tcpa_add_measurement(4L, EV_ACTION, 0L);
+}
+
+/*
+ * Add measurement to log about retuning from int 19h
+ */
+ void
+tcpa_returned_int19h()
+{
+	tcpa_add_measurement(4L, EV_ACTION, 1L);
+}
+
+/*
+ * Add event separators for PCRs 0 to 7; specs 8.2.3
+ */
+ void
+tcpa_add_event_separators()
+{
+	Bit32u pcrIndex = 0L;
+	while (pcrIndex <= 7L) {
+		tcpa_add_measurement(pcrIndex, EV_SEPARATOR, 0L);
+		pcrIndex ++;
+	}
+}
+
+/*
+ * Add a wake event to the log
+ */
+ void
+tcpa_wake_event()
+{
+	Bit16u cs = get_CS();
+	tcpa_add_measurement_to_log(6L,
+	                            EV_ACTION,
+	                            10L,
+	                            cs,
+	                            wake_event_1,
+	                            strlen(cs, wake_event_1));
+}
+
+/*
+ * Add measurement to the log about option rom scan
+ * 10.4.3 : action 14
+ */
+ void
+tcpa_start_option_rom_scan()
+{
+	tcpa_add_measurement(2L, EV_ACTION, 14L);
+}
+
+/*
+ * Add measurement to the log about an option rom
+ */
+ void
+tcpa_option_rom(seg)
+    Bit16u seg;
+{
+	Bit32u len = read_byte(seg, 2) << 9;
+	Bit32u addr = seg << 4;
+	Bit8u append[32]; /* TCG_PCClientTaggedEventStruct and
+	                     OptionROMExecuteStructure; specs 10.4.2.1 */
+	Bit8u ipb[0x10];  /* HashAll Input Block; specs 12.10 */
+
+	memsetb(get_SS(), append, 0x0, 32  );
+	memsetb(get_SS(), ipb   , 0x0, 0x10);
+
+	append[0] = 7; /* Option ROM Execute */
+	append[4] = 24;/* size of OptionROMExecute Structure */
+	/* leave the rest to '0' */
+
+        /* 12.10 table 21 */
+	ipb[0] = 0x10;  /* little endian! */
+
+	ipb[4] = (addr >> 00) & 0xff;
+	ipb[5] = (addr >> 08) & 0xff;
+	ipb[6] = (addr >> 16) & 0xff;
+	ipb[7] = (addr >> 24) & 0xff;
+
+	ipb[8] = (len >> 0) & 0xff;
+	ipb[9] = (len >> 8) & 0xff;
+
+	ipb[12] = TPM_ALG_SHA;
+
+	_TCG_HashAll(get_SS(),
+	             ipb,
+	             get_SS(),
+	             append+12,
+	             TCG_MAGIC,
+	             0L,
+	             0L);
+
+	tcpa_add_measurement_to_log(2L,
+	                            EV_EVENT_TAG,
+	                            0L,
+	                            get_SS(),
+	                            append,
+	                            32);
+}
+
+/*
+ * Add a measurement to the log in support of 8.2.5.3
+ * Creates two log entries
+ *
+ * Input parameter:
+ *  seg    : segment where the IPL data are located
+ */
+ void
+tcpa_ipl(seg)
+    Bit16u seg;
+{
+	/* specs: 8.2.5.3 */
+	Bit32u addr = (Bit32u)(seg << 4);
+	/* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+	tcpa_add_measurement_to_log_simple(4L,
+	                                   EV_IPL,
+	                                   addr,
+	                                   0x1b8L);
+	/* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+	tcpa_add_measurement_to_log_simple(5L,
+	                                   EV_IPL_PARTITION_DATA,
+	                                   addr + 0x1b8L,
+	                                   0x48L);
+}
+
+/* definition of used code/data segment descriptors */
+#define PM_NORMAL_CS (gdt_entry_pm_cs       - gdt_base)
+#define PM_16BIT_CS  (gdt_entry_pm_16bit_cs - gdt_base)
+#define PM_32BIT_DS  (gdt_entry_pm_32bit_ds - gdt_base)
+
+  ASM_START
+
+    ; Switch into protected mode to allow access to 32 bit addresses.
+    ; This function allows switching into protected mode.
+    ; (the specs says big real mode, but that will not work)
+    ;
+    ; preserves all registers and prepares cs, ds, es, ss for usage
+    ; in protected mode; while in prot.mode interrupts remain disabled
+switch_to_protmode:
+    cli
+
+    ; have to fix the stack for proper return address in 32 bit mode
+    push WORD #(REAL_MODE_CODE_SEGMENT>>12)	;extended return address
+    push bp					;pop@A1
+    mov bp, sp
+    push eax					;pop@A2
+    mov eax, 2[bp]				; fix return address
+    rol eax, #16
+    mov 2[bp], eax
+
+    mov eax, esp
+    ror eax, #16				; hi(esp)
+    push ax					; remember it
+    push es
+    push ds
+    push cs
+    push ss
+    call _store_segment_registers
+    add sp, #10
+
+    ; calculate protected-mode esp from ss:sp
+    and esp, #0xffff
+    xor eax, eax
+    mov ax, ss
+    rol eax, #4
+    add eax, esp
+    mov esp, eax
+
+    seg cs
+    lgdt my_gdtdesc				; switch to own table
+
+    mov eax, cr0
+    or	al, #0x1				; protected mode 'on'
+    mov cr0, eax
+
+    jmpf DWORD (SEGMENT_OFFSET | switch_to_protmode_goon_1), #PM_NORMAL_CS
+
+    START_PM_CODE
+
+switch_to_protmode_goon_1:
+    mov ax, #PM_32BIT_DS			; 32 bit segment that allows
+    mov ds, ax					; to reach all 32 bit
+    mov es, ax					; addresses
+    mov ss, ax
+
+    pop eax					;@A2
+    pop bp					;@A1
+    ret
+
+    END_PM_CODE
+
+
+
+    .align 16
+gdt_base:
+    ; see Intel SW Dev. Manuals section 3.4.5, Volume 3 for meaning of bits
+    .word 0,0
+    .byte 0,0,0,0
+
+gdt_entry_pm_cs:
+    ; 32 bit code segment for protected mode
+    .word 0xffff, 0x0000
+    .byte 0x00, 0x9a, 0xcf, 0x00
+
+gdt_entry_pm_16bit_cs:
+    ; temp. 16 bit code segment used while in protected mode
+    .word 0xffff, 0x0000
+    .byte SEGMENT_OFFSET >> 16, 0x9a, 0x0, 0x0
+
+gdt_entry_pm_32bit_ds:
+    ; (32 bit) data segment (r/w) reaching all possible areas in 32bit memory
+    ; 4kb granularity
+    .word 0xffff, 0x0000
+    .byte 0x0, 0x92, 0xcf, 0x0
+gdt_entry_end:
+
+my_gdtdesc:
+    .word (gdt_entry_end - gdt_base) - 1
+    .long gdt_base | SEGMENT_OFFSET
+
+
+realmode_gdtdesc:				;to be used in real mode
+    .word 0xffff
+    .long 0x0
+
+
+
+switch_to_realmode:
+    ; Implementation of switching from protected mode to real mode
+    ; restores all registers and prepares cs, es, ds, ss to be used
+    ; in real mode
+    START_PM_CODE
+
+    ; need to fix up the stack to return in 16 bit mode
+    ; currently the 32 bit return address is on the stack
+    push bp					;pop@A1
+    mov bp, sp
+    push eax					;pop@X
+
+    mov eax, [bp]				; return address low 16bits
+                  				; and 'bp' are being moved
+    mov 2[bp], eax
+
+    pop eax					;@X
+    add sp, #2					; adjust stack for 'lost' bytes
+
+    push eax					;pop@1
+    push bx					;pop@2
+    push si					;pop@3
+
+    call _ebda_ss_offset32			; get the offset of the ss
+    mov bx, ax					; entry within the ebda.
+
+    jmpf switch_to_realmode_goon_1, #PM_16BIT_CS
+
+    END_PM_CODE
+
+switch_to_realmode_goon_1:
+    mov eax, cr0
+    and al, #0xfe				; protected mode 'off'
+    mov cr0, eax
+
+    jmpf switch_to_realmode_goon_2, #REAL_MODE_CODE_SEGMENT
+
+switch_to_realmode_goon_2:
+
+    ; get orig. 'ss' without using the stack (no 'call'!)
+    xor eax, eax			; clear upper 16 bits (and lower)
+    mov ax, #0x40			; where is the ebda located?
+    mov ds, ax
+    mov si, #0xe
+    seg ds
+    mov ax, [si]			; ax = segment of ebda
+
+    mov ds, ax				; segment of ebda
+    seg ds
+    mov ax, [bx]			; stack segment - bx has been set above
+    mov ss, ax
+
+    ; from esp and ss calculate real-mode sp
+    rol eax, #4
+    sub esp, eax
+
+    call _get_register_ds			; get orig. 'ds'
+    mov ds, ax
+    call _get_register_es			; get orig. 'es'
+    mov es, ax
+    call _get_register_esp_hi			; fix the upper 16 bits of esp
+    ror esp, #16
+    mov sp, ax
+    rol esp, #16
+
+    seg cs
+    lgdt realmode_gdtdesc
+
+    sti						; allow interrupts
+
+    pop si					;@3
+    pop bx					;@2
+    pop eax					;@1
+    pop bp					;@A1
+
+    ret
+
+    ASM_END
+
+
+/*
+ * Helper function to get the offset of the reg_ss within the ebda struct
+ * Only 'C' can tell the offset.
+ */
+Bit16u
+ebda_ss_offset32()
+{
+    ASM_START
+    START_PM_CODE				// need to have this
+    ASM_END					// compiled for protected mode
+    return &EbdaData->tcpa.reg_ss;		// 'C' knows the offset!
+    ASM_START
+    END_PM_CODE
+    ASM_END
+}
+
+    ASM_START
+
+
+
+TCG_StatusCheck:
+    ; specs: 12.5
+    ;
+    ; Input:
+    ;  None at this level
+    ; Ouput:
+    ;  As specified in the specs; eax contains error code, '0' for success
+
+    ; Check whether the TPM is present at all
+    ; is special MADriver function call
+    ; Build stack for MADriverCall
+    push dx				;pop@1
+
+    mov ax, #(CODE_MAIsTPMPresent)	; MAIsTPMPresent
+
+    call _TCG_DoMADriverCall
+    ; return code is in dx
+    and dx, dx
+    jne tcg_statuscheck_goon_1
+
+    pop dx				;@1
+    mov eax, #(TCG_PC_TPMERROR | (TCG_PC_TPM_NOT_PRESENT) << 16)
+
+    ret					; EXIT
+tcg_statuscheck_goon_1:
+    ; Prepare paramters for DoMADriverCall
+
+    mov ax, #(CODE_MAInitTPM)		; MAInitTPM
+    mov dx, #(TPM_ST_CLEAR)
+
+    call _TCG_DoMADriverCall
+    ; return code is in dx
+    and dx, dx
+    je  tcg_statuscheck_ok_1
+
+    mov ax, dx
+    pop dx				;@1
+    ret					; EXIT
+tcg_statuscheck_ok_1:
+
+    call _tcpa_get_lasa_base_ptr;
+    ror eax, #16
+    mov ax, dx
+    rol eax, #16
+    mov esi, eax
+
+    call _tcpa_get_lasa_last_ptr
+    ror eax, #16
+    mov ax, dx
+    rol eax, #16
+    mov edi, eax
+
+    xor eax, eax
+    mov ebx, #(TCG_MAGIC)
+    mov ch, #0x1
+    mov cl, #0x2
+    xor edx, edx
+
+    pop dx				;@1
+    ret					; EXIT
+
+
+
+
+TCG_HashLogExtendEvent:
+    ; specs: 12.6
+    ; Input:
+    ;  es:di Pointer to HashLogExtendEvent Input Block
+    ;  ds:si Pointer to HashLogExtendEvent Output Block
+    ;  ebx : 0x41504354 (not verified here)
+    ;  ecx : 0          (not verified here)
+    ;  edx : 0          (not verified here)
+    ; Ouput:
+    ;  eax: error code, '0' for success
+
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_hashlogextendevent_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret					;EXIT
+
+tcg_hashlogextendevent_ok_0:
+    push cx				;pop @1
+    seg es
+    mov cx, [di]			;check input block
+    cmp cx, #0x18			;short version?
+    je hashlogextendevent_ok_1	 	;yes
+    cmp cx, #0x1c			;long version?
+    je hashlogextendevent_ok_1 		;yes
+
+    pop cx				;@1
+
+    ; must initialize minimum output block
+    mov 0x0[si], #0x4
+    mov 0x2[si], #0x0
+
+    mov eax, dword #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+    ret					; EXIT
+
+hashlogextendevent_ok_1:
+
+    ; Build a HashLogEvent Input Block on the stack
+    push edx				; pop @2
+    push ecx				; pop @3
+    push bp				; pop @4
+    sub sp, #0x1c			; pop @5
+    mov bp, sp
+
+    mov 0x0[bp], #0x1c			; IPBlength
+    mov 0x2[bp], #0x0			; reserved
+
+    seg es
+    mov eax, dword ptr 0x4[di]		; copy HashDataPtr
+    mov dword 0x4[bp], eax
+
+    seg es
+    mov eax, dword ptr 0x8[di]		; copy HashDataLen
+    mov dword 0x8[bp], eax
+
+    seg es
+    mov eax, dword ptr 0xc[di]		; copy PCRIndex
+    mov dword 0xc[bp], eax
+
+    ; type 1 or type 2 message?
+    cmp cx, #0x18			;short input block?
+    jne hashlogextendevent_long_1
+
+    ; type 1 message (short)
+    seg es
+    mov eax, dword ptr 0x10[di]		; read LogDataPtr
+    seg es
+    mov ecx, dword ptr 0x14[di]		; read LogDataLen
+
+    jmp hashlogextendevent_goon_1
+
+hashlogextendevent_long_1:
+    ; type 2 message (long)
+    seg es
+    mov eax, dword ptr 0x14[di]		; read LogDataPtr
+    seg es
+    mov ecx, dword ptr 0x18[di]		; read LogDataLen
+
+hashlogextendevent_goon_1:
+    mov dword 0x14[bp], eax		; LogDataPtr
+    mov dword 0x18[bp], ecx		; LogDataPtr
+
+    ; copy the LogEventType
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov ecx, 0x4[eax]			; LogEventType from PCClientPCREventStruc
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    mov dword 0x10[bp], ecx		; LogEventType
+
+
+    ; put the pointer to the LogEvent Input in es:di
+    push es				;pop @6
+    push di				;pop @7
+    mov ax, ss
+    mov es, ax
+    mov di, bp
+
+    ; create a HashLog Event Output Block on the stack
+    push ds				;pop @8
+    push si				;pop @9
+
+    sub sp, #0x8			;adjust @10
+    ; put the pointer to the LogEvent Output in ds:si
+    mov ax, ss
+    mov ds, ax
+    mov si, sp
+
+    ; Call HashLogEvent
+    mov eax, #(TCG_MAGIC)
+    ; es:di LogEvent Input block
+    ; ds:si LogEvent Output block
+    call TCG_HashLogEvent
+
+    ; want to have ss:bp to be HashLogEvent Output block
+    mov bp, sp
+
+    add sp, #0x8			;@10
+    pop si				;@9
+    pop ds				;@8
+    pop di				;@7
+    pop es				;@6
+
+    ; error by HashLogEvent; save it; must do Extend anyway
+    mov edx, eax
+
+    ; ds:si contains pointer to HashLogExtendEvent Output block
+    ; es:di contains pointer to HashLogExtendEvent Input Block
+    ; ss:bp contains pointer to HashLogEvent Output block
+
+    ; need to fill HashLogExtendEvent Output structure
+    mov 0x0[si], #0x1c			; OPBlength
+    mov 0x2[si], #0x0			; Reserved
+
+    mov eax, dword 0x4[bp]		; read EventNumber
+    mov dword 0x4[si], eax		; write EventNumber
+
+    ; get the hash from the PCClientPCREventStruc
+    seg es
+    mov ax, 0x0[di]			; length
+    cmp ax, #0x18			; short input block?
+    jne hashlogextendevent_long_2
+
+    ; short input block
+    seg es
+    mov eax, dword ptr 0x10[di]		; read LogDataPtr
+    jmp hashlogextendevent_goon_2
+
+hashlogextendevent_long_2:
+    ; long input block
+    seg es
+    mov eax, dword ptr 0x14[di]		; read LogDataPtr
+
+hashlogextendevent_goon_2:
+
+    ; copy the hash into the output block using the stack
+    ; to avoid switching back and forth between pm and rm
+    call switch_to_protmode
+    START_PM_CODE
+
+    push dword #8[eax]
+    push dword #12[eax]
+    push dword #16[eax]
+    push dword #20[eax]
+    push dword #24[eax]
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop dword #24[si]
+    pop dword #20[si]
+    pop dword #16[si]
+    pop dword #12[si]
+    pop dword #8[si]
+
+    ; TCG_TPM_Extend
+    ; Parameters
+    ; ds:si: Hash to extend PCR with
+    ; eax  : PCR Index
+    seg es
+    mov dword eax, dword 0xc[di]	; PCR Index
+
+    add si, #8				; adjust to position of hash
+
+    call _TCG_TPM_Extend
+
+    ; Check for error code from previously called HashLog function
+    cmp edx, #0
+    je hashlogextendevent_goon_3
+
+    ; return the error code form the HashLog function instead
+    mov eax, edx
+
+hashlogextendevent_goon_3:
+    ; adjust si to point to the beginning of the opb
+    sub si, #8
+
+hashlogextendevent_out_1:
+    add sp, #0x1c			;@5
+    pop bp				;@4
+    pop ecx				;@3
+    pop edx				;@2
+
+    pop cx				;@1
+
+    ret
+
+
+
+
+
+
+
+TCG_PassThroughToTPM:
+    ; specs: 12.7
+    ;
+    ; Input:
+    ;  es:di Pointer to TPM Input Block
+    ;  ds:si Pointer to TPM Output Block
+    ;  ebx : 0x41504354     (not verified here)
+    ;  ecx : 0	            (not verified here)
+    ;  edx : 0              (not verified here)
+    ; Output:
+    ;  eax : error code, '0' for success
+
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_passthroughtotpm_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret
+
+tcg_passthroughtotpm_ok_0:
+    ; interface still up
+    seg es
+    cmp 0x0[di], #0x8			; input block ok?
+    jge passthroughtotpm_ok_1
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+passthroughtotpm_err_exit_1:
+    ; input block too short - return error
+    ; must initialize minimum output block
+    mov 0x0[si], #0x4
+    mov 0x2[si], #0x0
+
+    ret					; EXIT
+
+passthroughtotpm_ok_1:
+    push ecx				;pop@1
+    push ebx				;pop@2
+    push edx				;pop@3
+    xor ecx, ecx
+
+    seg es
+    mov cx, 0x4[di]			;size of output buffer
+    cmp cx, #0x4
+    jge passthroughtotpm_ok_2
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+    jmp passthroughtotpm_err_exit_1
+
+passthroughtotpm_ok_2:
+    ; should now transmit the data to the low level driver
+
+    ; Send the data
+    ; ax: Code of MATransmit function
+    ; edx: start of input buffer
+    ; ecx: length of output buffer
+    ; ebx: pointer to place result into
+
+    ; edx from es:[di+8]
+
+    Calc32FromSegOff(edx, dx, es, di, eax, ax)
+    add edx, #8
+
+    ; calculate ebx from ds:[si+4]
+    Calc32FromSegOff(ebx, bx, ds, si, eax, ax)
+    add ebx, #4
+
+    ; actual buffer is 4 bytes shorter due to header of
+    ; PassThroughToTPM Output block; that is from si + 4
+    sub ecx, #4
+
+    mov ax, #(CODE_MATransmit)		; MAIsTPMPresent
+    call _TCG_DoMADriverCall
+
+    xor eax, eax
+    ; result is in dl
+    cmp dl, #0
+    je passthroughtotpm_ok_3
+
+    ; create proper error code
+    mov al, dl
+    rol eax, #16
+    mov al, #(TCG_PC_TPMERROR)
+
+passthroughtotpm_ok_3:
+    pop edx				;@3
+    pop ebx				;@2
+    pop ecx				;@1
+    ret					; EXIT
+
+
+
+TCG_ShutdownPreBootInterface:
+    ; specs: 12.8
+    ;
+    ; Input:
+    ;  es:di Pointer to HashLogEvent Input Block
+    ;  ds:si Pointer to HashLogEvent Output Block
+    ;  ebx : 0x41504354    (not verified here)
+    ;  ecx : 0             (not verified here)
+    ;  edx : 0             (not verified here)
+    ; Ouput:
+    ;  eax : error code, '0' for success
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_shutdownprebootinterface_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret
+
+tcg_shutdownprebootinterface_ok_0:
+    call _TCG_ShutdownPreBootInterface
+    xor eax, eax
+    ret
+
+
+TCG_HashLogEvent:
+    ; specs: 12.9
+    ;
+    ; Input:
+    ;  es:di Pointer to HashLogEvent Input Block
+    ;  ds:si Pointer to HashLogEvent Output Block
+    ;  ebx : 0x41504354    (not verified here)
+    ;  ecx : 0             (not verified here)
+    ;  edx : 0             (not verified here)
+    ; Output:
+    ;  eax : error code: '0' for success
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_hashlogevent_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    jmp hashlogevent_err_exit_1
+
+tcg_hashlogevent_ok_0:
+    seg es
+    mov ax, 0x0[di]
+    cmp ax, #0x1c
+    je hashlogevent_ok_1
+    mov eax, dword #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+
+hashlogevent_err_exit_1:
+    ; must initialize minimum output block
+    mov word ptr 0x0[si], word #0x4
+    mov word ptr 0x2[si], word #0x0
+
+    ret
+
+hashlogevent_ok_1:
+    ; test the TCG_PCClientPCREventStruc
+    push ecx				;pop @1
+    push edx				;pop @2
+    push ebx				;pop @3
+    seg es
+    mov ebx, dword ptr 0x14[di]		; LogDataPtr
+    seg es
+    mov ecx, dword ptr 0x18[di]		; LogDataLen
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov edx, 0x0[ebx]			; PCRIndex
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    seg es
+    cmp dword 0xc[di], edx		; PCRIndex compare
+    je hashlogevent_ok_2
+
+    jmp hashlogevent_err_exit_2		; EXIT
+
+hashlogevent_ok_2:
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov edx, dword 0x4[ebx]		; EventType
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    seg es
+    cmp dword 0x10[di], edx		; EventType compare
+    je hashlogevent_ok_3
+
+hashlogevent_err_exit_2:
+    pop ebx				;@3
+    pop edx				;@2
+    pop ecx				;@1
+    mov eax, dword #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+
+    jmp hashlogevent_err_exit_1		; EXIT
+
+hashlogevent_ok_3:
+    seg es
+    mov edx, dword ptr 0x4[di]		; hash data ptr
+    seg es
+    mov ecx, dword ptr 0x8[di]		; hash data len
+
+    cmp edx, #0				; test hash data ptr != 0
+    jne hashlogevent_goon_1
+    cmp edx, #0				; test hash data len != 0
+    je hashlogevent_no_hashall
+
+hashlogevent_goon_1:
+    ; create a HashAll Input Parameter Block on the stack
+    push es				;pop @4
+    push di				;pop @5
+    sub sp, #0x10			;adjust @6
+
+    ; let es:di point to the structure
+    mov ax, ss
+    mov es, ax
+    mov di, sp
+
+    ; initialize the structure
+    seg es
+    mov 0x0[di], #0x10			; IPBlength
+    seg es
+    mov 0x2[di], #0x0			; Reserved
+    seg es
+    mov dword 0x4[di], edx		; HashDataPtr
+    seg es
+    mov dword 0x8[di], ecx		; HashDataLen
+    seg es
+    mov dword 0xc[di], #(TPM_ALG_SHA)	; AlgorithmID
+
+    ; create room for a SHA1 digest on the stack
+    push ds				;pop @7
+    push si				;pop @8
+    sub sp, #20				;adjust @9
+
+    ; let ds:si point to the structure
+    mov ax, ss
+    mov ds, ax
+    mov si, sp
+
+    ; no initialization necessary
+    ; hash it
+    call TCG_HashAll
+
+    ; ds:si contains hash if eax == 0
+    ; check return code from TCG_HashAll
+    cmp eax, #0
+    je	hashlogevent_ok_4
+
+    ; something went wrong while hashing the data
+    add sp, #20				;@9
+    pop si				;@8
+    pop ds				;@7
+
+    add sp, #0x10			;@6
+    pop di				;@5
+    pop es    				;@4
+
+    pop ebx				;@3
+    pop edx				;@2
+    pop ecx				;@1
+
+    jmp hashlogevent_err_exit_1		; EXIT
+
+
+hashlogevent_ok_4:
+    ; hashing was done ok
+
+    ; copy the hash into the TCG_PCClientPCREventStruct
+    ; ebx contains address of this structure
+
+    ; use reverse copying of data through the stack to avoid
+    ; switch between protected and real mode
+    push dword 0[si]
+    push dword 4[si]
+    push dword 8[si]
+    push dword 12[si]
+    push dword 16[si]
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    pop dword 24[ebx]
+    pop dword 20[ebx]
+    pop dword 16[ebx]
+    pop dword 12[ebx]
+    pop dword  8[ebx]
+
+    call switch_to_realmode
+    END_PM_CODE
+    ; hash is copied
+
+    add sp, #20				;@9
+    pop si				;@8
+    pop ds				;@7
+
+    add sp, #0x10			;@6
+    pop di				;@5
+    pop es    				;@4
+
+hashlogevent_no_hashall:
+    ; getting here after HashAll has been call or also if not
+    ; ebx must contain the PCClientPCRStruct pointer
+
+
+    ; extend the log with this event
+    push ebx				;pop@A
+    call _tcpa_extend_acpi_log
+    pop ebx				;@A
+
+    ; expecting eax to return the entry number somehow
+    ; error code in upper 16 bits and lower 16 bits
+    ; hold event number; 0 if error code is set
+    and ax, ax
+    jne hashlogevent_ok_5
+
+    ; error while updating the log
+    ; need minimal initialization of output block
+    mov 0x0[si], #0x4
+    mov 0x2[si], #0x0
+    ; bring down the error code to lower 16 bits
+    ror eax, #16
+    jmp hashlogevent_out_1		; EXIT
+
+hashlogevent_ok_5:
+    ; updating the log was fine
+    ; the log event number is in lower 16 bits
+
+    ; update the output structure
+    mov 0x0[si], #8
+    mov 0x2[si], #0
+    mov dword 0x4[si], eax
+
+    mov eax, #TCG_PC_OK
+
+hashlogevent_out_1:
+    pop ebx				;@3
+    pop edx				;@2
+    pop ecx				;@1
+
+    ret					; EXIT
+
+
+TCG_HashAll:
+    ; specs: 12.10
+    ; Input:
+    ;  es:di HashAll Input Block
+    ;  ds:si Pointer to place for digest
+    ;  ebx : 0x41504354    (not verified here)
+    ;  ecx : 0             (not verified here)
+    ;  edx : 0             (not verified here)
+    ; Output:
+    ;  eax : error code: '0' for success
+
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_hashall_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret
+
+tcg_hashall_ok_0:
+    seg es
+    mov ax, 0x0[di]
+    cmp ax, #0x10
+    je hashall_ok_1
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+    ret					; EXIT
+
+hashall_ok_1:
+    seg es
+    mov eax, dword 0xc[di]; ; algorithm id
+    cmp eax, #(TPM_ALG_SHA)
+    je hashall_ok_2
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INVALID_ACCESS_REQUEST << 16))
+    ret					; EXIT
+
+hashall_ok_2:
+    push ecx				;pop@1
+    push edx				;pop@2
+    push ebx				;pop@3
+    seg es
+    mov edx, dword ptr 0x4[di]; 	; data to hash
+    seg es
+    mov ecx, dword ptr 0x8[di]; 	; length of data
+
+    ; hash the data
+    ; ax: Code of MAHashAll function
+    ; edx: start of input buffer
+    ; ecx: Length of input buffer
+    ; ebx: pointer to place digest into; must be 20 bytes long
+
+    ; calculate ebx from ds:si
+
+    Calc32FromSegOff(ebx, bx, ds, si, eax, ax)
+
+    mov ax, #(CODE_MAHashAll)		; MAIsTPMPresent
+    call _TCG_DoMADriverCall
+    ; error code is in edx
+    mov eax, edx
+
+    pop ebx				;@3
+    pop edx				;@2
+    pop ecx				;@1
+
+    ret
+
+
+TCG_TSS:
+    ; specs: 12.11
+    ; Input:
+    ;  es:di TSS Input Parameter Block
+    ;  ds:di TSS Output Parameter Block
+    ;  ebx : 0x41504354    (not verified here)
+    ;  ecx : 0             (not verified here)
+    ;  edx : 0             (not verified here)
+    ; Output:
+    ;  eax : error code: '0' for success
+
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_tss_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret
+
+tcg_tss_ok_0:
+
+    mov 0x0[si], #4
+    mov 0x2[si], #0
+
+    mov eax, #(TCG_PC_UNSUPPORTED)
+    ret
+
+
+
+TCG_CompactHashLogExtendEvent:
+    ; specs: 12.12
+    ; Input:
+    ;  es:di Buffer to be hashed
+    ;  esi: event field value
+    ;  ebx = 0x41504354                    (not verified here)
+    ;  ecx : length of es:di buffer
+    ;  edx : PCR Number
+    ; Output:
+    ;  eax : return code
+    ;  edx : event number that was logged
+    ;        ** all other registers are preserved **
+
+    call _TCG_IsShutdownPreBootInterface
+    cmp ax, #0
+    je tcg_compacthashlogextendevent_ok_0
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INTERFACE_SHUTDOWN << 16))
+    ret
+
+tcg_compacthashlogextendevent_ok_0:
+
+    ; sanity check of parameters; see 12.12
+    mov ax, es
+    cmp ax, #0
+    jne tcg_compacthashlogextendevent_goon_1
+    cmp di, #0
+    jne tcg_compacthashlogextendevent_goon_1
+
+    mov eax, #(TCG_PC_TPMERROR | (TCG_INVALID_INPUT_PARA << 16))
+    ret					;EXIT
+
+tcg_compacthashlogextendevent_goon_1:
+    push bp				;pop@1
+
+    ; create space for a
+    ; HashLogExtendEvent Input + Output blocks
+    ; PCClientPCREventStruc block
+    sub sp, #(0x18 + (8 + 20) + 36)	;adjust@2
+    mov bp, sp
+
+    ; fill out HashLogExtendEvent Input Block
+    mov ax, #0x18
+    mov 0x0[bp], ax			; IPBlength
+
+    mov ax, #0x0
+    mov 0x2[bp], ax			; Reserved
+
+    Calc32FromSegOff(eax, ax, es, di, ebx, bx)
+
+    mov dword 0x4[bp], eax		; HashDataPtr
+    mov dword 0x8[bp], ecx		; HashDataLen
+    mov dword 0xc[bp], edx		; PCRIndex
+
+    Calc32FromSegOff(eax, ax, ss, bp, ebx, bx)
+    add eax, #(0x18 + 8 + 20)
+
+    mov dword 0x10[bp], eax		; LogDataPtr (located on stack)
+
+    mov eax, #32			; size of PCClientPCREventStruc
+    mov dword 0x14[bp], eax
+
+    add bp, #(0x18 + (8 + 20))		; point to PCCliencPCREventStruc
+
+    mov dword 0x0[bp], edx		; PCRIndex
+    mov eax, #(EV_COMPACT_HASH)		; eventType
+    mov dword 0x4[bp], eax
+
+    mov eax, #4
+    mov dword 28[bp], eax		; eventDataSize = 4
+    mov dword 32[bp], esi		; eventData
+
+    sub bp, #(8 + 20)			; point to output  block
+    push ds				;pop@3
+    push si				;pop@4
+    mov ax, ss
+    mov ds, ax
+    mov si, bp
+
+    sub bp, #0x18			; point to input block
+
+    push es				;pop@5
+    push di				;pop@6
+    mov es, ax
+    mov di, bp
+
+    ; ds:si Output block
+    ; es:di Input Block
+    call TCG_HashLogExtendEvent
+
+    mov edx, dword 0x4[si]
+
+    pop di				;@6
+    pop es				;@5
+    pop si				;@4
+    pop ds				;@3
+    add sp, #(0x18 + (8 +20) + 36)	;@2
+    pop bp				;@1
+    ret
+
+
+/*
+ * vendore-specific functions
+ */
+
+_TCG_TPM_Extend:
+    ; Extend a given PCR with a given hash = run the TPM_Extend function
+    ;
+    ; Input:
+    ;  ds:si: Hash to extend PCR with
+    ;  eax  : PCR Index
+    ; Output:
+    ;  eax : errorcode; '0' for success
+
+    push bp				;pop @1
+    push ecx				;pop @2
+
+    ; make room for a
+    ; PassThroughToTPM + Extend Command + Output Block
+    ; on the stack
+    sub sp, #(8+34+30)			;adjust @3
+    mov bp, sp
+
+    ; Initialize the PassThroughToTPM Input Block
+    mov cx, #(8+34)			; total length
+    mov 0[bp], cx			; IPBlength
+
+    mov cx, #0
+    mov 2[bp], cx			; Reserved
+    mov 6[bp], cx			; Reserved
+
+    mov cx, #30
+    mov 4[bp], cx
+
+    ; Initialize the request - adjust bp (pointer)
+    add bp, #8
+
+    mov cx, #0xc100			; big endian 0x00, 0xc1
+    mov 0[bp], cx			; Tag
+
+    mov ecx, #0x0
+    mov dword 2[bp], ecx		; clear length
+    mov cl, #34
+    mov 5[bp], cl			; Length
+
+    mov ecx, #0x0
+    mov dword 6[bp], ecx
+    mov cl, #0x14
+    mov 9[bp], cl			; Ordinal (Extend=0x14)
+
+    mov 13[bp], al			; PCR Index
+    shr eax, #8
+    mov 12[bp], al
+    shr eax, #8
+    mov 11[bp], al
+    shr eax, #8
+    mov 10[bp], al
+
+    ; copy the digest
+    mov eax, dword 0[si]
+    mov dword 14[bp], eax
+
+    mov eax, dword 4[si]
+    mov dword 18[bp], eax
+
+    mov eax, dword 8[si]
+    mov dword 22[bp], eax
+
+    mov eax, dword 12[si]
+    mov dword 26[bp], eax
+
+    mov eax, dword 16[si]
+    mov dword 30[bp], eax
+
+    sub bp, #8				; points at Input block again
+    push es				;pop@4
+    push di				;pop@5
+    push ds				;pop@6
+    push si				;pop@7
+
+    ; create es:di from ss:bp
+    ; create ds:si from ss:(bp+8+34)
+    mov ax, ss
+    mov es, ax
+    mov di, bp
+
+    mov ds, ax
+    add bp, #(8+34)			; bp points at output block
+    mov si, bp
+
+    push edx				;pop@8
+
+    call TCG_PassThroughToTPM
+    ; only the result from this operation is intersting
+
+    pop edx				;@8
+    pop si				;@7
+    pop ds				;@6
+    pop di				;@5
+    pop es				;@4
+    add sp, #(8+34+30)			;@3
+    pop ecx				;@2
+    pop bp				;@1
+    ret
+
+
+/*
+ * low-level driver support implementation
+ */
+
+BIOSDriverHeader:
+    .word 0x55aa			; Signature
+    .long 0x00000000			; Pointer to beginning of code
+    .word 0x0000			; total size of driver
+#if TPM_TYPE == TPM_TIS
+    .long TPM_TIS_BASE_ADDRESS          ; base address of TIS interface
+#elif TPM_TYPE == TPM_ATMEL
+    .long 0x00000000			; ignored by that driver
+#endif
+    .long 0x00000000			; alternate address
+    .byte 0xff				; IRQ level
+    .byte 0xff				; DMA channel
+    .byte 0x00				; XOR-checksum of driver
+    .byte 0x00				; Reserved
+    .long 0x00000000			; PCI PFA
+    .long 0x00000000			; USB, CardBus, etc.
+    .long 0x00000000			; TPM Configuration port location
+
+
+  ; MA Driver Implementation
+_TCG_DoMADriverCall:
+    ; build the stack frame to call the MA Driver.
+    ; Input:
+    ; ax: contains function number to call
+    ; other registers prepared for the function's parameters
+    push eax				;pop@1
+    push si				;pop@2
+
+    push ax				;adjust@3
+
+    ; Pointer to BIOS Driver Header
+    mov eax, #BIOSDriverHeader + SEGMENT_OFFSET
+
+    push eax				;adjust@4
+
+    ; specs: 14.2.5  MADriver wants to return via 'retf'
+    callf MADriverCall, REAL_MODE_CODE_SEGMENT
+
+    add sp, #6				;@4,@3
+    pop si				;@2
+    pop eax				;@1
+    ret
+
+
+  ; Implementation of MA Driver function call dispatcher
+  ; Call this function instead of the other ones directly!
+  ;
+MADriverCall:
+    push bp				;pop@1 (this moves the layout on
+    					;       the stack by 2!)
+    push ax				;pop@2
+
+    mov bp,sp
+
+    ; check which function to call
+    mov al, (0x04+0x08)[bp]		; read FunctionNum (14.2.5)
+
+    cmp al, #(CODE_MAInitTPM)		; MAInitTPM?
+    jne _madrivercall_goon_1
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MAInitTPM			; EXIT
+
+_madrivercall_goon_1:
+    cmp al, #(CODE_MAHashAllExtendTPM)
+    jne _madrivercall_goon_2
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MAHashAllExtendTPM		; EXIT
+
+_madrivercall_goon_2:
+    cmp al, #(CODE_MAPhysicalPresenceTPM)
+    jne _madrivercall_goon_3
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MAPhysicalPresenceTPM		; EXIT
+
+_madrivercall_goon_3:
+    cmp al, #(CODE_MAIsTPMPresent)
+    jne _madrivercall_goon_4
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MAIsTPMPresent			; EXIT
+
+_madrivercall_goon_4:
+    cmp al, #(CODE_MAHashAll)
+    jne _madrivercall_goon_5
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MAHashAll			; EXIT
+
+_madrivercall_goon_5:
+    cmp al, #(CODE_MATransmit)
+    jne _madrivercall_goon_6
+
+    pop ax				;@2
+    pop bp				;@1
+    jmp _MATransmit			; EXIT
+
+_madrivercall_goon_6:
+    pop ax				;@2
+    pop bp				;@1
+    retf				; EXIT
+
+
+
+_MAInitTPM:
+    ; specs: 14.2.7.1
+    ; Input:
+    ;  stack layout as in 14.2.5
+    ;  DL = bMAInitTPMFctID; 14.2.6.3
+    ; Output:
+    ;  DL = return code
+    push ebp				;pop@1
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    ;let bp point to the return address
+    ;need this to call _MAInitTPM32
+
+    mov bp, sp
+    add bp, #4
+
+    call _MAInitTPM32
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebp				;@1
+    retf
+
+
+
+
+_MAInitTPM32:
+    START_PM_CODE
+    ; is anything selected according to 14.2.6.3?
+    cmp dl, #0
+    jne _mainittpm32_goon_1
+    ret					;EXIT
+
+_mainittpm32_goon_1:
+    push eax				;pop@1
+    push ecx				;pop@2
+    push ebx				;pop@3
+
+    mov eax, #CMD_TPM_Startup_0x01 + SEGMENT_OFFSET
+    ; copy buffer onto stack, 12 bytes
+    mov ecx, #12
+    sub esp, ecx			;adjust@4
+
+_mainittpm32_loop_1:
+    dec ecx
+    cmp ecx, #0
+    jl  _mainittpm32_goon_2
+    mov bl, [eax+ecx]
+    mov [esp+ecx], bl
+
+    jmp _mainittpm32_loop_1
+
+_mainittpm32_goon_2:
+    ; stick startup type into command
+    mov #11[eax], dl
+
+    ; send the command
+    ; edx: buffer address with data to send to the TPM
+    ; ecx: length of output buffer
+    ; ebx: pointer for output buffer
+    mov edx, eax
+    mov ecx, #10			; 10 bytes response
+
+    sub esp, ecx			; adjust@5
+    mov ebx, esp			; Calc32Simple
+
+    call _MATransmit32
+    ; result code is in dl; becomes the result code of this function
+
+    add esp, ecx			;@5
+    add esp, #12			;@4
+
+    pop ebx				;@3
+    pop ecx				;@2
+    pop eax				;@1
+    ret
+
+    END_PM_CODE
+
+
+_MAHashAllExtendTPM:
+    ; 14.2.7.2
+    ; Input:
+    ; stack layout as in 14.2.5
+    ; edx = pointer to start addess of input buffer
+    ; ecx = pcrIndex and Length of input buffer
+    ; Stack layout as described in 14.2.5
+    ; Output:
+    ;  DL = return code
+    push ebp				;pop@1
+    push eax				;pop@2
+
+    call switch_to_protmode
+
+    START_PM_CODE
+
+    ;let ebp point to the return address
+    ;need this to call _MAHashAll32
+    mov ebp, esp
+    add ebp, #4
+
+    ;build 'extend' request and response on the stack
+
+    sub esp, #(30+34)			;adjust@A
+    mov ebx, esp			; Calc32Simple
+
+    ; let ebx point to where the hash goes into the Extend command
+    add ebx, #14
+
+    push edx				;pop@B
+    push ecx				;pop@C
+    and ecx, #0xffff			;only length is interesting
+
+    ; Calculate the hash over the data
+    call _MAHashAll32
+    ; error code in edx
+    and edx, edx
+    je _mahashallextendtpm_ok_0
+
+    pop ecx				;@C
+    pop edx				;@B
+
+    mov edx, #(TPM_GENERAL_ERROR)
+    jmp _mahashallextend_exit_1		; EXIT
+
+_mahashallextendtpm_ok_0:
+    pop ecx				;@C
+    pop edx				;@B
+
+    ; build extend function
+    sub ebx, #14
+
+    mov byte 0[ebx], #0x0		;tag
+    mov byte 1[ebx], #0xc1
+
+    mov dword 2[ebx], #0		;length of packet
+    mov byte 5[ebx], #34
+
+    mov dword 6[ebx], #0		;ordinal
+    mov byte 9[ebx], #0x14		;ordinal 0x14=Extend
+
+    ; write PCR
+    ror ecx, #16
+    mov dword 10[ebx], #0		;ordinal
+    mov byte 12[ebx], ch
+    mov byte 13[ebx], cl
+    rol ecx, #16
+
+    ; send the command
+    ; edx: buffer address with data to send to the TPM
+    ; ecx: length of output buffer
+    ; ebx: pointer for output buffer
+    push ebx				;pop@B
+    push ecx				;pop@C
+    push edx				;pop@D
+
+    mov edx, ebx
+
+    mov ecx, #30
+    add ebx, #34
+
+    call _MATransmit32
+    ; error code is in dl
+    mov al, dl
+
+    pop edx				;@D
+    pop ecx				;@C
+    pop ebx    				;@B
+
+    mov dl, al
+
+_mahashallextend_exit_1:
+    add esp, #(30+34)			;@A
+
+    call switch_to_realmode
+
+    END_PM_CODE
+
+    pop eax				;@2
+    pop ebp				;@1
+    retf
+
+
+
+_MAPhysicalPresenceTPM:
+    ; 14.2.7.3
+    ; Input:
+    ; stack layout as in 14.2.5
+    ; dx = bMAPhyPresenceTPMCmdId; 14.2.6.4
+    ; Ouput:
+    ; dx = return code
+    push ebp				;pop@1
+    push eax				;pop@2
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    ;let ebp point to the return address
+    ;need this to call _MAHashAll32
+    mov ebp, esp
+    add ebp, #4
+
+    ;build 'physical presence' request and response on the stack
+
+    push edx				;pop@A
+    push ecx				;pop@B
+    push ebx				;pop@C
+
+    sub esp, #(12+10)			;adjust @D
+
+    ; build command
+    mov ebx, esp			; Calc32Simple
+
+    mov byte #0[ebx], #0		;tag
+    mov byte #1[ebx], #0xc1		;
+
+    mov dword #2[ebx], #0		;length
+    mov #5[ebx], #12
+
+    mov byte #6[ebx], #0x4		;ordinal
+    mov byte #7[ebx], #0
+    mov byte #8[ebx], #0
+    mov byte #9[ebx], #0xa
+
+    mov byte #10[ebx], dh		;flags
+    mov byte #11[ebx], dl
+
+    ; send the command
+    ; edx: buffer address with data to send to the TPM
+    ; ecx: length of output buffer
+    ; ebx: pointer for output buffer
+    mov edx, ebx			;request buffer ptr
+    add ebx, #12			;pointer to output buffer
+    mov ecx, #10			;length for response
+
+    call _MATransmit32
+
+    ;error code is in dl
+    mov al, dl
+
+    add esp, #(12+10)			;@D
+
+    pop ebx				;@C
+    pop ecx				;@B
+    pop edx				;@A
+
+    mov dl, al
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop eax				;@2
+    pop ebp				;@1
+    retf
+
+
+
+_MAIsTPMPresent:
+    ; Input:
+    ;  stack layout as in 14.2.5
+    ;  nothing else
+    ; Output:
+    ;  dx: 0, no TPM available, 1 TPM is available
+
+    push ebp				;pop@1
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov bp, sp
+    add bp, #4
+
+    call _MAIsTPMPresent32
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebp				;@1
+    retf				; EXIT
+
+
+
+
+_MAIsTPMPresent32:
+
+    START_PM_CODE
+
+    push eax				;pop@1
+
+    mov eax, dword (0x04)[bp]		; pointer to BIOS Header
+    mov eax, dword 0x8[eax]		; base address
+
+    ; Input  : eax : base address of TPM
+    ; Output : dx  : 0: no TPM present, 1 TPM is present
+    call TPM_IsPresentTPM32
+
+    pop eax				;@1
+    ret
+
+    END_PM_CODE
+
+
+_MAHashAll:
+    ; Input:
+    ;  stack layout as in 14.2.5
+    ;  edx: buffer address with data to hash
+    ;  ecx: length of data to hash
+    ;  ebx: pointer for result
+    ; Output
+    ;  edx: Error code
+    push ebp				;pop@1
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    ;let ebp point to the return address
+    ;need this to call _MAHashAll32
+    xor ebp, ebp
+    mov bp, sp
+    add bp, #4
+
+    call _MAHashAll32
+    ; error code is in edx
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebp				;@1
+    retf
+
+
+_MAHashAll32:
+    ; Input:
+    ;  edx: buffer address with data to hash
+    ;  ecx: length of data to hash
+    ;  ebx: pointer for result
+    ;  ebp: pointer to stack layout as in 14.2.5
+    ; Output
+    ;  edx: Error code
+    START_PM_CODE
+#if BX_TCGBIOS_SHA1_NO_HARDWARE
+    call switch_to_realmode
+    END_PM_CODE
+
+    push ebx		; pop@1
+    push ecx		; pop@2
+    push edx		; pop@3
+    call _sha1
+
+    add esp, #12	; @3,2,1
+
+    call switch_to_protmode
+    START_PM_CODE
+    xor edx, edx
+    ret
+#else
+
+    push eax				;pop@1
+    push ebx				;pop@2
+    push ecx				;pop@3
+    push edi				;pop@4
+    push esi				;pop@5
+
+    push ebx				;pop@A
+    push ecx				;pop@B
+    push edx				;pop@C
+
+    mov edx, #CMD_TPM_SHA1Start + SEGMENT_OFFSET
+
+    mov ecx, #14
+
+    sub esp, ecx			;adjust@D
+
+    mov ebx, esp			; Calc32Simple
+
+    call _MATransmit32
+    ; error code is in dl
+
+    add esp, ecx			;@D
+
+    ; check 'dl'
+    cmp dl, #0
+    beq _mahashall32_goon_0
+
+    ; error related to transmission
+    pop edx				;@C
+    pop ecx				;@B
+    pop ebx				;@A
+    jmp _mahashall32_goon_4		;@5-@1 and EXIT
+
+_mahashall32_goon_0:
+    ; no transmission error
+    ; check result of command
+    cmp dword ptr #6[ebx], dword #0
+    je _mahashall32_result_ok
+
+    ; clear what is to be the hash
+    mov #10[ebx], dword #0
+    mov #14[ebx], dword #0
+    mov #18[ebx], dword #0
+    mov #22[ebx], dword #0
+    mov #26[ebx], dword #0
+
+    ; result indicates failure
+    pop edx				;@C
+    pop ecx				;@B
+    pop ebx				;@A
+
+    mov edx, #(TCG_PC_TPMERROR | (TCG_TCG_COMMAND_ERROR << 16))
+
+    jmp _mahashall32_goon_4
+
+_mahashall32_result_ok:
+    mov al, #11[ebx]
+    mov ah, #10[ebx]
+    rol eax, #16
+    mov al, #13[ebx]			;read number of bytes that can
+    mov ah, #12[ebx]			;be sent to SHA1Update in one chunk
+
+    pop edx				;@C
+    pop ecx				;@B
+    pop ebx				;@A
+
+    ; write the number of bytes that SHA1Update can have into the
+    ; result array
+    ; use the result array as follows:
+    ; bytes 0-3: max. size of chunk
+    ; bytes 4-7: bytes left to send
+
+    ; limit the amount of bytes to send to between 0x40 and 0xfc0
+    cmp eax, #0x40
+    jge _mahashall32_ok_0
+    mov eax, #0x40
+
+_mahashall32_ok_0:
+    cmp eax, #0xc00
+    jle _mahashall32_ok_1
+
+    mov eax, #0xc00
+
+_mahashall32_ok_1:
+    mov 0[ebx],eax
+    mov 4[ebx],ecx
+    mov esi, edx			;index into source data array
+
+_mahashall32_loop_1:
+    mov ecx, 4[ebx]			; bytes left to send
+    ; still more than 64 bytes to send?
+    cmp ecx, #64
+    jle _mahashall32_sha1complete
+
+    ; determine how many bytes to send in command
+    and ecx, #0xffffffc0		; get multiple of 64
+    ; less than in one chunk?
+    cmp ecx, 0[ebx]			; compare against max chunk size
+    jle _mahashall32_goon_1		; less than max chunk size
+
+    ; transmit 'max. chunk size' bytes in this step
+    mov ecx, 0[ebx]			; limit to max chunk size
+_mahashall32_goon_1:
+    ; ecx contains number of bytes to transmit now
+    ; esi points at index in source
+
+    ; update the number of bytes to still send next time
+    mov eax, 4[ebx]			; currently left to send
+    sub eax, ecx			; minus what will be sent now
+    mov 4[ebx], eax			; write back
+
+    ;  make room on the stack for the command head only
+    sub esp, #14			; adjust@A
+    mov edi, esp			; Calc32Simple
+
+    push ecx				;pop@B
+
+    ;initialize command on stack
+    mov 0[edi], byte #0x00		;Tag
+    mov 1[edi], byte #0xc1		;Tag
+
+    add ecx, #14			;total length of packet (bulk + hdr)
+
+    mov 5[edi], cl			;write length of packet
+    mov 4[edi], ch
+    ror ecx, #16
+    mov 3[edi], cl
+    mov 2[edi], ch
+    ror ecx, #16
+
+    sub ecx, #14			;number of bulk data
+
+    mov 6[edi], dword #0		;command code
+    mov byte 9[edi], #0xA1		;SHA1Update
+
+    mov #13[edi], cl			;write length of bulk data
+    mov #12[edi], ch
+    ror ecx, #16
+    mov #11[edi], cl
+    mov #10[edi], ch
+    rol ecx, #16
+
+    push edx				;pop@C
+
+    ;create structure for sending chunks on stack
+    ; end marker
+    push dword #0			;adjust@D
+
+    ; length of bulk data to send
+    push cx				;adjust@D
+    ; pointer to bulk
+    push esi				;adjust@D
+
+    ; update source pointer by the amount that was just sent in the body
+    add esi, ecx
+
+    ; SHA1_Update header
+    push word #14			;adjust@D
+    ; SHA1_Update ptr
+
+    push edi				;adjust@D
+
+    mov edx, esp			; Calc32Simple
+
+    ; create room for response on stack
+    push ebx				;pop@E
+    mov ecx, #10			;10 bytes for response
+
+    sub esp, ecx			;adjust@F
+
+    mov ebx, esp			; Calc32Simple
+
+    ; edx : pointer to parts for command
+    ; ecx : size for response
+    ; ebx : pointer for response
+    call _MATransmitMultiple32
+
+    add esp, ecx			;@F
+    pop ebx				;@E
+    add esp, #(4 + 2 * 6)		;@D
+    pop edx				;@C
+    pop ecx				;@B
+    add esp, #14			;@A
+
+    jmp _mahashall32_loop_1
+
+    ; Send the SHA1Complete message with the rest of the data
+_mahashall32_sha1complete:
+    ;ecx contains amount of bytes to send now
+    ;esi points at next byte in bulk to send
+
+    push ebx				;pop @A
+    ;build the command on the stack
+
+    ;  make room on the stack for the command including bulk
+    sub esp, #14			;adjust@B
+    sub esp, ecx			;adjust@C
+    mov edi, esp			; Calc32Simple
+
+    push ecx				;pop@D
+
+    ;initialize command on stack
+    mov byte 0[edi], #0x00		;tag
+    mov byte 1[edi], #0xc1		;tag
+
+    add ecx, #14			;total length of packet
+
+    mov 5[edi], cl			;write length of packet
+    mov 4[edi], ch			;lower 16 bits
+    ror ecx, #16
+    mov 3[edi], cl			;upper 16 bits
+    mov 2[edi], ch
+    ror ecx, #16
+
+    sub ecx, #14			;number of bulk data
+
+    mov 6[edi], dword #0		;command code
+    mov byte 9[edi], #0xA2		;SHA1Complete
+
+    mov #10[edi], dword #0x0
+    mov #13[edi], cl			;write length of bulk data
+
+    push edx				;pop@E
+    mov edx, ecx
+
+    ; copy the bulk - 'ecx' bytes
+_mahashall32_loop_3:
+    dec ecx
+    cmp ecx, #0
+    jl _mahashall32_goon_3
+    mov al, [esi + ecx]
+    mov #14[edi + ecx], al
+    jmp _mahashall32_loop_3
+
+_mahashall32_goon_3:
+    mov ecx, edx			;amount of bytes sent
+
+    ; update source pointer by the amount that was just copied
+    add esi, ecx
+
+    ; prepare registers for sending command
+    ; edx : command
+    ; ecx : size for response
+    ; ebx : pointer for response
+    mov edx, edi
+
+    mov ecx, #30			; 30 bytes for response
+
+    sub esp, ecx			;adjust@F
+
+    mov ebx, esp			; Calc32Simple
+
+    call _MATransmit32
+
+    mov edi, ebx
+
+    add esp, ecx			;@F
+    pop edx				;@E
+    pop ecx				;@D
+    add esp, ecx			;@C
+    add esp, #14			;@B
+    pop ebx				;@A
+
+    ; no error occurred
+    xor edx, edx
+
+    ; Should have result hash on the stack now at 10[edi]
+    ; copy response into output buffer - 20 bytes
+    mov ecx, #20
+_mahashall32_loop_4:
+    dec ecx
+    cmp ecx, #0
+    jl _mahashall32_goon_4
+    mov al, #10[edi+ecx]
+    mov [ebx+ecx], al
+    jmp _mahashall32_loop_4
+
+
+_mahashall32_goon_4:
+    pop esi				;@5
+    pop edi				;@4
+    pop ecx				;@3
+    pop ebx				;@2
+    pop eax				;@1
+    ret
+#endif
+    END_PM_CODE
+
+
+wait_pit_ms_32:
+    ; PIT docu at
+    ; http://bochs.sourceforge.net/techspec/intel-82c54-timer.pdf.gz
+    START_PM_CODE
+
+    push ebx				;pop@1
+    push ecx				;pop@2
+    push edx				;pop@3
+
+    shl eax, #10			; scale the ms by ~PIT frequency
+    mov ebx, eax			; timeout to ebx
+
+    xor ecx, ecx
+
+    mov al, #(0x80+0x10)		;ctr2, lsb, mode 0, 16bit countdown
+    outb 0x43, al
+    xor al, al
+    outb 0x42, al			; start countdown at 0
+
+wait_pit_ms_32_loop_1:
+    ; time expired?
+    cmp ebx, #0
+    jle wait_pit_ms_32_exit_1
+
+    ; still need to wait
+    mov al, #0x80			;ctr2, counter latch
+    outb 0x43, al
+    inb al, 0x42			;current counter value
+
+    sub cl, al				; delta since last read
+    sub ebx, ecx			; decrement total wait time by delta
+    mov cl, al				; remember current state
+
+    jmp wait_pit_ms_32_loop_1
+
+wait_pit_ms_32_exit_1:
+                                        ; stop counter 2
+    xor al, al				;(0x80+0x10)
+    outb 0x42, al
+
+    pop edx
+    pop ecx
+    pop ebx
+    ret
+
+    END_PM_CODE
+
+
+_MATransmit:
+    ; Input:
+    ;  stack layout as in 14.2.5
+    ;  edx: buffer address with data to send to the TPM
+    ;  ecx: length of output buffer
+    ;  ebx: pointer for output buffer
+    ; Output:
+    ;  dl: Error code
+    push ebp					;pop@1
+
+    ; real_to_prot trashes edx, need to save it here
+    call switch_to_protmode
+    START_PM_CODE
+
+    mov ebp, esp
+    add ebp, #4
+
+    call _MATransmit32
+    ; error code is in dl
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    pop ebp					;@1
+    retf
+
+
+
+    ; MATransmit with access to 32bit addresses.
+    ; Input:
+    ;  edx: address of buffer for TPM command to send
+    ;  ecx: length of output buffer for response
+    ;  ebx: result buffer pointer
+    ;   bp: pointing to stack layout as described in 14.2.5
+    ;       4[bp] must contain pointer to BIOS header!
+    ; Ouput:
+    ;  dl: Error code
+_MATransmit32:
+
+    START_PM_CODE
+
+    push eax					;pop@1
+
+    ; address of buffer to send into eax
+    mov eax, edx
+
+    ; address of TPM into edx
+    mov edx, dword 0x04[bp]			; pointer to BIOS Header
+    mov dword edx, dword 0x8[edx]		; base address of TPM
+
+    push eax					;pop@2
+
+    ; activate the TPM
+    call TPM_ActivateTPM32
+    cmp al, #1
+    je matransmit32_goon_0
+
+    ; TPM not active
+    pop eax					;@2
+
+    mov dl, #TCG_FATAL_COM_ERROR
+
+    jmp matransmit32_exit_0			; EXIT
+
+matransmit32_goon_0:
+    pop eax					;@2
+
+    ; send command
+    ; eax : data
+    ; edx : addr of TPM
+    ; ecx : length of data to send
+    push ecx					;pop@3
+    mov ch, 2[eax]
+    mov cl, 3[eax]
+    rol ecx, #16
+    mov ch, 4[eax]
+    mov cl, 5[eax]
+    call TPM_SendDataTPM32
+
+    pop ecx					;@3
+
+    push edx					;pop@A
+    ; wait for data to become valid
+    call TPM_WaitDataValidTPM32
+    ; error code in dl, 0 for success
+    cmp dl, #0
+    je matransmit32_goon_1
+
+    ; data not valid
+
+    pop edx					;@A
+
+    mov dl, #TCG_BLOCK_READ_TIMEOUT
+
+    jmp matransmit32_exit_0			; EXIT
+
+matransmit32_goon_1:
+    pop edx					;@A
+    push edx					;pop@B
+    ; wait for response to become ready
+    call TPM_WaitResponseReadyTPM32
+    cmp dl, #0
+    je matransmit32_goon_2
+
+    pop edx					;@B
+    ; data not ready
+
+    mov dl, #TCG_BLOCK_READ_TIMEOUT
+
+    jmp matransmit32_exit_0			; EXIT
+
+matransmit32_goon_2:
+    pop edx					;@B
+    push edx					;pop@C
+    ; now read the response
+
+    call TPM_ReadResponseTPM32
+
+    pop edx					;@C
+
+    call TPM_ReadyTPM32
+    mov dl, #TPM_OK
+
+    jmp matransmit32_exit_1			; EXIT
+
+matransmit32_exit_0:
+    call TPM_ReadyTPM32
+
+matransmit32_exit_1:
+    pop eax					;@1
+
+    ; result in 'dl'
+    ret
+
+    END_PM_CODE
+
+
+
+    ; MATransmitMultiple32 with access to 32bit addresses.
+    ; Input:
+    ;  edx: address of structure with TPM command blocks to send
+    ;       (4 byte pointer to data, 2 byte describing size)
+    ;  ecx: length of output buffer for response
+    ;  ebx: result buffer pointer
+    ;   bp: pointing to stack layout as described in 14.2.5
+    ;       4[bp] must contain pointer to BIOS header!
+    ; Ouput:
+    ;  dl: Error code
+_MATransmitMultiple32:
+
+    START_PM_CODE
+
+    push eax					;pop@1
+
+    ; address of buffer to send from edx into eax
+    mov eax, edx
+
+    ; address of TPM into edx
+    mov edx, dword 0x04[bp]			; pointer to BIOS Header
+    mov dword edx, dword 0x8[edx]		; base address of TPM
+
+    push eax					;pop@2
+
+    ; activate the TPM
+    call TPM_ActivateTPM32
+    cmp al, #1
+    je matransmitmultiple32_goon_0
+
+    ; TPM not active
+    pop eax					;@2
+
+    mov dl, #TCG_FATAL_COM_ERROR
+
+    jmp matransmitmultiple32_exit_0		; EXIT
+
+matransmitmultiple32_goon_0:
+    pop eax					;@2
+
+    push ecx					;pop@A1
+    xor ecx, ecx
+matransmitmultiple32_loop_0:
+    push eax					;pop@A2
+    push ecx					;pop@A3
+    push ebx					;pop@A4
+    ; send command
+    ; eax : data
+    ; edx : addr of TPM
+    ; ecx : length of data to send
+
+    ; actual buffer with data into eax
+    mov ebx, [eax + ecx]
+    and ebx, ebx
+    je matransmitmultiple32_goon_3
+
+    ; length of data to send into ecx
+    mov cx, 4[eax + ecx]
+    and ecx, #0xffff
+
+    mov eax, ebx
+    call TPM_SendDataTPM32
+
+    pop ebx					;@A4
+    pop ecx					;@A3
+    pop eax					;@A2
+
+    ; next chunk
+    add ecx, #6
+
+    jmp matransmitmultiple32_loop_0		; LOOP
+
+matransmitmultiple32_goon_3:
+    pop ebx					;@A4
+    pop ecx					;@A3
+    pop eax					;@A2
+    pop ecx					;@A1
+
+    push edx					;pop@A
+    ; wait for data to become valid
+    call TPM_WaitDataValidTPM32
+    ; error code in dl, 0 for success
+    cmp dl, #0
+    je matransmitmultiple32_goon_1
+
+    ; data not valid
+
+    pop edx					;@A
+
+    mov dl, #TCG_BLOCK_READ_TIMEOUT
+
+    jmp matransmitmultiple32_exit_0
+
+matransmitmultiple32_goon_1:
+    pop edx					;@A
+    push edx					;pop@B
+    ; wait for response to become ready
+    call TPM_WaitResponseReadyTPM32
+    cmp dl, #0
+    je matransmitmultiple32_goon_2
+
+    pop edx					;@B
+    ; data not ready
+
+    mov dl, #TCG_BLOCK_READ_TIMEOUT
+
+    jmp matransmitmultiple32_exit_0
+
+matransmitmultiple32_goon_2:
+    pop edx					;@B
+    push edx					;pop@C
+    ; now read the response
+
+    call TPM_ReadResponseTPM32
+
+    pop edx					;@C
+
+    call TPM_ReadyTPM32
+    mov dl, #TPM_OK
+
+    jmp matransmitmultiple32_exit_1
+
+matransmitmultiple32_exit_0:
+    call TPM_ReadyTPM32
+
+matransmitmultiple32_exit_1:
+    pop eax					;@1
+
+    ; result in 'dl'
+    ret
+
+    END_PM_CODE
+
+
+
+
+CMD_TPM_Startup_0x01_IPB:
+    .word 0x8+0xc, 0x00, 4+10, 0x00
+CMD_TPM_Startup_0x01:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x01
+
+CMD_TSC_PhysicalPresence_0x20_IPB:
+    .word 0x8+0xc, 0x00, 4+10, 0x00
+CMD_TSC_PhysicalPresence_0x20:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x20
+
+CMD_TSC_PhysicalPresence_0x08_IPB:
+    .word 0x8+0xc, 0x00, 4+10, 0x00
+CMD_TSC_PhysicalPresence_0x80:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x08
+
+CMD_TSC_PhysicalPresence_0x100_IPB:
+    .word 0x8+0xc, 0x00, 4+10, 0x00
+CMD_TSC_PhysicalPresence_0x100:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x01, 0x00
+
+CMD_TSC_PhysicalPresence_0x10_IPB:
+    .word 0x8+0xc, 0x00, 4+10, 0x00
+CMD_TSC_PhysicalPresence_0x10:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x10
+
+CMD_TPM_PhysicalEnable_IPB:
+    .word 0x8+0xa, 0x00, 4+10, 0x00
+CMD_TPM_PhysicalEnable:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x6f
+
+CMD_TPM_PhysicalSetDeactivated_0x00_IPB:
+    .word 0x8+0xb, 0x00, 4+10, 0x00
+CMD_TPM_PhysicalSetDeactivated_0x00:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x72, 0x00
+
+CMD_TPM_SHA1Start_IPB:
+    .word 0x8+0xa, 0x00, 4+10, 0x00
+CMD_TPM_SHA1Start:
+    .byte 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa0
+
+
+/* command list table referencing above input blocks */
+__TCG_CommandList:
+    .word CMD_TPM_Startup_0x01_IPB
+    .word CMD_TSC_PhysicalPresence_0x20_IPB
+    .word CMD_TSC_PhysicalPresence_0x08_IPB
+    .word CMD_TSC_PhysicalPresence_0x100_IPB
+    .word CMD_TSC_PhysicalPresence_0x10_IPB
+    .word CMD_TPM_PhysicalEnable_IPB
+    .word CMD_TPM_PhysicalSetDeactivated_0x00_IPB
+    .word CMD_TPM_SHA1Start_IPB
+
+
+_TCG_SendCommand:
+    ; parameters
+    ; edx: Constant defining which command to send from the list
+    ; ds:si : pointer to memory for output block
+    ; ecx : size of output block (0 for no output block provided)
+    ;       The output block MUST be of the size required for the
+    ;       function that is called; MAX is currently 30
+    ;       A minimum of 14 bytes must be provided, if any is
+    ;       provided; 0 may be passed otherwise so that the function
+    ;       allocates memory on the stack
+    ; Return
+    ;  eax: return error code
+    ;        A TPM error will be indictad by
+    ;         (tpm_error_code << 16 | 0x4)
+    ;
+    ; ds:si : updated output block if one was provided
+    push si					;pop@1
+    push cx					;pop@3
+    push edx					;pop@4
+    push bx					;pop@5
+    push es					;pop@6
+
+    ; move the index to eax
+    mov eax, edx
+
+    ; get the address of the actual command
+    ; data are located in the code segment!
+    mov di, #__TCG_CommandList
+    shl ax, #1
+    mov bx, ax
+    seg cs
+    mov di, [di+bx]
+
+    mov ax, cs
+    mov es, ax
+
+    ; did user provide buffer?
+    and ecx, ecx
+    je _tcg_sendcommand_allocbuffer
+
+    ; check whether we have at least 4+10 bytes for output
+    ; 4 bytes are for the plain output header, 10 bytes
+    ; so we can receive the TPM error code
+    cmp ecx, #14
+    jge _tcg_sendcommand_goon_1
+
+    ; not enough space for output buffer
+    mov eax, #((TCG_INVALID_COM_REQUEST << 16 ) | TCG_PC_TPMERROR)
+    jmp _tcg_sendcommand_goon_2			; EXIT
+
+_tcg_sendcommand_allocbuffer:
+    push ds					;@7
+
+    ; determine length of output needed command
+    seg es
+    mov dx, 0x4[di]
+
+    ; create an Output block on the stack and
+
+    add dx, #0x4				; plain Header of Output block
+    sub sp, dx					;adjust@8
+
+    mov ax, ss
+    mov ds, ax
+    mov si, sp
+
+_tcg_sendcommand_goon_1:
+    ; ds:si pointer to output block
+    ; es:di pointer to input block
+    call TCG_PassThroughToTPM
+
+    ; direct error from the PassThrough?
+    and eax, eax
+    jne _tcg_sendcommand_goon_3
+
+    ; and error indicated by the tpm ?
+    seg ds
+    mov eax, #(4+6)[si]
+    cmp eax, #0
+    je _tcg_sendcommand_goon_3
+
+    ; TPM indicated error code; make it visible to the caller
+    rol eax, #16
+    mov ax, #4
+
+_tcg_sendcommand_goon_3:
+    ; did user provide output buffer? if yes, I did not allocate one
+    and ecx, ecx
+    jne _tcg_sendcommand_goon_2
+
+    add sp, dx					;@8
+    pop ds					;@7
+
+_tcg_sendcommand_goon_2:
+    pop es					;@6
+    pop bx					;@5
+    pop edx					;@4
+    pop cx					;@3
+    pop si					;@1
+    ret
+
+
+
+
+_TCG_TransmitBuffer:
+    ; Input
+    ;  es:di : pointer to buffer to send to TPM; must be a TPM formatted
+    ;          command
+    ;  ds:si : pointer to memory for output block
+    ;  ecx : size of output block (0 for no output block provided)
+    ; Output
+    ;  eax: return error code
+    ;  ds:si : updated output block if one was provided
+    push cx					;pop@1
+    push edx					;pop@2
+    push bx					;pop@3
+    push bp					;pop@4
+
+    ; determine length of input block needed for command
+    seg es
+    mov dl, 0x5[di]
+    seg es
+    mov dh, 0x4[di]
+    add dx, #8
+
+    ; create an Output block on the stack and
+    sub sp, dx					;adjust@5
+    mov bp, sp
+    push dx					;pop@6
+
+    mov 0x0[bp], dx				; IPBlength
+    xor bx,bx
+    mov 0x2[bp], bx				; Reserved
+    mov 0x4[bp], cx				; Output block length
+    mov 0x6[bp], bx				; Reserved
+
+    ; copy command buffer into 0x8[es:bp]
+    sub dx, #8
+    mov bx, dx					; bx is counter
+
+    push es					;pop@7
+    push di					;pop@8
+    push si					;pop@9
+    push ds					;pop@10
+
+    mov si, bp
+    mov ax, ss
+    mov ds, ax
+
+    ; copy ommand into PassThroughInput block
+_tcg_transmitbuffer_loop_1:
+    and bx, bx
+    je _tcg_transmitbuffer_goon_1
+    dec bx
+
+    seg es
+    mov al, [di+bx]
+    mov 0x8[si+bx], al
+
+    jmp _tcg_transmitbuffer_loop_1
+
+_tcg_transmitbuffer_goon_1:
+    pop ds					;@10
+    pop si					;@9
+    ; es:di pointer to block to send to TPM
+    ; ds:si pointer to output block for result
+    mov ax, ss
+    mov es, ax
+    mov di, bp
+
+    call TCG_PassThroughToTPM
+
+    pop di					;@8
+    pop es					;@7
+    pop dx					;@6
+    add sp, dx					;@5
+    pop bp					;@4
+    pop bx					;@3
+    pop edx					;@2
+    pop cx					;@1
+    ret
+
+
+_tpm_initialize_tpm:
+    ; Initialize the TPM by sending the initial command
+    ; sequence of depending on physical presence
+    ;  TPM_Startup(0x1)
+    ;  if pp:
+    ;   TSC_PhysicalPresence(0x20)
+    ;   TSC_PhysicalPresence(0x08)
+    ;   TPM_PhysicalEnable()
+    ;   TPM_PhysicalSetDeactivated(FALSE)
+    ;  else
+    ;   TSC_PhysicalPresence(0x100)
+    ;   TSC_PhysicalPresence(0x10)
+    ; to it.
+    ;
+    ; Inputs
+    ;  al : 0 for no physical presence, 1 for physical presence
+    ; Ouputs:
+    ;  eax : errorcode, '0' for no encountered error
+
+    push ebx					;pop@1
+    push ecx					;pop@2
+    push edx					;pop@3
+
+    mov bl, al					;physical presence status
+    ; no buffer is provided for result
+    xor ecx, ecx
+
+    mov edx, #IDX_CMD_TPM_Startup_0x01
+    call _TCG_SendCommand
+    ; if this one fails, it is ok.
+    ; and eax, eax
+    ; jne _tpm_initializetpm_exit_1
+
+    cmp bl, #0					;physical presence?
+    je _tpm_initialize_tpm_no_pp
+
+    mov edx, #IDX_CMD_TSC_PhysicalPresence_0x20
+    call _TCG_SendCommand
+    and eax, eax
+    jne _tpm_initializetpm_exit_1
+
+    mov edx, #IDX_CMD_TSC_PhysicalPresence_0x08
+    call _TCG_SendCommand
+    and eax, eax
+    jne _tpm_initializetpm_exit_1
+
+    mov edx, #IDX_CMD_TPM_PhysicalEnable
+    call _TCG_SendCommand
+    and eax, eax
+    jne _tpm_initializetpm_exit_1
+
+    mov edx, #IDX_CMD_TPM_PhysicalSetDeactivated_0x00
+    call _TCG_SendCommand
+    jmp _tpm_initializetpm_exit_1
+
+_tpm_initialize_tpm_no_pp:
+    mov edx, #IDX_CMD_TSC_PhysicalPresence_0x100
+    call _TCG_SendCommand
+    and eax, eax
+    jne _tpm_initializetpm_exit_1
+
+    mov edx, #IDX_CMD_TSC_PhysicalPresence_0x10
+    call _TCG_SendCommand
+    and eax, eax
+    jne _tpm_initializetpm_exit_1
+
+_tpm_initializetpm_exit_1:
+    pop edx					;@3
+    pop ecx					;@2
+    pop ebx					;@1
+    ret
+
+
+
+_tcpa_initialize_tpm:
+    push eax					;pop@1
+    push bx					;pop@2
+
+#if BX_TCGBIOS_PHYSICAL_PRESENCE
+    xor bx, bx
+
+    call switch_to_protmode
+    START_PM_CODE
+
+    ; wait for 1000 ms to give user a chance to press a key
+    mov eax, #1000
+    call wait_pit_ms_32
+
+    call switch_to_realmode
+    END_PM_CODE
+
+    ; determine whether a key has been pressed
+    mov ah, #1
+    int #0x16
+    je _tcpa_initialize_tpm_no_key
+
+    ; currently any key press is sufficient to assert physical presence
+    call _print_physicalpresence
+    mov bx, #1			; physical presence
+_tcpa_initialize_tpm_loop_1:
+    mov ah, #0			; drain key presses
+    int #0x16
+
+    mov ah, #1			; more keystrokes?
+    int #0x16
+    jne _tcpa_initialize_tpm_loop_1	; drain more
+
+_tcpa_initialize_tpm_no_key:
+    mov ax, bx
+#else
+    mov ax, #1
+#endif
+    call _tpm_initialize_tpm
+    pop bx					;@2
+    pop eax					;@1
+    ret
+
+  ASM_END
+
+#if BX_TCGBIOS_PHYSICAL_PRESENCE
+ void print_physicalpresence()
+ {
+   printf("Physical presence asserted\n");
+ }
+#endif
+
+  // GLUE CODE section for transition between C code and
+  // TCG BIOS calling convention
+
+  ASM_START
+_tcg_callfunc_es_di_ds_si_ebx_ecx_edx:
+    ;
+    ; Call a function with parameters in registers
+    ; es,di,ds,si,ebx,ecx,edx
+    ; Input:
+    ;  The address of the function to be call is expected in 'ax'
+    ;  bp : expected to be set when this function is called
+    ;
+    push es
+    push di
+    push ds
+    push si
+    push ebx
+    push ecx
+    push edx
+
+    push ax
+
+    mov  ax, 4[bp]
+    mov  es, ax
+    mov  ax, 6[bp]
+    mov  di, ax
+    mov  ax, 8[bp]
+    mov  ds, ax
+    mov  ax, 10[bp]
+    mov  si, ax
+    mov  ebx, dword ptr 12[bp]
+    mov  ecx, dword ptr 16[bp]
+    mov  edx, dword ptr 20[bp]
+
+    pop ax
+    seg cs
+    call ax
+
+    pop edx
+    pop ecx
+    pop ebx
+    pop si
+    pop ds
+    pop di
+    pop es
+
+    // 32 bit return code is expected in ax/dx by the 'C' interface
+    ror eax, #16
+    mov dx, ax
+    ror eax, #16
+    ret
+  ASM_END
+
+
+  // 12.5 TCG_StatusCheck -- Glue code
+    Bit32u
+  _TCG_StatusCheck()
+  {
+  ASM_START
+    call TCG_StatusCheck
+
+    // 32 bit return code is expected in ax/dx by the 'C' interface
+    ror eax, #16
+    mov dx, ax
+    rol eax, #16
+  ASM_END
+  }
+
+
+  // 12.6 TCG_HashLogExtendEvent -  Glue function
+    Bit32u
+  _TCG_HashLogExtendEvent(es, di, ds, si, ebx, ecx, edx)
+    Bit16u es;
+    Bit16u di;
+    Bit16u ds;
+    Bit16u si;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    mov ax, #TCG_HashLogExtendEvent
+    call _tcg_callfunc_es_di_ds_si_ebx_ecx_edx
+
+    pop bp					;@1
+  ASM_END
+  }
+
+
+  // 12.7 TCG_PassThroughToTPM -  Glue function
+   Bit32u
+  _TCG_PassThroughToTPM(es, di, ds, si, ebx, ecx, edx)
+    Bit16u es;
+    Bit16u di;
+    Bit16u ds;
+    Bit16u si;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+  {
+  ASM_START
+    push bp
+    mov  bp, sp
+
+    mov ax, #TCG_PassThroughToTPM
+    call _tcg_callfunc_es_di_ds_si_ebx_ecx_edx
+
+    pop bp
+  ASM_END
+  }
+
+  // 12.8 TCG_ShutdownPreBootInterface -  Glue function
+    Bit32u
+  _TCG_ShutdownPreBootInterface(ebx)
+    Bit32u ebx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    push ebx					;pop@2
+
+    mov  ebx, dword ptr 4[bp]
+    call TCG_ShutdownPreBootInterface
+
+    pop ebx					;@2
+    pop bp					;@1
+
+    // 32 bit return code is expected in ax/dx by the 'C' interface
+    ror eax, #16
+    mov dx, ax
+    ror eax, #16
+  ASM_END
+  }
+
+
+  // 12.9 TCG_HashLogEvent -  Glue function
+    Bit32u
+  _TCG_HashLogEvent(es, di, ds, si, ebx, ecx, edx)
+    Bit16u es;
+    Bit16u di;
+    Bit16u ds;
+    Bit16u si;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    mov ax, #TCG_HashLogEvent
+    call _tcg_callfunc_es_di_ds_si_ebx_ecx_edx
+
+    pop bp					;@1
+  ASM_END
+  }
+
+
+  // 12.10 TCG_HashAll - Glue Function
+    Bit32u
+  _TCG_HashAll(es, di, ds, si, ebx, ecx, edx)
+    Bit16u es;
+    Bit16u di;
+    Bit16u ds;
+    Bit16u si;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    mov ax, #TCG_HashAll
+    call _tcg_callfunc_es_di_ds_si_ebx_ecx_edx
+
+    pop bp					;@1
+  ASM_END
+  }
+
+
+  // 12.11 TCG_TSS - Glue function
+  Bit32u
+   _TCG_TSS(es, di, ds, si, ebx, ecx, edx)
+    Bit16u es;
+    Bit16u di;
+    Bit16u ds;
+    Bit16u si;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    mov ax, #TCG_TSS
+    call _tcg_callfunc_es_di_ds_si_ebx_ecx_edx
+
+    pop bp					;@1
+  ASM_END
+  }
+
+
+  // 12.12 TCG_CompactHashLogExtendEvent - Glue function
+  Bit32u
+   _TCG_CompactHashLogExtendEvent(es, di, esi, ebx, ecx, edx, edx_ptr)
+    Bit16u es;
+    Bit16u di;
+    Bit32u esi;
+    Bit32u ebx;
+    Bit32u ecx;
+    Bit32u edx;
+    Bit16u edx_ptr;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov bp, sp
+
+    push es					;pop@2
+    push di					;pop@3
+    push esi					;pop@4
+    push ebx					;pop@5
+    push ecx					;pop@6
+    push edx					;pop@7
+
+    mov  ax, 4[bp]
+    mov  es, ax
+    mov  ax, 6[bp]
+    mov  di, ax
+    mov  esi, dword ptr 8[bp]
+    mov  ebx, dword ptr 12[bp]
+    mov  ecx, dword ptr 16[bp]
+    mov  edx, dword ptr 20[bp]
+    call TCG_CompactHashLogExtendEvent
+
+    push bp					;pop@8
+    mov bp, word ptr 24[bp]			; edx_ptr
+    mov [bp], edx
+    pop bp					;@8
+
+    pop edx					;@7
+    pop ecx					;@6
+    pop ebx					;@5
+    pop esi					;@4
+    pop di					;@3
+    pop es					;@2
+
+    pop bp					;@1
+
+    // 32 bit return code is expected in ax/dx by the 'C' interface
+    ror eax, #16
+    mov dx, ax
+    ror eax, #16
+  ASM_END
+  }
+
+
+  // 12.12 TCG_SendCommand - Glue function
+  Bit32u
+   __TCG_SendCommand(edx)
+    Bit32u edx;
+  {
+  ASM_START
+    push bp					;pop@1
+    mov  bp, sp
+
+    push edx					;pop@2
+
+    mov  edx, dword ptr 4[bp]
+    call _TCG_SendCommand
+
+    pop edx					;@2
+    pop bp					;@1
+
+    // 32 bit return code is expected in ax/dx by the 'C' interface
+    ror eax, #16
+    mov dx, ax
+    ror eax, #16
+  ASM_END
+  }
+
+
+/*
+ * Store registers in the EBDA; used to keep the registers'
+ * content in a well-defined place during protected mode execution
+ */
+  void
+store_segment_registers(ss, cs, ds, es, esp_hi)
+  Bit16u ss, cs, ds, es, esp_hi;
+{
+	Bit16u ebda_seg = read_word(0x0040, 0x000E);
+	write_word(ebda_seg, &EbdaData->tcpa.reg_ss, ss);
+	write_word(ebda_seg, &EbdaData->tcpa.reg_cs, cs);
+	write_word(ebda_seg, &EbdaData->tcpa.reg_ds, ds);
+	write_word(ebda_seg, &EbdaData->tcpa.reg_es, es);
+	write_word(ebda_seg, &EbdaData->tcpa.esp_hi, esp_hi);
+}
+
+
+
+/*
+ * get the segment register 'cs' value from the EBDA
+ */
+Bit16u
+get_register_cs()
+{
+	return read_word_from_ebda(&EbdaData->tcpa.reg_cs);
+}
+
+/*
+ * get the segment register 'ds' value from the EBDA
+ */
+Bit16u
+get_register_ds()
+{
+	return read_word_from_ebda(&EbdaData->tcpa.reg_ds);
+}
+
+/*
+ * get the segment register 'es' value from the EBDA
+ */
+Bit16u
+get_register_es()
+{
+	return read_word_from_ebda(&EbdaData->tcpa.reg_es);
+}
+
+/*
+ * get the upper 16 bits of the esp from the EBDA
+ */
+Bit16u
+get_register_esp_hi()
+{
+	return read_word_from_ebda(&EbdaData->tcpa.esp_hi);
+}
+
+/*
+ * Check whether the TCG interface has been shut down
+ */
+Bit16u
+TCG_IsShutdownPreBootInterface()
+{
+	Bit16u res = read_word_from_ebda(&EbdaData->tcpa.flags);
+	res &= STATUS_FLAG_SHUTDOWN;
+	return res;
+}
+
+/*
+ * Make the TCG interface as having been shut down
+ */
+void
+TCG_ShutdownPreBootInterface()
+{
+	Bit16u ebda_seg = read_word(0x0040, 0x000E);
+	Bit16u flags = read_word(ebda_seg, &EbdaData->tcpa.flags);
+	write_word(ebda_seg, flags | STATUS_FLAG_SHUTDOWN);
+}
+
+/*
+ * C-dispatcher for the TCG BIOS functions
+ */
+  void
+int1a_function32(regs, ES, DS, FLAGS)
+  pushad_regs_t regs;
+  Bit16u ES, DS, FLAGS;
+{
+	switch (regs.u.r8.ah) {
+	case 0xbb:
+		/*
+		 * all functions except for TCG_StatusCheck need to have the
+		 * TCG_MAGIC in 'ebx'.
+		 */
+		if (regs.u.r8.al != 0 &&
+		    regs.u.r32.ebx != TCG_MAGIC) {
+		    SET_CF();
+		    return;
+		}
+		switch(regs.u.r8.al) {
+		case 0x00:
+			regs.u.r32.eax = _TCG_StatusCheck();
+			if (regs.u.r32.eax == 0L) {
+				regs.u.r32.eax = 0L;
+				regs.u.r32.ebx = TCG_MAGIC;
+				regs.u.r8.ch = TCG_VERSION_MAJOR;
+				regs.u.r8.cl = TCG_VERSION_MINOR;
+				regs.u.r32.edx = 0x0L;
+				regs.u.r32.esi = tcpa_get_lasa_base_ptr();
+				regs.u.r32.edi = tcpa_get_lasa_last_ptr();
+				CLEAR_CF();
+			}
+			break;
+
+		case 0x01:
+			regs.u.r32.eax =
+				_TCG_HashLogExtendEvent(ES,
+				                        regs.u.r16.di,
+				                        DS,
+				                        regs.u.r16.si,
+				                        regs.u.r32.ebx,
+				                        regs.u.r32.ecx,
+				                        regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x02:
+			regs.u.r32.eax =
+				_TCG_PassThroughToTPM(ES,
+				                      regs.u.r16.di,
+				                      DS,
+				                      regs.u.r16.si,
+				                      regs.u.r32.ebx,
+				                      regs.u.r32.ecx,
+				                      regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x03:
+			regs.u.r32.eax =
+				_TCG_ShutdownPreBootInterface(regs.u.r32.ebx);
+			CLEAR_CF();
+			break;
+
+		case 0x04:
+			regs.u.r32.eax =
+				_TCG_HashLogEvent(ES,
+				                  regs.u.r16.di,
+				                  DS,
+				                  regs.u.r16.si,
+				                  regs.u.r32.ebx,
+				                  regs.u.r32.ecx,
+				                  regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x05:
+			regs.u.r32.eax =
+				_TCG_HashAll(ES,
+				             regs.u.r16.di,
+				             DS,
+				             regs.u.r16.si,
+				             regs.u.r32.ebx,
+				             regs.u.r32.ecx,
+				             regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x06:
+			regs.u.r32.eax =
+				_TCG_TSS(ES,
+				         regs.u.r16.di,
+				         DS,
+				         regs.u.r16.si,
+				         regs.u.r32.ebx,
+				         regs.u.r32.ecx,
+				         regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x07:
+			regs.u.r32.eax =
+				_TCG_CompactHashLogExtendEvent(ES,
+				                               regs.u.r16.di,
+				                               regs.u.r32.esi,
+				                               regs.u.r32.ebx,
+				                               regs.u.r32.ecx,
+				                               regs.u.r32.edx,
+				                               &regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		case 0x80:
+			regs.u.r32.eax =
+			 __TCG_SendCommand(regs.u.r32.edx);
+			CLEAR_CF();
+			break;
+
+		default:
+			SET_CF();
+		}
+
+	default:
+		SET_CF();
+		break;
+	}
+}
Index: root/xen-unstable.hg/tools/firmware/rombios/tcgbios.h
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/firmware/rombios/tcgbios.h
@@ -0,0 +1,177 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+/* supported TPM interfaces */
+#define TPM_TIS         0x2   /* tpm_tis.h */
+#define TPM_ATMEL       0x1   /* tpm_atmel.h */
+
+/* TCPA ACPI definitions */
+#define TCPA_ACPI_CLASS_CLIENT          0
+#define TCPA_ACPI_CLASS_SERVER          1
+
+/* 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_ST_CLEAR                      0x0
+#define TPM_ST_STATE                      0x1
+#define TPM_ST_DEACTIVATED                0x2
+
+/* event types: 10.4.1 / table 11 */
+#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
+
+
+// MA Driver defines
+#define CODE_MAInitTPM                    0x01
+#define CODE_MAHashAllExtendTPM           0x02
+#define CODE_MAPhysicalPresenceTPM        0x03
+/* vendor specific ones */
+#define CODE_MAIsTPMPresent               0x80
+#define CODE_MAHashAll                    0x81
+#define CODE_MATransmit                   0x82
+
+/*
+  indices for commands to be sent via proprietary
+   _TCG_SendCommand function
+ */
+#define IDX_CMD_TPM_Startup_0x01                0
+#define IDX_CMD_TSC_PhysicalPresence_0x20       1
+#define IDX_CMD_TSC_PhysicalPresence_0x08       2
+#define IDX_CMD_TSC_PhysicalPresence_0x100      3
+#define IDX_CMD_TSC_PhysicalPresence_0x10       4
+#define IDX_CMD_TPM_PhysicalEnable              5
+#define IDX_CMD_TPM_PhysicalSetDeactivated_0x00 6
+#define IDX_CMD_TPM_SHA1Start                   7
+
+
+/* hardware registers for TPM TIS */
+#define TPM_ACCESS                 0x0
+#define TPM_INT_ENABLE             0x8
+#define TPM_INT_VECTOR             0xc
+#define TPM_INT_STATUS             0x10
+#define TPM_INTF_CAPABILITY        0x14
+#define TPM_STS                    0x18
+#define TPM_DATA_FIFO              0x24
+#define TPM_DID_VID                0xf00
+#define TPM_RID                    0xf04
+
+/* address of locality 0 (TIS) */
+#define TPM_TIS_BASE_ADDRESS        0xfed40000
+#define ACPI_2_0_TCPA_SIGNATURE ASCII32('T','C','P','A') /* "TCPA" */
+
+#define ASCII32(a,b,c,d)     ((((Bit32u)a) <<  0) | (((Bit32u)b) <<  8) | \
+                              (((Bit32u)c) << 16) | (((Bit32u)d) << 24)  )
+
+/* extension for the EBDA */
+typedef struct {
+  Bit32u   tcpa_ptr;
+  Bit32u   lasa_last_ptr;
+  Bit16u   entry_count;
+} tcpa_acpi_t;
+
+typedef struct {
+  tcpa_acpi_t tcpa_acpi;
+  Bit16u flags;
+  Bit16u reg_ss;
+  Bit16u reg_cs;
+  Bit16u reg_ds;
+  Bit16u reg_es;
+  Bit16u esp_hi;
+} tcpa_t;
+
+#define STATUS_FLAG_SHUTDOWN                (1 << 0)
+
+
+/* some utility functions */
+Bit8u read_byte_addr32(addr);
+Bit32u read_dword_addr32(addr);
+void write_byte_addr32(addr, val);
+Bit16u strlen();
+
+/* tcpa ACPI related functions */
+Bit32u tcpa_get_lasa_base_ptr();
+Bit32u tcpa_get_lasa_last_ptr();
+Bit16u check_tcpa();
+Bit32u tcpa_extend_acpi_log(entry_ptr);
+void tcpa_acpi_init();
+Bit16u tcpa_add_measurement_to_log();
+void tcpa_add_measurement();
+void tcpa_calling_int19h();
+void tcpa_returned_int19h();
+void tcpa_add_event_separators();
+void tcpa_start_option_rom_scan();
+void tcpa_wake_event();
+void tcpa_option_rom();
+void tcpa_ipl();
+
+/* misc prototypes */
+void store_segment_registers(ss, cs, ds, es);
+Bit16u get_register_ss();
+Bit16u get_register_cs();
+Bit16u get_register_ds();
+Bit16u get_register_es();
+Bit32u _TCG_HashAll();
+
+
+#endif
Index: root/xen-unstable.hg/tools/firmware/rombios/tpm_atmel.c
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/firmware/rombios/tpm_atmel.c
@@ -0,0 +1,355 @@
+/*
+ * Implementation of a low-level Atmel TPM driver
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+  ASM_START
+
+   ; a macro for reading the address of the data register from the TPM
+MACRO GET_PORT_ADDR_DX
+    push eax		;pop@1
+    xor eax, eax
+    mov al, #9		; select register 9
+    outb 0x4e, al
+    inb al, 0x4f	; read hi(address)
+    rol ax, #8
+    mov al, #8		; select register 8
+    outb 0x4e, al
+    inb al, 0x4f	; read lo(address)
+    mov edx, eax	; edx contains (port) address now
+    pop eax		;@1
+MEND
+
+    ;#########################################################
+    ; Device-specific code
+    ; TPM ATMEL interface
+    ;#########################################################
+TPM_ActivateTPM32:
+    ; Activate the TPM via its interface
+    ; Input:
+    ; edx : base address of TPM (locality 0) [ignored here]
+    ; Output
+    ; ax : 0 = TPM not ready, 1 = TPM is ready
+
+    START_PM_CODE
+    push ebx				;pop@1
+    push ecx				;pop@2
+    push edx				;pop@3
+
+    GET_PORT_ADDR_DX
+
+    ; send an abort for any previously not-read response
+    mov al, #1
+    inc dx
+    outb dx, al				; an ABORT
+    dec dx
+
+    mov ecx, #20
+    mov bl, #0x8			;TPM Ready
+    call tpm_wait_state32
+
+    pop edx				;@3
+    pop ecx				;@2
+    pop ebx				;@1
+    ret
+
+    END_PM_CODE
+
+TPM_ReadyTPM32:
+    ; Activate the TPM via its interface
+    ; Input:
+    ; edx : base address of TPM (locality 0) [ignored here]
+    ; Output
+    ; ax : 0 = TPM not ready, 1 = TPM is ready
+
+    START_PM_CODE
+
+    call TPM_ActivateTPM32
+    ret
+
+    END_PM_CODE
+
+
+TPM_SendDataTPM32:
+    ; Send a command (partial or complete) to the TPM
+    ; Input
+    ;  edx : base address of TPM (locality 0) [ignored here]
+    ;  eax : pointer to data to send
+    ;  ecx : number of bytes to send
+    ; Output
+    ;  none so far (!!!)
+
+    START_PM_CODE
+
+    push ecx				;pop@1
+    push ebx				;pop@2
+    push edx				;pop@3
+    push eax				;pop@4
+
+    GET_PORT_ADDR_DX
+
+    xor ebx, ebx
+
+tpm_senddatatpm32_loop_1:
+
+    push eax				;pop@5
+    mov al, [eax + ebx]
+    outb dx, al				;write to output port
+    pop eax				;@5
+
+    inc ebx
+    cmp ecx, ebx
+    je tpm_senddatatpm32_done
+    jmp tpm_senddatatpm32_loop_1
+
+tpm_senddatatpm32_done:
+    pop eax				;@4
+    pop edx				;@3
+    pop ebx				;@2
+    pop ecx				;@1
+    ret
+
+    END_PM_CODE
+
+
+TPM_ReadResponseTPM32:
+    ; Input:
+    ;  edx: base address of TPM [ignored here]
+    ;  ebx: pointer to output buffer
+    ;  ecx: length of output buffer
+    ; Output
+    ;  none so far (!!!)
+
+    START_PM_CODE
+
+    push esi				;pop@1
+    push edx				;pop@2
+    push eax				;pop@3
+
+    GET_PORT_ADDR_DX
+
+    xor esi, esi
+
+tpm_readresponsetpm32_loop_1:
+    ;return buffer exhausted?
+    cmp ecx, esi
+    je tpm_readresponsetpm32_end_1
+
+    push eax				;pop@A
+    push ecx				;pop@B
+    push ebx				;pop@C
+
+    mov ecx, #1
+    mov bl, #0x2			;Data available mask
+    call tpm_wait_state32
+
+    cmp eax, #0
+    je tpm_readresponsetpm32_end_2		; timeout occurred
+
+    ; data is available
+
+    ; read data from TPM and write it into buffer
+
+    pop ebx				;@C
+
+    inb al, dx
+    mov [ebx + esi], al
+
+    ; now only get eax/ecx back!
+    pop ecx				;@B
+    pop eax				;@A
+
+    inc esi
+    jmp tpm_readresponsetpm32_loop_1
+
+tpm_readresponsetpm32_end_2:
+    pop ebx				;@C
+    pop ecx				;@B
+    pop eax				;@A
+
+tpm_readresponsetpm32_end_1:
+    pop eax				;@3
+    pop edx				;@2
+    pop esi				;@1
+    ret
+
+    END_PM_CODE
+
+TPM_WaitDataValidTPM32:
+    ; Input
+    ; edx : base address of TPM (locality 0) [ignored here]
+    ; Ouput:
+    ; dl : error code, 0 for success
+
+    START_PM_CODE
+
+    mov dx, #0
+    ret
+
+    END_PM_CODE
+
+TPM_WaitResponseReadyTPM32:
+    ; Input:
+    ; edx: base of TPM [ignored here]
+    ; Ouput
+    ; dl : error code, 0 for success
+
+    START_PM_CODE
+
+    push eax				;pop@A
+    push ecx				;pop@B
+    push ebx				;pop@C
+
+    GET_PORT_ADDR_DX
+
+    mov ecx, #2000			;2000ms
+    mov bl, #0x2			;Data available mask
+    call tpm_wait_state32
+
+    mov dl, #0
+
+    cmp al, #0
+    jne tpm_waitresponsereadytpm32_end_1	; timeout NOT occurred
+
+    mov dl, #(TCG_NO_RESPONSE)
+
+tpm_waitresponsereadytpm32_end_1:
+    ; data is available
+    pop ebx				;@C
+    pop ecx				;@B
+    pop eax				;@A
+
+    ret
+
+    END_PM_CODE
+
+TPM_Atmel_signature:
+    ;     index , expected value
+    .byte 0x4, 0x41
+    .byte 0x5, 0x54
+    .byte 0x6, 0x4d
+    .byte 0x7, 0x4c
+    .byte 0x0, 0x1
+    .byte 0x1, 0x1
+    .byte 0xff
+
+TPM_IsPresentTPM32:
+    ; Simple test whether the TPM device is
+    ; available on this platfrom.
+    ;
+    ; Input:
+    ; edx: base of TPM [ignored here]
+    ; Output:
+    ; dx : 0 TPM is NOT present, != 0 TPM is present
+
+    START_PM_CODE
+
+    call TPM_ActivateTPM32
+
+    push ecx				;pop@1
+    push ebx				;pop@2
+    push eax				;pop@3
+
+    xor dx, dx				; assuming no TPM here
+
+    mov ebx, #TPM_Atmel_signature + SEGMENT_OFFSET
+    xor ecx, ecx
+
+tpm_ispresenttpm32_loop_1:
+    mov al, [ebx + ecx]
+    outb 0x4e, al
+    inb al, 0x4f
+
+    inc ecx
+    cmp [ebx + ecx], al
+    jne tpm_ispresenttpm32_notfound
+
+    inc ecx
+    cmp byte #0[ebx + ecx], #0xff
+    jne tpm_ispresenttpm32_loop_1
+
+    mov dx, #1				; a TPM is here
+
+tpm_ispresenttpm32_notfound:
+
+    pop eax				;@3
+    pop ebx				;@2
+    pop ecx				;@1
+    ret
+
+    END_PM_CODE
+
+
+tpm_wait_state32:
+    ; Wait for the state of the TPM or until the timeout
+    ; has been reached
+    ; Parameters:
+    ; Input:
+    ;  edx : address of locality to be used [ignored here]
+    ;  ecx : timeout in ms
+    ;  bl  : mask for 1[eax] to wait for
+    ; Result:
+    ;  eax : 1 = state is reached, 0 = timeout occurred
+
+    START_PM_CODE
+
+    push ecx				;pop@1
+    push ebx				;pop@2
+    push edx				;pop@3
+
+tpm_wait_state32_loop_1:
+    ; timeout reached?
+    dec ecx
+    cmp ecx, #0xffffffff
+    jne tpm_wait_state32_goon_1
+
+    xor eax, eax			;timeout has  been reached
+    jmp tpm_wait_state32_exit_1
+
+tpm_wait_state32_goon_1:
+
+    ; read the state
+    inc dx
+    inb al, dx				; read state information
+    dec dx
+
+    and al, bl				; mask the expected state
+    cmp al, bl				; compare against expected state
+    jne tpm_wait_state32_goon_2
+
+    ; state has been reached
+    mov eax, #1
+    jmp tpm_wait_state32_exit_1
+
+tpm_wait_state32_goon_2:
+    ; need to wait a little longer
+    mov eax, #1
+    call wait_pit_ms_32
+
+    jmp tpm_wait_state32_loop_1
+
+tpm_wait_state32_exit_1:
+    pop edx				;@3
+    pop ebx				;@2
+    pop ecx				;@1
+    ret
+
+    END_PM_CODE
+
+    ASM_END
Index: root/xen-unstable.hg/tools/firmware/rombios/tpm_tis.c
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/firmware/rombios/tpm_tis.c
@@ -0,0 +1,347 @@
+/*
+ * Implementation of a low-level TPM TIS driver
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+  ASM_START
+
+    ;#########################################################
+    ; Device-specific code
+    ; TPM-TIS interface
+    ;#########################################################
+TPM_ActivateTPM32:
+    ; activate the TPM
+    ; Input:
+    ; edx : base address of TPM (locality 0)
+    ; Output:
+    ; eax : 0 = TPM not ready, 1 = TPM is ready
+
+    START_PM_CODE
+
+    push bx				;pop@1
+    push ecx				;pop@2
+
+    mov bl, #0x2			; request access to locality
+    mov TPM_ACCESS[edx], bl
+
+    mov bl, TPM_ACCESS[edx]		; got it?
+    and bl, #0x20
+    jne tpm_activatetpm32_goon_0
+
+    xor eax, eax
+    jmp tpm_activatetpm32_exit_0
+
+tpm_activatetpm32_goon_0:
+    mov bl, #%01000000			; make TPM ready
+    mov TPM_STS[edx],bl			; p. 53
+
+    mov ecx, #100			; wait 100ms for TPM to be ready
+    mov bl, #%01000000			; active signal
+
+    call tpm_wait_sts32
+    // return eax as returned from tpm_wait_sts32
+
+tpm_activatetpm32_exit_0:
+    pop ecx				;@2
+    pop bx				;@1
+    ret
+
+    END_PM_CODE
+
+
+
+TPM_ReadyTPM32:
+    ; put the TPM into ready state so it accepts commands
+    ; Input:
+    ; edx : base address of TPM (locality 0)
+    ; Output:
+    ; eax : 0 = TPM not ready, 1 = TPM is ready
+    START_PM_CODE
+
+    push bx				;pop@1
+    push ecx				;pop@2
+
+    mov bl, #%01000000			; make TPM ready
+    mov TPM_STS[edx],bl			; p. 53
+
+    mov ecx, #100			; wait 100ms for TPM to be ready
+    mov bl, #%01000000			; active signal
+
+    call tpm_wait_sts32
+    // return eax as returned from tpm_wait_sts32
+
+    pop ecx				;@2
+    pop bx				;@1
+    ret
+
+    END_PM_CODE
+
+
+
+TPM_SendDataTPM32:
+    ; Send a command to the TPM
+    ; Input
+    ;  edx : base address of TPM (locality 0)
+    ;  eax : pointer to data to send
+    ;  ecx : number of bytes to send
+    ; Output
+    ;  none so far (!!!)
+
+    START_PM_CODE
+
+    push bx					;pop@1
+    push esi					;pop@2
+    push ecx					;pop@3
+
+    xor esi, esi
+
+tpm_sendcommandtpm32_loop_1:
+    mov bl, TPM_STS+1[edx]			; read burst
+    mov bh, TPM_STS+2[edx]			;
+    and bx, bx
+    jne tpm_sendcommandtpm32_goon_2
+    push eax					;pop@A
+    mov eax, #1
+    call wait_pit_ms_32
+    pop eax					;@A
+    jmp tpm_sendcommandtpm32_loop_1
+
+tpm_sendcommandtpm32_goon_2:
+
+tpm_sendcommandtpm32_loop_2:
+    ; can send data
+    push cx					;pop@B
+    mov cl,[eax+esi]
+    mov TPM_DATA_FIFO[edx],cl			; p. 54
+    pop cx					;@B
+    inc esi
+
+    ; anything left to transmit?
+    cmp ecx, esi
+
+    je tpm_sendcommandtpm32_exit_1
+
+    ; yes. any burst room left?
+    dec bx
+    and bx, bx
+    jne tpm_sendcommandtpm32_loop_2
+
+    ; must get burst room again
+    jmp tpm_sendcommandtpm32_loop_1
+
+tpm_sendcommandtpm32_exit_1:
+    pop ecx					;@3
+    pop esi					;@2
+    pop bx					;@1
+    ret
+
+    END_PM_CODE
+
+TPM_ReadResponseTPM32:
+    ; Input:
+    ; edx: base address of TPM
+    ;  ebx: pointer to output buffer
+    ;  ecx: length of output buffer
+    ; Output
+    ;  none so far (!!!)
+
+    START_PM_CODE
+
+    push esi					;pop@1
+    push eax					;pop@2
+
+    xor esi, esi
+
+tpm_readresponsetpm32_loop_1:
+    ; return buffer exhausted?
+    cmp ecx, esi
+    je tpm_readresponsetpm32_end_1
+
+    mov al, TPM_DATA_FIFO[edx]			; read data
+    mov [ebx+esi], al				; write to output buffer
+
+    inc esi
+    ; still data available? - nothing left if flag is cleared
+    mov al, TPM_STS[edx]			; read flags
+    and al, #%00010000				; dataAvail?
+    je tpm_readresponsetpm32_end_1
+    jmp tpm_readresponsetpm32_loop_1
+
+tpm_readresponsetpm32_end_1:
+    pop eax					;@2
+    pop esi					;@1
+    ret
+
+    END_PM_CODE
+
+TPM_WaitDataValidTPM32:
+    ; Input
+    ; edx : base address of TPM (locality 0)
+    ; Ouput:
+    ; dl : error code, 0 for success
+
+    START_PM_CODE
+
+    push ebx					;pop@A
+    push ecx					;pop@B
+    push eax					;pop@C
+
+    mov bl, #%10000000				;dataValid mask
+    mov ecx, #1000				;max wait 1000ms
+    call tpm_wait_sts32				;wait for TPM state
+
+    mov dl, #0
+
+    ; state reached?
+    cmp al, #1
+    je tpm_waitdatavalidtpm32_goon_1
+
+    mov dl, #(TCG_NO_RESPONSE)
+
+tpm_waitdatavalidtpm32_goon_1:
+    pop eax					;@C
+    pop ecx					;@B
+    pop ebx					;@A
+
+    ret
+
+    END_PM_CODE
+
+TPM_WaitResponseReadyTPM32:
+    ; Input:
+    ; edx: base of TPM
+    ; Ouput
+    ; dl : error code, 0 for success
+
+    START_PM_CODE
+
+    push ebx					;pop@A
+    push ecx					;pop@B
+    push eax					;pop@C
+
+    ; all data transmitted and TPM is happy
+    ; start processing the command on the TPM
+    mov cl, #%00100000
+    mov TPM_STS[edx], cl			; p. 53 (tpmGo)
+
+    mov bl, #%00010000				;dataAvail mask
+    mov ecx, #2000				;max wait 2000ms
+    call tpm_wait_sts32				;wait for TPM state
+
+    mov dl, #0
+    ; state reached?
+    cmp al, #1
+    je tpm_waitresponsereadytpm32_goon_3
+
+    mov dl, #(TCG_NO_RESPONSE)
+
+tpm_waitresponsereadytpm32_goon_3:
+    ; data is indicated as being available
+    pop eax					;@C
+    pop ecx					;@B
+    pop ebx					;@A
+    ret
+
+    END_PM_CODE
+
+TPM_IsPresentTPM32:
+    ; Simple test whether the TPM device (TPM TIS) is
+    ; available on this platfrom.
+    ;
+    ; Input:
+    ; edx: base of TPM
+    ; Output:
+    ; dx : 0 TPM is NOT present, != 0 TPM is present
+
+    START_PM_CODE
+
+    push ecx				;pop@1
+
+    mov ecx, #TPM_DID_VID[edx]		; read TPM_DID_VID_0
+
+    ; Assuming that a TPM is present
+    mov dx, #1
+
+    cmp ecx, #0				; only '0' and '-1' are not recognized as TPMs
+    jne tpm_ispresenttpm32_exit_1
+    cmp ecx, #0xffffffff
+    jne tpm_ispresenttpm32_exit_1
+
+    ; no TPM present
+    xor dx, dx
+
+tpm_ispresenttpm32_exit_1:
+
+    pop ecx				;@1
+    ret
+
+    END_PM_CODE
+
+tpm_wait_sts32:
+    ; Wait for the state of the TPM or until the timeout
+    ; has been reached
+    ; Parameters:
+    ; Input:
+    ;  edx : address of locality to be used
+    ;  ecx : timeout in ms
+    ;  bl  : mask for TP_STS
+    ; Result:
+    ;  eax : 1 = state is reached, 0 = timeout occurred
+
+    START_PM_CODE
+
+    push ecx				;pop@1
+    push ebx				;pop@2
+
+tpm_wait_sts32_loop_1:
+    ; timeout reached?
+    dec ecx
+    cmp ecx, #0xffffffff
+    jne tpm_wait_sts32_goon_1
+
+    xor eax, eax			;timeout has  been reached
+    jmp tpm_wait_sts32_exit_1
+
+tpm_wait_sts32_goon_1:
+    ; read the state
+    mov bh, TPM_STS[edx]
+    and bh, bl
+    cmp bh, bl
+    jne tpm_wait_sts32_goon_2
+
+    ; state has been reached
+    mov eax, #1
+    jmp tpm_wait_sts32_exit_1
+
+tpm_wait_sts32_goon_2:
+    ; need to wait a little longer
+
+    mov eax, #1
+    call wait_pit_ms_32
+
+    jmp tpm_wait_sts32_loop_1
+
+tpm_wait_sts32_exit_1:
+    pop ebx				;@2
+    pop ecx				;@1
+    ret
+
+    END_PM_CODE
+
+    ASM_END

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-12-12 15:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-07 22:04 [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS Stefan Berger
2006-12-08  9:24 ` Keir Fraser
2006-12-08 13:30   ` Stefan Berger
2006-12-08 13:36     ` Keir Fraser
2006-12-11 15:26       ` Stefan Berger
2006-12-11 15:43         ` Keir Fraser
2006-12-12 15:25           ` Stefan Berger
2006-12-12 15:53             ` Keir Fraser

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.