* [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,
+ ®s.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* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
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
0 siblings, 1 reply; 8+ messages in thread
From: Keir Fraser @ 2006-12-08 9:24 UTC (permalink / raw)
To: Stefan Berger, Xen-devel
On 7/12/06 22:04, "Stefan Berger" <stefanb@us.ibm.com> wrote:
> 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_PCClientImplementatio
> nforBIOS_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.
Is there a good reason for it being implemented almost entirely in assembly
language?
-- Keir
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-08 9:24 ` Keir Fraser
@ 2006-12-08 13:30 ` Stefan Berger
2006-12-08 13:36 ` Keir Fraser
0 siblings, 1 reply; 8+ messages in thread
From: Stefan Berger @ 2006-12-08 13:30 UTC (permalink / raw)
To: Keir Fraser; +Cc: Xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 1093 bytes --]
xen-devel-bounces@lists.xensource.com wrote on 12/08/2006 04:24:31 AM:
> On 7/12/06 22:04, "Stefan Berger" <stefanb@us.ibm.com> wrote:
>
> > 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_PCClientImplementatio
> > nforBIOS_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.
>
> Is there a good reason for it being implemented almost entirely in
assembly
> language?
The compiled TCG extension code adds approximately 0x2500 bytes to the
BIOS and would add more to it if it was written in 'C'.
Stefan
>
> -- Keir
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
[-- Attachment #1.2: Type: text/html, Size: 1492 bytes --]
[-- Attachment #2: 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
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-08 13:30 ` Stefan Berger
@ 2006-12-08 13:36 ` Keir Fraser
2006-12-11 15:26 ` Stefan Berger
0 siblings, 1 reply; 8+ messages in thread
From: Keir Fraser @ 2006-12-08 13:36 UTC (permalink / raw)
To: Stefan Berger, Keir Fraser; +Cc: Xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 684 bytes --]
On 8/12/06 13:30, "Stefan Berger" <stefanb@us.ibm.com> wrote:
>> > Is there a good reason for it being implemented almost entirely in assembly
>> > language?
>
> The compiled TCG extension code adds approximately 0x2500 bytes to the BIOS
> and would add more to it if it was written in 'C'.
Presumably only those who want TPM functionality will run with the
TPM-enabled BIOS, and they are unlikely to care whether the implementation
is e.g., 10kB or 15kB. Even people not using the TPM capabilities are not
really going to care about a few kilobytes. It¹s not like you¹re constrained
to 64kB (0xF0000-0xFFFFF) you can stick the 32-bit code below 4GB.
-- Keir
[-- Attachment #1.2: Type: text/html, Size: 1299 bytes --]
[-- Attachment #2: 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
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-08 13:36 ` Keir Fraser
@ 2006-12-11 15:26 ` Stefan Berger
2006-12-11 15:43 ` Keir Fraser
0 siblings, 1 reply; 8+ messages in thread
From: Stefan Berger @ 2006-12-11 15:26 UTC (permalink / raw)
Cc: Xen-devel, Keir Fraser
[-- Attachment #1.1: Type: text/plain, Size: 1885 bytes --]
Keir Fraser <keir@xensource.com> wrote on 12/08/2006 08:36:05 AM:
> On 8/12/06 13:30, "Stefan Berger" <stefanb@us.ibm.com> wrote:
> > Is there a good reason for it being implemented almost entirely in
assembly
> > language?
>
> The compiled TCG extension code adds approximately 0x2500 bytes to
> the BIOS and would add more to it if it was written in 'C'.
>
> Presumably only those who want TPM functionality will run with the
> TPM-enabled BIOS, and they are unlikely to care whether the
> implementation is e.g., 10kB or 15kB. Even people not using the TPM
> capabilities are not really going to care about a few kilobytes. It?
> s not like you?re constrained to 64kB (0xF0000-0xFFFFF) ? you can
> stick the 32-bit code below 4GB.
Someone who wants to add new functionality to the Bochs BIOS might care
about the amount of free space in that 64kb segment. Currently there's
enough room left even with the TPM extensions.
Even if we move these extensions to some 32bit area, the hook into the 1Ah
interrupt and all those other function calls surrounded by #if BX_TCGBIOS
in rombios.c are needed as well as later on some code that switches into
protected mode and jumps up into the 32 bit area. The BIOS code should at
some point be compiled with those TPM extensions independent of whether a
TPM is available in the VM or not. The extensions don't influence the BIOS
if a TPM is not available.
How would you connect the two code areas and the functions? Would
hvmloader write the 32 bit address somewhere into the Bochs BIOS and the
to reach the 32 bit area one uses a jump table to call all those functions
up there? I'd really rather leave the TPM extensions in the BIOS segment
for now. The bulk of the code is located in its own file anyway. I will
convert parts of the code to 'C', though.
Stefan
>
> -- Keir
[-- Attachment #1.2: Type: text/html, Size: 2283 bytes --]
[-- Attachment #2: 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
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-11 15:26 ` Stefan Berger
@ 2006-12-11 15:43 ` Keir Fraser
2006-12-12 15:25 ` Stefan Berger
0 siblings, 1 reply; 8+ messages in thread
From: Keir Fraser @ 2006-12-11 15:43 UTC (permalink / raw)
To: Stefan Berger, Keir Fraser; +Cc: Xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 2145 bytes --]
I would imagine this working by having generic real-mode/32-bit gateway
routines in rombios, and then getting the hell out to 32-bit protected mode
asap for new code. The advantages are that you get to code in C, compiled
with a modern optimising compiler (gcc), and that you avoid the silly 64kB
limitation. As you say, hvmloader would be responsible for poking the
routines into high memory, marking them as E820_RESERVED, and then doing
some jump-table poking in rombios (which might more generically, and
grandiosely, be termed linking¹ of the BIOS and its extensions :-).
TBH I¹m not happy to check in big gobs of assembly code, or even really bcc
C/asm code. We should do the leg work to be able to use gcc. An hvmloader
type of environment is what we should aim for -- another way of looking at
this is removing hvmloader¹s restriction of only running at bootstrap so
that it can also provide ongoing run-time services.
-- Keir
On 11/12/06 15:26, "Stefan Berger" <stefanb@us.ibm.com> wrote:
> Someone who wants to add new functionality to the Bochs BIOS might care about
> the amount of free space in that 64kb segment. Currently there's enough room
> left even with the TPM extensions.
> Even if we move these extensions to some 32bit area, the hook into the 1Ah
> interrupt and all those other function calls surrounded by #if BX_TCGBIOS in
> rombios.c are needed as well as later on some code that switches into
> protected mode and jumps up into the 32 bit area. The BIOS code should at some
> point be compiled with those TPM extensions independent of whether a TPM is
> available in the VM or not. The extensions don't influence the BIOS if a TPM
> is not available.
>
> How would you connect the two code areas and the functions? Would hvmloader
> write the 32 bit address somewhere into the Bochs BIOS and the to reach the 32
> bit area one uses a jump table to call all those functions up there? I'd
> really rather leave the TPM extensions in the BIOS segment for now. The bulk
> of the code is located in its own file anyway. I will convert parts of the
> code to 'C', though.
[-- Attachment #1.2: Type: text/html, Size: 2828 bytes --]
[-- Attachment #2: 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
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-11 15:43 ` Keir Fraser
@ 2006-12-12 15:25 ` Stefan Berger
2006-12-12 15:53 ` Keir Fraser
0 siblings, 1 reply; 8+ messages in thread
From: Stefan Berger @ 2006-12-12 15:25 UTC (permalink / raw)
Cc: Xen-devel, Keir Fraser
[-- Attachment #1.1: Type: text/plain, Size: 2900 bytes --]
Keir Fraser <keir@xensource.com> wrote on 12/11/2006 10:43:27 AM:
>
> I would imagine this working by having generic real-mode/32-bit
> gateway routines in rombios, and then getting the hell out to 32-bit
> protected mode asap for new code. The advantages are that you get to
> code in C, compiled with a modern optimising compiler (gcc), and
> that you avoid the silly 64kB limitation. As you say, hvmloader
Since I am running out of space in the BIOS segment now while converting
the functions to 'C'...
Do you know of some good 'constructs' that can be left in the rombios as
markers for linking the two pieces? I'd like to start with lifting up a
single function into 32 bit space and then continuously put more up there,
but get the linking right. Probably funneling everything through a single
function and demultiplexing in 32 bit space is not what we would want.
I suppose HVMloader will have to carry a relocateable file (-fPIC) and be
able to re-locate it to whatever memory could be reserved.
Stefan
> would be responsible for poking the routines into high memory,
> marking them as E820_RESERVED, and then doing some jump-table poking
> in rombios (which might more generically, and grandiosely, be termed
> ?linking? of the BIOS and its extensions :-).
>
> TBH I?m not happy to check in big gobs of assembly code, or even
> really bcc C/asm code. We should do the leg work to be able to use
> gcc. An hvmloader type of environment is what we should aim for --
> another way of looking at this is removing hvmloader?s restriction
> of only running at bootstrap so that it can also provide ongoing
> run-time services.
>
> -- Keir
>
> On 11/12/06 15:26, "Stefan Berger" <stefanb@us.ibm.com> wrote:
> Someone who wants to add new functionality to the Bochs BIOS might
> care about the amount of free space in that 64kb segment. Currently
> there's enough room left even with the TPM extensions.
> Even if we move these extensions to some 32bit area, the hook into
> the 1Ah interrupt and all those other function calls surrounded by
> #if BX_TCGBIOS in rombios.c are needed as well as later on some code
> that switches into protected mode and jumps up into the 32 bit area.
> The BIOS code should at some point be compiled with those TPM
> extensions independent of whether a TPM is available in the VM or
> not. The extensions don't influence the BIOS if a TPM is not available.
>
> How would you connect the two code areas and the functions? Would
> hvmloader write the 32 bit address somewhere into the Bochs BIOS and
> the to reach the 32 bit area one uses a jump table to call all those
> functions up there? I'd really rather leave the TPM extensions in
> the BIOS segment for now. The bulk of the code is located in its own
> file anyway. I will convert parts of the code to 'C', though.
[-- Attachment #1.2: Type: text/html, Size: 3493 bytes --]
[-- Attachment #2: 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
* Re: [PATCH] [Firmware] TCG BIOS extensions for the Bochs BIOS
2006-12-12 15:25 ` Stefan Berger
@ 2006-12-12 15:53 ` Keir Fraser
0 siblings, 0 replies; 8+ messages in thread
From: Keir Fraser @ 2006-12-12 15:53 UTC (permalink / raw)
To: Stefan Berger; +Cc: Xen-devel
[-- Attachment #1.1: Type: text/plain, Size: 1196 bytes --]
On 12/12/06 3:25 pm, "Stefan Berger" <stefanb@us.ibm.com> wrote:
> Since I am running out of space in the BIOS segment now while converting the
> functions to 'C'...
> Do you know of some good 'constructs' that can be left in the rombios as
> markers for linking the two pieces? I'd like to start with lifting up a single
> function into 32 bit space and then continuously put more up there, but get
> the linking right. Probably funneling everything through a single function and
> demultiplexing in 32 bit space is not what we would want.
>
> I suppose HVMloader will have to carry a relocateable file (-fPIC) and be able
> to re-locate it to whatever memory could be reserved.
How about just have a table below 1MB, indexed by function id (where
function ids also are statically allocated too). This table will be produced
as part of the building and linking of the 32-bit extensions (it¹ll probably
be a C array of pointers, in its own data section which the linker will know
to place at the very start of the extension ROM): it can then be patched
into the rombios at compile time, or copied to a pre-decided address below
1MB by hvmloader at boot time.
-- Keir
[-- Attachment #1.2: Type: text/html, Size: 1866 bytes --]
[-- Attachment #2: 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.