[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] (no subject)
# HG changeset patch # User emellor@xxxxxxxxxxxxxxxxxxxxxx # Node ID 51484df99be1195e07d06021dabb414167993c40 # Parent 55f73916d319801065ffcdf6041b54e2770b9c03 # Parent 1a84eec7433193dc7277b7a84930e18d88475486 Merged. --- linux-2.6-xen-sparse/drivers/xen/tpmfront/Makefile | 2 linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c | 767 ----------- linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h | 40 linux-2.6-xen-sparse/include/xen/tpmfe.h | 40 .hgignore | 2 docs/misc/vtpm.txt | 10 extras/mini-os/Makefile | 8 extras/mini-os/include/lib.h | 1 extras/mini-os/include/os.h | 3 extras/mini-os/include/types.h | 2 extras/mini-os/sched.c | 2 extras/mini-os/traps.c | 10 extras/mini-os/x86_32.S | 53 extras/mini-os/x86_64.S | 273 +--- linux-2.6-xen-sparse/arch/ia64/xen-mkbuildtree-pre | 22 linux-2.6-xen-sparse/drivers/char/tpm/Kconfig | 3 linux-2.6-xen-sparse/drivers/char/tpm/Makefile | 2 linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.c | 546 ++++++++ linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h | 38 linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c | 1247 +++++++++++-------- linux-2.6-xen-sparse/drivers/xen/Kconfig | 8 linux-2.6-xen-sparse/drivers/xen/Makefile | 1 linux-2.6-xen-sparse/drivers/xen/tpmback/common.h | 2 linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c | 3 linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c | 83 - linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c | 2 linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h | 1 linux-2.6-xen-sparse/mm/Kconfig | 6 tools/python/xen/xend/XendBootloader.py | 8 tools/python/xen/xend/XendDomainInfo.py | 5 tools/python/xen/xm/create.py | 17 xen/arch/x86/hvm/svm/svm.c | 72 - xen/arch/x86/hvm/svm/vmcb.c | 55 xen/arch/x86/hvm/vmx/vmx.c | 41 xen/arch/x86/x86_32/mm.c | 15 xen/arch/x86/x86_64/mm.c | 18 36 files changed, 1635 insertions(+), 1773 deletions(-) diff -r 55f73916d319 -r 51484df99be1 .hgignore --- a/.hgignore Tue May 02 18:17:59 2006 +0100 +++ b/.hgignore Thu May 04 14:19:19 2006 +0100 @@ -14,6 +14,7 @@ .*\.orig$ .*\.rej$ .*/a\.out$ +.*cscope\.*$ ^[^/]*\.bz2$ ^TAGS$ ^dist/.*$ @@ -184,7 +185,6 @@ ^tools/xm-test/ramdisk/buildroot ^xen/BLOG$ ^xen/TAGS$ -^xen/cscope\.*$ ^xen/arch/x86/asm-offsets\.s$ ^xen/arch/x86/boot/mkelf32$ ^xen/arch/x86/xen\.lds$ diff -r 55f73916d319 -r 51484df99be1 docs/misc/vtpm.txt --- a/docs/misc/vtpm.txt Tue May 02 18:17:59 2006 +0100 +++ b/docs/misc/vtpm.txt Thu May 04 14:19:19 2006 +0100 @@ -21,17 +21,23 @@ linux-2.6.??-xen/.config file: linux-2.6.??-xen/.config file: CONFIG_XEN_TPMDEV_BACKEND=y -CONFIG_XEN_TPMDEV_GRANT=y -CONFIG_TCG_TPM=m +CONFIG_TCG_TPM=y CONFIG_TCG_NSC=m CONFIG_TCG_ATMEL=m +CONFIG_TCG_XEN=y You must also enable the virtual TPM to be built: In Config.mk in the Xen root directory set the line VTPM_TOOLS ?= y + +and in + +tools/vtpm/Rules.mk set the line + +BUILD_EMULATOR = y Now build the Xen sources from Xen's root directory: diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/Makefile --- a/extras/mini-os/Makefile Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/Makefile Thu May 04 14:19:19 2006 +0100 @@ -60,4 +60,12 @@ clean: %.o: %.S $(HDRS) Makefile $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $@ +define all_sources + ( find . -follow -name SCCS -prune -o -name '*.[chS]' -print ) +endef +.PHONY: cscope +cscope: + $(all_sources) > cscope.files + cscope -k -b -q + diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/include/lib.h --- a/extras/mini-os/include/lib.h Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/include/lib.h Thu May 04 14:19:19 2006 +0100 @@ -56,6 +56,7 @@ #define _LIB_H_ #include <stdarg.h> +#include <stddef.h> #include <console.h> /* printing */ diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/include/os.h --- a/extras/mini-os/include/os.h Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/include/os.h Thu May 04 14:19:19 2006 +0100 @@ -6,9 +6,6 @@ #ifndef _OS_H_ #define _OS_H_ - -#define NULL 0 - #if __GNUC__ == 2 && __GNUC_MINOR__ < 96 #define __builtin_expect(x, expected_value) (x) diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/include/types.h --- a/extras/mini-os/include/types.h Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/include/types.h Thu May 04 14:19:19 2006 +0100 @@ -34,8 +34,6 @@ typedef unsigned long u64; typedef unsigned long u64; #endif -typedef unsigned int size_t; - /* FreeBSD compat types */ typedef unsigned char u_char; typedef unsigned int u_int; diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/sched.c --- a/extras/mini-os/sched.c Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/sched.c Thu May 04 14:19:19 2006 +0100 @@ -324,7 +324,7 @@ void th_f2(void *data) void init_sched(void) { - printk("Initialising scheduler, idle_thread %p\n", idle_thread); + printk("Initialising scheduler\n"); idle_thread = create_thread("Idle", idle_thread_fn, NULL); INIT_LIST_HEAD(&idle_thread->thread_list); diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/traps.c --- a/extras/mini-os/traps.c Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/traps.c Thu May 04 14:19:19 2006 +0100 @@ -123,8 +123,13 @@ void do_page_fault(struct pt_regs *regs, void do_page_fault(struct pt_regs *regs, unsigned long error_code) { unsigned long addr = read_cr2(); - printk("Page fault at linear address %p, regs %p, code %lx\n", addr, regs, - error_code); +#if defined(__x86_64__) + printk("Page fault at linear address %p, rip %p, code %lx\n", + addr, regs->rip, error_code); +#else + printk("Page fault at linear address %p, eip %p, code %lx\n", + addr, regs->eip, error_code); +#endif dump_regs(regs); page_walk(addr); do_exit(); @@ -195,7 +200,6 @@ static trap_info_t trap_table[] = { { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug }, { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error }, { 17, 0, __KERNEL_CS, (unsigned long)alignment_check }, - { 18, 0, __KERNEL_CS, (unsigned long)machine_check }, { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error }, { 0, 0, 0, 0 } }; diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/x86_32.S --- a/extras/mini-os/x86_32.S Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/x86_32.S Thu May 04 14:19:19 2006 +0100 @@ -30,10 +30,10 @@ hypercall_page: hypercall_page: .org 0x3000 -ES = 0x1c -ORIG_EAX = 0x20 -EIP = 0x24 -CS = 0x28 +ES = 0x20 +ORIG_EAX = 0x24 +EIP = 0x28 +CS = 0x2C #define ENTRY(X) .globl X ; X : @@ -69,7 +69,7 @@ ENTRY(divide_error) pushl $0 # no error code pushl $do_divide_error do_exception: - pushl %ds + pushl %ds pushl %eax xorl %eax, %eax pushl %ebp @@ -92,7 +92,7 @@ do_exception: pushl %edx pushl %eax call *%edi - addl $8,%esp + jmp ret_from_exception ret_from_exception: movb CS(%esp),%cl @@ -223,69 +223,54 @@ ENTRY(invalid_op) pushl $do_invalid_op jmp do_exception + ENTRY(coprocessor_segment_overrun) pushl $0 pushl $do_coprocessor_segment_overrun jmp do_exception + ENTRY(invalid_TSS) pushl $do_invalid_TSS jmp do_exception + ENTRY(segment_not_present) pushl $do_segment_not_present jmp do_exception + ENTRY(stack_segment) pushl $do_stack_segment jmp do_exception + ENTRY(general_protection) pushl $do_general_protection jmp do_exception + ENTRY(alignment_check) pushl $do_alignment_check jmp do_exception -# This handler is special, because it gets an extra value on its stack, -# which is the linear faulting address. -# fastcall register usage: %eax = pt_regs, %edx = error code, -# %ecx = fault address + ENTRY(page_fault) - pushl %ds - pushl %eax - xorl %eax, %eax - pushl %ebp - pushl %edi - pushl %esi - pushl %edx - decl %eax /* eax = -1 */ - pushl %ecx - pushl %ebx - cld - movl ORIG_EAX(%esp), %edi - movl %eax, ORIG_EAX(%esp) - movl %es, %ecx - movl %ecx, ES(%esp) - movl $(__KERNEL_DS),%eax - movl %eax, %ds - movl %eax, %es - pushl %edi - movl %esp, %eax - pushl %eax - call do_page_fault - jmp ret_from_exception - + pushl $do_page_fault + jmp do_exception + ENTRY(machine_check) pushl $0 pushl $do_machine_check jmp do_exception + ENTRY(spurious_interrupt_bug) pushl $0 pushl $do_spurious_interrupt_bug jmp do_exception + + ENTRY(thread_starter) popl %eax diff -r 55f73916d319 -r 51484df99be1 extras/mini-os/x86_64.S --- a/extras/mini-os/x86_64.S Tue May 02 18:17:59 2006 +0100 +++ b/extras/mini-os/x86_64.S Thu May 04 14:19:19 2006 +0100 @@ -13,40 +13,6 @@ #define ENTRY(X) .globl X ; X : .globl _start, shared_info, hypercall_page -#define SAVE_ALL \ - cld; \ - pushq %rdi; \ - pushq %rsi; \ - pushq %rdx; \ - pushq %rcx; \ - pushq %rax; \ - pushq %r8; \ - pushq %r9; \ - pushq %r10; \ - pushq %r11; \ - pushq %rbx; \ - pushq %rbp; \ - pushq %r12; \ - pushq %r13; \ - pushq %r14; \ - pushq %r15; - -#define RESTORE_ALL \ - popq %r15; \ - popq %r14; \ - popq %r13; \ - popq %r12; \ - popq %rbp; \ - popq %rbx; \ - popq %r11; \ - popq %r10; \ - popq %r9; \ - popq %r8; \ - popq %rax; \ - popq %rcx; \ - popq %rdx; \ - popq %rsi; \ - popq %rdi _start: cld @@ -240,7 +206,17 @@ error_call_handler: # CFI_ENDPROC .endm - +.macro errorentry sym +# XCPT_FRAME + movq (%rsp),%rcx + movq 8(%rsp),%r11 + addq $0x10,%rsp /* rsp points to the error code */ + pushq %rax +# CFI_ADJUST_CFA_OFFSET 8 + leaq \sym(%rip),%rax + jmp error_entry +# CFI_ENDPROC +.endm #define XEN_GET_VCPU_INFO(reg) movq HYPERVISOR_shared_info,reg #define XEN_PUT_VCPU_INFO(reg) @@ -319,159 +295,84 @@ ENTRY(failsafe_callback) popq %r11 iretq -error_code: - SAVE_ALL - movq %rsp,%rdi - movl 15*8+4(%rsp),%eax - leaq exception_table(%rip),%rdx - callq *(%rdx,%rax,8) - RESTORE_ALL - addq $8,%rsp - iretq - + +ENTRY(coprocessor_error) + zeroentry do_coprocessor_error + + +ENTRY(simd_coprocessor_error) + zeroentry do_simd_coprocessor_error + + +ENTRY(device_not_available) + zeroentry do_device_not_available + + +ENTRY(debug) +# INTR_FRAME +# CFI_ADJUST_CFA_OFFSET 8 */ + zeroentry do_debug +# CFI_ENDPROC + + +ENTRY(int3) +# INTR_FRAME +# CFI_ADJUST_CFA_OFFSET 8 */ + zeroentry do_int3 +# CFI_ENDPROC + +ENTRY(overflow) + zeroentry do_overflow + + +ENTRY(bounds) + zeroentry do_bounds + + +ENTRY(invalid_op) + zeroentry do_invalid_op + + +ENTRY(coprocessor_segment_overrun) + zeroentry do_coprocessor_segment_overrun + + +ENTRY(invalid_TSS) + errorentry do_invalid_TSS + + +ENTRY(segment_not_present) + errorentry do_segment_not_present + + +/* runs on exception stack */ +ENTRY(stack_segment) +# XCPT_FRAME + errorentry do_stack_segment +# CFI_ENDPROC + + +ENTRY(general_protection) + errorentry do_general_protection + + +ENTRY(alignment_check) + errorentry do_alignment_check + + ENTRY(divide_error) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_divide_error,4(%rsp) - jmp error_code - -ENTRY(coprocessor_error) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_copro_error,4(%rsp) - jmp error_code - -ENTRY(simd_coprocessor_error) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_simd_error,4(%rsp) - jmp error_code - -ENTRY(device_not_available) - popq %rcx - popq %r11 - movl $TRAP_no_device,4(%rsp) - jmp error_code - -ENTRY(debug) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_debug,4(%rsp) - jmp error_code - -ENTRY(int3) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_int3,4(%rsp) - jmp error_code - -ENTRY(overflow) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_overflow,4(%rsp) - jmp error_code - -ENTRY(bounds) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_bounds,4(%rsp) - jmp error_code - -ENTRY(invalid_op) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_invalid_op,4(%rsp) - jmp error_code - -ENTRY(coprocessor_segment_overrun) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_copro_seg,4(%rsp) - jmp error_code - -ENTRY(invalid_TSS) - popq %rcx - popq %r11 - movl $TRAP_invalid_tss,4(%rsp) - jmp error_code - -ENTRY(segment_not_present) - popq %rcx - popq %r11 - movl $TRAP_no_segment,4(%rsp) - jmp error_code - -ENTRY(stack_segment) - popq %rcx - popq %r11 - movl $TRAP_stack_error,4(%rsp) - jmp error_code - -ENTRY(general_protection) - popq %rcx - popq %r11 - movl $TRAP_gp_fault,4(%rsp) - jmp error_code - -ENTRY(alignment_check) - popq %rcx - popq %r11 - movl $TRAP_alignment_check,4(%rsp) - jmp error_code - -ENTRY(virt_cr2) - .quad 0 + zeroentry do_divide_error + + +ENTRY(spurious_interrupt_bug) + zeroentry do_spurious_interrupt_bug + + ENTRY(page_fault) - popq %rcx - popq %r11 - popq virt_cr2(%rip) - movl $TRAP_page_fault,4(%rsp) - jmp error_code - -ENTRY(machine_check) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_machine_check,4(%rsp) - jmp error_code - -ENTRY(spurious_interrupt_bug) - popq %rcx - popq %r11 - pushq $0 - movl $TRAP_spurious_int,4(%rsp) - jmp error_code - -ENTRY(exception_table) - .quad do_divide_error - .quad do_debug - .quad 0 # nmi - .quad do_int3 - .quad do_overflow - .quad do_bounds - .quad do_invalid_op - .quad 0 - .quad 0 - .quad do_coprocessor_segment_overrun - .quad do_invalid_TSS - .quad do_segment_not_present - .quad do_stack_segment - .quad do_general_protection - .quad do_page_fault - .quad do_spurious_interrupt_bug - .quad do_coprocessor_error - .quad do_alignment_check - .quad do_machine_check - .quad do_simd_coprocessor_error + errorentry do_page_fault + + + ENTRY(thread_starter) diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/arch/ia64/xen-mkbuildtree-pre --- a/linux-2.6-xen-sparse/arch/ia64/xen-mkbuildtree-pre Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/arch/ia64/xen-mkbuildtree-pre Thu May 04 14:19:19 2006 +0100 @@ -14,28 +14,12 @@ function try_to_mv() { fi } -function try_to_mkdir() { - if [ ! -e $2 ] - then - mv $1 $2 - mkdir $1 - fi -} - -try_to_mkdir mm mm.xen-x86 -try_to_mv net net.xen-x86 -try_to_mv kernel kernel.xen-x86 -try_to_mv drivers/acpi/tables.c drivers/acpi/tables.c.xen-x86 -#try_to_mv arch/xen/kernel drivers/xen/core -#try_to_mkdir arch/xen arch/xen.xen-x86 -#try_to_mv arch/xen.xen-x86/configs arch/xen -#try_to_mv include/asm-generic include/asm-generic.xen-x86 -try_to_mkdir include/linux include/linux.xen-x86 +try_to_mv mm/Kconfig mm/Kconfig.xen-x86 # need to grab a couple of xen-modified files for generic_page_range and # typedef pte_fn_t which are used by driver/xen blkif -ln -sf ../mm.xen-x86/memory.c mm/ -ln -sf ../linux.xen-x86/mm.h include/linux/ +#ln -sf ../mm.xen-x86/memory.c mm/ +#ln -sf ../linux.xen-x86/mm.h include/linux/ #eventually asm-xsi-offsets needs to be part of hypervisor.h/hypercall.h ln -sf ../../../../xen/include/asm-ia64/asm-xsi-offsets.h include/asm-ia64/xen/ diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/char/tpm/Kconfig --- a/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Thu May 04 14:19:19 2006 +0100 @@ -51,7 +51,7 @@ config TCG_INFINEON config TCG_XEN tristate "XEN TPM Interface" - depends on TCG_TPM && XEN && XEN_TPMDEV_FRONTEND + depends on TCG_TPM && XEN ---help--- If you want to make TPM support available to a Xen user domain, say Yes and it will @@ -60,4 +60,3 @@ config TCG_XEN tpm_xen. endmenu - diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/char/tpm/Makefile --- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Thu May 04 14:19:19 2006 +0100 @@ -8,4 +8,4 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o -obj-$(CONFIG_TCG_XEN) += tpm_xen.o +obj-$(CONFIG_TCG_XEN) += tpm_xen.o tpm_vtpm.o diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Thu May 04 14:19:19 2006 +0100 @@ -1,536 +1,767 @@ /* - * Copyright (C) 2004 IBM Corporation + * Copyright (c) 2005, IBM Corporation * - * Authors: - * Leendert van Doorn <leendert@xxxxxxxxxxxxxx> - * Dave Safford <safford@xxxxxxxxxxxxxx> - * Reiner Sailer <sailer@xxxxxxxxxxxxxx> - * Kylene Hall <kjhall@xxxxxxxxxx> - * Stefan Berger <stefanb@xxxxxxxxxx> + * Author: Stefan Berger, stefanb@xxxxxxxxxx + * Grant table support: Mahadevan Gomathisankaran * - * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx> + * This code has been derived from drivers/xen/netfront/netfront.c * - * Device driver for TCG/TCPA TPM (trusted platform module) for XEN. - * Specifications at www.trustedcomputinggroup.org + * Copyright (c) 2002-2004, K A Fraser * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. */ +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> #include <asm/uaccess.h> -#include <linux/list.h> -#include <xen/tpmfe.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include "tpm.h" - -/* read status bits */ -enum { - STATUS_BUSY = 0x01, - STATUS_DATA_AVAIL = 0x02, - STATUS_READY = 0x04 +#include <xen/evtchn.h> +#include <xen/interface/grant_table.h> +#include <xen/interface/io/tpmif.h> +#include <xen/xenbus.h> +#include "tpm_vtpm.h" + +#undef DEBUG + +/* local structures */ +struct tpm_private { + tpmif_tx_interface_t *tx; + atomic_t refcnt; + unsigned int evtchn; + unsigned int irq; + u8 is_connected; + u8 is_suspended; + + spinlock_t tx_lock; + + struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE]; + + atomic_t tx_busy; + void *tx_remember; + domid_t backend_id; + wait_queue_head_t wait_q; + + struct xenbus_device *dev; + int ring_ref; }; -#define MIN(x,y) ((x) < (y)) ? (x) : (y) - -struct transmission { - struct list_head next; - unsigned char *request; - unsigned int request_len; - unsigned char *rcv_buffer; - unsigned int buffersize; - unsigned int flags; +struct tx_buffer { + unsigned int size; // available space in data + unsigned int len; // used space in data + unsigned char *data; // pointer to a page }; -enum { - TRANSMISSION_FLAG_WAS_QUEUED = 0x1 + +/* locally visible variables */ +static grant_ref_t gref_head; +static struct tpm_private *my_priv; + +/* local function prototypes */ +static irqreturn_t tpmif_int(int irq, + void *tpm_priv, + struct pt_regs *ptregs); +static void tpmif_rx_action(unsigned long unused); +static int tpmif_connect(struct xenbus_device *dev, + struct tpm_private *tp, + domid_t domid); +static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0); +static int tpmif_allocate_tx_buffers(struct tpm_private *tp); +static void tpmif_free_tx_buffers(struct tpm_private *tp); +static void tpmif_set_connected_state(struct tpm_private *tp, + u8 newstate); +static int tpm_xmit(struct tpm_private *tp, + const u8 * buf, size_t count, int userbuffer, + void *remember); +static void destroy_tpmring(struct tpm_private *tp); + +#define DPRINTK(fmt, args...) \ + pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args) +#define IPRINTK(fmt, args...) \ + printk(KERN_INFO "xen_tpm_fr: " fmt, ##args) +#define WPRINTK(fmt, args...) \ + printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args) + +#define GRANT_INVALID_REF 0 + + +static inline int +tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len, + int isuserbuffer) +{ + int copied = len; + + if (len > txb->size) { + copied = txb->size; + } + if (isuserbuffer) { + if (copy_from_user(txb->data, src, copied)) + return -EFAULT; + } else { + memcpy(txb->data, src, copied); + } + txb->len = len; + return copied; +} + +static inline struct tx_buffer *tx_buffer_alloc(void) +{ + struct tx_buffer *txb = kzalloc(sizeof (struct tx_buffer), + GFP_KERNEL); + + if (txb) { + txb->len = 0; + txb->size = PAGE_SIZE; + txb->data = (unsigned char *)__get_free_page(GFP_KERNEL); + if (txb->data == NULL) { + kfree(txb); + txb = NULL; + } + } + return txb; +} + + +static inline void tx_buffer_free(struct tx_buffer *txb) +{ + if (txb) { + free_page((long)txb->data); + kfree(txb); + } +} + +/************************************************************** + Utility function for the tpm_private structure +**************************************************************/ +static inline void tpm_private_init(struct tpm_private *tp) +{ + spin_lock_init(&tp->tx_lock); + init_waitqueue_head(&tp->wait_q); + atomic_set(&tp->refcnt, 1); +} + +static inline void tpm_private_put(void) +{ + if ( atomic_dec_and_test(&my_priv->refcnt)) { + tpmif_free_tx_buffers(my_priv); + kfree(my_priv); + my_priv = NULL; + } +} + +static struct tpm_private *tpm_private_get(void) +{ + int err; + if (!my_priv) { + my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL); + if (my_priv) { + tpm_private_init(my_priv); + err = tpmif_allocate_tx_buffers(my_priv); + if (err < 0) { + tpm_private_put(); + } + } + } else { + atomic_inc(&my_priv->refcnt); + } + return my_priv; +} + +/************************************************************** + + The interface to let the tpm plugin register its callback + function and send data to another partition using this module + +**************************************************************/ + +static DEFINE_MUTEX(suspend_lock); +/* + * Send data via this module by calling this function + */ +int vtpm_vd_send(struct tpm_chip *chip, + struct tpm_private *tp, + const u8 * buf, size_t count, void *ptr) +{ + int sent; + + mutex_lock(&suspend_lock); + sent = tpm_xmit(tp, buf, count, 0, ptr); + mutex_unlock(&suspend_lock); + + return sent; +} + +/************************************************************** + XENBUS support code +**************************************************************/ + +static int setup_tpmring(struct xenbus_device *dev, + struct tpm_private *tp) +{ + tpmif_tx_interface_t *sring; + int err; + + tp->ring_ref = GRANT_INVALID_REF; + + sring = (void *)__get_free_page(GFP_KERNEL); + if (!sring) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); + return -ENOMEM; + } + tp->tx = sring; + + err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx)); + if (err < 0) { + free_page((unsigned long)sring); + tp->tx = NULL; + xenbus_dev_fatal(dev, err, "allocating grant reference"); + goto fail; + } + tp->ring_ref = err; + + err = tpmif_connect(dev, tp, dev->otherend_id); + if (err) + goto fail; + + return 0; +fail: + destroy_tpmring(tp); + return err; +} + + +static void destroy_tpmring(struct tpm_private *tp) +{ + tpmif_set_connected_state(tp, 0); + + if (tp->ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(tp->ring_ref, 0, + (unsigned long)tp->tx); + tp->ring_ref = GRANT_INVALID_REF; + tp->tx = NULL; + } + + if (tp->irq) + unbind_from_irqhandler(tp->irq, tp); + + tp->evtchn = tp->irq = 0; +} + + +static int talk_to_backend(struct xenbus_device *dev, + struct tpm_private *tp) +{ + const char *message = NULL; + int err; + xenbus_transaction_t xbt; + + err = setup_tpmring(dev, tp); + if (err) { + xenbus_dev_fatal(dev, err, "setting up ring"); + goto out; + } + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + xenbus_dev_fatal(dev, err, "starting transaction"); + goto destroy_tpmring; + } + + err = xenbus_printf(xbt, dev->nodename, + "ring-ref","%u", tp->ring_ref); + if (err) { + message = "writing ring-ref"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, + "event-channel", "%u", tp->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0); + if (err == -EAGAIN) + goto again; + if (err) { + xenbus_dev_fatal(dev, err, "completing transaction"); + goto destroy_tpmring; + } + + xenbus_switch_state(dev, XenbusStateConnected); + + return 0; + +abort_transaction: + xenbus_transaction_end(xbt, 1); + if (message) + xenbus_dev_error(dev, err, "%s", message); +destroy_tpmring: + destroy_tpmring(tp); +out: + return err; +} + +/** + * Callback received when the backend's state changes. + */ +static void backend_changed(struct xenbus_device *dev, + XenbusState backend_state) +{ + struct tpm_private *tp = dev->data; + DPRINTK("\n"); + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateUnknown: + break; + + case XenbusStateConnected: + tpmif_set_connected_state(tp, 1); + break; + + case XenbusStateClosing: + tpmif_set_connected_state(tp, 0); + break; + + case XenbusStateClosed: + if (tp->is_suspended == 0) { + device_unregister(&dev->dev); + } + xenbus_switch_state(dev, XenbusStateClosed); + break; + } +} + + +static int tpmfront_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int err; + int handle; + struct tpm_private *tp = tpm_private_get(); + + if (!tp) + return -ENOMEM; + + err = xenbus_scanf(XBT_NULL, dev->nodename, + "handle", "%i", &handle); + if (XENBUS_EXIST_ERR(err)) + return err; + + if (err < 0) { + xenbus_dev_fatal(dev,err,"reading virtual-device"); + return err; + } + + tp->dev = dev; + dev->data = tp; + + err = talk_to_backend(dev, tp); + if (err) { + tpm_private_put(); + dev->data = NULL; + return err; + } + return 0; +} + + +static int tpmfront_remove(struct xenbus_device *dev) +{ + struct tpm_private *tp = (struct tpm_private *)dev->data; + destroy_tpmring(tp); + return 0; +} + +static int tpmfront_suspend(struct xenbus_device *dev) +{ + struct tpm_private *tp = (struct tpm_private *)dev->data; + u32 ctr; + + /* lock, so no app can send */ + mutex_lock(&suspend_lock); + tp->is_suspended = 1; + + for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 25; ctr++) { + if ((ctr % 10) == 0) + printk("TPM-FE [INFO]: Waiting for outstanding request.\n"); + /* + * Wait for a request to be responded to. + */ + interruptible_sleep_on_timeout(&tp->wait_q, 100); + } + xenbus_switch_state(dev, XenbusStateClosed); + + if (atomic_read(&tp->tx_busy)) { + /* + * A temporary work-around. + */ + printk("TPM-FE [WARNING]: Resetting busy flag."); + atomic_set(&tp->tx_busy, 0); + } + + return 0; +} + +static int tpmfront_resume(struct xenbus_device *dev) +{ + struct tpm_private *tp = (struct tpm_private *)dev->data; + destroy_tpmring(tp); + return talk_to_backend(dev, tp); +} + +static int tpmif_connect(struct xenbus_device *dev, + struct tpm_private *tp, + domid_t domid) +{ + int err; + + tp->backend_id = domid; + + err = xenbus_alloc_evtchn(dev, &tp->evtchn); + if (err) + return err; + + err = bind_evtchn_to_irqhandler(tp->evtchn, + tpmif_int, SA_SAMPLE_RANDOM, "tpmif", + tp); + if (err <= 0) { + WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err); + return err; + } + + tp->irq = err; + return 0; +} + +static struct xenbus_device_id tpmfront_ids[] = { + { "vtpm" }, + { "" } }; -struct data_exchange { - struct transmission *current_request; - spinlock_t req_list_lock; - wait_queue_head_t req_wait_queue; - - struct list_head queued_requests; - - struct transmission *current_response; - spinlock_t resp_list_lock; - wait_queue_head_t resp_wait_queue; // processes waiting for responses - - struct transmission *req_cancelled; // if a cancellation was encounterd - - unsigned int fe_status; - unsigned int flags; +static struct xenbus_driver tpmfront = { + .name = "vtpm", + .owner = THIS_MODULE, + .ids = tpmfront_ids, + .probe = tpmfront_probe, + .remove = tpmfront_remove, + .resume = tpmfront_resume, + .otherend_changed = backend_changed, + .suspend = tpmfront_suspend, }; -enum { - DATAEX_FLAG_QUEUED_ONLY = 0x1 +static void __init init_tpm_xenbus(void) +{ + xenbus_register_frontend(&tpmfront); +} + +static void __exit exit_tpm_xenbus(void) +{ + xenbus_unregister_driver(&tpmfront); +} + +static int tpmif_allocate_tx_buffers(struct tpm_private *tp) +{ + unsigned int i; + + for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { + tp->tx_buffers[i] = tx_buffer_alloc(); + if (!tp->tx_buffers[i]) { + tpmif_free_tx_buffers(tp); + return -ENOMEM; + } + } + return 0; +} + +static void tpmif_free_tx_buffers(struct tpm_private *tp) +{ + unsigned int i; + + for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { + tx_buffer_free(tp->tx_buffers[i]); + } +} + +static void tpmif_rx_action(unsigned long priv) +{ + struct tpm_private *tp = (struct tpm_private *)priv; + + int i = 0; + unsigned int received; + unsigned int offset = 0; + u8 *buffer; + tpmif_tx_request_t *tx; + tx = &tp->tx->ring[i].req; + + atomic_set(&tp->tx_busy, 0); + wake_up_interruptible(&tp->wait_q); + + received = tx->size; + + buffer = kmalloc(received, GFP_ATOMIC); + if (NULL == buffer) { + goto exit; + } + + for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) { + struct tx_buffer *txb = tp->tx_buffers[i]; + tpmif_tx_request_t *tx; + unsigned int tocopy; + + tx = &tp->tx->ring[i].req; + tocopy = tx->size; + if (tocopy > PAGE_SIZE) { + tocopy = PAGE_SIZE; + } + + memcpy(&buffer[offset], txb->data, tocopy); + + gnttab_release_grant_reference(&gref_head, tx->ref); + + offset += tocopy; + } + + vtpm_vd_recv(buffer, received, tp->tx_remember); + kfree(buffer); + +exit: + + return; +} + + +static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) +{ + struct tpm_private *tp = tpm_priv; + unsigned long flags; + + spin_lock_irqsave(&tp->tx_lock, flags); + tpmif_rx_tasklet.data = (unsigned long)tp; + tasklet_schedule(&tpmif_rx_tasklet); + spin_unlock_irqrestore(&tp->tx_lock, flags); + + return IRQ_HANDLED; +} + + +static int tpm_xmit(struct tpm_private *tp, + const u8 * buf, size_t count, int isuserbuffer, + void *remember) +{ + tpmif_tx_request_t *tx; + TPMIF_RING_IDX i; + unsigned int offset = 0; + + spin_lock_irq(&tp->tx_lock); + + if (unlikely(atomic_read(&tp->tx_busy))) { + printk("tpm_xmit: There's an outstanding request/response " + "on the way!\n"); + spin_unlock_irq(&tp->tx_lock); + return -EBUSY; + } + + if (tp->is_connected != 1) { + spin_unlock_irq(&tp->tx_lock); + return -EIO; + } + + for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) { + struct tx_buffer *txb = tp->tx_buffers[i]; + int copied; + + if (NULL == txb) { + DPRINTK("txb (i=%d) is NULL. buffers initilized?\n" + "Not transmitting anything!\n", i); + spin_unlock_irq(&tp->tx_lock); + return -EFAULT; + } + copied = tx_buffer_copy(txb, &buf[offset], count, + isuserbuffer); + if (copied < 0) { + /* An error occurred */ + spin_unlock_irq(&tp->tx_lock); + return copied; + } + count -= copied; + offset += copied; + + tx = &tp->tx->ring[i].req; + + tx->addr = virt_to_machine(txb->data); + tx->size = txb->len; + + DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n", + txb->data[0],txb->data[1],txb->data[2],txb->data[3]); + + /* get the granttable reference for this page */ + tx->ref = gnttab_claim_grant_reference(&gref_head); + + if (-ENOSPC == tx->ref) { + spin_unlock_irq(&tp->tx_lock); + DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__); + return -ENOSPC; + } + gnttab_grant_foreign_access_ref( tx->ref, + tp->backend_id, + (tx->addr >> PAGE_SHIFT), + 0 /*RW*/); + wmb(); + } + + atomic_set(&tp->tx_busy, 1); + tp->tx_remember = remember; + mb(); + + DPRINTK("Notifying backend via event channel %d\n", + tp->evtchn); + + notify_remote_via_irq(tp->irq); + + spin_unlock_irq(&tp->tx_lock); + return offset; +} + + +static void tpmif_notify_upperlayer(struct tpm_private *tp) +{ + /* + * Notify upper layer about the state of the connection + * to the BE. + */ + if (tp->is_connected) { + vtpm_vd_status(TPM_VD_STATUS_CONNECTED); + } else { + vtpm_vd_status(TPM_VD_STATUS_DISCONNECTED); + } +} + + +static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected) +{ + /* + * Don't notify upper layer if we are in suspend mode and + * should disconnect - assumption is that we will resume + * The mutex keeps apps from sending. + */ + if (is_connected == 0 && tp->is_suspended == 1) { + return; + } + + /* + * Unlock the mutex if we are connected again + * after being suspended - now resuming. + * This also removes the suspend state. + */ + if (is_connected == 1 && tp->is_suspended == 1) { + tp->is_suspended = 0; + /* unlock, so apps can resume sending */ + mutex_unlock(&suspend_lock); + } + + if (is_connected != tp->is_connected) { + tp->is_connected = is_connected; + tpmif_notify_upperlayer(tp); + } +} + + + +/* ================================================================= + * Initialization function. + * ================================================================= + */ + +struct tpm_virtual_device tvd = { + .max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE, }; -static struct data_exchange dataex; - -static unsigned long disconnect_time; - -static struct tpmfe_device tpmfe; - -/* local function prototypes */ -static void __exit cleanup_xen(void); - - -/* ============================================================= - * Some utility functions - * ============================================================= - */ -static inline struct transmission * -transmission_alloc(void) -{ - return kzalloc(sizeof(struct transmission), GFP_KERNEL); -} - -static inline unsigned char * -transmission_set_buffer(struct transmission *t, - unsigned char *buffer, unsigned int len) -{ - kfree(t->request); - t->request = kmalloc(len, GFP_KERNEL); - if (t->request) { - memcpy(t->request, - buffer, - len); - t->request_len = len; - } - return t->request; -} - -static inline void -transmission_free(struct transmission *t) -{ - kfree(t->request); - kfree(t->rcv_buffer); - kfree(t); -} - -/* ============================================================= - * Interface with the TPM shared memory driver for XEN - * ============================================================= - */ -static int tpm_recv(const u8 *buffer, size_t count, const void *ptr) -{ - int ret_size = 0; - struct transmission *t; - - /* - * The list with requests must contain one request - * only and the element there must be the one that - * was passed to me from the front-end. - */ - if (dataex.current_request != ptr) { - printk("WARNING: The request pointer is different than the " - "pointer the shared memory driver returned to me. " - "%p != %p\n", - dataex.current_request, ptr); - } - - /* - * If the request has been cancelled, just quit here - */ - if (dataex.req_cancelled == (struct transmission *)ptr) { - if (dataex.current_request == dataex.req_cancelled) { - dataex.current_request = NULL; - } - transmission_free(dataex.req_cancelled); - dataex.req_cancelled = NULL; - return 0; - } - - if (NULL != (t = dataex.current_request)) { - transmission_free(t); - dataex.current_request = NULL; - } - - t = transmission_alloc(); - if (t) { - unsigned long flags; - t->rcv_buffer = kmalloc(count, GFP_KERNEL); - if (! t->rcv_buffer) { - transmission_free(t); - return -ENOMEM; - } - t->buffersize = count; - memcpy(t->rcv_buffer, buffer, count); - ret_size = count; - - spin_lock_irqsave(&dataex.resp_list_lock ,flags); - dataex.current_response = t; - spin_unlock_irqrestore(&dataex.resp_list_lock, flags); - wake_up_interruptible(&dataex.resp_wait_queue); - } - return ret_size; -} - - -static void tpm_fe_status(unsigned int flags) -{ - dataex.fe_status = flags; - if ((dataex.fe_status & TPMFE_STATUS_CONNECTED) == 0) { - disconnect_time = jiffies; - } -} - -/* ============================================================= - * Interface with the generic TPM driver - * ============================================================= - */ -static int tpm_xen_recv(struct tpm_chip *chip, u8 * buf, size_t count) -{ - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&dataex.resp_list_lock, flags); - /* - * Check if the previous operation only queued the command - * In this case there won't be a response, so I just - * return from here and reset that flag. In any other - * case I should receive a response from the back-end. - */ - if ((dataex.flags & DATAEX_FLAG_QUEUED_ONLY) != 0) { - dataex.flags &= ~DATAEX_FLAG_QUEUED_ONLY; - spin_unlock_irqrestore(&dataex.resp_list_lock, flags); - /* - * a little hack here. The first few measurements - * are queued since there's no way to talk to the - * TPM yet (due to slowness of the control channel) - * So we just make IMA happy by giving it 30 NULL - * bytes back where the most important part is - * that the result code is '0'. - */ - - count = MIN(count, 30); - memset(buf, 0x0, count); - return count; - } - /* - * Check whether something is in the responselist and if - * there's nothing in the list wait for something to appear. - */ - - if (NULL == dataex.current_response) { - spin_unlock_irqrestore(&dataex.resp_list_lock, flags); - interruptible_sleep_on_timeout(&dataex.resp_wait_queue, - 1000); - spin_lock_irqsave(&dataex.resp_list_lock ,flags); - } - - if (NULL != dataex.current_response) { - struct transmission *t = dataex.current_response; - dataex.current_response = NULL; - rc = MIN(count, t->buffersize); - memcpy(buf, t->rcv_buffer, rc); - transmission_free(t); - } - - spin_unlock_irqrestore(&dataex.resp_list_lock, flags); - return rc; -} - -static int tpm_xen_send(struct tpm_chip *chip, u8 * buf, size_t count) -{ - /* - * We simply pass the packet onto the XEN shared - * memory driver. - */ - unsigned long flags; +static int __init tpmif_init(void) +{ int rc; - struct transmission *t = transmission_alloc(); - - spin_lock_irqsave(&dataex.req_list_lock, flags); - /* - * If there's a current request, it must be the - * previous request that has timed out. - */ - if (dataex.current_request != NULL) { - printk("WARNING: Sending although there is a request outstanding.\n" - " Previous request must have timed out.\n"); - transmission_free(dataex.current_request); - dataex.current_request = NULL; - } - - if (t != NULL) { - unsigned int error = 0; - /* - * Queue the packet if the driver below is not - * ready, yet, or there is any packet already - * in the queue. - * If the driver below is ready, unqueue all - * packets first before sending our current - * packet. - * For each unqueued packet, except for the - * last (=current) packet, call the function - * tpm_xen_recv to wait for the response to come - * back. - */ - if ((dataex.fe_status & TPMFE_STATUS_CONNECTED) == 0) { - if (time_after(jiffies, disconnect_time + HZ * 10)) { - rc = -ENOENT; - } else { - /* - * copy the request into the buffer - */ - if (transmission_set_buffer(t, buf, count) - == NULL) { - transmission_free(t); - rc = -ENOMEM; - goto exit; - } - dataex.flags |= DATAEX_FLAG_QUEUED_ONLY; - list_add_tail(&t->next, &dataex.queued_requests); - rc = 0; - } - } else { - /* - * Check whether there are any packets in the queue - */ - while (!list_empty(&dataex.queued_requests)) { - /* - * Need to dequeue them. - * Read the result into a dummy buffer. - */ - unsigned char buffer[1]; - struct transmission *qt = (struct transmission *) dataex.queued_requests.next; - list_del(&qt->next); - dataex.current_request = qt; - spin_unlock_irqrestore(&dataex.req_list_lock, - flags); - - rc = tpm_fe_send(tpmfe.tpm_private, - qt->request, - qt->request_len, - qt); - - if (rc < 0) { - spin_lock_irqsave(&dataex.req_list_lock, flags); - if ((qt = dataex.current_request) != NULL) { - /* - * requeue it at the beginning - * of the list - */ - list_add(&qt->next, - &dataex.queued_requests); - } - dataex.current_request = NULL; - error = 1; - break; - } - /* - * After this point qt is not valid anymore! - * It is freed when the front-end is delivering the data - * by calling tpm_recv - */ - - /* - * Try to receive the response now into the provided dummy - * buffer (I don't really care about this response since - * there is no receiver anymore for this response) - */ - rc = tpm_xen_recv(chip, buffer, sizeof(buffer)); - - spin_lock_irqsave(&dataex.req_list_lock, flags); - } - - if (error == 0) { - /* - * Finally, send the current request. - */ - dataex.current_request = t; - /* - * Call the shared memory driver - * Pass to it the buffer with the request, the - * amount of bytes in the request and - * a void * pointer (here: transmission structure) - */ - rc = tpm_fe_send(tpmfe.tpm_private, - buf, count, t); - /* - * The generic TPM driver will call - * the function to receive the response. - */ - if (rc < 0) { - dataex.current_request = NULL; - goto queue_it; - } - } else { -queue_it: - if (transmission_set_buffer(t, buf, count) == NULL) { - transmission_free(t); - rc = -ENOMEM; - goto exit; - } - /* - * An error occurred. Don't event try - * to send the current request. Just - * queue it. - */ - dataex.flags |= DATAEX_FLAG_QUEUED_ONLY; - list_add_tail(&t->next, - &dataex.queued_requests); - rc = 0; - } - } - } else { - rc = -ENOMEM; - } - -exit: - spin_unlock_irqrestore(&dataex.req_list_lock, flags); - return rc; -} - -static void tpm_xen_cancel(struct tpm_chip *chip) -{ - unsigned long flags; - spin_lock_irqsave(&dataex.resp_list_lock,flags); - - dataex.req_cancelled = dataex.current_request; - - spin_unlock_irqrestore(&dataex.resp_list_lock,flags); -} - -static u8 tpm_xen_status(struct tpm_chip *chip) -{ - unsigned long flags; - u8 rc = 0; - spin_lock_irqsave(&dataex.resp_list_lock, flags); - /* - * Data are available if: - * - there's a current response - * - the last packet was queued only (this is fake, but necessary to - * get the generic TPM layer to call the receive function.) - */ - if (NULL != dataex.current_response || - 0 != (dataex.flags & DATAEX_FLAG_QUEUED_ONLY)) { - rc = STATUS_DATA_AVAIL; - } - spin_unlock_irqrestore(&dataex.resp_list_lock, flags); - return rc; -} - -static struct file_operations tpm_xen_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = tpm_open, - .read = tpm_read, - .write = tpm_write, - .release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); - -static struct attribute* xen_attrs[] = { - &dev_attr_pubek.attr, - &dev_attr_pcrs.attr, - &dev_attr_caps.attr, - &dev_attr_cancel.attr, - NULL, -}; - -static struct attribute_group xen_attr_grp = { .attrs = xen_attrs }; - -static struct tpm_vendor_specific tpm_xen = { - .recv = tpm_xen_recv, - .send = tpm_xen_send, - .cancel = tpm_xen_cancel, - .status = tpm_xen_status, - .req_complete_mask = STATUS_BUSY | STATUS_DATA_AVAIL, - .req_complete_val = STATUS_DATA_AVAIL, - .req_canceled = STATUS_READY, - .base = 0, - .attr_group = &xen_attr_grp, - .miscdev.fops = &tpm_xen_ops, - .buffersize = 64 * 1024, -}; - -static struct platform_device *pdev; - -static struct tpmfe_device tpmfe = { - .receive = tpm_recv, - .status = tpm_fe_status, -}; - - -static int __init init_xen(void) -{ - int rc; + struct tpm_private *tp; if ((xen_start_info->flags & SIF_INITDOMAIN)) { return -EPERM; } - /* - * Register device with the low lever front-end - * driver - */ - if ((rc = tpm_fe_register_receiver(&tpmfe)) < 0) { - goto err_exit; - } - - /* - * Register our device with the system. - */ - pdev = platform_device_register_simple("tpm_vtpm", -1, NULL, 0); - if (IS_ERR(pdev)) { - rc = PTR_ERR(pdev); - goto err_unreg_fe; - } - - tpm_xen.buffersize = tpmfe.max_tx_size; - - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_xen)) < 0) { - goto err_unreg_pdev; - } - - dataex.current_request = NULL; - spin_lock_init(&dataex.req_list_lock); - init_waitqueue_head(&dataex.req_wait_queue); - INIT_LIST_HEAD(&dataex.queued_requests); - - dataex.current_response = NULL; - spin_lock_init(&dataex.resp_list_lock); - init_waitqueue_head(&dataex.resp_wait_queue); - - disconnect_time = jiffies; - - return 0; - - -err_unreg_pdev: - platform_device_unregister(pdev); -err_unreg_fe: - tpm_fe_unregister_receiver(); - -err_exit: + + tp = tpm_private_get(); + if (!tp) { + rc = -ENOMEM; + goto failexit; + } + + tvd.tpm_private = tp; + rc = init_vtpm(&tvd); + if (rc) + goto init_vtpm_failed; + + IPRINTK("Initialising the vTPM driver.\n"); + if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE, + &gref_head ) < 0) { + rc = -EFAULT; + goto gnttab_alloc_failed; + } + + init_tpm_xenbus(); + return 0; + +gnttab_alloc_failed: + cleanup_vtpm(); +init_vtpm_failed: + tpm_private_put(); +failexit: + return rc; } -static void __exit cleanup_xen(void) -{ - struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); - if (chip) { - tpm_remove_hardware(chip->dev); - platform_device_unregister(pdev); - tpm_fe_unregister_receiver(); - } -} - -module_init(init_xen); -module_exit(cleanup_xen); - -MODULE_AUTHOR("Stefan Berger (stefanb@xxxxxxxxxx)"); -MODULE_DESCRIPTION("TPM Driver for XEN (shared memory)"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); + +static void __exit tpmif_exit(void) +{ + cleanup_vtpm(); + tpm_private_put(); + exit_tpm_xenbus(); + gnttab_free_grant_references(gref_head); +} + +module_init(tpmif_init); +module_exit(tpmif_exit); + +MODULE_LICENSE("Dual BSD/GPL"); + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/Kconfig --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig Thu May 04 14:19:19 2006 +0100 @@ -173,14 +173,6 @@ config XEN_BLKDEV_TAP to a character device, allowing device prototyping in application space. Odds are that you want to say N here. -config XEN_TPMDEV_FRONTEND - tristate "TPM-device frontend driver" - default n - select TCG_TPM - select TCG_XEN - help - The TPM-device frontend driver. - config XEN_SCRUB_PAGES bool "Scrub memory before freeing it to Xen" default y diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Thu May 04 14:19:19 2006 +0100 @@ -16,7 +16,6 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blk obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ -obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmback/common.h --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Thu May 04 14:19:19 2006 +0100 @@ -50,6 +50,8 @@ typedef struct tpmif_st { grant_handle_t shmem_handle; grant_ref_t shmem_ref; struct page *pagerange; + + char devname[20]; } tpmif_t; void tpmif_disconnect_complete(tpmif_t * tpmif); diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c Thu May 04 14:19:19 2006 +0100 @@ -32,6 +32,7 @@ static tpmif_t *alloc_tpmif(domid_t domi tpmif->domid = domid; tpmif->status = DISCONNECTED; tpmif->tpm_instance = instance; + snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid); atomic_set(&tpmif->refcnt, 1); tpmif->pagerange = balloon_alloc_empty_page_range(TPMIF_TX_RING_SIZE); @@ -144,7 +145,7 @@ int tpmif_map(tpmif_t *tpmif, unsigned l tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr; tpmif->irq = bind_evtchn_to_irqhandler( - tpmif->evtchn, tpmif_be_int, 0, "tpmif-backend", tpmif); + tpmif->evtchn, tpmif_be_int, 0, tpmif->devname, tpmif); tpmif->shmem_ref = shared_page; tpmif->active = 1; diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c Thu May 04 14:19:19 2006 +0100 @@ -28,7 +28,8 @@ struct data_exchange { struct list_head pending_pak; struct list_head current_pak; unsigned int copied_so_far; - u8 has_opener; + u8 has_opener:1; + u8 aborted:1; rwlock_t pak_lock; // protects all of the previous fields wait_queue_head_t wait_queue; }; @@ -101,6 +102,16 @@ static inline int copy_to_buffer(void *t return 0; } + +static void dataex_init(struct data_exchange *dataex) +{ + INIT_LIST_HEAD(&dataex->pending_pak); + INIT_LIST_HEAD(&dataex->current_pak); + dataex->has_opener = 0; + rwlock_init(&dataex->pak_lock); + init_waitqueue_head(&dataex->wait_queue); +} + /*************************************************************** Packet-related functions ***************************************************************/ @@ -148,11 +159,12 @@ static struct packet *packet_alloc(tpmif u32 size, u8 req_tag, u8 flags) { struct packet *pak = NULL; - pak = kzalloc(sizeof (struct packet), GFP_KERNEL); + pak = kzalloc(sizeof (struct packet), GFP_ATOMIC); if (NULL != pak) { if (tpmif) { pak->tpmif = tpmif; pak->tpm_instance = tpmif->tpm_instance; + tpmif_get(tpmif); } pak->data_len = size; pak->req_tag = req_tag; @@ -180,6 +192,9 @@ static void packet_free(struct packet *p if (timer_pending(&pak->processing_timer)) { BUG(); } + + if (pak->tpmif) + tpmif_put(pak->tpmif); kfree(pak->data_buffer); /* * cannot do tpmif_put(pak->tpmif); bad things happen @@ -271,7 +286,6 @@ int _packet_write(struct packet *pak, struct gnttab_map_grant_ref map_op; struct gnttab_unmap_grant_ref unmap_op; tpmif_tx_request_t *tx; - unsigned long pfn, mfn, mfn_orig; tx = &tpmif->tx->ring[i].req; @@ -294,12 +308,6 @@ int _packet_write(struct packet *pak, DPRINTK(" Grant table operation failure !\n"); return 0; } - - pfn = __pa(MMAP_VADDR(tpmif, i)) >> PAGE_SHIFT; - mfn = FOREIGN_FRAME(map_op.dev_bus_addr >> PAGE_SHIFT); - mfn_orig = pfn_to_mfn(pfn); - - set_phys_to_machine(pfn, mfn); tocopy = MIN(size - offset, PAGE_SIZE); @@ -310,8 +318,6 @@ int _packet_write(struct packet *pak, return -EFAULT; } tx->size = tocopy; - - set_phys_to_machine(pfn, mfn_orig); gnttab_set_unmap_op(&unmap_op, MMAP_VADDR(tpmif, i), GNTMAP_host_map, handle); @@ -514,27 +520,41 @@ static ssize_t vtpm_op_read(struct file unsigned long flags; write_lock_irqsave(&dataex.pak_lock, flags); + if (dataex.aborted) { + dataex.aborted = 0; + dataex.copied_so_far = 0; + write_unlock_irqrestore(&dataex.pak_lock, flags); + return -EIO; + } if (list_empty(&dataex.pending_pak)) { write_unlock_irqrestore(&dataex.pak_lock, flags); wait_event_interruptible(dataex.wait_queue, !list_empty(&dataex.pending_pak)); write_lock_irqsave(&dataex.pak_lock, flags); + dataex.copied_so_far = 0; } if (!list_empty(&dataex.pending_pak)) { unsigned int left; + pak = list_entry(dataex.pending_pak.next, struct packet, next); - left = pak->data_len - dataex.copied_so_far; + list_del(&pak->next); + write_unlock_irqrestore(&dataex.pak_lock, flags); DPRINTK("size given by app: %d, available: %d\n", size, left); ret_size = MIN(size, left); ret_size = packet_read(pak, ret_size, data, size, 1); + + write_lock_irqsave(&dataex.pak_lock, flags); + if (ret_size < 0) { - ret_size = -EFAULT; + del_singleshot_timer_sync(&pak->processing_timer); + packet_free(pak); + dataex.copied_so_far = 0; } else { DPRINTK("Copied %d bytes to user buffer\n", ret_size); @@ -545,7 +565,6 @@ static ssize_t vtpm_op_read(struct file del_singleshot_timer_sync(&pak-> processing_timer); - list_del(&pak->next); list_add_tail(&pak->next, &dataex.current_pak); /* * The more fontends that are handled at the same time, @@ -554,6 +573,8 @@ static ssize_t vtpm_op_read(struct file mod_timer(&pak->processing_timer, jiffies + (num_frontends * 60 * HZ)); dataex.copied_so_far = 0; + } else { + list_add(&pak->next, &dataex.pending_pak); } } } @@ -601,8 +622,8 @@ static ssize_t vtpm_op_write(struct file if (pak == NULL) { write_unlock_irqrestore(&dataex.pak_lock, flags); - printk(KERN_ALERT "No associated packet! (inst=%d)\n", - ntohl(vrh.instance_no)); + DPRINTK(KERN_ALERT "No associated packet! (inst=%d)\n", + ntohl(vrh.instance_no)); return -EFAULT; } @@ -784,15 +805,17 @@ static int tpm_send_fail_message(struct return rc; } -static void _vtpm_release_packets(struct list_head *head, - tpmif_t * tpmif, int send_msgs) -{ +static int _vtpm_release_packets(struct list_head *head, + tpmif_t * tpmif, int send_msgs) +{ + int aborted = 0; + int c = 0; struct packet *pak; - struct list_head *pos, - *tmp; + struct list_head *pos, *tmp; list_for_each_safe(pos, tmp, head) { pak = list_entry(pos, struct packet, next); + c += 1; if (tpmif == NULL || pak->tpmif == tpmif) { int can_send = 0; @@ -808,8 +831,11 @@ static void _vtpm_release_packets(struct tpm_send_fail_message(pak, pak->req_tag); } packet_free(pak); - } - } + if (c == 1) + aborted = 1; + } + } + return aborted; } int vtpm_release_packets(tpmif_t * tpmif, int send_msgs) @@ -818,7 +844,9 @@ int vtpm_release_packets(tpmif_t * tpmif write_lock_irqsave(&dataex.pak_lock, flags); - _vtpm_release_packets(&dataex.pending_pak, tpmif, send_msgs); + dataex.aborted = _vtpm_release_packets(&dataex.pending_pak, + tpmif, + send_msgs); _vtpm_release_packets(&dataex.current_pak, tpmif, send_msgs); write_unlock_irqrestore(&dataex.pak_lock, flags); @@ -1020,11 +1048,7 @@ static int __init tpmback_init(void) return rc; } - INIT_LIST_HEAD(&dataex.pending_pak); - INIT_LIST_HEAD(&dataex.current_pak); - dataex.has_opener = 0; - rwlock_init(&dataex.pak_lock); - init_waitqueue_head(&dataex.wait_queue); + dataex_init(&dataex); spin_lock_init(&tpm_schedule_list_lock); INIT_LIST_HEAD(&tpm_schedule_list); @@ -1041,6 +1065,7 @@ module_init(tpmback_init); static void __exit tpmback_exit(void) { + vtpm_release_packets(NULL, 0); tpmif_xenbus_exit(); tpmif_interface_exit(); misc_deregister(&vtpms_miscdevice); diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Thu May 04 14:19:19 2006 +0100 @@ -183,7 +183,7 @@ void *xenbus_dev_request_and_reply(struc mutex_unlock(&xs_state.request_mutex); - if ((msg->type == XS_TRANSACTION_END) || + if ((req_msg.type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) up_read(&xs_state.suspend_mutex); diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h Thu May 04 14:19:19 2006 +0100 @@ -134,7 +134,6 @@ HYPERVISOR_poll( #define pte_mfn(_x) pte_pfn(_x) #define __pte_ma(_x) ((pte_t) {(_x)}) #define phys_to_machine_mapping_valid(_x) (1) -#define kmap_flush_unused() do {} while (0) #define pfn_pte_ma(_x,_y) __pte_ma(0) #ifndef CONFIG_XEN_IA64_DOM0_VP //XXX #define set_phys_to_machine(_x,_y) do {} while (0) diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/mm/Kconfig --- a/linux-2.6-xen-sparse/mm/Kconfig Tue May 02 18:17:59 2006 +0100 +++ b/linux-2.6-xen-sparse/mm/Kconfig Thu May 04 14:19:19 2006 +0100 @@ -126,14 +126,14 @@ comment "Memory hotplug is currently inc # Default to 4 for wider testing, though 8 might be more appropriate. # ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. # PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes. -# XEN uses the mapping field on pagetable pages to store a pointer to -# the destructor. +# XEN on x86 architecture uses the mapping field on pagetable pages to store a +# pointer to the destructor. This conflicts with pte_lock_deinit(). # config SPLIT_PTLOCK_CPUS int default "4096" if ARM && !CPU_CACHE_VIPT default "4096" if PARISC && !PA20 - default "4096" if XEN + default "4096" if X86_XEN || X86_64_XEN default "4" # diff -r 55f73916d319 -r 51484df99be1 tools/python/xen/xend/XendBootloader.py --- a/tools/python/xen/xend/XendBootloader.py Tue May 02 18:17:59 2006 +0100 +++ b/tools/python/xen/xend/XendBootloader.py Thu May 04 14:19:19 2006 +0100 @@ -19,13 +19,13 @@ from XendLogging import log from XendLogging import log from XendError import VmError -def bootloader(blexec, disk, quiet = 0, entry = None): +def bootloader(blexec, disk, quiet = 0, blargs = None): """Run the boot loader executable on the given disk and return a config image. @param blexec Binary to use as the boot loader @param disk Disk to run the boot loader on. @param quiet Run in non-interactive mode, just booting the default. - @param entry Default entry to boot.""" + @param blargs Arguments to pass to the bootloader.""" if not os.access(blexec, os.X_OK): msg = "Bootloader isn't executable" @@ -48,8 +48,8 @@ def bootloader(blexec, disk, quiet = 0, if quiet: args.append("-q") args.append("--output=%s" %(fifo,)) - if entry is not None: - args.append("--entry=%s" %(entry,)) + if blargs is not None: + args.extend(blargs.split()) args.append(disk) try: diff -r 55f73916d319 -r 51484df99be1 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Tue May 02 18:17:59 2006 +0100 +++ b/tools/python/xen/xend/XendDomainInfo.py Thu May 04 14:19:19 2006 +0100 @@ -132,6 +132,7 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [ ('memory', int), ('maxmem', int), ('bootloader', str), + ('bootloader_args', str), ('features', str), ] @@ -571,6 +572,7 @@ class XendDomainInfo: defaultInfo('memory', lambda: 0) defaultInfo('maxmem', lambda: 0) defaultInfo('bootloader', lambda: None) + defaultInfo('bootloader_args', lambda: None) defaultInfo('backend', lambda: []) defaultInfo('device', lambda: []) defaultInfo('image', lambda: None) @@ -1630,7 +1632,8 @@ class XendDomainInfo: if disk is None: continue fn = blkdev_uname_to_file(disk) - blcfg = bootloader(self.info['bootloader'], fn, 1) + blcfg = bootloader(self.info['bootloader'], fn, 1, + self.info['bootloader_args']) break if blcfg is None: msg = "Had a bootloader specified, but can't find disk" diff -r 55f73916d319 -r 51484df99be1 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Tue May 02 18:17:59 2006 +0100 +++ b/tools/python/xen/xm/create.py Thu May 04 14:19:19 2006 +0100 @@ -122,9 +122,13 @@ gopts.var('bootloader', val='FILE', fn=set_value, default=None, use="Path to bootloader.") +gopts.var('bootargs', val='NAME', + fn=set_value, default=None, + use="Arguments to pass to boot loader") + gopts.var('bootentry', val='NAME', fn=set_value, default=None, - use="Entry to boot via boot loader") + use="DEPRECATED. Entry to boot via boot loader. Use bootargs.") gopts.var('kernel', val='FILE', fn=set_value, default=None, @@ -620,8 +624,13 @@ def run_bootloader(vals): (uname, dev, mode, backend) = vals.disk[0] file = blkif.blkdev_uname_to_file(uname) + if vals.bootentry: + warn("The bootentry option is deprecated. Use bootargs and pass " + "--entry= directly.") + vals.bootargs = "--entry=%s" %(vals.bootentry,) + return bootloader(vals.bootloader, file, not vals.console_autoconnect, - vals.bootentry) + vals.bootargs) def make_config(vals): """Create the domain configuration. @@ -654,8 +663,10 @@ def make_config(vals): config.append(['backend', ['tpmif']]) if vals.bootloader: + config_image = run_bootloader(vals) config.append(['bootloader', vals.bootloader]) - config_image = run_bootloader(vals) + if vals.bootargs: + config.append(['bootloader_args'], vals.bootargs) else: config_image = configure_image(vals) config.append(['image', config_image]) diff -r 55f73916d319 -r 51484df99be1 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Tue May 02 18:17:59 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Thu May 04 14:19:19 2006 +0100 @@ -79,6 +79,8 @@ void svm_dump_regs(const char *from, str static void svm_relinquish_guest_resources(struct domain *d); +/* Host save area */ +struct host_save_area *host_save_area[ NR_CPUS ] = {0}; static struct asid_pool ASIDpool[NR_CPUS]; /* @@ -185,11 +187,16 @@ void stop_svm(void) void stop_svm(void) { u32 eax, edx; + int cpu = smp_processor_id(); /* We turn off the EFER_SVME bit. */ rdmsr(MSR_EFER, eax, edx); eax &= ~EFER_SVME; wrmsr(MSR_EFER, eax, edx); + + /* release the HSA */ + free_host_save_area( host_save_area[ cpu ] ); + host_save_area[ cpu ] = NULL; printk("AMD SVM Extension is disabled.\n"); } @@ -431,8 +438,11 @@ int start_svm(void) int start_svm(void) { u32 eax, ecx, edx; - - /* Xen does not fill x86_capability words except 0. */ + u32 phys_hsa_lo, phys_hsa_hi; + u64 phys_hsa; + int cpu = smp_processor_id(); + + /* Xen does not fill x86_capability words except 0. */ ecx = cpuid_ecx(0x80000001); boot_cpu_data.x86_capability[5] = ecx; @@ -443,7 +453,14 @@ int start_svm(void) eax |= EFER_SVME; wrmsr(MSR_EFER, eax, edx); asidpool_init(smp_processor_id()); - printk("AMD SVM Extension is enabled for cpu %d.\n", smp_processor_id()); + printk("AMD SVM Extension is enabled for cpu %d.\n", cpu ); + + /* Initialize the HSA for this core */ + host_save_area[ cpu ] = alloc_host_save_area(); + phys_hsa = (u64) virt_to_maddr( host_save_area[ cpu ] ); + phys_hsa_lo = (u32) phys_hsa; + phys_hsa_hi = (u32) (phys_hsa >> 32); + wrmsr(MSR_K8_VM_HSAVE_PA, phys_hsa_lo, phys_hsa_hi); /* Setup HVM interfaces */ hvm_funcs.disable = stop_svm; @@ -546,20 +563,6 @@ void save_svm_cpu_user_regs(struct vcpu ctxt->ds = vmcb->ds.sel; } -#if defined (__x86_64__) -void svm_store_cpu_user_regs(struct cpu_user_regs *regs, struct vcpu *v ) -{ - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - - regs->rip = vmcb->rip; - regs->rsp = vmcb->rsp; - regs->rflags = vmcb->rflags; - regs->cs = vmcb->cs.sel; - regs->ds = vmcb->ds.sel; - regs->es = vmcb->es.sel; - regs->ss = vmcb->ss.sel; -} -#elif defined (__i386__) void svm_store_cpu_user_regs(struct cpu_user_regs *regs, struct vcpu *v) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; @@ -571,11 +574,11 @@ void svm_store_cpu_user_regs(struct cpu_ regs->ds = vmcb->ds.sel; regs->es = vmcb->es.sel; regs->ss = vmcb->ss.sel; -} -#endif + regs->fs = vmcb->fs.sel; + regs->gs = vmcb->gs.sel; +} /* XXX Use svm_load_cpu_guest_regs instead */ -#if defined (__i386__) void svm_load_cpu_user_regs(struct vcpu *v, struct cpu_user_regs *regs) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; @@ -588,30 +591,17 @@ void svm_load_cpu_user_regs(struct vcpu vmcb->rflags = regs->eflags; vmcb->cs.sel = regs->cs; vmcb->rip = regs->eip; + + vmcb->ds.sel = regs->ds; + vmcb->es.sel = regs->es; + vmcb->fs.sel = regs->fs; + vmcb->gs.sel = regs->gs; + if (regs->eflags & EF_TF) *intercepts |= EXCEPTION_BITMAP_DB; else *intercepts &= ~EXCEPTION_BITMAP_DB; } -#else /* (__i386__) */ -void svm_load_cpu_user_regs(struct vcpu *v, struct cpu_user_regs *regs) -{ - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - u32 *intercepts = &v->arch.hvm_svm.vmcb->exception_intercepts; - - /* Write the guest register value into VMCB */ - vmcb->rax = regs->rax; - vmcb->ss.sel = regs->ss; - vmcb->rsp = regs->rsp; - vmcb->rflags = regs->rflags; - vmcb->cs.sel = regs->cs; - vmcb->rip = regs->rip; - if (regs->rflags & EF_TF) - *intercepts |= EXCEPTION_BITMAP_DB; - else - *intercepts &= ~EXCEPTION_BITMAP_DB; -} -#endif /* !(__i386__) */ int svm_paging_enabled(struct vcpu *v) { @@ -735,10 +725,6 @@ static void svm_relinquish_guest_resourc { if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) ) continue; -#if 0 - /* Memory leak by not freeing this. XXXKAF: *Why* is not per core?? */ - free_host_save_area(v->arch.hvm_svm.host_save_area); -#endif destroy_vmcb(&v->arch.hvm_svm); free_monitor_pagetable(v); diff -r 55f73916d319 -r 51484df99be1 xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Tue May 02 18:17:59 2006 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Thu May 04 14:19:19 2006 +0100 @@ -36,9 +36,11 @@ #include <xen/kernel.h> #include <xen/domain_page.h> +extern struct host_save_area *host_save_area[]; extern int svm_dbg_on; extern int asidpool_assign_next( struct vmcb_struct *vmcb, int retire_current, int oldcore, int newcore); +extern void set_hsa_to_guest( struct arch_svm_struct *arch_svm ); #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */ @@ -309,8 +311,6 @@ int construct_vmcb(struct arch_svm_struc { int error; long rc=0; - struct host_save_area *hsa = NULL; - u64 phys_hsa; memset(arch_svm, 0, sizeof(struct arch_svm_struct)); @@ -320,36 +320,9 @@ int construct_vmcb(struct arch_svm_struc goto err_out; } - /* - * The following code is for allocating host_save_area. - * Note: We either allocate a Host Save Area per core or per VCPU. - * However, we do not want a global data structure - * for HSA per core, we decided to implement a HSA for each VCPU. - * It will waste space since VCPU number is larger than core number. - * But before we find a better place for HSA for each core, we will - * stay will this solution. - */ - - if (!(hsa = alloc_host_save_area())) - { - printk("Failed to allocate Host Save Area\n"); - rc = -ENOMEM; - goto err_out; - } - - phys_hsa = (u64) virt_to_maddr(hsa); - arch_svm->host_save_area = hsa; - arch_svm->host_save_pa = phys_hsa; - + /* update the HSA for the current Core */ + set_hsa_to_guest( arch_svm ); arch_svm->vmcb_pa = (u64) virt_to_maddr(arch_svm->vmcb); - - if ((error = load_vmcb(arch_svm, arch_svm->host_save_pa))) - { - printk("construct_vmcb: load_vmcb failed: VMCB = %lx\n", - (unsigned long) arch_svm->host_save_pa); - rc = -EINVAL; - goto err_out; - } if ((error = construct_vmcb_controls(arch_svm))) { @@ -458,18 +431,11 @@ void svm_do_launch(struct vcpu *v) } -int load_vmcb(struct arch_svm_struct *arch_svm, u64 phys_hsa) -{ - u32 phys_hsa_lo, phys_hsa_hi; - - phys_hsa_lo = (u32) phys_hsa; - phys_hsa_hi = (u32) (phys_hsa >> 32); - - wrmsr(MSR_K8_VM_HSAVE_PA, phys_hsa_lo, phys_hsa_hi); - set_bit(ARCH_SVM_VMCB_LOADED, &arch_svm->flags); - return 0; -} - +void set_hsa_to_guest( struct arch_svm_struct *arch_svm ) +{ + arch_svm->host_save_area = host_save_area[ smp_processor_id() ]; + arch_svm->host_save_pa = (u64)virt_to_maddr( arch_svm->host_save_area ); +} /* * Resume the guest. @@ -481,6 +447,9 @@ void svm_do_resume(struct vcpu *v) struct hvm_time_info *time_info = &vpit->time_info; svm_stts(v); + + /* make sure the HSA is set for the current core */ + set_hsa_to_guest( &v->arch.hvm_svm ); /* pick up the elapsed PIT ticks and re-enable pit_timer */ if ( time_info->first_injected ) { diff -r 55f73916d319 -r 51484df99be1 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Tue May 02 18:17:59 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu May 04 14:19:19 2006 +0100 @@ -475,6 +475,45 @@ static void vmx_store_cpu_guest_regs( __vmptrld(virt_to_maddr(current->arch.hvm_vmx.vmcs)); } +/* + * The VMX spec (section 4.3.1.2, Checks on Guest Segment + * Registers) says that virtual-8086 mode guests' segment + * base-address fields in the VMCS must be equal to their + * corresponding segment selector field shifted right by + * four bits upon vmentry. + * + * This function (called only for VM86-mode guests) fixes + * the bases to be consistent with the selectors in regs + * if they're not already. Without this, we can fail the + * vmentry check mentioned above. + */ +static void fixup_vm86_seg_bases(struct cpu_user_regs *regs) +{ + int err = 0; + unsigned long base; + + err |= __vmread(GUEST_ES_BASE, &base); + if (regs->es << 4 != base) + err |= __vmwrite(GUEST_ES_BASE, regs->es << 4); + err |= __vmread(GUEST_CS_BASE, &base); + if (regs->cs << 4 != base) + err |= __vmwrite(GUEST_CS_BASE, regs->cs << 4); + err |= __vmread(GUEST_SS_BASE, &base); + if (regs->ss << 4 != base) + err |= __vmwrite(GUEST_SS_BASE, regs->ss << 4); + err |= __vmread(GUEST_DS_BASE, &base); + if (regs->ds << 4 != base) + err |= __vmwrite(GUEST_DS_BASE, regs->ds << 4); + err |= __vmread(GUEST_FS_BASE, &base); + if (regs->fs << 4 != base) + err |= __vmwrite(GUEST_FS_BASE, regs->fs << 4); + err |= __vmread(GUEST_GS_BASE, &base); + if (regs->gs << 4 != base) + err |= __vmwrite(GUEST_GS_BASE, regs->gs << 4); + + BUG_ON(err); +} + void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) { if ( v != current ) @@ -511,6 +550,8 @@ void vmx_load_cpu_guest_regs(struct vcpu __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); else __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); + if (regs->eflags & EF_VM) + fixup_vm86_seg_bases(regs); __vmwrite(GUEST_CS_SELECTOR, regs->cs); __vmwrite(GUEST_RIP, regs->eip); diff -r 55f73916d319 -r 51484df99be1 xen/arch/x86/x86_32/mm.c --- a/xen/arch/x86/x86_32/mm.c Tue May 02 18:17:59 2006 +0100 +++ b/xen/arch/x86/x86_32/mm.c Thu May 04 14:19:19 2006 +0100 @@ -155,17 +155,10 @@ void subarch_init_memory(void) * 64-bit operations on them. Also, just for sanity, we assert the size * of the structure here. */ - if ( (offsetof(struct page_info, u.inuse._domain) != - (offsetof(struct page_info, count_info) + sizeof(u32))) || - ((offsetof(struct page_info, count_info) & 7) != 0) || - (sizeof(struct page_info) != 24) ) - { - printk("Weird page_info layout (%ld,%ld,%d)\n", - offsetof(struct page_info, count_info), - offsetof(struct page_info, u.inuse._domain), - sizeof(struct page_info)); - BUG(); - } + BUILD_BUG_ON(offsetof(struct page_info, u.inuse._domain) != + (offsetof(struct page_info, count_info) + sizeof(u32))); + BUILD_BUG_ON((offsetof(struct page_info, count_info) & 7) != 0); + BUILD_BUG_ON(sizeof(struct page_info) != 24); /* M2P table is mappable read-only by privileged domains. */ for ( i = 0; i < (mpt_size >> L2_PAGETABLE_SHIFT); i++ ) diff -r 55f73916d319 -r 51484df99be1 xen/arch/x86/x86_64/mm.c --- a/xen/arch/x86/x86_64/mm.c Tue May 02 18:17:59 2006 +0100 +++ b/xen/arch/x86/x86_64/mm.c Thu May 04 14:19:19 2006 +0100 @@ -145,19 +145,11 @@ void subarch_init_memory(void) * count_info and domain fields must be adjacent, as we perform atomic * 64-bit operations on them. */ - if ( ((offsetof(struct page_info, u.inuse._domain) != - (offsetof(struct page_info, count_info) + sizeof(u32)))) || - ((offsetof(struct page_info, count_info) & 7) != 0) || - (sizeof(struct page_info) != - (32 + BITS_TO_LONGS(NR_CPUS)*sizeof(long))) ) - { - printk("Weird page_info layout (%ld,%ld,%ld,%ld)\n", - offsetof(struct page_info, count_info), - offsetof(struct page_info, u.inuse._domain), - sizeof(struct page_info), - 32 + BITS_TO_LONGS(NR_CPUS)*sizeof(long)); - for ( ; ; ) ; - } + BUILD_BUG_ON(offsetof(struct page_info, u.inuse._domain) != + (offsetof(struct page_info, count_info) + sizeof(u32))); + BUILD_BUG_ON((offsetof(struct page_info, count_info) & 7) != 0); + BUILD_BUG_ON(sizeof(struct page_info) != + (32 + BITS_TO_LONGS(NR_CPUS)*sizeof(long))); /* M2P table is mappable read-only by privileged domains. */ for ( v = RDWR_MPT_VIRT_START; diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.c Thu May 04 14:19:19 2006 +0100 @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2006 IBM Corporation + * + * Authors: + * Stefan Berger <stefanb@xxxxxxxxxx> + * + * Generic device driver part for device drivers in a virtualized + * environment. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ + +#include <asm/uaccess.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include "tpm.h" +#include "tpm_vtpm.h" + +/* read status bits */ +enum { + STATUS_BUSY = 0x01, + STATUS_DATA_AVAIL = 0x02, + STATUS_READY = 0x04 +}; + +#define MIN(x,y) ((x) < (y)) ? (x) : (y) + +struct transmission { + struct list_head next; + + unsigned char *request; + size_t request_len; + size_t request_buflen; + + unsigned char *response; + size_t response_len; + size_t response_buflen; + + unsigned int flags; +}; + +enum { + TRANSMISSION_FLAG_WAS_QUEUED = 0x1 +}; + +struct vtpm_state { + struct transmission *current_request; + spinlock_t req_list_lock; + wait_queue_head_t req_wait_queue; + + struct list_head queued_requests; + + struct transmission *current_response; + spinlock_t resp_list_lock; + wait_queue_head_t resp_wait_queue; // processes waiting for responses + + struct transmission *req_cancelled; // if a cancellation was encounterd + + u8 vd_status; + u8 flags; + + unsigned long disconnect_time; + + struct tpm_virtual_device *tpmvd; +}; + +enum { + DATAEX_FLAG_QUEUED_ONLY = 0x1 +}; + + +/* local variables */ +static struct vtpm_state *vtpms; + +/* local function prototypes */ +static int _vtpm_send_queued(struct tpm_chip *chip); + + +/* ============================================================= + * Some utility functions + * ============================================================= + */ +static void vtpm_state_init(struct vtpm_state *vtpms) +{ + vtpms->current_request = NULL; + spin_lock_init(&vtpms->req_list_lock); + init_waitqueue_head(&vtpms->req_wait_queue); + INIT_LIST_HEAD(&vtpms->queued_requests); + + vtpms->current_response = NULL; + spin_lock_init(&vtpms->resp_list_lock); + init_waitqueue_head(&vtpms->resp_wait_queue); + + vtpms->disconnect_time = jiffies; +} + + +static inline struct transmission *transmission_alloc(void) +{ + return kzalloc(sizeof(struct transmission), GFP_ATOMIC); +} + +static unsigned char * +transmission_set_req_buffer(struct transmission *t, + unsigned char *buffer, size_t len) +{ + if (t->request_buflen < len) { + kfree(t->request); + t->request = kmalloc(len, GFP_KERNEL); + if (!t->request) { + t->request_buflen = 0; + return NULL; + } + t->request_buflen = len; + } + + memcpy(t->request, buffer, len); + t->request_len = len; + + return t->request; +} + +static unsigned char * +transmission_set_res_buffer(struct transmission *t, + const unsigned char *buffer, size_t len) +{ + if (t->response_buflen < len) { + kfree(t->response); + t->response = kmalloc(len, GFP_ATOMIC); + if (!t->response) { + t->response_buflen = 0; + return NULL; + } + t->response_buflen = len; + } + + memcpy(t->response, buffer, len); + t->response_len = len; + + return t->response; +} + +static inline void transmission_free(struct transmission *t) +{ + kfree(t->request); + kfree(t->response); + kfree(t); +} + +/* ============================================================= + * Interface with the lower layer driver + * ============================================================= + */ +/* + * Lower layer uses this function to make a response available. + */ +int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr) +{ + unsigned long flags; + int ret_size = 0; + struct transmission *t; + + /* + * The list with requests must contain one request + * only and the element there must be the one that + * was passed to me from the front-end. + */ + spin_lock_irqsave(&vtpms->resp_list_lock, flags); + if (vtpms->current_request != ptr) { + printk("WARNING: The request pointer is different than the " + "pointer the shared memory driver returned to me. " + "%p != %p\n", + vtpms->current_request, ptr); + } + + /* + * If the request has been cancelled, just quit here + */ + if (vtpms->req_cancelled == (struct transmission *)ptr) { + if (vtpms->current_request == vtpms->req_cancelled) { + vtpms->current_request = NULL; + } + transmission_free(vtpms->req_cancelled); + vtpms->req_cancelled = NULL; + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + return 0; + } + + if (NULL != (t = vtpms->current_request)) { + transmission_free(t); + vtpms->current_request = NULL; + } + + t = transmission_alloc(); + if (t) { + if (!transmission_set_res_buffer(t, buffer, count)) { + transmission_free(t); + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + return -ENOMEM; + } + ret_size = count; + vtpms->current_response = t; + wake_up_interruptible(&vtpms->resp_wait_queue); + } + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + + return ret_size; +} + + +/* + * Lower layer indicates its status (connected/disconnected) + */ +void vtpm_vd_status(u8 vd_status) +{ + vtpms->vd_status = vd_status; + if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) { + vtpms->disconnect_time = jiffies; + } +} + +/* ============================================================= + * Interface with the generic TPM driver + * ============================================================= + */ +static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + int rc = 0; + unsigned long flags; + + /* + * Check if the previous operation only queued the command + * In this case there won't be a response, so I just + * return from here and reset that flag. In any other + * case I should receive a response from the back-end. + */ + spin_lock_irqsave(&vtpms->resp_list_lock, flags); + if ((vtpms->flags & DATAEX_FLAG_QUEUED_ONLY) != 0) { + vtpms->flags &= ~DATAEX_FLAG_QUEUED_ONLY; + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + /* + * The first few commands (measurements) must be + * queued since it might not be possible to talk to the + * TPM, yet. + * Return a response of up to 30 '0's. + */ + + count = MIN(count, 30); + memset(buf, 0x0, count); + return count; + } + /* + * Check whether something is in the responselist and if + * there's nothing in the list wait for something to appear. + */ + + if (!vtpms->current_response) { + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + interruptible_sleep_on_timeout(&vtpms->resp_wait_queue, + 1000); + spin_lock_irqsave(&vtpms->resp_list_lock ,flags); + } + + if (vtpms->current_response) { + struct transmission *t = vtpms->current_response; + vtpms->current_response = NULL; + rc = MIN(count, t->response_len); + memcpy(buf, t->response, rc); + transmission_free(t); + } + + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + return rc; +} + +static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) +{ + int rc = 0; + unsigned long flags; + struct transmission *t = transmission_alloc(); + + if (!t) + return -ENOMEM; + /* + * If there's a current request, it must be the + * previous request that has timed out. + */ + spin_lock_irqsave(&vtpms->req_list_lock, flags); + if (vtpms->current_request != NULL) { + printk("WARNING: Sending although there is a request outstanding.\n" + " Previous request must have timed out.\n"); + transmission_free(vtpms->current_request); + vtpms->current_request = NULL; + } + spin_unlock_irqrestore(&vtpms->req_list_lock, flags); + + /* + * Queue the packet if the driver below is not + * ready, yet, or there is any packet already + * in the queue. + * If the driver below is ready, unqueue all + * packets first before sending our current + * packet. + * For each unqueued packet, except for the + * last (=current) packet, call the function + * tpm_xen_recv to wait for the response to come + * back. + */ + if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) { + if (time_after(jiffies, + vtpms->disconnect_time + HZ * 10)) { + rc = -ENOENT; + } else { + goto queue_it; + } + } else { + /* + * Send all queued packets. + */ + if (_vtpm_send_queued(chip) == 0) { + + vtpms->current_request = t; + + rc = vtpm_vd_send(chip, + vtpms->tpmvd->tpm_private, + buf, + count, + t); + /* + * The generic TPM driver will call + * the function to receive the response. + */ + if (rc < 0) { + vtpms->current_request = NULL; + goto queue_it; + } + } else { +queue_it: + if (!transmission_set_req_buffer(t, buf, count)) { + transmission_free(t); + rc = -ENOMEM; + goto exit; + } + /* + * An error occurred. Don't event try + * to send the current request. Just + * queue it. + */ + spin_lock_irqsave(&vtpms->req_list_lock, flags); + vtpms->flags |= DATAEX_FLAG_QUEUED_ONLY; + list_add_tail(&t->next, &vtpms->queued_requests); + spin_unlock_irqrestore(&vtpms->req_list_lock, flags); + } + } + +exit: + return rc; +} + + +/* + * Send all queued requests. + */ +static int _vtpm_send_queued(struct tpm_chip *chip) +{ + int rc; + int error = 0; + long flags; + unsigned char buffer[1]; + + spin_lock_irqsave(&vtpms->req_list_lock, flags); + + while (!list_empty(&vtpms->queued_requests)) { + /* + * Need to dequeue them. + * Read the result into a dummy buffer. + */ + struct transmission *qt = (struct transmission *) + vtpms->queued_requests.next; + list_del(&qt->next); + vtpms->current_request = qt; + spin_unlock_irqrestore(&vtpms->req_list_lock, flags); + + rc = vtpm_vd_send(chip, + vtpms->tpmvd->tpm_private, + qt->request, + qt->request_len, + qt); + + if (rc < 0) { + spin_lock_irqsave(&vtpms->req_list_lock, flags); + if ((qt = vtpms->current_request) != NULL) { + /* + * requeue it at the beginning + * of the list + */ + list_add(&qt->next, + &vtpms->queued_requests); + } + vtpms->current_request = NULL; + error = 1; + break; + } + /* + * After this point qt is not valid anymore! + * It is freed when the front-end is delivering + * the data by calling tpm_recv + */ + /* + * Receive response into provided dummy buffer + */ + rc = vtpm_recv(chip, buffer, sizeof(buffer)); + spin_lock_irqsave(&vtpms->req_list_lock, flags); + } + + spin_unlock_irqrestore(&vtpms->req_list_lock, flags); + + return error; +} + +static void vtpm_cancel(struct tpm_chip *chip) +{ + unsigned long flags; + spin_lock_irqsave(&vtpms->resp_list_lock,flags); + + vtpms->req_cancelled = vtpms->current_request; + + spin_unlock_irqrestore(&vtpms->resp_list_lock,flags); +} + +static u8 vtpm_status(struct tpm_chip *chip) +{ + u8 rc = 0; + unsigned long flags; + + spin_lock_irqsave(&vtpms->resp_list_lock, flags); + /* + * Data are available if: + * - there's a current response + * - the last packet was queued only (this is fake, but necessary to + * get the generic TPM layer to call the receive function.) + */ + if (vtpms->current_response || + 0 != (vtpms->flags & DATAEX_FLAG_QUEUED_ONLY)) { + rc = STATUS_DATA_AVAIL; + } + spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); + return rc; +} + +static struct file_operations vtpm_ops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = tpm_open, + .read = tpm_read, + .write = tpm_write, + .release = tpm_release, +}; + +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); + +static struct attribute *vtpm_attrs[] = { + &dev_attr_pubek.attr, + &dev_attr_pcrs.attr, + &dev_attr_caps.attr, + &dev_attr_cancel.attr, + NULL, +}; + +static struct attribute_group vtpm_attr_grp = { .attrs = vtpm_attrs }; + +static struct tpm_vendor_specific tpm_vtpm = { + .recv = vtpm_recv, + .send = vtpm_send, + .cancel = vtpm_cancel, + .status = vtpm_status, + .req_complete_mask = STATUS_BUSY | STATUS_DATA_AVAIL, + .req_complete_val = STATUS_DATA_AVAIL, + .req_canceled = STATUS_READY, + .base = 0, + .attr_group = &vtpm_attr_grp, + .miscdev = { + .fops = &vtpm_ops, + }, +}; + +static struct platform_device *pdev; + +int __init init_vtpm(struct tpm_virtual_device *tvd) +{ + int rc; + + /* vtpms is global - only allow one user */ + if (vtpms) + return -EBUSY; + + vtpms = kzalloc(sizeof(struct vtpm_state), GFP_KERNEL); + if (!vtpms) + return -ENOMEM; + + vtpm_state_init(vtpms); + vtpms->tpmvd = tvd; + + pdev = platform_device_register_simple("tpm_vtpm", -1, NULL, 0); + if (IS_ERR(pdev)) { + rc = PTR_ERR(pdev); + goto err_free_mem; + } + + if (tvd) + tpm_vtpm.buffersize = tvd->max_tx_size; + + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_vtpm)) < 0) { + goto err_unreg_pdev; + } + + return 0; + +err_unreg_pdev: + platform_device_unregister(pdev); +err_free_mem: + kfree(vtpms); + vtpms = NULL; + + return rc; +} + +void __exit cleanup_vtpm(void) +{ + struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); + if (chip) { + tpm_remove_hardware(chip->dev); + platform_device_unregister(pdev); + } + kfree(vtpms); + vtpms = NULL; +} diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h Thu May 04 14:19:19 2006 +0100 @@ -0,0 +1,38 @@ +#ifndef TPM_VTPM_H +#define TPM_VTPM_H + +struct tpm_chip; +struct tpm_private; + +struct tpm_virtual_device { + /* + * This field indicates the maximum size the driver can + * transfer in one chunk. It is filled in by the front-end + * driver and should be propagated to the generic tpm driver + * for allocation of buffers. + */ + unsigned int max_tx_size; + /* + * The following is a private structure of the underlying + * driver. It is passed as parameter in the send function. + */ + struct tpm_private *tpm_private; +}; + +enum vdev_status { + TPM_VD_STATUS_DISCONNECTED = 0x0, + TPM_VD_STATUS_CONNECTED = 0x1 +}; + +/* this function is called from tpm_vtpm.c */ +int vtpm_vd_send(struct tpm_chip *tc, + struct tpm_private * tp, + const u8 * buf, size_t count, void *ptr); + +/* these functions are offered by tpm_vtpm.c */ +int __init init_vtpm(struct tpm_virtual_device *); +void __exit cleanup_vtpm(void); +int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr); +void vtpm_vd_status(u8 status); + +#endif diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmfront/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/Makefile Tue May 02 18:17:59 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - -obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront.o diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c Tue May 02 18:17:59 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,767 +0,0 @@ -/* - * Copyright (c) 2005, IBM Corporation - * - * Author: Stefan Berger, stefanb@xxxxxxxxxx - * Grant table support: Mahadevan Gomathisankaran - * - * This code has been derived from drivers/xen/netfront/netfront.c - * - * Copyright (c) 2002-2004, K A Fraser - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation; or, when distributed - * separately from the Linux kernel or incorporated into other - * software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <xen/tpmfe.h> -#include <linux/err.h> -#include <linux/mutex.h> -#include <asm/io.h> -#include <xen/evtchn.h> -#include <xen/interface/grant_table.h> -#include <xen/interface/io/tpmif.h> -#include <asm/uaccess.h> -#include <xen/xenbus.h> -#include <xen/interface/grant_table.h> - -#include "tpmfront.h" - -#undef DEBUG - -/* locally visible variables */ -static grant_ref_t gref_head; -static struct tpm_private *my_priv; - -/* local function prototypes */ -static irqreturn_t tpmif_int(int irq, - void *tpm_priv, - struct pt_regs *ptregs); -static void tpmif_rx_action(unsigned long unused); -static int tpmif_connect(struct xenbus_device *dev, - struct tpm_private *tp, - domid_t domid); -static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0); -static int tpmif_allocate_tx_buffers(struct tpm_private *tp); -static void tpmif_free_tx_buffers(struct tpm_private *tp); -static void tpmif_set_connected_state(struct tpm_private *tp, - u8 newstate); -static int tpm_xmit(struct tpm_private *tp, - const u8 * buf, size_t count, int userbuffer, - void *remember); -static void destroy_tpmring(struct tpm_private *tp); - -#define DPRINTK(fmt, args...) \ - pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args) -#define IPRINTK(fmt, args...) \ - printk(KERN_INFO "xen_tpm_fr: " fmt, ##args) -#define WPRINTK(fmt, args...) \ - printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args) - -#define GRANT_INVALID_REF 0 - - -static inline int -tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len, - int isuserbuffer) -{ - int copied = len; - - if (len > txb->size) { - copied = txb->size; - } - if (isuserbuffer) { - if (copy_from_user(txb->data, src, copied)) - return -EFAULT; - } else { - memcpy(txb->data, src, copied); - } - txb->len = len; - return copied; -} - -static inline struct tx_buffer *tx_buffer_alloc(void) -{ - struct tx_buffer *txb = kzalloc(sizeof (struct tx_buffer), - GFP_KERNEL); - - if (txb) { - txb->len = 0; - txb->size = PAGE_SIZE; - txb->data = (unsigned char *)__get_free_page(GFP_KERNEL); - if (txb->data == NULL) { - kfree(txb); - txb = NULL; - } - } - return txb; -} - - -static inline void tx_buffer_free(struct tx_buffer *txb) -{ - if (txb) { - free_page((long)txb->data); - kfree(txb); - } -} - -/************************************************************** - Utility function for the tpm_private structure -**************************************************************/ -static inline void tpm_private_init(struct tpm_private *tp) -{ - spin_lock_init(&tp->tx_lock); - init_waitqueue_head(&tp->wait_q); -} - -static inline void tpm_private_free(void) -{ - tpmif_free_tx_buffers(my_priv); - kfree(my_priv); - my_priv = NULL; -} - -static struct tpm_private *tpm_private_get(void) -{ - int err; - if (!my_priv) { - my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL); - if (my_priv) { - tpm_private_init(my_priv); - err = tpmif_allocate_tx_buffers(my_priv); - if (err < 0) { - tpm_private_free(); - } - } - } - return my_priv; -} - -/************************************************************** - - The interface to let the tpm plugin register its callback - function and send data to another partition using this module - -**************************************************************/ - -static DEFINE_MUTEX(upperlayer_lock); -static DEFINE_MUTEX(suspend_lock); -static struct tpmfe_device *upperlayer_tpmfe; - -/* - * Send data via this module by calling this function - */ -int tpm_fe_send(struct tpm_private *tp, const u8 * buf, size_t count, void *ptr) -{ - int sent; - - mutex_lock(&suspend_lock); - sent = tpm_xmit(tp, buf, count, 0, ptr); - mutex_unlock(&suspend_lock); - - return sent; -} -EXPORT_SYMBOL(tpm_fe_send); - -/* - * Register a callback for receiving data from this module - */ -int tpm_fe_register_receiver(struct tpmfe_device *tpmfe_dev) -{ - int rc = 0; - - mutex_lock(&upperlayer_lock); - if (NULL == upperlayer_tpmfe) { - upperlayer_tpmfe = tpmfe_dev; - tpmfe_dev->max_tx_size = TPMIF_TX_RING_SIZE * PAGE_SIZE; - tpmfe_dev->tpm_private = tpm_private_get(); - if (!tpmfe_dev->tpm_private) { - rc = -ENOMEM; - } - } else { - rc = -EBUSY; - } - mutex_unlock(&upperlayer_lock); - return rc; -} -EXPORT_SYMBOL(tpm_fe_register_receiver); - -/* - * Unregister the callback for receiving data from this module - */ -void tpm_fe_unregister_receiver(void) -{ - mutex_lock(&upperlayer_lock); - upperlayer_tpmfe = NULL; - mutex_unlock(&upperlayer_lock); -} -EXPORT_SYMBOL(tpm_fe_unregister_receiver); - -/* - * Call this function to send data to the upper layer's - * registered receiver function. - */ -static int tpm_fe_send_upperlayer(const u8 * buf, size_t count, - const void *ptr) -{ - int rc = 0; - - mutex_lock(&upperlayer_lock); - - if (upperlayer_tpmfe && upperlayer_tpmfe->receive) - rc = upperlayer_tpmfe->receive(buf, count, ptr); - - mutex_unlock(&upperlayer_lock); - return rc; -} - -/************************************************************** - XENBUS support code -**************************************************************/ - -static int setup_tpmring(struct xenbus_device *dev, - struct tpm_private *tp) -{ - tpmif_tx_interface_t *sring; - int err; - - tp->ring_ref = GRANT_INVALID_REF; - - sring = (void *)__get_free_page(GFP_KERNEL); - if (!sring) { - xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); - return -ENOMEM; - } - tp->tx = sring; - - err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx)); - if (err < 0) { - free_page((unsigned long)sring); - tp->tx = NULL; - xenbus_dev_fatal(dev, err, "allocating grant reference"); - goto fail; - } - tp->ring_ref = err; - - err = tpmif_connect(dev, tp, dev->otherend_id); - if (err) - goto fail; - - return 0; -fail: - destroy_tpmring(tp); - return err; -} - - -static void destroy_tpmring(struct tpm_private *tp) -{ - tpmif_set_connected_state(tp, 0); - - if (tp->ring_ref != GRANT_INVALID_REF) { - gnttab_end_foreign_access(tp->ring_ref, 0, - (unsigned long)tp->tx); - tp->ring_ref = GRANT_INVALID_REF; - tp->tx = NULL; - } - - if (tp->irq) - unbind_from_irqhandler(tp->irq, tp); - - tp->evtchn = tp->irq = 0; -} - - -static int talk_to_backend(struct xenbus_device *dev, - struct tpm_private *tp) -{ - const char *message = NULL; - int err; - xenbus_transaction_t xbt; - - err = setup_tpmring(dev, tp); - if (err) { - xenbus_dev_fatal(dev, err, "setting up ring"); - goto out; - } - -again: - err = xenbus_transaction_start(&xbt); - if (err) { - xenbus_dev_fatal(dev, err, "starting transaction"); - goto destroy_tpmring; - } - - err = xenbus_printf(xbt, dev->nodename, - "ring-ref","%u", tp->ring_ref); - if (err) { - message = "writing ring-ref"; - goto abort_transaction; - } - - err = xenbus_printf(xbt, dev->nodename, - "event-channel", "%u", tp->evtchn); - if (err) { - message = "writing event-channel"; - goto abort_transaction; - } - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) - goto again; - if (err) { - xenbus_dev_fatal(dev, err, "completing transaction"); - goto destroy_tpmring; - } - - xenbus_switch_state(dev, XenbusStateConnected); - - return 0; - -abort_transaction: - xenbus_transaction_end(xbt, 1); - if (message) - xenbus_dev_error(dev, err, "%s", message); -destroy_tpmring: - destroy_tpmring(tp); -out: - return err; -} - -/** - * Callback received when the backend's state changes. - */ -static void backend_changed(struct xenbus_device *dev, - XenbusState backend_state) -{ - struct tpm_private *tp = dev->data; - DPRINTK("\n"); - - switch (backend_state) { - case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateUnknown: - break; - - case XenbusStateConnected: - tpmif_set_connected_state(tp, 1); - break; - - case XenbusStateClosing: - tpmif_set_connected_state(tp, 0); - break; - - case XenbusStateClosed: - if (tp->is_suspended == 0) { - device_unregister(&dev->dev); - } - xenbus_switch_state(dev, XenbusStateClosed); - break; - } -} - - -static int tpmfront_probe(struct xenbus_device *dev, - const struct xenbus_device_id *id) -{ - int err; - int handle; - struct tpm_private *tp = tpm_private_get(); - - if (!tp) - return -ENOMEM; - - err = xenbus_scanf(XBT_NULL, dev->nodename, - "handle", "%i", &handle); - if (XENBUS_EXIST_ERR(err)) - return err; - - if (err < 0) { - xenbus_dev_fatal(dev,err,"reading virtual-device"); - return err; - } - - tp->dev = dev; - dev->data = tp; - - err = talk_to_backend(dev, tp); - if (err) { - tpm_private_free(); - dev->data = NULL; - return err; - } - return 0; -} - - -static int tpmfront_remove(struct xenbus_device *dev) -{ - struct tpm_private *tp = (struct tpm_private *)dev->data; - destroy_tpmring(tp); - return 0; -} - -static int tpmfront_suspend(struct xenbus_device *dev) -{ - struct tpm_private *tp = (struct tpm_private *)dev->data; - u32 ctr; - - /* lock, so no app can send */ - mutex_lock(&suspend_lock); - xenbus_switch_state(dev, XenbusStateClosed); - tp->is_suspended = 1; - - for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 25; ctr++) { - if ((ctr % 10) == 0) - printk("TPM-FE [INFO]: Waiting for outstanding request.\n"); - /* - * Wait for a request to be responded to. - */ - interruptible_sleep_on_timeout(&tp->wait_q, 100); - } - - if (atomic_read(&tp->tx_busy)) { - /* - * A temporary work-around. - */ - printk("TPM-FE [WARNING]: Resetting busy flag."); - atomic_set(&tp->tx_busy, 0); - } - - return 0; -} - -static int tpmfront_resume(struct xenbus_device *dev) -{ - struct tpm_private *tp = (struct tpm_private *)dev->data; - destroy_tpmring(tp); - return talk_to_backend(dev, tp); -} - -static int tpmif_connect(struct xenbus_device *dev, - struct tpm_private *tp, - domid_t domid) -{ - int err; - - tp->backend_id = domid; - - err = xenbus_alloc_evtchn(dev, &tp->evtchn); - if (err) - return err; - - err = bind_evtchn_to_irqhandler(tp->evtchn, - tpmif_int, SA_SAMPLE_RANDOM, "tpmif", - tp); - if (err <= 0) { - WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err); - return err; - } - - tp->irq = err; - return 0; -} - -static struct xenbus_device_id tpmfront_ids[] = { - { "vtpm" }, - { "" } -}; - -static struct xenbus_driver tpmfront = { - .name = "vtpm", - .owner = THIS_MODULE, - .ids = tpmfront_ids, - .probe = tpmfront_probe, - .remove = tpmfront_remove, - .resume = tpmfront_resume, - .otherend_changed = backend_changed, - .suspend = tpmfront_suspend, -}; - -static void __init init_tpm_xenbus(void) -{ - xenbus_register_frontend(&tpmfront); -} - -static void __exit exit_tpm_xenbus(void) -{ - xenbus_unregister_driver(&tpmfront); -} - -static int tpmif_allocate_tx_buffers(struct tpm_private *tp) -{ - unsigned int i; - - for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { - tp->tx_buffers[i] = tx_buffer_alloc(); - if (!tp->tx_buffers[i]) { - tpmif_free_tx_buffers(tp); - return -ENOMEM; - } - } - return 0; -} - -static void tpmif_free_tx_buffers(struct tpm_private *tp) -{ - unsigned int i; - - for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { - tx_buffer_free(tp->tx_buffers[i]); - } -} - -static void tpmif_rx_action(unsigned long priv) -{ - struct tpm_private *tp = (struct tpm_private *)priv; - - int i = 0; - unsigned int received; - unsigned int offset = 0; - u8 *buffer; - tpmif_tx_request_t *tx; - tx = &tp->tx->ring[i].req; - - received = tx->size; - - buffer = kmalloc(received, GFP_KERNEL); - if (NULL == buffer) { - goto exit; - } - - for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) { - struct tx_buffer *txb = tp->tx_buffers[i]; - tpmif_tx_request_t *tx; - unsigned int tocopy; - - tx = &tp->tx->ring[i].req; - tocopy = tx->size; - if (tocopy > PAGE_SIZE) { - tocopy = PAGE_SIZE; - } - - memcpy(&buffer[offset], txb->data, tocopy); - - gnttab_release_grant_reference(&gref_head, tx->ref); - - offset += tocopy; - } - - tpm_fe_send_upperlayer(buffer, received, tp->tx_remember); - kfree(buffer); - -exit: - atomic_set(&tp->tx_busy, 0); - wake_up_interruptible(&tp->wait_q); -} - - -static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) -{ - struct tpm_private *tp = tpm_priv; - unsigned long flags; - - spin_lock_irqsave(&tp->tx_lock, flags); - tpmif_rx_tasklet.data = (unsigned long)tp; - tasklet_schedule(&tpmif_rx_tasklet); - spin_unlock_irqrestore(&tp->tx_lock, flags); - - return IRQ_HANDLED; -} - - -static int tpm_xmit(struct tpm_private *tp, - const u8 * buf, size_t count, int isuserbuffer, - void *remember) -{ - tpmif_tx_request_t *tx; - TPMIF_RING_IDX i; - unsigned int offset = 0; - - spin_lock_irq(&tp->tx_lock); - - if (unlikely(atomic_read(&tp->tx_busy))) { - printk("tpm_xmit: There's an outstanding request/response " - "on the way!\n"); - spin_unlock_irq(&tp->tx_lock); - return -EBUSY; - } - - if (tp->is_connected != 1) { - spin_unlock_irq(&tp->tx_lock); - return -EIO; - } - - for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) { - struct tx_buffer *txb = tp->tx_buffers[i]; - int copied; - - if (NULL == txb) { - DPRINTK("txb (i=%d) is NULL. buffers initilized?\n" - "Not transmitting anything!\n", i); - spin_unlock_irq(&tp->tx_lock); - return -EFAULT; - } - copied = tx_buffer_copy(txb, &buf[offset], count, - isuserbuffer); - if (copied < 0) { - /* An error occurred */ - spin_unlock_irq(&tp->tx_lock); - return copied; - } - count -= copied; - offset += copied; - - tx = &tp->tx->ring[i].req; - - tx->addr = virt_to_machine(txb->data); - tx->size = txb->len; - - DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n", - txb->data[0],txb->data[1],txb->data[2],txb->data[3]); - - /* get the granttable reference for this page */ - tx->ref = gnttab_claim_grant_reference(&gref_head); - - if (-ENOSPC == tx->ref) { - spin_unlock_irq(&tp->tx_lock); - DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__); - return -ENOSPC; - } - gnttab_grant_foreign_access_ref( tx->ref, - tp->backend_id, - (tx->addr >> PAGE_SHIFT), - 0 /*RW*/); - wmb(); - } - - atomic_set(&tp->tx_busy, 1); - tp->tx_remember = remember; - mb(); - - DPRINTK("Notifying backend via event channel %d\n", - tp->evtchn); - - notify_remote_via_irq(tp->irq); - - spin_unlock_irq(&tp->tx_lock); - return offset; -} - - -static void tpmif_notify_upperlayer(struct tpm_private *tp) -{ - /* - * Notify upper layer about the state of the connection - * to the BE. - */ - mutex_lock(&upperlayer_lock); - - if (upperlayer_tpmfe != NULL) { - if (tp->is_connected) { - upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED); - } else { - upperlayer_tpmfe->status(0); - } - } - mutex_unlock(&upperlayer_lock); -} - - -static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected) -{ - /* - * Don't notify upper layer if we are in suspend mode and - * should disconnect - assumption is that we will resume - * The mutex keeps apps from sending. - */ - if (is_connected == 0 && tp->is_suspended == 1) { - return; - } - - /* - * Unlock the mutex if we are connected again - * after being suspended - now resuming. - * This also removes the suspend state. - */ - if (is_connected == 1 && tp->is_suspended == 1) { - tp->is_suspended = 0; - /* unlock, so apps can resume sending */ - mutex_unlock(&suspend_lock); - } - - if (is_connected != tp->is_connected) { - tp->is_connected = is_connected; - tpmif_notify_upperlayer(tp); - } -} - - -/* ================================================================= - * Initialization function. - * ================================================================= - */ - -static int __init tpmif_init(void) -{ - IPRINTK("Initialising the vTPM driver.\n"); - if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE, - &gref_head ) < 0) { - return -EFAULT; - } - - init_tpm_xenbus(); - - return 0; -} - -module_init(tpmif_init); - -static void __exit tpmif_exit(void) -{ - exit_tpm_xenbus(); - gnttab_free_grant_references(gref_head); -} - -module_exit(tpmif_exit); - -MODULE_LICENSE("Dual BSD/GPL"); - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h Tue May 02 18:17:59 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#ifndef TPM_FRONT_H -#define TPM_FRONT_H - -struct tpm_private { - tpmif_tx_interface_t *tx; - unsigned int evtchn; - unsigned int irq; - u8 is_connected; - u8 is_suspended; - - spinlock_t tx_lock; - - struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE]; - - atomic_t tx_busy; - void *tx_remember; - domid_t backend_id; - wait_queue_head_t wait_q; - - struct xenbus_device *dev; - int ring_ref; -}; - -struct tx_buffer { - unsigned int size; // available space in data - unsigned int len; // used space in data - unsigned char *data; // pointer to a page -}; - -#endif - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -r 55f73916d319 -r 51484df99be1 linux-2.6-xen-sparse/include/xen/tpmfe.h --- a/linux-2.6-xen-sparse/include/xen/tpmfe.h Tue May 02 18:17:59 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#ifndef TPM_FE_H -#define TPM_FE_H - -struct tpm_private; - -struct tpmfe_device { - /* - * Let upper layer receive data from front-end - */ - int (*receive)(const u8 *buffer, size_t count, const void *ptr); - /* - * Indicate the status of the front-end to the upper - * layer. - */ - void (*status)(unsigned int flags); - - /* - * This field indicates the maximum size the driver can - * transfer in one chunk. It is filled out by the front-end - * driver and should be propagated to the generic tpm driver - * for allocation of buffers. - */ - unsigned int max_tx_size; - /* - * The following is a private structure of the underlying - * driver. It's expected as first parameter in the send function. - */ - struct tpm_private *tpm_private; -}; - -enum { - TPMFE_STATUS_DISCONNECTED = 0x0, - TPMFE_STATUS_CONNECTED = 0x1 -}; - -int tpm_fe_send(struct tpm_private * tp, const u8 * buf, size_t count, void *ptr); -int tpm_fe_register_receiver(struct tpmfe_device *); -void tpm_fe_unregister_receiver(void); - -#endif _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |