ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c @ 14096:58086aa7c70a

linux, tpm: Fix argument to grant table operation
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Fri Feb 23 16:24:07 2007 +0000 (2007-02-23)
parents d275951acf10
children cc18ea7309b3
line source
1 /*
2 * Copyright (c) 2005, IBM Corporation
3 *
4 * Author: Stefan Berger, stefanb@us.ibm.com
5 * Grant table support: Mahadevan Gomathisankaran
6 *
7 * This code has been derived from drivers/xen/netfront/netfront.c
8 *
9 * Copyright (c) 2002-2004, K A Fraser
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation; or, when distributed
14 * separately from the Linux kernel or incorporated into other
15 * software packages, subject to the following license:
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this source file (the "Software"), to deal in the Software without
19 * restriction, including without limitation the rights to use, copy, modify,
20 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
21 * and to permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included in
25 * all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 * IN THE SOFTWARE.
34 */
36 #include <linux/errno.h>
37 #include <linux/err.h>
38 #include <linux/interrupt.h>
39 #include <linux/mutex.h>
40 #include <asm/uaccess.h>
41 #include <xen/evtchn.h>
42 #include <xen/interface/grant_table.h>
43 #include <xen/interface/io/tpmif.h>
44 #include <xen/gnttab.h>
45 #include <xen/xenbus.h>
46 #include "tpm.h"
47 #include "tpm_vtpm.h"
49 #undef DEBUG
51 /* local structures */
52 struct tpm_private {
53 struct tpm_chip *chip;
55 tpmif_tx_interface_t *tx;
56 atomic_t refcnt;
57 unsigned int irq;
58 u8 is_connected;
59 u8 is_suspended;
61 spinlock_t tx_lock;
63 struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE];
65 atomic_t tx_busy;
66 void *tx_remember;
68 domid_t backend_id;
69 wait_queue_head_t wait_q;
71 struct xenbus_device *dev;
72 int ring_ref;
73 };
75 struct tx_buffer {
76 unsigned int size; // available space in data
77 unsigned int len; // used space in data
78 unsigned char *data; // pointer to a page
79 };
82 /* locally visible variables */
83 static grant_ref_t gref_head;
84 static struct tpm_private *my_priv;
86 /* local function prototypes */
87 static irqreturn_t tpmif_int(int irq,
88 void *tpm_priv,
89 struct pt_regs *ptregs);
90 static void tpmif_rx_action(unsigned long unused);
91 static int tpmif_connect(struct xenbus_device *dev,
92 struct tpm_private *tp,
93 domid_t domid);
94 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
95 static int tpmif_allocate_tx_buffers(struct tpm_private *tp);
96 static void tpmif_free_tx_buffers(struct tpm_private *tp);
97 static void tpmif_set_connected_state(struct tpm_private *tp,
98 u8 newstate);
99 static int tpm_xmit(struct tpm_private *tp,
100 const u8 * buf, size_t count, int userbuffer,
101 void *remember);
102 static void destroy_tpmring(struct tpm_private *tp);
103 void __exit tpmif_exit(void);
105 #define DPRINTK(fmt, args...) \
106 pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
107 #define IPRINTK(fmt, args...) \
108 printk(KERN_INFO "xen_tpm_fr: " fmt, ##args)
109 #define WPRINTK(fmt, args...) \
110 printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args)
112 #define GRANT_INVALID_REF 0
115 static inline int
116 tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len,
117 int isuserbuffer)
118 {
119 int copied = len;
121 if (len > txb->size) {
122 copied = txb->size;
123 }
124 if (isuserbuffer) {
125 if (copy_from_user(txb->data, src, copied))
126 return -EFAULT;
127 } else {
128 memcpy(txb->data, src, copied);
129 }
130 txb->len = len;
131 return copied;
132 }
134 static inline struct tx_buffer *tx_buffer_alloc(void)
135 {
136 struct tx_buffer *txb = kzalloc(sizeof (struct tx_buffer),
137 GFP_KERNEL);
139 if (txb) {
140 txb->len = 0;
141 txb->size = PAGE_SIZE;
142 txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
143 if (txb->data == NULL) {
144 kfree(txb);
145 txb = NULL;
146 }
147 }
148 return txb;
149 }
152 static inline void tx_buffer_free(struct tx_buffer *txb)
153 {
154 if (txb) {
155 free_page((long)txb->data);
156 kfree(txb);
157 }
158 }
160 /**************************************************************
161 Utility function for the tpm_private structure
162 **************************************************************/
163 static inline void tpm_private_init(struct tpm_private *tp)
164 {
165 spin_lock_init(&tp->tx_lock);
166 init_waitqueue_head(&tp->wait_q);
167 atomic_set(&tp->refcnt, 1);
168 }
170 static inline void tpm_private_put(void)
171 {
172 if ( atomic_dec_and_test(&my_priv->refcnt)) {
173 tpmif_free_tx_buffers(my_priv);
174 kfree(my_priv);
175 my_priv = NULL;
176 }
177 }
179 static struct tpm_private *tpm_private_get(void)
180 {
181 int err;
182 if (!my_priv) {
183 my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL);
184 if (my_priv) {
185 tpm_private_init(my_priv);
186 err = tpmif_allocate_tx_buffers(my_priv);
187 if (err < 0) {
188 tpm_private_put();
189 }
190 }
191 } else {
192 atomic_inc(&my_priv->refcnt);
193 }
194 return my_priv;
195 }
197 /**************************************************************
199 The interface to let the tpm plugin register its callback
200 function and send data to another partition using this module
202 **************************************************************/
204 static DEFINE_MUTEX(suspend_lock);
205 /*
206 * Send data via this module by calling this function
207 */
208 int vtpm_vd_send(struct tpm_private *tp,
209 const u8 * buf, size_t count, void *ptr)
210 {
211 int sent;
213 mutex_lock(&suspend_lock);
214 sent = tpm_xmit(tp, buf, count, 0, ptr);
215 mutex_unlock(&suspend_lock);
217 return sent;
218 }
220 /**************************************************************
221 XENBUS support code
222 **************************************************************/
224 static int setup_tpmring(struct xenbus_device *dev,
225 struct tpm_private *tp)
226 {
227 tpmif_tx_interface_t *sring;
228 int err;
230 tp->ring_ref = GRANT_INVALID_REF;
232 sring = (void *)__get_free_page(GFP_KERNEL);
233 if (!sring) {
234 xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
235 return -ENOMEM;
236 }
237 tp->tx = sring;
239 err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
240 if (err < 0) {
241 free_page((unsigned long)sring);
242 tp->tx = NULL;
243 xenbus_dev_fatal(dev, err, "allocating grant reference");
244 goto fail;
245 }
246 tp->ring_ref = err;
248 err = tpmif_connect(dev, tp, dev->otherend_id);
249 if (err)
250 goto fail;
252 return 0;
253 fail:
254 destroy_tpmring(tp);
255 return err;
256 }
259 static void destroy_tpmring(struct tpm_private *tp)
260 {
261 tpmif_set_connected_state(tp, 0);
263 if (tp->ring_ref != GRANT_INVALID_REF) {
264 gnttab_end_foreign_access(tp->ring_ref, 0,
265 (unsigned long)tp->tx);
266 tp->ring_ref = GRANT_INVALID_REF;
267 tp->tx = NULL;
268 }
270 if (tp->irq)
271 unbind_from_irqhandler(tp->irq, tp);
273 tp->irq = 0;
274 }
277 static int talk_to_backend(struct xenbus_device *dev,
278 struct tpm_private *tp)
279 {
280 const char *message = NULL;
281 int err;
282 struct xenbus_transaction xbt;
284 err = setup_tpmring(dev, tp);
285 if (err) {
286 xenbus_dev_fatal(dev, err, "setting up ring");
287 goto out;
288 }
290 again:
291 err = xenbus_transaction_start(&xbt);
292 if (err) {
293 xenbus_dev_fatal(dev, err, "starting transaction");
294 goto destroy_tpmring;
295 }
297 err = xenbus_printf(xbt, dev->nodename,
298 "ring-ref","%u", tp->ring_ref);
299 if (err) {
300 message = "writing ring-ref";
301 goto abort_transaction;
302 }
304 err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
305 irq_to_evtchn_port(tp->irq));
306 if (err) {
307 message = "writing event-channel";
308 goto abort_transaction;
309 }
311 err = xenbus_transaction_end(xbt, 0);
312 if (err == -EAGAIN)
313 goto again;
314 if (err) {
315 xenbus_dev_fatal(dev, err, "completing transaction");
316 goto destroy_tpmring;
317 }
319 xenbus_switch_state(dev, XenbusStateConnected);
321 return 0;
323 abort_transaction:
324 xenbus_transaction_end(xbt, 1);
325 if (message)
326 xenbus_dev_error(dev, err, "%s", message);
327 destroy_tpmring:
328 destroy_tpmring(tp);
329 out:
330 return err;
331 }
333 /**
334 * Callback received when the backend's state changes.
335 */
336 static void backend_changed(struct xenbus_device *dev,
337 enum xenbus_state backend_state)
338 {
339 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
340 DPRINTK("\n");
342 switch (backend_state) {
343 case XenbusStateInitialising:
344 case XenbusStateInitWait:
345 case XenbusStateInitialised:
346 case XenbusStateUnknown:
347 break;
349 case XenbusStateConnected:
350 tpmif_set_connected_state(tp, 1);
351 break;
353 case XenbusStateClosing:
354 tpmif_set_connected_state(tp, 0);
355 xenbus_frontend_closed(dev);
356 break;
358 case XenbusStateClosed:
359 tpmif_set_connected_state(tp, 0);
360 if (tp->is_suspended == 0)
361 device_unregister(&dev->dev);
362 xenbus_frontend_closed(dev);
363 break;
364 }
365 }
367 struct tpm_virtual_device tvd = {
368 .max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE,
369 };
371 static int tpmfront_probe(struct xenbus_device *dev,
372 const struct xenbus_device_id *id)
373 {
374 int err;
375 int handle;
376 struct tpm_private *tp = tpm_private_get();
378 if (!tp)
379 return -ENOMEM;
381 tp->chip = init_vtpm(&dev->dev, &tvd, tp);
383 if (IS_ERR(tp->chip)) {
384 return PTR_ERR(tp->chip);
385 }
387 err = xenbus_scanf(XBT_NIL, dev->nodename,
388 "handle", "%i", &handle);
389 if (XENBUS_EXIST_ERR(err))
390 return err;
392 if (err < 0) {
393 xenbus_dev_fatal(dev,err,"reading virtual-device");
394 return err;
395 }
397 tp->dev = dev;
399 err = talk_to_backend(dev, tp);
400 if (err) {
401 tpm_private_put();
402 return err;
403 }
404 return 0;
405 }
408 static int tpmfront_remove(struct xenbus_device *dev)
409 {
410 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
411 destroy_tpmring(tp);
412 cleanup_vtpm(&dev->dev);
413 return 0;
414 }
416 static int tpmfront_suspend(struct xenbus_device *dev)
417 {
418 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
419 u32 ctr;
420 /* lock, so no app can send */
421 mutex_lock(&suspend_lock);
422 tp->is_suspended = 1;
424 for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 300; ctr++) {
425 if ((ctr % 10) == 0)
426 printk("TPM-FE [INFO]: Waiting for outstanding "
427 "request.\n");
428 /*
429 * Wait for a request to be responded to.
430 */
431 interruptible_sleep_on_timeout(&tp->wait_q, 100);
432 }
433 xenbus_switch_state(dev, XenbusStateClosing);
435 if (atomic_read(&tp->tx_busy)) {
436 /*
437 * A temporary work-around.
438 */
439 printk("TPM-FE [WARNING]: Resetting busy flag.");
440 atomic_set(&tp->tx_busy, 0);
441 }
443 return 0;
444 }
446 static int tpmfront_resume(struct xenbus_device *dev)
447 {
448 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
449 destroy_tpmring(tp);
450 return talk_to_backend(dev, tp);
451 }
453 static int tpmif_connect(struct xenbus_device *dev,
454 struct tpm_private *tp,
455 domid_t domid)
456 {
457 int err;
459 tp->backend_id = domid;
461 err = bind_listening_port_to_irqhandler(
462 domid, tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp);
463 if (err <= 0) {
464 WPRINTK("bind_listening_port_to_irqhandler failed "
465 "(err=%d)\n", err);
466 return err;
467 }
468 tp->irq = err;
470 return 0;
471 }
473 static struct xenbus_device_id tpmfront_ids[] = {
474 { "vtpm" },
475 { "" }
476 };
478 static struct xenbus_driver tpmfront = {
479 .name = "vtpm",
480 .owner = THIS_MODULE,
481 .ids = tpmfront_ids,
482 .probe = tpmfront_probe,
483 .remove = tpmfront_remove,
484 .resume = tpmfront_resume,
485 .otherend_changed = backend_changed,
486 .suspend = tpmfront_suspend,
487 };
489 static void __init init_tpm_xenbus(void)
490 {
491 xenbus_register_frontend(&tpmfront);
492 }
494 static void __exit exit_tpm_xenbus(void)
495 {
496 xenbus_unregister_driver(&tpmfront);
497 }
499 static int tpmif_allocate_tx_buffers(struct tpm_private *tp)
500 {
501 unsigned int i;
503 for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
504 tp->tx_buffers[i] = tx_buffer_alloc();
505 if (!tp->tx_buffers[i]) {
506 tpmif_free_tx_buffers(tp);
507 return -ENOMEM;
508 }
509 }
510 return 0;
511 }
513 static void tpmif_free_tx_buffers(struct tpm_private *tp)
514 {
515 unsigned int i;
517 for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
518 tx_buffer_free(tp->tx_buffers[i]);
519 }
520 }
522 static void tpmif_rx_action(unsigned long priv)
523 {
524 struct tpm_private *tp = (struct tpm_private *)priv;
526 int i = 0;
527 unsigned int received;
528 unsigned int offset = 0;
529 u8 *buffer;
530 tpmif_tx_request_t *tx;
531 tx = &tp->tx->ring[i].req;
533 atomic_set(&tp->tx_busy, 0);
534 wake_up_interruptible(&tp->wait_q);
536 received = tx->size;
538 buffer = kmalloc(received, GFP_ATOMIC);
539 if (NULL == buffer) {
540 goto exit;
541 }
543 for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) {
544 struct tx_buffer *txb = tp->tx_buffers[i];
545 tpmif_tx_request_t *tx;
546 unsigned int tocopy;
548 tx = &tp->tx->ring[i].req;
549 tocopy = tx->size;
550 if (tocopy > PAGE_SIZE) {
551 tocopy = PAGE_SIZE;
552 }
554 memcpy(&buffer[offset], txb->data, tocopy);
556 gnttab_release_grant_reference(&gref_head, tx->ref);
558 offset += tocopy;
559 }
561 vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember);
562 kfree(buffer);
564 exit:
566 return;
567 }
570 static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs)
571 {
572 struct tpm_private *tp = tpm_priv;
573 unsigned long flags;
575 spin_lock_irqsave(&tp->tx_lock, flags);
576 tpmif_rx_tasklet.data = (unsigned long)tp;
577 tasklet_schedule(&tpmif_rx_tasklet);
578 spin_unlock_irqrestore(&tp->tx_lock, flags);
580 return IRQ_HANDLED;
581 }
584 static int tpm_xmit(struct tpm_private *tp,
585 const u8 * buf, size_t count, int isuserbuffer,
586 void *remember)
587 {
588 tpmif_tx_request_t *tx;
589 TPMIF_RING_IDX i;
590 unsigned int offset = 0;
592 spin_lock_irq(&tp->tx_lock);
594 if (unlikely(atomic_read(&tp->tx_busy))) {
595 printk("tpm_xmit: There's an outstanding request/response "
596 "on the way!\n");
597 spin_unlock_irq(&tp->tx_lock);
598 return -EBUSY;
599 }
601 if (tp->is_connected != 1) {
602 spin_unlock_irq(&tp->tx_lock);
603 return -EIO;
604 }
606 for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) {
607 struct tx_buffer *txb = tp->tx_buffers[i];
608 int copied;
610 if (NULL == txb) {
611 DPRINTK("txb (i=%d) is NULL. buffers initilized?\n"
612 "Not transmitting anything!\n", i);
613 spin_unlock_irq(&tp->tx_lock);
614 return -EFAULT;
615 }
616 copied = tx_buffer_copy(txb, &buf[offset], count,
617 isuserbuffer);
618 if (copied < 0) {
619 /* An error occurred */
620 spin_unlock_irq(&tp->tx_lock);
621 return copied;
622 }
623 count -= copied;
624 offset += copied;
626 tx = &tp->tx->ring[i].req;
628 tx->addr = virt_to_machine(txb->data);
629 tx->size = txb->len;
631 DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n",
632 txb->data[0],txb->data[1],txb->data[2],txb->data[3]);
634 /* get the granttable reference for this page */
635 tx->ref = gnttab_claim_grant_reference(&gref_head);
637 if (-ENOSPC == tx->ref) {
638 spin_unlock_irq(&tp->tx_lock);
639 DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__);
640 return -ENOSPC;
641 }
642 gnttab_grant_foreign_access_ref( tx->ref,
643 tp->backend_id,
644 virt_to_mfn(txb->data),
645 0 /*RW*/);
646 wmb();
647 }
649 atomic_set(&tp->tx_busy, 1);
650 tp->tx_remember = remember;
652 mb();
654 notify_remote_via_irq(tp->irq);
656 spin_unlock_irq(&tp->tx_lock);
657 return offset;
658 }
661 static void tpmif_notify_upperlayer(struct tpm_private *tp)
662 {
663 /*
664 * Notify upper layer about the state of the connection
665 * to the BE.
666 */
667 if (tp->is_connected) {
668 vtpm_vd_status(tp->chip, TPM_VD_STATUS_CONNECTED);
669 } else {
670 vtpm_vd_status(tp->chip, TPM_VD_STATUS_DISCONNECTED);
671 }
672 }
675 static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
676 {
677 /*
678 * Don't notify upper layer if we are in suspend mode and
679 * should disconnect - assumption is that we will resume
680 * The mutex keeps apps from sending.
681 */
682 if (is_connected == 0 && tp->is_suspended == 1) {
683 return;
684 }
686 /*
687 * Unlock the mutex if we are connected again
688 * after being suspended - now resuming.
689 * This also removes the suspend state.
690 */
691 if (is_connected == 1 && tp->is_suspended == 1) {
692 tp->is_suspended = 0;
693 /* unlock, so apps can resume sending */
694 mutex_unlock(&suspend_lock);
695 }
697 if (is_connected != tp->is_connected) {
698 tp->is_connected = is_connected;
699 tpmif_notify_upperlayer(tp);
700 }
701 }
705 /* =================================================================
706 * Initialization function.
707 * =================================================================
708 */
711 static int __init tpmif_init(void)
712 {
713 long rc = 0;
714 struct tpm_private *tp;
716 if (is_initial_xendomain())
717 return -EPERM;
719 tp = tpm_private_get();
720 if (!tp) {
721 rc = -ENOMEM;
722 goto failexit;
723 }
725 IPRINTK("Initialising the vTPM driver.\n");
726 if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE,
727 &gref_head ) < 0) {
728 rc = -EFAULT;
729 goto gnttab_alloc_failed;
730 }
732 init_tpm_xenbus();
733 return 0;
735 gnttab_alloc_failed:
736 tpm_private_put();
737 failexit:
739 return (int)rc;
740 }
743 void __exit tpmif_exit(void)
744 {
745 exit_tpm_xenbus();
746 tpm_private_put();
747 gnttab_free_grant_references(gref_head);
748 }
750 module_init(tpmif_init);
752 MODULE_LICENSE("Dual BSD/GPL");