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,8 @@ #define BX_USE_ATADRV 1 #define BX_ELTORITO_BOOT 1 +#define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */ + #define BX_MAX_ATA_INTERFACES 4 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2) @@ -1847,6 +1849,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"); test_gateway(); } @@ -7658,7 +7663,9 @@ ASM_END return 0x00000000; } } - +#if BX_TCGBIOS + tcpa_add_bootdevice((Bit32u)0, (Bit32u)bootdrv); +#endif // check signature if instructed by cmos reg 0x38, only for floppy // bootchk = 1 : signature check disabled // bootchk = 0 : signature check enabled @@ -7677,6 +7684,10 @@ ASM_END return 0x00000000; } } + +#if BX_TCGBIOS + tcpa_ipl((Bit32u)bootseg); /* specs: 8.2.3 steps 4 and 5 */ +#endif #if BX_ELTORITO_BOOT // Print out the boot string @@ -9408,6 +9419,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 @@ -9426,6 +9440,20 @@ rom_scan_loop: add al, #0x04 block_count_rounded: +#if BX_TCGBIOS + push ax + push ds + push ecx + xor ax, ax + mov ds, ax + and ecx, #0xffff + push ecx ;; segment where option rom is located at + call _tcpa_option_rom /* specs: 3.2.3.3 */ + add sp, #4 ;; pop segment + pop ecx ;; original ecx + pop ds + pop ax +#endif xor bx, bx ;; Restore DS back to 0000: mov ds, bx push ax ;; Save AX @@ -9691,6 +9719,16 @@ post_default_ints: in al, 0x71 mov 0x0410, ax +#if BX_TCGBIOS + call _tcpa_acpi_init + + push dword #0 + call _tcpa_initialize_tpm + add sp, #4 + + call _tcpa_do_measure_POSTs + call _tcpa_wake_event /* specs: 3.2.3.7 */ +#endif ;; Parallel setup SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler) @@ -9811,9 +9849,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: @@ -10296,6 +10341,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,263 @@ +/* + * Implementation of stub functions for calls to the TCG BIOS + * extension in 32bit memory area. + * + * 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 + */ + +/******************************************************************* + Support for TCPA ACPI logging + ******************************************************************/ + +/* + * 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; +{ + ASM_START + DoUpcall IDX_TCPA_EXTEND_ACPI_LOG + ASM_END +} + + +/* + initialize the TCPA ACPI subsystem; find the ACPI tables and determine + where the TCPA table is. + */ + void +tcpa_acpi_init() +{ + ASM_START + DoUpcall IDX_TCPA_ACPI_INIT + ASM_END +} + + +/* + * Add measurement to log about call of int 19h + */ + void +tcpa_calling_int19h() +{ + ASM_START + DoUpcall IDX_TCPA_CALLING_INT19H + ASM_END +} + +/* + * Add measurement to log about retuning from int 19h + */ + void +tcpa_returned_int19h() +{ + ASM_START + DoUpcall IDX_TCPA_RETURNED_INT19H + ASM_END +} + +/* + * Add event separators for PCRs 0 to 7; specs 8.2.3 + */ + void +tcpa_add_event_separators() +{ + ASM_START + DoUpcall IDX_TCPA_ADD_EVENT_SEPARATORS + ASM_END +} + + +/* + * Add a wake event to the log + */ + void +tcpa_wake_event() +{ + ASM_START + DoUpcall IDX_TCPA_WAKE_EVENT + ASM_END +} + + +/* + * Add measurement to the log about option rom scan + * 10.4.3 : action 14 + */ + void +tcpa_start_option_rom_scan() +{ + ASM_START + DoUpcall IDX_TCPA_START_OPTION_ROM_SCAN + ASM_END +} + + +/* + * Add measurement to the log about an option rom + */ + void +tcpa_option_rom(seg) + Bit32u seg; +{ + ASM_START + DoUpcall IDX_TCPA_OPTION_ROM + ASM_END +} + +/* + * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to + * the list of measurements. + */ +void + tcpa_add_bootdevice(bootcd, bootdrv) + Bit32u bootcd; + Bit32u bootdrv; +{ + ASM_START + DoUpcall IDX_TCPA_ADD_BOOTDEVICE + ASM_END +} + +/* + * 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) + Bit32u seg; +{ + ASM_START + DoUpcall IDX_TCPA_IPL + ASM_END +} + + +Bit32u +tcpa_initialize_tpm(physpres) + Bit32u physpres; +{ + ASM_START + DoUpcall IDX_TCPA_INITIALIZE_TPM + ASM_END +} + +void +tcpa_measure_post(from, to) + Bit32u from; + Bit32u to; +{ + ASM_START + DoUpcall IDX_TCPA_MEASURE_POST + ASM_END +} + +ASM_START +MACRO POST_MEASURE + push word #0x000f + push #?2 + push word #0x000f + push #?1 + call _tcpa_measure_post + add sp, #8 +MEND +ASM_END + +void +tcpa_do_measure_POSTs() +{ + ASM_START + + POST_MEASURE post, nmi + POST_MEASURE floppy_drive_post, hard_drive_post + POST_MEASURE hard_drive_post, ebda_post + POST_MEASURE ebda_post, eoi_jmp_post + POST_MEASURE eoi_jmp_post, timer_tick_post + POST_MEASURE timer_tick_post, int76_handler + + ret + ASM_END +} + +Bit32u +TCGInterruptHandler(regs_ptr, es, ds, flags_ptr) + Bit32u regs_ptr; + Bit16u es; + Bit16u ds; + Bit32u flags_ptr; +{ + ASM_START + DoUpcall IDX_TCGINTERRUPTHANDLER + ASM_END +} + +/* + * C-dispatcher for the TCG BIOS functions + */ +#define TCG_MAGIC 0x41504354L + void +int1a_function32(regs, ES, DS, FLAGS) + pushad_regs_t regs; + Bit16u ES, DS, FLAGS; +{ + Bit16u rc; + + 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: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + TCGInterruptHandler(((Bit32u)get_SS() << 4) + (Bit32u)®s, + ES, DS, + ((Bit32u)get_SS() << 4) + (Bit32u)&FLAGS); + break; + + default: + SET_CF(); + } + default: + SET_CF(); + break; + } +} 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 32bitgateway.c +BIOS-bochs-latest: rombios.c biossums 32bitgateway.c tcgbios.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/32bit/32bitbios.c =================================================================== --- root.orig/xen-unstable.hg/tools/firmware/rombios/32bit/32bitbios.c +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/32bitbios.c @@ -55,6 +55,22 @@ uint32_t jumptable[IDX_LAST+1] __attribu TABLE_ENTRY(IDX_ADD , add), TABLE_ENTRY(IDX_SET_STATIC , set_static), + TABLE_ENTRY(IDX_TCPA_ACPI_INIT, tcpa_acpi_init), + TABLE_ENTRY(IDX_TCPA_EXTEND_ACPI_LOG, tcpa_extend_acpi_log), + + TABLE_ENTRY(IDX_TCGINTERRUPTHANDLER, TCGInterruptHandler), + + TABLE_ENTRY(IDX_TCPA_CALLING_INT19H, tcpa_calling_int19h), + TABLE_ENTRY(IDX_TCPA_RETURNED_INT19H, tcpa_returned_int19h), + TABLE_ENTRY(IDX_TCPA_ADD_EVENT_SEPARATORS, tcpa_add_event_separators), + TABLE_ENTRY(IDX_TCPA_WAKE_EVENT, tcpa_wake_event), + TABLE_ENTRY(IDX_TCPA_ADD_BOOTDEVICE, tcpa_add_bootdevice), + TABLE_ENTRY(IDX_TCPA_START_OPTION_ROM_SCAN, tcpa_start_option_rom_scan), + TABLE_ENTRY(IDX_TCPA_OPTION_ROM, tcpa_option_rom), + TABLE_ENTRY(IDX_TCPA_IPL, tcpa_ipl), + TABLE_ENTRY(IDX_TCPA_MEASURE_POST, tcpa_measure_post), + + TABLE_ENTRY(IDX_TCPA_INITIALIZE_TPM, tcpa_initialize_tpm), TABLE_ENTRY(IDX_LAST , 0) /* keep last */ }; Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/Makefile =================================================================== --- root.orig/xen-unstable.hg/tools/firmware/rombios/32bit/Makefile +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/Makefile @@ -1,17 +1,30 @@ +SOURCES = util.c TARGET = 32bitbios_flat.h CFLAGS = -Wall -Werror -Wunused -Werror-implicit-function-declaration CFLAGS += -fomit-frame-pointer -fno-builtin CFLAGS += -I../ +SUBDIRS = tcgbios + MODULES = 32bitbios.o +MODULES += tcgbios/tcgbiosext.o +MODULES += util.o + +.PHONY: all subdirs -.PHONY: all +all : subdirs $(TARGET) -all : $(TARGET) +subdirs : + @for subdir in $(SUBDIRS); do \ + $(MAKE) -C $$subdir all; \ + done; \ clean :: rm -rf *.o $(TARGET) + @for subdir in $(SUBDIRS); do \ + $(MAKE) -C $$subdir $@; \ + done; \ $(TARGET) : 32bitbios_all.o $(SOURCES) unref=`nm -u 32bitbios_all.o` @@ -22,5 +35,5 @@ $(TARGET) : 32bitbios_all.o $(SOURCES) bash mkhex highbios_array 32bitbios_all.o > $(TARGET); \ fi -32bitbios_all.o : 32bitbios.o $(MODULES) +32bitbios_all.o : $(MODULES) ld -r $(MODULES) -o 32bitbios_all.o Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/Makefile =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/Makefile @@ -0,0 +1,18 @@ +TARGET=tcgbiosext.o +FILES=tcgbios tpm_drivers +OBJECTS=$(foreach f,$(FILES),$(f).o) + +CFLAGS = -Wall -Werror -Wunused -Werror-implicit-function-declaration +CFLAGS += -fomit-frame-pointer -fno-builtin -nostdlib +CFLAGS += -I../ -I../../ + +all : $(TARGET) + +clean:: + rm -rf *.o $(TARGET) + +%.o : %.c + gcc $(CFLAGS) -c $^ -o $@ + +$(TARGET): $(OBJECTS) + ld -r $^ -o $@ Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tcgbios.c =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tcgbios.c @@ -0,0 +1,1526 @@ +/* + * 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 + */ +#include "rombios_compat.h" +#include "tpm_drivers.h" + +#include "tcgbios.h" +#include "32bitprotos.h" +#include "util.h" + + +/* local structure and variables */ +struct ptti_cust { + uint16_t ipblength; + uint16_t reserved; + uint16_t opblength; + uint16_t reserved2; + uint8_t tpmoperandin[18]; +} __attribute__((packed)); + +struct ptti_cust CMD_TPM_Startup_0x01_IPB = { + 0x8+0xc, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x01 }, +}; + +struct ptti_cust CMD_TSC_PhysicalPresence_0x20_IPB = { + 0x8+0xc, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x20 }, +}; + +struct ptti_cust CMD_TSC_PhysicalPresence_0x08_IPB = { + 0x8+0xc, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x08 }, +}; + +struct ptti_cust CMD_TSC_PhysicalPresence_0x100_IPB = { + 0x8+0xc, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x01, 0x00 }, +}; + +struct ptti_cust CMD_TSC_PhysicalPresence_0x10_IPB = { + 0x8+0xc, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x0a, 0x00, 0x10 }, +}; + +struct ptti_cust CMD_TPM_PhysicalEnable_IPB = { + 0x8+0xa, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x6f }, +}; + +struct ptti_cust CMD_TPM_PhysicalSetDeactivated_0x00_IPB = { + 0x8+0xb, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x72, 0x00 } +}; +struct ptti_cust CMD_TPM_SHA1Start_IPB = { + 0x8+0xa, 0x00, 4+10, 0x00, + { 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa0 }, +}; + +struct ptti_cust CMD_TPM_GetCap_Version_IPB = { + 0x8+0x12, 0x00, 4+18, 0x00, + {0x00, 0xc1, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 }, +}; + +struct ptti_cust *TCG_CommandList[] = { + &CMD_TPM_Startup_0x01_IPB, + &CMD_TSC_PhysicalPresence_0x20_IPB, + &CMD_TSC_PhysicalPresence_0x08_IPB, + &CMD_TSC_PhysicalPresence_0x100_IPB, + &CMD_TSC_PhysicalPresence_0x10_IPB, + &CMD_TPM_PhysicalEnable_IPB, + &CMD_TPM_PhysicalSetDeactivated_0x00_IPB, + &CMD_TPM_SHA1Start_IPB, +}; + +/* local function prototypes */ +static void sha1(const unsigned char *data, uint32_t length, unsigned char *hash); +static uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx); +static uint32_t HashAll32(struct hai *hai, unsigned char *hash, + uint32_t magic, uint32_t ecx, uint32_t edx); +static uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, + struct hleeo *hleeo, + uint32_t magic, uint32_t ecx, uint32_t edx); +static uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, + uint32_t ebx, uint32_t ecx, uint32_t edx); +static uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto, + uint32_t magic, uint32_t ecx, uint32_t edx); +static uint32_t MA_Transmit(unsigned char *cmdbuffer, + unsigned char *respbuffer, + uint32_t respbufferlen); + +static unsigned char *tcpa_get_lasa_last_ptr(void); +static unsigned char *tcpa_get_lasa_base_ptr(void); +static void tcpa_reset_acpi_log(void); +static uint32_t tcpa_get_laml(void); + + +extern struct tpm_driver tpm_drivers[]; + +/* utility functions */ + +static inline uint32_t bswap(uint32_t a) +{ + return ( ( a >> 24 ) & 0x000000ff) | + ( ( a >> 8 ) & 0x0000ff00) | + ( ( a << 8 ) & 0x00ff0000) | + ( ( a << 24 ) & 0xff000000); +} + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + +typedef struct { + struct acpi_20_tcpa *tcpa_ptr; + unsigned char *lasa_last_ptr; + uint16_t entry_count; + uint16_t flags; +} tcpa_acpi_t; + +static tcpa_acpi_t tcpa_acpi; + + +/* low level driver implementation */ +static int tpm_driver_to_use = TPM_INVALID_DRIVER; + +static +uint32_t MA_IsTPMPresent() +{ + uint32_t rc = 0; + unsigned int i; + for (i = 0; i < TPM_NUM_DRIVERS; i++) { + struct tpm_driver *td = &tpm_drivers[i]; + if (td->probe(td->baseaddr) != 0) { + tpm_driver_to_use = i; + rc = 1; + break; + } + } + return rc; +} + +static +uint32_t MA_InitTPM(uint16_t startupcode) +{ + uint32_t rc = 0; + /* low-level initialize the TPM */ + unsigned char command[sizeof(CMD_TPM_Startup_0x01_IPB.tpmoperandin)]; + unsigned char response[10]; + uint32_t response_size = sizeof(response); + + memcpy(command, + CMD_TPM_Startup_0x01_IPB.tpmoperandin, + sizeof(CMD_TPM_Startup_0x01_IPB.tpmoperandin)); + command[10] = (startupcode >> 8) & 0xff; + command[11] = (startupcode >> 0) & 0xff; + rc = MA_Transmit(command, response, response_size); + + return rc; +} + +static +uint32_t MA_Transmit(unsigned char *cmdbuffer, + unsigned char *respbuffer, + uint32_t respbufferlen) +{ + uint32_t rc = 0; + uint32_t irc; + struct tpm_driver *td; + + if (tpm_driver_to_use == TPM_INVALID_DRIVER) + return TCG_FATAL_COM_ERROR; + + td = &tpm_drivers[tpm_driver_to_use]; + + if (rc == 0) { + irc = td->activate(td->baseaddr); + if (irc == 0) { + /* tpm could not be activated */ + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc == 0) { + uint32_t *tmp = (uint32_t *)&cmdbuffer[2]; + uint32_t len = bswap(*tmp); + irc = td->senddata(td->baseaddr, + cmdbuffer, + len); + if (irc != 0) { + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc == 0) { + irc = td->waitdatavalid(td->baseaddr); + if (irc != 0) { + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc == 0) { + irc = td->waitrespready(td->baseaddr, 2000); + if (irc != 0) { + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc == 0) { + irc = td->readresp(td->baseaddr, + respbuffer, + respbufferlen); + if (irc != 0) { + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc == 0) { + irc = td->ready(td->baseaddr); + } + + return rc; +} + + +static +uint8_t acpi_validate_entry(struct acpi_header *hdr) +{ + uint8_t sum = 0; + unsigned int length = hdr->length; + unsigned int ctr; + unsigned char *addr = (unsigned char *)hdr; + + for (ctr = 0; ctr < length; ctr++) + sum += addr[ctr]; + + return sum; +} + + +void tcpa_acpi_init(void) +{ + struct acpi_20_rsdt *rsdt; + uint32_t length; + struct acpi_20_tcpa *tcpa; + uint16_t found = 0; + uint16_t rsdp_off; + uint16_t off; + struct acpi_20_rsdp *rsdp; + + if (MA_IsTPMPresent() == 0) { + return; + } + + /* scan memory in steps of 16 bytes in the ACPI_SEGMENT segment */ + found = 0; + for (rsdp_off = 0; rsdp_off < 0xfff0; rsdp_off += 0x10) { + char *_rsdp = (char *)(ACPI_SEGMENT << 4); + /* check for expected string */ + if (!strncmp( &_rsdp[rsdp_off], "RSD PTR ", 8)) { + found = 1; + rsdp = (struct acpi_20_rsdp *)&_rsdp[rsdp_off]; + break; + } + } + + if (rsdp) { + uint32_t ctr = 0; + /* get RSDT from RSDP */ + rsdt = (struct acpi_20_rsdt *)rsdp->rsdt_address; + /* rsdt may be anywhere in 32bit space */ + length = rsdt->header.length; + off = 36; + while ((off + 3) < length) { + /* try all pointers to structures */ + tcpa = (struct acpi_20_tcpa *)rsdt->entry[ctr]; + /* valid TCPA ACPI table ? */ + if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature && + acpi_validate_entry(&tcpa->header) == 0) { + found = 1; + break; + } + off += 4; + ctr++; + } + } + + if (found == 0) { + printf("TCPA ACPI was NOT found!\n"); + tcpa = 0; + } + + /* initialize the TCPA part of the EBDA with our data */ + tcpa_acpi.tcpa_ptr = tcpa; + tcpa_acpi.lasa_last_ptr = 0; + tcpa_acpi.entry_count = 0; + tcpa_acpi.flags = 0; + tcpa_reset_acpi_log(); +} + +/* clear the ACPI log */ +static void tcpa_reset_acpi_log(void) +{ + unsigned char *lasa = tcpa_get_lasa_base_ptr(); + if (lasa) + memset(lasa, 0x0, tcpa_get_laml()); +} + + +uint32_t tcpa_extend_acpi_log(uint32_t entry_ptr) +{ + uint32_t res = 0; + unsigned char *lasa_last = tcpa_get_lasa_last_ptr(); + unsigned char *lasa_base = tcpa_get_lasa_base_ptr(); + uint32_t size; + uint16_t entry_count = tcpa_acpi.entry_count; + struct pcpes *pcpes = (struct pcpes *)entry_ptr; + + if (lasa_last == 0) { + lasa_last = lasa_base; + } else { + struct pcpes *pcpes = (struct pcpes *)lasa_last; + /* skip the last entry in the log */ + size = pcpes->eventdatasize; + size += 32; + lasa_last += size; + } + + if (lasa_last == 0) { + res = ((uint32_t)TCG_PC_LOGOVERFLOW << 16); + } + + if (res == 0) { + uint32_t laml = tcpa_get_laml(); + size = pcpes->eventdatasize; + size += 32; + if ((lasa_last + size - lasa_base) > laml) { + res = (TCG_PC_LOGOVERFLOW << 16); + } + } + + if (res == 0) { + /* copy the log entry into the ACPI log */ + memcpy((char *)lasa_last, (char *)entry_ptr, size); + /* + * update the pointers and entry counter that were modified + * due to the new entry in the log + */ + tcpa_acpi.lasa_last_ptr = lasa_last; + entry_count++; + tcpa_acpi.entry_count = entry_count; + + res = entry_count; + } + return res; +} + +static +unsigned char *tcpa_get_lasa_last_ptr(void) +{ + return tcpa_acpi.lasa_last_ptr; +} + +static +unsigned char *tcpa_get_lasa_base_ptr(void) +{ + unsigned char *lasa = 0; + struct acpi_20_tcpa *tcpa = tcpa_acpi.tcpa_ptr; + if (tcpa != 0) { + uint32_t class = tcpa->platform_class; + if (class == TCPA_ACPI_CLASS_CLIENT) { + /* client type */ + lasa = (unsigned char *)(long)tcpa->u.client.lasa; + } else if (class == TCPA_ACPI_CLASS_SERVER) { + /* server type */ + lasa = (unsigned char *)(long)tcpa->u.server.lasa; + } + } + return lasa; +} + +static +uint32_t tcpa_get_laml(void) +{ + uint32_t laml = 0; + struct acpi_20_tcpa *tcpa = tcpa_acpi.tcpa_ptr; + if (tcpa != 0) { + uint32_t class = tcpa->platform_class; + if (class == TCPA_ACPI_CLASS_CLIENT) { + /* client type */ + laml = tcpa->u.client.laml; + } else if (class == TCPA_ACPI_CLASS_SERVER) { + laml = tcpa->u.server.laml; + } + } + return laml; +} + + + +/* + * 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 : pointer to the data (i.e., string) to be added to the log + * length : length of the data + */ +static uint16_t +tcpa_add_measurement_to_log(uint32_t pcrIndex, + uint32_t event_type, + uint32_t event_id, + const char *data_ptr, + uint32_t length) +{ + uint32_t rc = 0; + struct hleei_short hleei; + struct hleeo hleeo; + uint8_t _pcpes[32+400]; + struct pcpes *pcpes = (struct pcpes *)_pcpes; + uint8_t *data = (uint8_t *)data_ptr; + + if (length < sizeof(_pcpes)-32) { + memset(pcpes, 0x0, 32); + pcpes->pcrindex = pcrIndex; + pcpes->eventtype = event_type; + pcpes->eventdatasize = length; + memcpy(&_pcpes[32], data, length); + + hleei.ipblength = 0x18; + hleei.reserved = 0x0; + hleei.hashdataptr = (uint32_t)&_pcpes[32]; + hleei.hashdatalen = length; + hleei.pcrindex = pcrIndex; + hleei.logdataptr = (uint32_t)_pcpes; + hleei.logdatalen = length + 32; + rc = HashLogExtendEvent32(&hleei, + &hleeo, + TCG_MAGIC, + 0x0, + 0x0); + } else { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_GENERAL_ERROR << 16)); + } + + return rc; +} + +static +uint16_t tcpa_add_pcpes_to_log(struct pcpes *pcpes) +{ + uint32_t rc = 0; + struct hleei_short hleei; + struct hleeo hleeo; + + hleei.ipblength = 0x18; + hleei.reserved = 0x0; + hleei.hashdataptr = 0; + hleei.hashdatalen = 0; + hleei.pcrindex = pcpes->pcrindex; + hleei.logdataptr = (uint32_t)pcpes; + hleei.logdatalen = sizeof(pcpes); + + rc = HashLogExtendEvent32(&hleei, + &hleeo, + TCG_MAGIC, + 0x0, + 0x0); + + return rc; +} + + +/* + * Add a measurement to the log; further description of the data + * that are to be hashed are NOT appended to the TCG_PCClientPCREventStruc. + * Input parameters: + * pcrIndex : PCR to extend + * event_type : type of event; specs 10.4.1 + * ptr : 32 bit pointer to the data to be hashed + * length : length of the data to be hashed + * + * Returns lower 16 bit of return code of TCG_HashLogExtendEvent. '0' means + * success, otherwise an error is indicated. + */ +static +uint16_t tcpa_add_measurement_to_log_simple(uint32_t pcrIndex, + uint16_t event_type, + uint8_t *ptr, uint32_t length) +{ + uint32_t rc = 0; + struct hleei_short hleei; + struct hleeo hleeo; + struct pcpes pcpes; + + memset(&pcpes, 0x0, sizeof(pcpes)); + pcpes.pcrindex = pcrIndex; + pcpes.eventtype = event_type; + pcpes.eventdatasize = length; + + hleei.ipblength = 0x18; + hleei.reserved = 0x0; + hleei.hashdataptr = (uint32_t)ptr; + hleei.hashdatalen = length; + hleei.pcrindex = pcrIndex; + hleei.logdataptr = (uint32_t)&pcpes; + hleei.logdatalen = 32; + + rc = HashLogExtendEvent32(&hleei, + &hleeo, + TCG_MAGIC, + 0x0, + 0x0); + return rc; +} + +/* table of event types according to 10.4.1 / table 11 */ +static const 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(uint32_t pcrIndex, + uint16_t event_type, + uint32_t data) +{ + const char *string; + + switch (event_type) { + case EV_SEPARATOR: + tcpa_add_measurement_to_log(pcrIndex, + event_type, + 0, + evt_separator, + strlen(evt_separator)); + break; + case EV_ACTION: + string = ev_action[data /* event_id */]; + tcpa_add_measurement_to_log(pcrIndex, + event_type, + data, + string, + strlen(string)); + + break; + } +} + + +/* + * Add measurement to log about call of int 19h + */ +void tcpa_calling_int19h() +{ + tcpa_add_measurement(4, EV_ACTION, 0); +} + +/* + * Add measurement to log about retuning from int 19h + */ +void tcpa_returned_int19h() +{ + tcpa_add_measurement(4, EV_ACTION, 1); +} + +/* + * Add event separators for PCRs 0 to 7; specs 8.2.3 + */ +void tcpa_add_event_separators() +{ + uint32_t pcrIndex = 0; + while (pcrIndex <= 7) { + tcpa_add_measurement(pcrIndex, EV_SEPARATOR, 0); + pcrIndex ++; + } +} + + +/* + * Add a wake event to the log + */ +void tcpa_wake_event() +{ + tcpa_add_measurement_to_log(6, + EV_ACTION, + 10, + wake_event_1, + strlen(wake_event_1)); +} + +/* + * add the boot device to the measurement log + */ +void tcpa_add_bootdevice(uint32_t bootcd, uint32_t bootdrv) +{ + char *string; + if (bootcd == 0) { + if (bootdrv == 0) { + string = "Booting BCV device 00h (Floppy)"; + } else if (bootdrv == 0x80) { + string = "Booting BCV device 80h (HDD)"; + } else { + string = "Booting unknown device"; + } + } else { + string = "Booting from CD ROM device"; + } + tcpa_add_measurement_to_log(4, 5, 0, + string, strlen(string)); +} + +/* + * Add measurement to the log about option rom scan + * 10.4.3 : action 14 + */ +void tcpa_start_option_rom_scan() +{ + tcpa_add_measurement(2, EV_ACTION, 14); +} + + +/* + * Add measurement to the log about an option rom + */ +void tcpa_option_rom(uint32_t seg) +{ + uint32_t len = read_byte(seg, 2) << 9; + uint8_t *addr = (uint8_t *)ADDR_FROM_SEG_OFF(seg,0); + char append[32]; /* TCG_PCClientTaggedEventStruct and + OptionROMExecuteStructure; specs 10.4.2.1 */ + struct hai hai; /* HashAll Input Block; specs 12.10 */ + + memset(append, 0x0, sizeof(append)); + + append[0] = 7; /* Option ROM Execute */ + append[4] = 24;/* size of OptionROMExecute Structure */ + /* leave the rest to '0' */ + + /* 12.10 table 21 */ + hai.ipblength = 0x10; + hai.reserved = 0; + hai.hashdataptr = (uint32_t)addr; + hai.hashdatalen = len; + hai.algorithmid = TPM_ALG_SHA; + + HashAll32(&hai, + (unsigned char *)append+12, + TCG_MAGIC, + 0, + 0); + + tcpa_add_measurement_to_log(2, + EV_EVENT_TAG, + 0, + 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(Bit32u seg) +{ + /* specs: 8.2.5.3 */ + uint8_t *addr = (uint8_t *)ADDR_FROM_SEG_OFF(seg,0); + /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */ + tcpa_add_measurement_to_log_simple(4, + EV_IPL, + addr, + 0x1b8); + /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */ + tcpa_add_measurement_to_log_simple(5, + EV_IPL_PARTITION_DATA, + addr + 0x1b8, + 0x48); +} + +void tcpa_measure_post(Bit32u from, Bit32u to) +{ + struct pcpes pcpes; /* PCClientPCREventStruc */ + memset(&pcpes, 0x0, sizeof(pcpes)); + int len = to - from; + + if (len > 0) { + sha1((unsigned char *)from, + to-from, + (unsigned char *)&pcpes.digest); + + pcpes.eventtype = EV_POST_CODE; + pcpes.eventdatasize = 0; + pcpes.pcrindex = 0; + tcpa_add_pcpes_to_log(&pcpes); + } +} + +static +uint32_t SendCommand32(uint32_t idx, + struct pttto *pttto, + uint32_t size_ptto) +{ + uint32_t rc = 0; + struct pttti *pttti = (struct pttti *)TCG_CommandList[idx]; + uint8_t _pttto[30]; + + if (size_ptto > 0 && size_ptto < 14) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_INPUT_PARA << 16)); + } + + if (rc == 0) { + if (size_ptto == 0) { + pttto = (struct pttto *)_pttto; + size_ptto = sizeof(_pttto); + } + pttti->opblength = size_ptto; + } + + if (rc == 0) { + if (pttti->opblength > size_ptto) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_OUTPUT_BUFFER_TOO_SHORT << 16)); + } + } + + if (rc == 0) { + rc = PassThroughToTPM32(pttti, + pttto, + TCG_MAGIC, + 0x0, + 0x0); + } + + return rc; +} + + +uint32_t tcpa_initialize_tpm(uint32_t physpres) +{ + uint32_t rc = 0; + uint8_t _pttto[40]; + struct pttto *pttto = (struct pttto *)_pttto; + uint32_t pttto_size = sizeof(_pttto); + + if (rc == 0) { + rc = SendCommand32(IDX_CMD_TPM_Startup_0x01, pttto, pttto_size); + } + + if (rc == 0 && physpres != 0) { + rc = SendCommand32(IDX_CMD_TSC_PhysicalPresence_0x20, + pttto, pttto_size); + } + + if (rc == 0 && physpres != 0) { + rc = SendCommand32(IDX_CMD_TSC_PhysicalPresence_0x08, + pttto, pttto_size); + } + + if (rc == 0 && physpres != 0) { + rc = SendCommand32(IDX_CMD_TPM_PhysicalEnable, + pttto, pttto_size); + } + + if (rc == 0 && physpres != 0) { + rc = SendCommand32(IDX_CMD_TPM_PhysicalSetDeactivated_0x00, + pttto, pttto_size); + } + + if (rc == 0) { + rc = SendCommand32(IDX_CMD_TSC_PhysicalPresence_0x100, + pttto, pttto_size); + } + + if (rc == 0) { + rc = SendCommand32(IDX_CMD_TSC_PhysicalPresence_0x10, + pttto, pttto_size); + } + return rc; +} + + +uint16_t TCG_IsShutdownPreBootInterface(void) +{ + return tcpa_acpi.flags & STATUS_FLAG_SHUTDOWN; +} + + +static +uint32_t _TCG_TPM_Extend(unsigned char *hash, uint32_t pcrindex) +{ + uint32_t rc; + uint8_t _pttti[8+34]; + uint8_t _pttto[4+30]; + struct pttti *pttti = (struct pttti*)&_pttti; + struct pttto *pttto = (struct pttto*)&_pttto; + + pttti->ipblength = 8 + 34; + pttti->reserved = 0; + pttti->opblength = 4 + 30; + pttti->reserved2 = 0; + + _pttti[8 + 0] = 0x0; + _pttti[8 + 1] = 0xc1; + *(uint32_t *)&_pttti[8 + 2] = bswap(34); + *(uint32_t *)&_pttti[8 + 6] = bswap(0x14); + *(uint32_t *)&_pttti[8 + 10]= bswap(pcrindex); + memcpy(&_pttti[8+14], hash, 20); + + rc = PassThroughToTPM32(pttti, + pttto, + TCG_MAGIC, + 0x0, + 0x0); + /* sanity check of result */ + if (_pttto[4] != 0x00 || _pttto[5] != 0xc4) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_FATAL_COM_ERROR << 16)); + } + + if (rc != 0) { + /* + Invalidate the log since system did not process this + extend properly. + */ + tcpa_reset_acpi_log(); + memset(&tcpa_acpi, 0x0, sizeof(tcpa_acpi)); + TCG_ShutdownPreBootInterface(0); + } + return rc; +} + + +static +uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, + struct hleeo *hleeo, + uint32_t magic, + uint32_t ecx, + uint32_t edx) +{ + uint32_t rc = 0; + uint16_t size; + struct hlei hlei ; /* HashLogEventInput block */ + struct hleo hleo; /* HashLogEventOutput block */ + struct hleei_long *hleei_l = (struct hleei_long *)hleei_s; + int sh; + uint32_t logdataptr; + + if (TCG_IsShutdownPreBootInterface() != 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (rc == 0) { + /* short or long version? */ + size = hleei_s->ipblength; + if (size == 0x18) { + /* short */ + sh = 1; + } else if (size == 0x1c) { + /* long */ + sh = 0; + } else { + /* bad input block */ + rc = TCG_PC_TPMERROR | + ((uint32_t)(TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + uint32_t hashdataptr; + uint32_t hashdatalen; + uint32_t pcrindex; + uint32_t logeventtype; + uint32_t logdatalen; + uint32_t eventnumber; + uint8_t hash[20]; + struct pcpes *pcpes; + + hashdataptr = hleei_s->hashdataptr; + hashdatalen = hleei_s->hashdatalen; + pcrindex = hleei_s->pcrindex; + if (sh) { + logdataptr = hleei_s->logdataptr; + logdatalen = hleei_s->logdatalen; + } else { + logdataptr = hleei_l->logdataptr; + logdatalen = hleei_l->logdatalen; + } + + pcpes = (struct pcpes *)logdataptr; + logeventtype = pcpes->eventtype; + + /* fill out HashLogEventInput block 'hlie' */ + hlei.ipblength = 0x1c; + hlei.reserved = 0; + hlei.hashdataptr = hashdataptr; + hlei.hashdatalen = hashdatalen; + hlei.pcrindex = pcrindex; + hlei.logeventtype= logeventtype; + hlei.logdataptr = logdataptr; + hlei.logdatalen = logdatalen; + + rc = HashLogEvent32(&hlei, + &hleo, + TCG_MAGIC, + 0x0, + 0x0); + eventnumber = hleo.eventnumber; + + hleeo->opblength = 8 + 20; + hleeo->reserved = 0; + hleeo->eventnumber = eventnumber; + + memcpy(hash, (unsigned char *)logdataptr + 0x8, 20); + _TCG_TPM_Extend(hash, pcrindex); + } + + if (rc != 0) { + hleeo->opblength = 4; + hleeo->reserved = 0; + } + return rc; + +} + + +static +uint32_t PassThroughToTPM32(struct pttti *pttti, + struct pttto *pttto, + uint32_t magic, + uint32_t ecx, + uint32_t edx) +{ + uint32_t rc = 0; + uint8_t *cmd32; + uint32_t resbuflen; + + if (TCG_IsShutdownPreBootInterface() != 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (rc == 0) { + if (pttti->ipblength < 0x8 + 10) { + rc = TCG_PC_TPMERROR | + ((uint32_t)(TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + if (pttti->opblength < 0x4) { + rc = TCG_PC_TPMERROR | + ((uint32_t)(TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + uint8_t *resbuf32; + + cmd32 = &pttti->tpmoperandin[0]; + resbuflen = pttti->opblength - 4; + resbuf32 = &pttto->tpmoperandout[0]; + + rc = MA_Transmit(cmd32, resbuf32, resbuflen); + } + + if (rc == 0) { + pttto->opblength = resbuflen+4; + pttto->reserved = 0; + } + + if (rc != 0) { + pttto->opblength = 0; + pttto->reserved = 0; + } + + return rc; +} + + +static +uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx) +{ + uint32_t rc = 0; + if (TCG_IsShutdownPreBootInterface() == 0) { + tcpa_acpi.flags |= STATUS_FLAG_SHUTDOWN; + } else { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + return rc; +} + + +static +uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, + uint32_t ebx, + uint32_t ecx, + uint32_t edx) +{ + uint32_t rc = 0; + uint16_t size; + uint32_t logdataptr; + uint32_t logdatalen; + uint32_t hashdataptr; + uint32_t hashdatalen; + + if (TCG_IsShutdownPreBootInterface() != 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (rc == 0) { + size = hlei->ipblength; + if (size != 0x1c) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + struct pcpes *pcpes; + logdataptr = hlei->logdataptr; + logdatalen = hlei->logdatalen; + pcpes = (struct pcpes *)logdataptr; + if (pcpes->pcrindex != hlei->pcrindex) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + struct pcpes *pcpes= (struct pcpes *)logdataptr; + if (pcpes->eventtype != hlei->logeventtype) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + uint32_t entry; + hashdataptr = hlei->hashdataptr; + hashdatalen = hlei->hashdatalen; + + if ((hashdataptr != 0) | (hashdatalen != 0)) { + uint8_t hash[20]; + struct hai hai; /* HashAll Input Block */ + hai.ipblength = 0x10; + hai.reserved = 0x0; + hai.hashdataptr = hashdataptr; + hai.hashdatalen = hashdatalen; + hai.algorithmid = TPM_ALG_SHA; + rc = HashAll32(&hai, + hash, + TCG_MAGIC, + 0x0, + 0x0); + + if (rc == 0) { + /* hashing was done ok */ + memcpy((unsigned char *)logdataptr + 8, + hash, + 20); + } + } + + if (rc == 0) { + /* extend the log with this event */ + entry = tcpa_extend_acpi_log(logdataptr); + if ((uint16_t)entry == 0) { + /* upper 16 bits hold error code */ + rc = (entry >> 16); + } + } + + if (rc == 0) { + /* updating the log was fine */ + hleo->opblength = 8; + hleo->reserved = 0; + hleo->eventnumber = entry; + } + } + + if (rc != 0) { + hleo->opblength = 2; + hleo->reserved = 0; + } + + return rc; +} + +static +uint32_t HashAll32(struct hai *hai, unsigned char *hash, + uint32_t magic, + uint32_t ecx, + uint32_t edx) +{ + uint32_t rc = 0; + + if (TCG_IsShutdownPreBootInterface() != 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (rc == 0) { + if (hai->ipblength != 0x10) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + if (hai->algorithmid != TPM_ALG_SHA) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_ACCESS_REQUEST << 16)); + } + } + + if (rc == 0) { + uint8_t *hashdataptr32; + uint32_t hashdatalen32; + + hashdataptr32 = (uint8_t *)hai->hashdataptr; + hashdatalen32 = hai->hashdatalen; + + sha1(hashdataptr32, + hashdatalen32, + hash); + } + + return rc; +} + + +static +uint32_t TSS32(struct ti *ti, struct to *to, + uint32_t ebx, + uint32_t ecx, + uint32_t edx) +{ + uint32_t rc = 0; + if (TCG_IsShutdownPreBootInterface() == 0) { + rc = TCG_PC_UNSUPPORTED; + } else { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (rc != 0) { + to->opblength = 4; + to->reserved = 0; + } + + return rc; +} + +static +uint32_t CompactHashLogExtendEvent32(unsigned char *buffer, + uint32_t info, + uint32_t magic, + uint32_t length, + uint32_t pcrindex, + uint32_t *edx_ptr) +{ + uint32_t rc = 0; + struct hleeo hleeo; + + if (TCG_IsShutdownPreBootInterface() != 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INTERFACE_SHUTDOWN << 16)); + } + + if (buffer == 0) { + rc = (TCG_PC_TPMERROR | + ((uint32_t)TCG_INVALID_INPUT_PARA << 16)); + } + + if (rc == 0) { + struct hleei_short hleei; + struct pcpes pcpes; + uint8_t *logdataptr; + uint8_t *hashdataptr; + + logdataptr = (uint8_t*)&pcpes; + hashdataptr = buffer; + + hleei.ipblength = 0x18; + hleei.reserved = 0x0; + hleei.hashdataptr = (uint32_t)hashdataptr; + hleei.hashdatalen = length; + hleei.pcrindex = pcrindex; + hleei.logdataptr = (uint32_t)logdataptr; + hleei.logdatalen = 32; + + memset(&pcpes, 0x0, 32); + pcpes.pcrindex = pcrindex; + pcpes.eventtype = 12; /* EV_COMPACT_HASH */ + pcpes.eventdatasize = 4; + pcpes.event = info; + + rc = HashLogExtendEvent32(&hleei, + &hleeo, + TCG_MAGIC, + 0x0, + 0x0); + } + + if (rc == 0) { + *edx_ptr = hleeo.eventnumber; + } + + return rc; +} + + + +/******************************************************************* + Calculation of SHA1 in SW + + See: RFC3174, Wikipedia's SHA1 alogrithm description + ******************************************************************/ +typedef struct _sha1_ctx { + uint32_t h[5]; +} sha1_ctx; + + +static inline uint32_t rol(val, rol) + uint32_t val; + uint16_t rol; +{ + return (val << rol) | (val >> (32 - rol)); +} + +static const uint32_t sha_ko[4] = { 0x5a827999, + 0x6ed9eba1, + 0x8f1bbcdc, + 0xca62c1d6 }; + + +static void sha1_block(uint32_t *w, sha1_ctx *ctx) +{ + uint32_t i; + uint32_t a,b,c,d,e,f; + uint32_t tmp; + uint32_t idx; + + /* change endianess of given data */ + for (i = 0; i < 16; i++) { + w[i] = bswap(w[i]); + } + + for (i = 16; i <= 79; i++) { + tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + w[i] = rol(tmp,1); + } + + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + + for (i = 0; i <= 79; i++) { + if (i <= 19) { + f = (b & c) | ((b ^ 0xffffffff) & d); + idx = 0; + } else if (i <= 39) { + f = b ^ c ^ d; + idx = 1; + } else if (i <= 59) { + f = (b & c) | (b & d) | (c & d); + idx = 2; + } else { + f = b ^ c ^ d; + idx = 3; + } + + tmp = rol(a, 5) + + f + + e + + sha_ko[idx] + + w[i]; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; +} + +static +void sha1_do(sha1_ctx *ctx, const unsigned char *data32, uint32_t length) +{ + uint32_t offset; + uint16_t num; + uint32_t bits = 0; + uint32_t w[80]; + uint32_t tmp; + + /* treat data in 64-byte chunks */ + for (offset = 0; length - offset >= 64; offset += 64) { + /* copy into the 'w' array */ + memcpy(w, data32 + offset, 64); + /* hash the block in the 'w' array */ + sha1_block((uint32_t *)w, ctx); + bits += (64 * 8); + } + + /* last block with less than 64 bytes */ + num = length - offset; + bits += (num << 3); + + memset(w, 0x0, 64); + memcpy(w, data32 + offset, num); + ((uint8_t *)w)[num] = 0x80; + + if (num >= 56) { + /* cannot append number of bits here */ + sha1_block((uint32_t *)w, ctx); + memset(w, 0x0, 60); + } + + /* write number of bits to end of block */ + tmp = bswap(bits); + memcpy(&w[15], &tmp, 4); + + sha1_block(w, ctx); + + /* need to switch result's endianess */ + for (num = 0; num < 5; num++) + ctx->h[num] = bswap(ctx->h[num]); +} + +/* sha1 initialization constants */ +static const uint32_t sha_const[5] = { + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0 +}; + +static +void sha1(const unsigned char *data, uint32_t length, unsigned char *hash) +{ + sha1_ctx ctx; + + memcpy(&ctx.h[0], sha_const, 20); + sha1_do(&ctx, data, length); + memcpy(hash, &ctx.h[0], 20); +} + + +uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, uint32_t flags_ptr) +{ + uint16_t DS = esds >> 16; + uint16_t ES = esds & 0xffff; + uint16_t *FLAGS = (uint16_t *)flags_ptr; + + switch(regs->u.r8.al) { + case 0x00: + if (MA_IsTPMPresent() == 0) { + /* no TPM available */ + regs->u.r32.eax = TCG_PC_TPMERROR | + ((uint32_t)(TCG_PC_TPM_NOT_PRESENT) << 16); + } else { + regs->u.r32.eax = MA_InitTPM(TPM_ST_CLEAR); + if (regs->u.r32.eax == 0) { + regs->u.r32.ebx = TCG_MAGIC; + regs->u.r8.ch = TCG_VERSION_MAJOR; + regs->u.r8.cl = TCG_VERSION_MINOR; + regs->u.r32.edx = 0x0; + regs->u.r32.esi = + (Bit32u)tcpa_get_lasa_base_ptr(); + regs->u.r32.edi = + (Bit32u)tcpa_get_lasa_last_ptr(); + CLEAR_CF(); + } + } + break; + + case 0x01: + regs->u.r32.eax = + HashLogExtendEvent32((struct hleei_short*) + ADDR_FROM_SEG_OFF(ES, + regs->u.r16.di), + (struct hleeo*) + ADDR_FROM_SEG_OFF(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 = + PassThroughToTPM32((struct pttti *) + ADDR_FROM_SEG_OFF(ES, + regs->u.r16.di), + (struct pttto *) + ADDR_FROM_SEG_OFF(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 = + HashLogEvent32((struct hlei*) + ADDR_FROM_SEG_OFF(ES, + regs->u.r16.di), + (struct hleo*) + ADDR_FROM_SEG_OFF(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 = + HashAll32((struct hai*) + ADDR_FROM_SEG_OFF(ES, + regs->u.r16.di), + (unsigned char *) + ADDR_FROM_SEG_OFF(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 = + TSS32((struct ti*)ADDR_FROM_SEG_OFF(ES, + regs->u.r16.di), + (struct to*)ADDR_FROM_SEG_OFF(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 = + CompactHashLogExtendEvent32((unsigned char *) + ADDR_FROM_SEG_OFF(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; + default: + SET_CF(); + } + + return 0; +} Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tcgbios.h =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tcgbios.h @@ -0,0 +1,288 @@ +#ifndef TCGBIOS_H +#define TCGBIOS_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_POST_CODE 1 +#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 ASCII32(a,b,c,d) ((((Bit32u)a) << 0) | (((Bit32u)b) << 8) | \ + (((Bit32u)c) << 16) | (((Bit32u)d) << 24) ) +#define ACPI_2_0_TCPA_SIGNATURE ASCII32('T','C','P','A') /* "TCPA" */ + + +#define STATUS_FLAG_SHUTDOWN (1 << 0) + +#define ACPI_SEGMENT 0xE000 + +/* Input and Output blocks for the TCG BIOS commands */ + +struct hleei_short +{ + uint16_t ipblength; + uint16_t reserved; + uint32_t hashdataptr; + uint32_t hashdatalen; + uint32_t pcrindex; + uint32_t logdataptr; + uint32_t logdatalen; +} __attribute__((packed)); + +struct hleei_long +{ + uint16_t ipblength; + uint16_t reserved; + uint32_t hashdataptr; + uint32_t hashdatalen; + uint32_t pcrindex; + uint32_t reserved2; + uint32_t logdataptr; + uint32_t logdatalen; +} __attribute__((packed)); + +struct hleeo +{ + uint16_t opblength; + uint16_t reserved; + uint32_t eventnumber; + uint8_t hashvalue[20]; +} __attribute__((packed)); + + + +struct pttti +{ + uint16_t ipblength; + uint16_t reserved; + uint16_t opblength; + uint16_t reserved2; + uint8_t tpmoperandin[0]; +} __attribute__((packed)); + +struct pttto +{ + uint16_t opblength; + uint16_t reserved; + uint8_t tpmoperandout[0]; +}; + + +struct hlei +{ + uint16_t ipblength; + uint16_t reserved; + uint32_t hashdataptr; + uint32_t hashdatalen; + uint32_t pcrindex; + uint32_t logeventtype; + uint32_t logdataptr; + uint32_t logdatalen; +} __attribute__((packed)); + +struct hleo +{ + uint16_t opblength; + uint16_t reserved; + uint32_t eventnumber; +} __attribute__((packed)); + +struct hai +{ + uint16_t ipblength; + uint16_t reserved; + uint32_t hashdataptr; + uint32_t hashdatalen; + uint32_t algorithmid; +} __attribute__((packed)); + +struct ti +{ + uint16_t ipblength; + uint16_t reserved; + uint16_t opblength; + uint16_t reserved2; + uint8_t tssoperandin[0]; +} __attribute__((packed)); + +struct to +{ + uint16_t opblength; + uint16_t reserved; + uint8_t tssoperandout[0]; +} __attribute__((packed)); + + +struct pcpes +{ + uint32_t pcrindex; + uint32_t eventtype; + uint8_t digest[20]; + uint32_t eventdatasize; + uint32_t event; +} __attribute__((packed)); + + +struct acpi_header +{ + uint32_t signature; + uint32_t length; + uint8_t revision; + uint8_t checksum; + uint8_t oem_id[6]; + uint64_t oem_table_id; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} __attribute__((packed)); + +struct acpi_20_rsdt { + struct acpi_header header; + uint32_t entry[1]; +} __attribute__((packed)); + +struct acpi_20_rsdp { + uint64_t signature; + uint8_t checksum; + uint8_t oem_id[6]; + uint8_t revision; + uint32_t rsdt_address; + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint8_t reserved[3]; +} __attribute__((packed)); + +struct acpi_20_tcpa_client { + uint32_t laml; + uint64_t lasa; +} __attribute__((packed)); + +struct acpi_20_tcpa_server { + uint16_t reserved; + uint32_t laml; + uint64_t lasa; + /* more here */ +} __attribute__((packed)); + +struct acpi_20_tcpa { + struct acpi_header header; + uint16_t platform_class; + union { + struct acpi_20_tcpa_client client; + struct acpi_20_tcpa_server server; + } u; +} __attribute__((packed)); + + +#endif Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tpm_drivers.c =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tpm_drivers.c @@ -0,0 +1,180 @@ +/* + * 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 + */ +#include "rombios_compat.h" +#include "util.h" + +#include "tpm_drivers.h" +#include "tcgbios.h" + +static uint32_t tis_wait_sts(uint8_t *addr, uint32_t time, + uint8_t mask, uint8_t expect) +{ + uint32_t rc = 0; + while (time > 0) { + uint8_t sts = addr[TPM_STS]; + if ((sts & mask) == expect) { + rc = 1; + break; + } + mssleep(1); + time--; + } + return rc; +} + +static uint32_t tis_activate(uint32_t baseaddr) +{ + uint32_t rc = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + uint8_t acc; + /* request access to locality */ + tis_addr[TPM_ACCESS] = 0x2; + + acc = tis_addr[TPM_ACCESS]; + if ((acc & 0x20) != 0) { + tis_addr[TPM_STS] = 0x40; + rc = tis_wait_sts(tis_addr, 100, 0x40, 0x40); + } + return rc; +} + +uint32_t tis_ready(uint32_t baseaddr) +{ + uint32_t rc = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + + tis_addr[TPM_STS] = 0x40; + rc = tis_wait_sts(tis_addr, 100, 0x40, 0x40); + + return rc; +} + +uint32_t tis_senddata(uint32_t baseaddr, unsigned char *data, uint32_t len) +{ + uint32_t rc = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + uint32_t offset = 0; + uint32_t end = 0; + + do { + uint16_t burst = 0; + uint32_t ctr = 0; + while (burst == 0 && ctr < 2000) { + burst = (((uint16_t)tis_addr[TPM_STS+1]) ) + + (((uint16_t)tis_addr[TPM_STS+2]) << 8); + if (burst == 0) { + mssleep(1); + ctr++; + } + } + + if (burst == 0) { + rc = TCG_RESPONSE_TIMEOUT; + break; + } + + while (1) { + tis_addr[TPM_DATA_FIFO] = data[offset]; + offset++; + burst--; + + if (burst == 0 || offset == len) { + break; + } + } + + if (offset == len) { + end = 1; + } + } while (end == 0); + + return rc; +} + +uint32_t tis_readresp(uint32_t baseaddr, unsigned char *buffer, uint32_t len) +{ + uint32_t rc = 0; + uint32_t offset = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + uint32_t sts; + + while (offset < len) { + buffer[offset] = tis_addr[TPM_DATA_FIFO]; + offset++; + sts = tis_addr[TPM_STS]; + /* data left ? */ + if ((sts & 0x10) == 0) { + break; + } + } + return rc; +} + + +uint32_t tis_waitdatavalid(uint32_t baseaddr) +{ + uint8_t *tis_addr = (uint8_t*)baseaddr; + uint32_t rc = 0; + if (tis_wait_sts(tis_addr, 1000, 0x80, 0x80) == 0) { + rc = TCG_NO_RESPONSE; + } + return rc; +} + +uint32_t tis_waitrespready(uint32_t baseaddr, uint32_t timeout) +{ + uint32_t rc = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + tis_addr[TPM_STS] = 0x20; + if (tis_wait_sts(tis_addr, timeout, 0x10, 0x10) == 0) { + rc = TCG_NO_RESPONSE; + } + return rc; +} + +/* if device is not there, return '0', '1' otherwise */ +uint32_t tis_probe(uint32_t baseaddr) +{ + uint32_t rc = 0; + uint8_t *tis_addr = (uint8_t*)baseaddr; + uint32_t didvid = *(uint32_t*)&tis_addr[TPM_DID_VID]; + if ((didvid != 0) && (didvid != 0xffffffff)) { + rc = 1; + } + return rc; +} + + +struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { + { + .baseaddr = TPM_TIS_BASE_ADDRESS, + .activate = tis_activate, + .ready = tis_ready, + .senddata = tis_senddata, + .readresp = tis_readresp, + .waitdatavalid = tis_waitdatavalid, + .waitrespready = tis_waitrespready, + .probe = tis_probe, + }, +}; Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tpm_drivers.h =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/tcgbios/tpm_drivers.h @@ -0,0 +1,18 @@ +#ifndef TPM_DRIVER_H +/* low level driver implementation */ +struct tpm_driver { + uint32_t baseaddr; + uint32_t (*activate)(uint32_t baseaddr); + uint32_t (*ready)(uint32_t baseaddr); + uint32_t (*senddata)(uint32_t baseaddr, unsigned char *data, uint32_t len); + uint32_t (*readresp)(uint32_t baseaddr, unsigned char *buffer, uint32_t len); + uint32_t (*waitdatavalid)(uint32_t baseaddr); + uint32_t (*waitrespready)(uint32_t baseaddr, uint32_t timeout); + uint32_t (*probe)(uint32_t baseaddr); +}; + +#define TPM_NUM_DRIVERS 1 + +#define TPM_INVALID_DRIVER -1 + +#endif Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/util.c =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/util.c @@ -0,0 +1,450 @@ +/* + * util.c: Helper library functions for HVMLoader. + * + * Leendert van Doorn, leendert@xxxxxxxxxxxxxx + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include +#include "util.h" + +static void putchar(char c); +#define isdigit(c) ((c) >= '0' && (c) <= '9') + +void outb(uint16_t addr, uint8_t val) +{ + __asm__ __volatile__ ( "outb %%al, %%dx" :: "d"(addr), "a"(val) ); +} + +void outw(uint16_t addr, uint16_t val) +{ + __asm__ __volatile__ ( "outw %%ax, %%dx" :: "d"(addr), "a"(val) ); +} + +void outl(uint16_t addr, uint32_t val) +{ + __asm__ __volatile__ ( "outl %%eax, %%dx" :: "d"(addr), "a"(val) ); +} + +uint8_t inb(uint16_t addr) +{ + uint8_t val; + __asm__ __volatile__ ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) ); + return val; +} + +uint16_t inw(uint16_t addr) +{ + uint16_t val; + __asm__ __volatile__ ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) ); + return val; +} + +uint32_t inl(uint16_t addr) +{ + uint32_t val; + __asm__ __volatile__ ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) ); + return val; +} + +char *itoa(char *a, unsigned int i) +{ + unsigned int _i = i, x = 0; + + do { + x++; + _i /= 10; + } while ( _i != 0 ); + + a += x; + *a-- = '\0'; + + do { + *a-- = (i % 10) + '0'; + i /= 10; + } while ( i != 0 ); + + return a + 1; +} + +int strcmp(const char *cs, const char *ct) +{ + signed char res; + + while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') ) + continue; + + return res; +} + +int strncmp(const char *s1, const char *s2, uint32_t n) +{ + uint32_t ctr; + for (ctr = 0; ctr < n; ctr++) + if (s1[ctr] != s2[ctr]) + return (int)(s1[ctr] - s2[ctr]); + return 0; +} + +void *memcpy(void *dest, const void *src, unsigned n) +{ + int t0, t1, t2; + + __asm__ __volatile__ ( + "cld\n" + "rep; movsl\n" + "testb $2,%b4\n" + "je 1f\n" + "movsw\n" + "1: testb $1,%b4\n" + "je 2f\n" + "movsb\n" + "2:" + : "=&c" (t0), "=&D" (t1), "=&S" (t2) + : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src) + : "memory" ); + return dest; +} + +void *memmove(void *dest, const void *src, unsigned n) +{ + if ( (long)dest > (long)src ) + { + n--; + while ( n > 0 ) + { + ((char *)dest)[n] = ((char *)src)[n]; + n--; + } + } + else + { + memcpy(dest, src, n); + } + return dest; +} + +char * +strcpy(char *dest, const char *src) +{ + char *p = dest; + while ( *src ) + *p++ = *src++; + *p = 0; + return dest; +} + +char * +strncpy(char *dest, const char *src, unsigned n) +{ + int i = 0; + char *p = dest; + + /* write non-NUL characters from src into dest until we run + out of room in dest or encounter a NUL in src */ + while ( (i < n) && *src ) + { + *p++ = *src++; + i++; + } + + /* pad remaining bytes of dest with NUL bytes */ + while ( i < n ) + { + *p++ = 0; + i++; + } + + return dest; +} + +unsigned +strlen(const char *s) +{ + int i = 0; + while ( *s++ ) + i++; + return i; +} + +void * +memset(void *s, int c, unsigned n) +{ + uint8_t b = (uint8_t) c; + uint8_t *p = (uint8_t *)s; + int i; + for ( i = 0; i < n; i++ ) + *p++ = b; + return s; +} + +int +memcmp(const void *s1, const void *s2, unsigned n) +{ + unsigned i; + uint8_t *p1 = (uint8_t *) s1; + uint8_t *p2 = (uint8_t *) s2; + + for ( i = 0; i < n; i++ ) + { + if ( p1[i] < p2[i] ) + return -1; + else if ( p1[i] > p2[i] ) + return 1; + } + + return 0; +} + +void +cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) +{ + __asm__ __volatile__ ( + "cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (idx) ); +} + +/* Write a two-character hex representation of 'byte' to digits[]. + Pre-condition: sizeof(digits) >= 2 */ +void +byte_to_hex(char *digits, uint8_t byte) +{ + uint8_t nybbel = byte >> 4; + + if ( nybbel > 9 ) + digits[0] = 'a' + nybbel-10; + else + digits[0] = '0' + nybbel; + + nybbel = byte & 0x0f; + if ( nybbel > 9 ) + digits[1] = 'a' + nybbel-10; + else + digits[1] = '0' + nybbel; +} + +/* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID + string. + + Pre-condition: sizeof(dest) >= 37 */ +void +uuid_to_string(char *dest, uint8_t *uuid) +{ + int i = 0; + char *p = dest; + + for ( i = 0; i < 4; i++ ) + { + byte_to_hex(p, uuid[i]); + p += 2; + } + *p++ = '-'; + for ( i = 4; i < 6; i++ ) + { + byte_to_hex(p, uuid[i]); + p += 2; + } + *p++ = '-'; + for ( i = 6; i < 8; i++ ) + { + byte_to_hex(p, uuid[i]); + p += 2; + } + *p++ = '-'; + for ( i = 8; i < 10; i++ ) + { + byte_to_hex(p, uuid[i]); + p += 2; + } + *p++ = '-'; + for ( i = 10; i < 16; i++ ) + { + byte_to_hex(p, uuid[i]); + p += 2; + } + *p = '\0'; +} + +static char *printnum(char *p, unsigned long num, int base) +{ + unsigned long n; + + if ( (n = num/base) > 0 ) + p = printnum(p, n, base); + *p++ = "0123456789abcdef"[(int)(num % base)]; + *p = '\0'; + return p; +} + +static void _doprint(void (*put)(char), char const *fmt, va_list ap) +{ + register char *str, c; + int lflag, zflag, nflag; + char buffer[17]; + unsigned value; + int i, slen, pad; + + for ( ; *fmt != '\0'; fmt++ ) + { + if ( *fmt != '%' ) + { + put(*fmt); + continue; + } + + pad = zflag = nflag = lflag = 0; + c = *++fmt; + if ( (c == '-') || isdigit(c) ) + { + if ( c == '-' ) + { + nflag = 1; + c = *++fmt; + } + zflag = c == '0'; + for ( pad = 0; isdigit(c); c = *++fmt ) + pad = (pad * 10) + c - '0'; + } + if ( c == 'l' ) /* long extension */ + { + lflag = 1; + c = *++fmt; + } + if ( (c == 'd') || (c == 'u') || (c == 'o') || (c == 'x') ) + { + if ( lflag ) + value = va_arg(ap, unsigned); + else + value = (unsigned) va_arg(ap, unsigned int); + str = buffer; + printnum(str, value, + c == 'o' ? 8 : (c == 'x' ? 16 : 10)); + goto printn; + } + else if ( (c == 'O') || (c == 'D') || (c == 'X') ) + { + value = va_arg(ap, unsigned); + str = buffer; + printnum(str, value, + c == 'O' ? 8 : (c == 'X' ? 16 : 10)); + printn: + slen = strlen(str); + for ( i = pad - slen; i > 0; i-- ) + put(zflag ? '0' : ' '); + while ( *str ) + put(*str++); + } + else if ( c == 's' ) + { + str = va_arg(ap, char *); + slen = strlen(str); + if ( nflag == 0 ) + for ( i = pad - slen; i > 0; i-- ) + put(' '); + while ( *str ) + put(*str++); + if ( nflag ) + for ( i = pad - slen; i > 0; i-- ) + put(' '); + } + else if ( c == 'c' ) + { + put(va_arg(ap, int)); + } + else + { + put(*fmt); + } + } +} + +static void putchar(char c) +{ + outb(0xe9, c); +} + +int printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _doprint(putchar, fmt, ap); + va_end(ap); + + return 0; +} + +int vprintf(const char *fmt, va_list ap) +{ + _doprint(putchar, fmt, ap); + return 0; +} + + +/* + * sleep by synchronizing with the PIT on channel 2 + * http://bochs.sourceforge.net/techspec/intel-82c54-timer.pdf.gz + */ +#define PIT_CTR2 0x80 +#define PIT_CTR1 0x40 +#define PIT_CTR0 0x00 + +#define PIT_RW_LSB 0x10 + +#define PIT_MODE0 0x0 + +#define PIT_CTR_16BIT 0x0 + +#define PIT_CMD_LATCH 0x0 + +#define PORT_PIT_CMD 0x43 +#define PORT_PIT_CTR2 0x42 +#define PORT_PIT_CTR1 0x41 +#define PORT_PIT_CTR0 0x40 + +#define PIT_FREQ 1193182 /* Hz */ + +#define PORT_PPI 0x61 + +void mssleep(uint32_t waittime) +{ + long int timeout = 0; + uint8_t last = 0x0; + uint8_t old_ppi = inb(PORT_PPI); + + /* use ctr2; ctr0 is used by the Bochs BIOS */ + /* ctr2 drives speaker -- turn it off */ + outb(PORT_PPI, old_ppi & 0xfc); + + outb(PORT_PIT_CMD, PIT_CTR2 | PIT_RW_LSB | PIT_MODE0 | PIT_CTR_16BIT); + outb(PORT_PIT_CTR2, last); /* start countdown */ + + while (timeout < (waittime * PIT_FREQ / 1000)) { + uint8_t cur, delta; + outb(PORT_PIT_CMD, PIT_CTR2 | PIT_CMD_LATCH); + cur = inb(PORT_PIT_CTR2); + delta = last - cur; + timeout += delta; + last = cur; + } + /* turn ctr2 off */ + outb(PORT_PIT_CMD, PIT_CTR2 | PIT_RW_LSB | PIT_MODE0 | PIT_CTR_16BIT); + outb(PORT_PIT_CTR2, 0xff); /* start countdown */ + outb(PORT_PIT_CTR2, 0x0); /* stop */ + + outb(PORT_PPI, old_ppi); +} Index: root/xen-unstable.hg/tools/firmware/rombios/32bit/util.h =================================================================== --- /dev/null +++ root/xen-unstable.hg/tools/firmware/rombios/32bit/util.h @@ -0,0 +1,28 @@ +#ifndef UTIL_H +#define UTIL_H + +void outb(uint16_t addr, uint8_t val); +void outw(uint16_t addr, uint16_t val); +void outl(uint16_t addr, uint32_t val); +uint8_t inb(uint16_t addr); +uint16_t inw(uint16_t addr); +uint32_t inl(uint16_t addr); +void mssleep(uint32_t time); + +char *itoa(char *a, unsigned int i); +int strcmp(const char *cs, const char *ct); +int strncmp(const char *s1, const char *s2, uint32_t n); +void *memcpy(void *dest, const void *src, unsigned n); +void *memmove(void *dest, const void *src, unsigned n); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, unsigned n); +unsigned strlen(const char *s); +void * memset(void *s, int c, unsigned n); +int memcmp(const void *s1, const void *s2, unsigned n); +void cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); +void byte_to_hex(char *digits, uint8_t byte); +void uuid_to_string(char *dest, uint8_t *uuid); +int printf(const char *fmt, ...); + + +#endif Index: root/xen-unstable.hg/tools/firmware/rombios/32bitprotos.h =================================================================== --- root.orig/xen-unstable.hg/tools/firmware/rombios/32bitprotos.h +++ root/xen-unstable.hg/tools/firmware/rombios/32bitprotos.h @@ -1,11 +1,29 @@ #ifndef PROTOS_HIGHBIOS #define PROTOS_HIGHBIOS + +/* shared include file for bcc and gcc */ + /* bcc does not like 'enum' */ -#define IDX_MULTIPLY 0 -#define IDX_ADD 1 -#define IDX_SET_STATIC 2 -#define IDX_LAST 3 /* keep last! */ +#define IDX_MULTIPLY 0 +#define IDX_ADD 1 +#define IDX_SET_STATIC 2 + +#define IDX_TCGINTERRUPTHANDLER 3 +#define IDX_TCPA_ACPI_INIT 4 +#define IDX_TCPA_EXTEND_ACPI_LOG 5 +#define IDX_TCPA_CALLING_INT19H 6 +#define IDX_TCPA_RETURNED_INT19H 7 +#define IDX_TCPA_ADD_EVENT_SEPARATORS 8 +#define IDX_TCPA_WAKE_EVENT 9 +#define IDX_TCPA_ADD_BOOTDEVICE 10 +#define IDX_TCPA_START_OPTION_ROM_SCAN 11 +#define IDX_TCPA_OPTION_ROM 12 +#define IDX_TCPA_IPL 13 +#define IDX_TCPA_INITIALIZE_TPM 14 +#define IDX_TCPA_MEASURE_POST 15 + +#define IDX_LAST 16 /* keep last! */ #ifdef GCC_PROTOS @@ -19,4 +37,19 @@ Bit32u multiply( PARMS(Bit32u a, Bit32u Bit32u add( PARMS(Bit32u a, Bit32u b) ); Bit32u set_static( PARMS(Bit32u) ); +Bit32u TCGInterruptHandler( PARMS(pushad_regs_t *regs, Bit32u esds, Bit32u flags_ptr)); + +void tcpa_acpi_init( PARMS(void) ); +Bit32u tcpa_extend_acpi_log( PARMS(Bit32u entry_ptr) ); +void tcpa_calling_int19h( PARMS(void) ); +void tcpa_returned_int19h( PARMS(void) ); +void tcpa_add_event_separators( PARMS(void) ); +void tcpa_wake_event( PARMS(void) ); +void tcpa_add_bootdevice( PARMS(Bit32u bootcd, Bit32u bootdrv) ); +void tcpa_start_option_rom_scan( PARMS(void) ); +void tcpa_option_rom( PARMS(Bit32u seg) ); +void tcpa_ipl( PARMS(Bit32u seg) ); +void tcpa_measure_post( PARMS(Bit32u from, Bit32u to) ); +Bit32u tcpa_initialize_tpm( PARMS(Bit32u physpres) ); + #endif Index: root/xen-unstable.hg/tools/firmware/rombios/32bitgateway.c =================================================================== --- root.orig/xen-unstable.hg/tools/firmware/rombios/32bitgateway.c +++ root/xen-unstable.hg/tools/firmware/rombios/32bitgateway.c @@ -484,3 +484,5 @@ test_gateway() printf("working correctly\n"); } } + +#include "tcgbios.c"