xen-vtx-unstable

view linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents dd668f7527cb
children
line source
1 /******************************************************************************
2 * drivers/xen/tpmback/interface.c
3 *
4 * Vritual TPM interface management.
5 *
6 * Copyright (c) 2005, IBM Corporation
7 *
8 * Author: Stefan Berger, stefanb@us.ibm.com
9 *
10 * This code has been derived from drivers/xen/netback/interface.c
11 * Copyright (c) 2004, Keir Fraser
12 */
14 #include "common.h"
15 #include <asm-xen/balloon.h>
17 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
19 #define TPMIF_HASHSZ (2 << 5)
20 #define TPMIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(TPMIF_HASHSZ-1))
22 static kmem_cache_t *tpmif_cachep;
23 int num_frontends = 0;
24 LIST_HEAD(tpmif_list);
27 tpmif_t *alloc_tpmif(domid_t domid, long int instance)
28 {
29 struct page *page;
30 tpmif_t *tpmif;
32 tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
33 if (!tpmif)
34 return ERR_PTR(-ENOMEM);
36 memset(tpmif, 0, sizeof(*tpmif));
37 tpmif->domid = domid;
38 tpmif->status = DISCONNECTED;
39 tpmif->tpm_instance = instance;
40 atomic_set(&tpmif->refcnt, 1);
42 page = balloon_alloc_empty_page_range(TPMIF_TX_RING_SIZE);
43 BUG_ON(page == NULL);
44 tpmif->mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
46 list_add(&tpmif->tpmif_list, &tpmif_list);
47 num_frontends++;
49 return tpmif;
50 }
53 void free_tpmif(tpmif_t *tpmif)
54 {
55 num_frontends--;
56 list_del(&tpmif->tpmif_list);
57 kmem_cache_free(tpmif_cachep, tpmif);
58 }
61 tpmif_t *tpmif_find(domid_t domid, long int instance)
62 {
63 tpmif_t *tpmif;
65 list_for_each_entry(tpmif, &tpmif_list, tpmif_list) {
66 if (tpmif->tpm_instance == instance) {
67 if (tpmif->domid == domid) {
68 tpmif_get(tpmif);
69 return tpmif;
70 } else {
71 return NULL;
72 }
73 }
74 }
76 return alloc_tpmif(domid, instance);
77 }
80 static int map_frontend_page(tpmif_t *tpmif, unsigned long localaddr,
81 unsigned long shared_page)
82 {
83 struct gnttab_map_grant_ref op = {
84 .host_addr = localaddr,
85 .flags = GNTMAP_host_map,
86 .ref = shared_page,
87 .dom = tpmif->domid,
88 };
90 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
92 if (op.handle < 0) {
93 DPRINTK(" Grant table operation failure !\n");
94 return op.handle;
95 }
97 tpmif->shmem_ref = shared_page;
98 tpmif->shmem_handle = op.handle;
99 tpmif->shmem_vaddr = localaddr;
100 return 0;
101 }
104 static void unmap_frontend_page(tpmif_t *tpmif)
105 {
106 struct gnttab_unmap_grant_ref op;
108 op.host_addr = tpmif->shmem_vaddr;
109 op.handle = tpmif->shmem_handle;
110 op.dev_bus_addr = 0;
112 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
113 }
116 int tpmif_map(tpmif_t *tpmif,
117 unsigned long shared_page, unsigned int evtchn)
118 {
119 struct vm_struct *vma;
120 evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
121 int err;
123 BUG_ON(tpmif->remote_evtchn);
125 if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
126 return -ENOMEM;
128 err = map_frontend_page(tpmif,
129 VMALLOC_VMADDR(vma->addr),
130 shared_page);
131 if (err) {
132 vfree(vma->addr);
133 return err;
134 }
136 op.u.bind_interdomain.dom1 = DOMID_SELF;
137 op.u.bind_interdomain.dom2 = tpmif->domid;
138 op.u.bind_interdomain.port1 = 0;
139 op.u.bind_interdomain.port2 = evtchn;
140 err = HYPERVISOR_event_channel_op(&op);
141 if (err) {
142 unmap_frontend_page(tpmif);
143 vfree(vma->addr);
144 return err;
145 }
147 tpmif->evtchn = op.u.bind_interdomain.port1;
148 tpmif->remote_evtchn = evtchn;
150 tpmif->tx = (tpmif_tx_interface_t *) vma->addr;
152 bind_evtchn_to_irqhandler(tpmif->evtchn,
153 tpmif_be_int,
154 0,
155 "tpmif-backend",
156 tpmif);
157 tpmif->status = CONNECTED;
158 tpmif->shmem_ref = shared_page;
159 tpmif->active = 1;
161 return 0;
162 }
165 static void __tpmif_disconnect_complete(void *arg)
166 {
167 evtchn_op_t op = { .cmd = EVTCHNOP_close };
168 tpmif_t *tpmif = (tpmif_t *) arg;
170 op.u.close.port = tpmif->evtchn;
171 op.u.close.dom = DOMID_SELF;
172 HYPERVISOR_event_channel_op(&op);
173 op.u.close.port = tpmif->remote_evtchn;
174 op.u.close.dom = tpmif->domid;
175 HYPERVISOR_event_channel_op(&op);
177 if (tpmif->evtchn)
178 unbind_evtchn_from_irqhandler(tpmif->evtchn, tpmif);
180 if (tpmif->tx) {
181 unmap_frontend_page(tpmif);
182 vfree(tpmif->tx);
183 }
185 free_tpmif(tpmif);
186 }
189 void tpmif_disconnect_complete(tpmif_t * tpmif)
190 {
191 INIT_WORK(&tpmif->work, __tpmif_disconnect_complete, (void *)tpmif);
192 schedule_work(&tpmif->work);
193 }
196 void __init tpmif_interface_init(void)
197 {
198 tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof(tpmif_t),
199 0, 0, NULL, NULL);
200 }