# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID cb215a84d1af0aa0143e52a459607f54503a51a7
# Parent b0338759544e116337f25d5cdebc59c38a6d40c5
Update vtpm driver following the recent changes to the
xenbus driver and its semantics.
Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx>
diff -r b0338759544e -r cb215a84d1af docs/misc/vtpm.txt
--- a/docs/misc/vtpm.txt Thu Nov 24 22:21:48 2005
+++ b/docs/misc/vtpm.txt Fri Nov 25 08:14:01 2005
@@ -73,7 +73,14 @@
where the TPM backend has been compiled into - this has to be
domain 0 at the moment - and which TPM instance the user domain
is supposed to talk to. Note that each running VM must use a
-different instance and that using instance 0 is NOT allowed.
+different instance and that using instance 0 is NOT allowed. The
+instance parameter is taken as the desired instance number, but
+the actual instance number that is assigned to the virtual machine
+can be different. This is the case if for example that particular
+instance is already used by another virtual machine. The association
+of which TPM instance number is used by which virtual machine is
+kept in the file /etc/xen/vtpm.db. Associations are maintained by
+domain name and instance number.
Note: If you do not want TPM functionality for your user domain simply
leave out the 'vtpm' line in the configuration file.
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
--- a/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Fri Nov 25 08:14:01 2005
@@ -17,15 +17,6 @@
obtained at: <http://sourceforge.net/projects/trousers>. To
compile this driver as a module, choose M here; the module
will be called tpm. If unsure, say N.
-
-config TCG_TIS
- tristate "TPM Interface Specification 1.2 Interface"
- depends on TCG_TPM
- ---help---
- If you have a TPM security chip that is compliant with the
- TCG TIS 1.2 TPM specification say Yes and it will be accessible
- from within Linux. To compile this driver as a module, choose
- M here; the module will be called tpm_tis.
config TCG_NSC
tristate "National Semiconductor TPM Interface"
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h Fri Nov 25 08:14:01 2005
@@ -28,7 +28,7 @@
#endif
typedef struct tpmif_st {
- struct list_head tpmif_list;
+ struct list_head tpmif_list;
/* Unique identifier for this interface. */
domid_t domid;
unsigned int handle;
@@ -83,6 +83,11 @@
#define MMAP_VADDR(t,_req) ((t)->mmap_vstart + ((_req) * PAGE_SIZE))
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
#endif /* __TPMIF__BACKEND__COMMON_H__ */
/*
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c Thu Nov 24
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c Fri Nov 25
08:14:01 2005
@@ -127,6 +127,10 @@
.u.bind_interdomain.remote_dom = tpmif->domid,
.u.bind_interdomain.remote_port = evtchn };
+ if (tpmif->irq) {
+ return 0;
+ }
+
if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
return -ENOMEM;
@@ -149,7 +153,6 @@
tpmif->irq = bind_evtchn_to_irqhandler(
tpmif->evtchn, tpmif_be_int, 0, "tpmif-backend", tpmif);
- tpmif->status = CONNECTED;
tpmif->shmem_ref = shared_page;
tpmif->active = 1;
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Thu Nov 24 22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Fri Nov 25 08:14:01 2005
@@ -1,4 +1,5 @@
/* Xenbus code for tpmif backend
+ Copyright (C) 2005 IBM Corporation
Copyright (C) 2005 Rusty Russell <rusty@xxxxxxxxxxxxxxx>
This program is free software; you can redistribute it and/or modify
@@ -29,72 +30,189 @@
long int frontend_id;
long int instance; // instance of TPM
+ u8 is_instance_set;// whether instance number has been set
/* watch front end for changes */
struct xenbus_watch backend_watch;
-
- struct xenbus_watch watch;
- char * frontpath;
+ XenbusState frontend_state;
};
+static void maybe_connect(struct backend_info *be);
+static void connect(struct backend_info *be);
+static int connect_ring(struct backend_info *be);
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len);
+static void frontend_changed(struct xenbus_device *dev,
+ XenbusState frontend_state);
+
static int tpmback_remove(struct xenbus_device *dev)
{
struct backend_info *be = dev->data;
- if (be->watch.node)
- unregister_xenbus_watch(&be->watch);
- unregister_xenbus_watch(&be->backend_watch);
-
- tpmif_vtpm_close(be->instance);
-
- if (be->tpmif)
+ if (be->backend_watch.node) {
+ unregister_xenbus_watch(&be->backend_watch);
+ kfree(be->backend_watch.node);
+ be->backend_watch.node = NULL;
+ }
+ if (be->tpmif) {
tpmif_put(be->tpmif);
-
- kfree(be->frontpath);
+ be->tpmif = NULL;
+ }
kfree(be);
+ dev->data = NULL;
return 0;
}
-
-static void frontend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- unsigned long ringref;
- unsigned int evtchn;
- unsigned long ready = 1;
- int err;
- struct xenbus_transaction *xbt;
+static int tpmback_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ struct backend_info *be = kmalloc(sizeof(struct backend_info),
+ GFP_KERNEL);
+
+ if (!be) {
+ xenbus_dev_fatal(dev, -ENOMEM,
+ "allocating backend structure");
+ return -ENOMEM;
+ }
+
+ memset(be, 0, sizeof(*be));
+
+ be->is_instance_set = FALSE;
+ be->dev = dev;
+ dev->data = be;
+
+ err = xenbus_watch_path2(dev, dev->nodename,
+ "instance", &be->backend_watch,
+ backend_changed);
+ if (err) {
+ goto fail;
+ }
+
+ err = xenbus_switch_state(dev, NULL, XenbusStateInitWait);
+ if (err) {
+ goto fail;
+ }
+ return 0;
+fail:
+ tpmback_remove(dev);
+ return err;
+}
+
+
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ int err;
+ long instance;
struct backend_info *be
- = container_of(watch, struct backend_info, watch);
-
- /* If other end is gone, delete ourself. */
- if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
- xenbus_rm(NULL, be->dev->nodename, "");
+ = container_of(watch, struct backend_info, backend_watch);
+ struct xenbus_device *dev = be->dev;
+
+ err = xenbus_scanf(NULL, dev->nodename,
+ "instance","%li", &instance);
+ if (XENBUS_EXIST_ERR(err)) {
+ return;
+ }
+
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading instance");
+ return;
+ }
+
+ if (be->is_instance_set != FALSE && be->instance != instance) {
+ printk(KERN_WARNING
+ "tpmback: changing instance (from %ld to %ld) "
+ "not allowed.\n",
+ be->instance, instance);
+ return;
+ }
+
+ if (be->is_instance_set == FALSE) {
+ be->tpmif = tpmif_find(dev->otherend_id,
+ instance);
+ if (IS_ERR(be->tpmif)) {
+ err = PTR_ERR(be->tpmif);
+ be->tpmif = NULL;
+ xenbus_dev_fatal(dev,err,"creating block interface");
+ return;
+ }
+ be->instance = instance;
+ be->is_instance_set = TRUE;
+
+ /*
+ * There's an unfortunate problem:
+ * Sometimes after a suspend/resume the
+ * state switch to XenbusStateInitialised happens
+ * *before* I get to this point here. Since then
+ * the connect_ring() must have failed (be->tpmif is
+ * still NULL), I just call it here again indirectly.
+ */
+ if (be->frontend_state == XenbusStateInitialised) {
+ frontend_changed(dev, be->frontend_state);
+ }
+ }
+}
+
+
+static void frontend_changed(struct xenbus_device *dev,
+ XenbusState frontend_state)
+{
+ struct backend_info *be = dev->data;
+ int err;
+
+ be->frontend_state = frontend_state;
+
+ switch (frontend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateConnected:
+ break;
+
+ case XenbusStateInitialised:
+ err = connect_ring(be);
+ if (err) {
+ return;
+ }
+ maybe_connect(be);
+ break;
+
+ case XenbusStateClosing:
+ xenbus_switch_state(dev, NULL, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ /*
+ * Notify the vTPM manager about the front-end
+ * having left.
+ */
+ tpmif_vtpm_close(be->instance);
device_unregister(&be->dev->dev);
- return;
- }
+ break;
+
+ case XenbusStateUnknown:
+ case XenbusStateInitWait:
+ default:
+ xenbus_dev_fatal(dev, -EINVAL,
+ "saw state %d at frontend",
+ frontend_state);
+ break;
+ }
+}
+
+
+
+static void maybe_connect(struct backend_info *be)
+{
+ int err;
if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
return;
- err = xenbus_gather(NULL, be->frontpath,
- "ring-ref", "%lu", &ringref,
- "event-channel", "%u", &evtchn, NULL);
- if (err) {
- xenbus_dev_error(be->dev, err,
- "reading %s/ring-ref and event-channel",
- be->frontpath);
- return;
- }
-
- err = tpmif_map(be->tpmif, ringref, evtchn);
- if (err) {
- xenbus_dev_error(be->dev, err,
- "mapping shared-frame %lu port %u",
- ringref, evtchn);
- return;
- }
-
+ connect(be);
+
+ /*
+ * Notify the vTPM manager about a new front-end.
+ */
err = tpmif_vtpm_open(be->tpmif,
be->frontend_id,
be->instance);
@@ -107,157 +225,75 @@
*/
return;
}
-
- /*
- * Tell the front-end that we are ready to go -
- * unless something bad happens
- */
+}
+
+
+static void connect(struct backend_info *be)
+{
+ struct xenbus_transaction *xbt;
+ int err;
+ struct xenbus_device *dev = be->dev;
+ unsigned long ready = 1;
+
again:
xbt = xenbus_transaction_start();
if (IS_ERR(xbt)) {
- xenbus_dev_error(be->dev, err, "starting transaction");
+ err = PTR_ERR(xbt);
+ xenbus_dev_fatal(be->dev, err, "starting transaction");
return;
}
err = xenbus_printf(xbt, be->dev->nodename,
"ready", "%lu", ready);
if (err) {
- xenbus_dev_error(be->dev, err, "writing 'ready'");
+ xenbus_dev_fatal(be->dev, err, "writing 'ready'");
goto abort;
}
+
+ err = xenbus_switch_state(dev, xbt, XenbusStateConnected);
+ if (err)
+ goto abort;
+
+ be->tpmif->status = CONNECTED;
err = xenbus_transaction_end(xbt, 0);
if (err == -EAGAIN)
goto again;
if (err) {
- xenbus_dev_error(be->dev, err, "end of transaction");
- goto abort;
- }
-
- xenbus_dev_ok(be->dev);
+ xenbus_dev_fatal(be->dev, err, "end of transaction");
+ }
return;
abort:
xenbus_transaction_end(xbt, 1);
}
-static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- int err;
- long int instance;
- struct backend_info *be
- = container_of(watch, struct backend_info, backend_watch);
+static int connect_ring(struct backend_info *be)
+{
struct xenbus_device *dev = be->dev;
-
- err = xenbus_scanf(NULL, dev->nodename, "instance", "%li", &instance);
- if (XENBUS_EXIST_ERR(err))
- return;
- if (err < 0) {
- xenbus_dev_error(dev, err, "reading 'instance' variable");
- return;
- }
-
- if (be->instance != -1 && be->instance != instance) {
- printk(KERN_WARNING
- "cannot change the instance\n");
- return;
- }
- be->instance = instance;
-
- if (be->tpmif == NULL) {
- unsigned int len = max(XS_WATCH_PATH, XS_WATCH_TOKEN) + 1;
- const char *vec[len];
-
- be->tpmif = tpmif_find(be->frontend_id,
- instance);
- if (IS_ERR(be->tpmif)) {
- err = PTR_ERR(be->tpmif);
- be->tpmif = NULL;
- xenbus_dev_error(dev, err, "creating interface");
- return;
+ unsigned long ring_ref;
+ unsigned int evtchn;
+ int err;
+
+ err = xenbus_gather(NULL, dev->otherend,
+ "ring-ref", "%lu", &ring_ref,
+ "event-channel", "%u", &evtchn, NULL);
+ if (err) {
+ xenbus_dev_error(dev, err,
+ "reading %s/ring-ref and event-channel",
+ dev->otherend);
+ return err;
+ }
+ if (be->tpmif != NULL) {
+ err = tpmif_map(be->tpmif, ring_ref, evtchn);
+ if (err) {
+ xenbus_dev_error(dev, err,
+ "mapping shared-frame %lu port %u",
+ ring_ref, evtchn);
+ return err;
}
-
- vec[XS_WATCH_PATH] = be->frontpath;
- vec[XS_WATCH_TOKEN] = NULL;
-
- /* Pass in NULL node to skip exist test. */
- frontend_changed(&be->watch, vec, len);
- }
-}
-
-
-static int tpmback_probe(struct xenbus_device *dev,
- const struct xenbus_device_id *id)
-{
- struct backend_info *be;
- char *frontend;
- int err;
-
- be = kmalloc(sizeof(*be), GFP_KERNEL);
- if (!be) {
- xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
- err = -ENOMEM;
- }
-
- memset(be, 0, sizeof(*be));
-
- frontend = NULL;
- err = xenbus_gather(NULL, dev->nodename,
- "frontend-id", "%li", &be->frontend_id,
- "frontend", NULL, &frontend,
- NULL);
- if (XENBUS_EXIST_ERR(err))
- goto free_be;
- if (err < 0) {
- xenbus_dev_error(dev, err,
- "reading %s/frontend or frontend-id",
- dev->nodename);
- goto free_be;
- }
- if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) {
- /* If we can't get a frontend path and a frontend-id,
- * then our bus-id is no longer valid and we need to
- * destroy the backend device.
- */
- err = -ENOENT;
- goto free_be;
- }
-
- be->dev = dev;
- be->backend_watch.node = dev->nodename;
- /* Implicitly calls backend_changed() once. */
- be->backend_watch.callback = backend_changed;
- be->instance = -1;
- err = register_xenbus_watch(&be->backend_watch);
- if (err) {
- be->backend_watch.node = NULL;
- xenbus_dev_error(dev, err, "adding backend watch on %s",
- dev->nodename);
- goto free_be;
- }
-
- be->frontpath = frontend;
- be->watch.node = be->frontpath;
- be->watch.callback = frontend_changed;
- err = register_xenbus_watch(&be->watch);
- if (err) {
- be->watch.node = NULL;
- xenbus_dev_error(dev, err,
- "adding frontend watch on %s",
- be->frontpath);
- goto free_be;
- }
-
- dev->data = be;
- return err;
-
-free_be:
- if (be->backend_watch.node)
- unregister_xenbus_watch(&be->backend_watch);
- kfree(frontend);
- kfree(be);
- return err;
+ }
+ return 0;
}
@@ -273,6 +309,7 @@
.ids = tpmback_ids,
.probe = tpmback_probe,
.remove = tpmback_remove,
+ .otherend_changed = frontend_changed,
};
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c Thu Nov 24
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c Fri Nov 25
08:14:01 2005
@@ -73,7 +73,8 @@
static void tpmif_connect(u16 evtchn, domid_t domid);
static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
static int tpm_allocate_buffers(struct tpm_private *tp);
-static void tpmif_set_connected_state(struct tpm_private *tp, int newstate);
+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);
@@ -212,87 +213,46 @@
XENBUS support code
**************************************************************/
-static void watch_for_status(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- struct tpmfront_info *info;
- int err;
- unsigned long ready;
- struct tpm_private *tp = &my_private;
- const char *node = vec[XS_WATCH_PATH];
-
- info = container_of(watch, struct tpmfront_info, watch);
- node += strlen(watch->node);
-
- if (tp->connected)
- return;
-
- err = xenbus_gather(NULL, watch->node,
- "ready", "%lu", &ready,
- NULL);
- if (err) {
- xenbus_dev_error(info->dev, err, "reading 'ready' field");
- return;
- }
-
- tpmif_set_connected_state(tp, 1);
-
- xenbus_dev_ok(info->dev);
-}
-
-
static int setup_tpmring(struct xenbus_device *dev,
- struct tpmfront_info * info,
- domid_t backend_id)
+ struct tpmfront_info * info)
{
tpmif_tx_interface_t *sring;
struct tpm_private *tp = &my_private;
int err;
- evtchn_op_t op = {
- .cmd = EVTCHNOP_alloc_unbound,
- .u.alloc_unbound.dom = DOMID_SELF,
- .u.alloc_unbound.remote_dom = backend_id } ;
sring = (void *)__get_free_page(GFP_KERNEL);
if (!sring) {
- xenbus_dev_error(dev, -ENOMEM, "allocating shared ring");
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
return -ENOMEM;
}
tp->tx = sring;
tpm_allocate_buffers(tp);
- err = gnttab_grant_foreign_access(backend_id,
- (virt_to_machine(tp->tx) >>
PAGE_SHIFT),
- 0);
-
- if (err == -ENOSPC) {
+ err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
+ if (err < 0) {
free_page((unsigned long)sring);
tp->tx = NULL;
- xenbus_dev_error(dev, err, "allocating grant reference");
- return err;
+ xenbus_dev_fatal(dev, err, "allocating grant reference");
+ goto fail;
}
info->ring_ref = err;
- err = HYPERVISOR_event_channel_op(&op);
- if (err) {
- gnttab_end_foreign_access(info->ring_ref, 0,
- (unsigned long)sring);
- tp->tx = NULL;
- xenbus_dev_error(dev, err, "allocating event channel");
- return err;
- }
-
- tpmif_connect(op.u.alloc_unbound.port, backend_id);
+ err = xenbus_alloc_evtchn(dev, &tp->evtchn);
+ if (err)
+ goto fail;
+
+ tpmif_connect(tp->evtchn, dev->otherend_id);
return 0;
+fail:
+ return err;
}
static void destroy_tpmring(struct tpmfront_info *info, struct tpm_private *tp)
{
- tpmif_set_connected_state(tp,0);
-
+ tpmif_set_connected_state(tp, FALSE);
if ( tp->tx != NULL ) {
gnttab_end_foreign_access(info->ring_ref, 0,
(unsigned long)tp->tx);
@@ -308,42 +268,20 @@
static int talk_to_backend(struct xenbus_device *dev,
struct tpmfront_info *info)
{
- char *backend;
- const char *message;
+ const char *message = NULL;
int err;
- int backend_id;
struct xenbus_transaction *xbt;
- backend = NULL;
- err = xenbus_gather(NULL, dev->nodename,
- "backend-id", "%i", &backend_id,
- "backend", NULL, &backend,
- NULL);
- if (XENBUS_EXIST_ERR(err))
- goto out;
- if (backend && strlen(backend) == 0) {
- err = -ENOENT;
- goto out;
- }
- if (err < 0) {
- xenbus_dev_error(dev, err, "reading %s/backend or backend-id",
- dev->nodename);
- goto out;
- }
-
- info->backend_id = backend_id;
- my_private.backend_id = backend_id;
-
- err = setup_tpmring(dev, info, backend_id);
+ err = setup_tpmring(dev, info);
if (err) {
- xenbus_dev_error(dev, err, "setting up ring");
+ xenbus_dev_fatal(dev, err, "setting up ring");
goto out;
}
again:
xbt = xenbus_transaction_start();
if (IS_ERR(xbt)) {
- xenbus_dev_error(dev, err, "starting transaction");
+ xenbus_dev_fatal(dev, err, "starting transaction");
goto destroy_tpmring;
}
@@ -361,34 +299,60 @@
goto abort_transaction;
}
+ err = xenbus_switch_state(dev, xbt, XenbusStateInitialised);
+ if (err) {
+ goto abort_transaction;
+ }
+
err = xenbus_transaction_end(xbt, 0);
if (err == -EAGAIN)
goto again;
if (err) {
- xenbus_dev_error(dev, err, "completing transaction");
+ xenbus_dev_fatal(dev, err, "completing transaction");
goto destroy_tpmring;
}
-
- info->watch.node = backend;
- info->watch.callback = watch_for_status;
- err = register_xenbus_watch(&info->watch);
- if (err) {
- xenbus_dev_error(dev, err, "registering watch on backend");
- goto destroy_tpmring;
- }
-
- info->backend = backend;
-
return 0;
abort_transaction:
xenbus_transaction_end(xbt, 1);
- xenbus_dev_error(dev, err, "%s", message);
+ if (message)
+ xenbus_dev_error(dev, err, "%s", message);
destroy_tpmring:
destroy_tpmring(info, &my_private);
out:
- kfree(backend);
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 = &my_private;
+ DPRINTK("\n");
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ break;
+
+ case XenbusStateConnected:
+ tpmif_set_connected_state(tp, TRUE);
+ break;
+
+ case XenbusStateClosing:
+ tpmif_set_connected_state(tp, FALSE);
+ break;
+
+ case XenbusStateClosed:
+ if (tp->is_suspended == FALSE) {
+ device_unregister(&dev->dev);
+ }
+ break;
+ }
}
@@ -398,8 +362,6 @@
int err;
struct tpmfront_info *info;
int handle;
- int len = max(XS_WATCH_PATH, XS_WATCH_TOKEN) + 1;
- const char *vec[len];
err = xenbus_scanf(NULL, dev->nodename,
"handle", "%i", &handle);
@@ -407,19 +369,19 @@
return err;
if (err < 0) {
- xenbus_dev_error(dev,err,"reading virtual-device");
+ xenbus_dev_fatal(dev,err,"reading virtual-device");
return err;
}
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
- xenbus_dev_error(dev,err,"allocating info structure");
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev,err,"allocating info structure");
return err;
}
memset(info, 0x0, sizeof(*info));
info->dev = dev;
- info->handle = handle;
dev->data = info;
err = talk_to_backend(dev, info);
@@ -428,41 +390,33 @@
dev->data = NULL;
return err;
}
-
- vec[XS_WATCH_PATH] = info->watch.node;
- vec[XS_WATCH_TOKEN] = NULL;
- watch_for_status(&info->watch, vec, len);
-
return 0;
}
+
static int tpmfront_remove(struct xenbus_device *dev)
{
struct tpmfront_info *info = dev->data;
- if (info->backend)
- unregister_xenbus_watch(&info->watch);
destroy_tpmring(info, &my_private);
- kfree(info->backend);
kfree(info);
-
return 0;
}
static int
tpmfront_suspend(struct xenbus_device *dev)
{
- struct tpmfront_info *info = dev->data;
struct tpm_private *tp = &my_private;
u32 ctr = 0;
/* lock, so no app can send */
down(&suspend_lock);
+ tp->is_suspended = TRUE;
while (atomic_read(&tp->tx_busy) && ctr <= 25) {
- if ((ctr % 10) == 0)
- printk("INFO: Waiting for outstanding request.\n");
+ if ((ctr % 10) == 0)
+ printk("TPM-FE [INFO]: Waiting for outstanding
request.\n");
/*
* Wait for a request to be responded to.
*/
@@ -474,14 +428,9 @@
/*
* A temporary work-around.
*/
- printk("WARNING: Resetting busy flag.");
+ printk("TPM-FE [WARNING]: Resetting busy flag.");
atomic_set(&tp->tx_busy, 0);
}
-
- unregister_xenbus_watch(&info->watch);
-
- kfree(info->backend);
- info->backend = NULL;
return 0;
}
@@ -492,8 +441,6 @@
struct tpmfront_info *info = dev->data;
int err = talk_to_backend(dev, info);
- /* unlock, so apps can resume sending */
- up(&suspend_lock);
return err;
}
@@ -530,12 +477,13 @@
.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_driver(&tpmfront);
+ xenbus_register_frontend(&tpmfront);
}
@@ -628,12 +576,13 @@
spin_lock_irq(&tp->tx_lock);
if (unlikely(atomic_read(&tp->tx_busy))) {
- printk("There's an outstanding request/response on the way!\n");
+ printk("tpm_xmit: There's an outstanding request/response "
+ "on the way!\n");
spin_unlock_irq(&tp->tx_lock);
return -EBUSY;
}
- if (tp->connected != 1) {
+ if (tp->is_connected != TRUE) {
spin_unlock_irq(&tp->tx_lock);
return -EIO;
}
@@ -705,24 +654,40 @@
down(&upperlayer_lock);
if (upperlayer_tpmfe != NULL) {
- switch (tp->connected) {
- case 1:
-
upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
- break;
-
- default:
- upperlayer_tpmfe->status(0);
- break;
+ if (tp->is_connected) {
+ upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
+ } else {
+ upperlayer_tpmfe->status(0);
}
}
up(&upperlayer_lock);
}
-static void tpmif_set_connected_state(struct tpm_private *tp, int newstate)
-{
- if (newstate != tp->connected) {
- tp->connected = newstate;
+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 semaphore keeps apps from sending.
+ */
+ if (is_connected == FALSE && tp->is_suspended == TRUE) {
+ return;
+ }
+
+ /*
+ * Unlock the semaphore if we are connected again
+ * after being suspended - now resuming.
+ * This also removes the suspend state.
+ */
+ if (is_connected == TRUE && tp->is_suspended == TRUE) {
+ tp->is_suspended = FALSE;
+ /* unlock, so apps can resume sending */
+ up(&suspend_lock);
+ }
+
+ if (is_connected != tp->is_connected) {
+ tp->is_connected = is_connected;
tpmif_notify_upperlayer(tp);
}
}
diff -r b0338759544e -r cb215a84d1af
linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h
--- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h Thu Nov 24
22:21:48 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h Fri Nov 25
08:14:01 2005
@@ -1,12 +1,17 @@
#ifndef TPM_FRONT_H
#define TPM_FRONT_H
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
-struct tpm_private
-{
+struct tpm_private {
tpmif_tx_interface_t *tx;
- unsigned int evtchn, irq;
- int connected;
+ unsigned int evtchn;
+ unsigned int irq;
+ u8 is_connected;
+ u8 is_suspended;
spinlock_t tx_lock;
@@ -16,25 +21,18 @@
void *tx_remember;
domid_t backend_id;
wait_queue_head_t wait_q;
+
};
-
-struct tpmfront_info
-{
- struct xenbus_watch watch;
- int handle;
+struct tpmfront_info {
struct xenbus_device *dev;
- char *backend;
int ring_ref;
- domid_t backend_id;
};
-
-struct tx_buffer
-{
+struct tx_buffer {
unsigned int size; // available space in data
unsigned int len; // used space in data
- unsigned char *data; // pointer to a page
+ unsigned char *data; // pointer to a page
};
#endif
diff -r b0338759544e -r cb215a84d1af tools/examples/Makefile
--- a/tools/examples/Makefile Thu Nov 24 22:21:48 2005
+++ b/tools/examples/Makefile Fri Nov 25 08:14:01 2005
@@ -26,9 +26,10 @@
XEN_SCRIPTS += network-nat vif-nat
XEN_SCRIPTS += block
XEN_SCRIPTS += block-enbd block-nbd
+XEN_SCRIPTS += vtpm
XEN_SCRIPT_DATA = xen-script-common.sh
XEN_SCRIPT_DATA += xen-hotplug-common.sh xen-network-common.sh vif-common.sh
-XEN_SCRIPT_DATA += block-common.sh
+XEN_SCRIPT_DATA += block-common.sh vtpm-common.sh
XEN_HOTPLUG_DIR = /etc/hotplug
XEN_HOTPLUG_SCRIPTS = xen-backend.agent
diff -r b0338759544e -r cb215a84d1af tools/examples/xen-backend.agent
--- a/tools/examples/xen-backend.agent Thu Nov 24 22:21:48 2005
+++ b/tools/examples/xen-backend.agent Fri Nov 25 08:14:01 2005
@@ -5,6 +5,9 @@
case "$XENBUS_TYPE" in
vbd)
/etc/xen/scripts/block "$ACTION"
+ ;;
+ vtpm)
+ /etc/xen/scripts/vtpm "$ACTION"
;;
vif)
[ -n "$script" ] && $script "$ACTION"
diff -r b0338759544e -r cb215a84d1af tools/examples/xen-backend.rules
--- a/tools/examples/xen-backend.rules Thu Nov 24 22:21:48 2005
+++ b/tools/examples/xen-backend.rules Fri Nov 25 08:14:01 2005
@@ -1,4 +1,5 @@
SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block
$env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm
$env{ACTION}"
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script}
online"
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline",
RUN+="$env{script} offline"
SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/bin/bash -c
'/usr/bin/xenstore-rm -t $$(/usr/bin/xenstore-read $env{XENBUS_PATH}/frontend)'"
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xend/image.py Fri Nov 25 08:14:01 2005
@@ -293,7 +293,7 @@
ret.append("-bridge")
ret.append("%s" % bridge)
if name == 'vtpm':
- instance = sxp.child_value(info, 'instance')
+ instance = sxp.child_value(info, 'pref_instance')
ret.append("-instance")
ret.append("%s" % instance)
return ret
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xend/server/tpmif.py
--- a/tools/python/xen/xend/server/tpmif.py Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xend/server/tpmif.py Fri Nov 25 08:14:01 2005
@@ -38,10 +38,10 @@
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- devid = int(sxp.child_value(config, 'instance', '0'))
+ devid = int(sxp.child_value(config, 'pref_instance', '0'))
log.info("The domain has a TPM with instance %d." % devid)
- back = { 'instance' : "%i" % devid }
+ back = { 'pref_instance' : "%i" % devid }
front = { 'handle' : "%i" % devid }
return (devid, back, front)
diff -r b0338759544e -r cb215a84d1af tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Thu Nov 24 22:21:48 2005
+++ b/tools/python/xen/xm/create.py Fri Nov 25 08:14:01 2005
@@ -220,11 +220,9 @@
fn=set_bool, default=0,
use="Make the domain a network interface backend.")
-gopts.var('tpmif', val='frontend=DOM',
- fn=append_value, default=[],
- use="""Make the domain a TPM interface backend. If frontend is given,
- the frontend in that domain is connected to this backend (not
- completely implemented, yet)""")
+gopts.var('tpmif', val='no|yes',
+ fn=append_value, default=0,
+ use="Make the domain a TPM interface backend.")
gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
fn=append_value, default=[],
@@ -273,9 +271,13 @@
gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
fn=append_value, default=[],
- use="""Add a tpm interface. On the backend side us the the given
- instance as virtual TPM instance. Use the backend in the given
- domain.""")
+ use="""Add a TPM interface. On the backend side use the given
+ instance as virtual TPM instance. The given number is merely the
+ preferred instance number. The hotplug script will determine
+ which instance number will actually be assigned to the domain.
+ The associtation between virtual machine and the TPM instance
+ number can be found in /etc/xen/vtpm.db. Use the backend in the
+ given domain.""")
gopts.var('nics', val="NUM",
fn=set_int, default=1,
@@ -465,33 +467,19 @@
if instance == "VTPMD":
instance = "0"
else:
- try:
- if int(instance) == 0:
- err('VM config error: vTPM instance must not be 0.')
- except ValueError:
- err('Vm config error: could not parse instance number.')
+ if instance != None:
+ try:
+ if int(instance) == 0:
+ err('VM config error: vTPM instance must not be
0.')
+ except ValueError:
+ err('Vm config error: could not parse instance
number.')
backend = d.get('backend')
config_vtpm = ['vtpm']
if instance:
- config_vtpm.append(['instance', instance])
+ config_vtpm.append(['pref_instance', instance])
if backend:
config_vtpm.append(['backend', backend])
config_devs.append(['device', config_vtpm])
-
-def configure_tpmif(config_devs, vals):
- """Create the config for virtual TPM interfaces.
- """
- tpmif = vals.tpmif
- tpmif_n = 1
- for idx in range(0, tpmif_n):
- if idx < len(tpmif):
- d = tpmif[idx]
- frontend = d.get('frontend')
- config_tpmif = ['tpmif']
- if frontend:
- config_tpmif.append(['frontend', frontend])
- config_devs.append(['device', config_tpmif])
-
def configure_vifs(config_devs, vals):
"""Create the config for virtual network interfaces.
@@ -685,22 +673,6 @@
vtpms.append(d)
vals.vtpm = vtpms
-def preprocess_tpmif(vals):
- if not vals.tpmif: return
- tpmifs = []
- for tpmif in vals.tpmif:
- d = {}
- a = tpmif.split(',')
- for b in a:
- (k, v) = b.strip().split('=', 1)
- k = k.strip()
- v = v.strip()
- if k not in ['frontend']:
- err('Invalid tpmif specifier: ' + vtpm)
- d[k] = v
- tpmifs.append(d)
- vals.tpmif = tpmifs
-
def preprocess_ip(vals):
if vals.ip or vals.dhcp != 'off':
dummy_nfs_server = '1.2.3.4'
@@ -791,7 +763,6 @@
preprocess_nfs(vals)
preprocess_vnc(vals)
preprocess_vtpm(vals)
- preprocess_tpmif(vals)
def make_domain(opts, config):
"""Create, build and start a domain.
diff -r b0338759544e -r cb215a84d1af tools/examples/vtpm
--- /dev/null Thu Nov 24 22:21:48 2005
+++ b/tools/examples/vtpm Fri Nov 25 08:14:01 2005
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+dir=$(dirname "$0")
+. "$dir/vtpm-common.sh"
+
+
+case "$command" in
+ online | offline)
+ exit 0
+ ;;
+esac
+
+case "$command" in
+ add)
+ vtpm_create_instance
+ ;;
+ remove)
+ vtpm_remove_instance
+ ;;
+esac
+
+log debug "Successful vTPM operation '$command'."
+success
diff -r b0338759544e -r cb215a84d1af tools/examples/vtpm-common.sh
--- /dev/null Thu Nov 24 22:21:48 2005
+++ b/tools/examples/vtpm-common.sh Fri Nov 25 08:14:01 2005
@@ -0,0 +1,281 @@
+#
+# Copyright (c) 2005 IBM Corporation
+# Copyright (c) 2005 XenSource Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
+
+findCommand "$@"
+if [ "$command" != "online" ] &&
+ [ "$command" != "offline" ] &&
+ [ "$command" != "add" ] &&
+ [ "$command" != "remove" ]
+then
+ log err "Invalid command: $command"
+ exit 1
+fi
+
+
+XENBUS_PATH="${XENBUS_PATH:?}"
+
+
+VTPMDB="/etc/xen/vtpm.db"
+
+#In the vtpm-impl file some commands should be defined:
+# vtpm_create, vtpm_setup, vtpm_reset, etc. (see below)
+#This should be indicated by setting VTPM_IMPL_DEFINED.
+if [ -r "$dir/vtpm-impl" ]; then
+ . "$dir/vtpm-impl"
+fi
+
+if [ -z "$VTPM_IMPL_DEFINED" ]; then
+ function vtpm_create () {
+ true
+ }
+ function vtpm_setup() {
+ true
+ }
+ function vtpm_reset() {
+ true
+ }
+ function vtpm_suspend() {
+ true
+ }
+ function vtpm_resume() {
+ true
+ }
+fi
+
+#Find the instance number for the vtpm given the name of the domain
+# Parameters
+# - vmname : the name of the vm
+# Return value
+# Returns '0' if instance number could not be found, otherwise
+# it returns the instance number in the variable 'instance'
+function find_instance () {
+ local vmname=$1
+ local ret=0
+ instance=`cat $VTPMDB | \
+ awk -vvmname=$vmname \
+ '{ \
+ if ( 1 != index($1,"#")) { \
+ if ( $1 == vmname ) { \
+ print $2; \
+ exit; \
+ } \
+ } \
+ }'`
+ if [ "$instance" != "" ]; then
+ ret=1
+ fi
+ return $ret
+}
+
+
+# Check whether a particular instance number is still available
+# returns '1' if it is available
+function is_free_instancenum () {
+ local instance=$1
+ local avail=1
+
+ #Allowed instance number range: 1-255
+ if [ $instance -eq 0 -o $instance -gt 255 ]; then
+ avail=0
+ else
+ instances=`cat $VTPMDB | \
+ gawk \
+ '{ \
+ if (1 != index($1,"#")) { \
+ printf("%s ",$2); \
+ } \
+ }'`
+ for i in $instances; do
+ if [ $i -eq $instance ]; then
+ avail=0
+ break
+ fi
+ done
+ fi
+ return $avail
+}
+
+
+# Get an available instance number given the database
+# Returns an unused instance number
+function get_free_instancenum () {
+ local ctr
+ local instances
+ local don
+ instances=`cat $VTPMDB | \
+ gawk \
+ '{ \
+ if (1 != index($1,"#")) { \
+ printf("%s ",$2); \
+ } \
+ }'`
+ ctr=1
+ don=0
+ while [ $don -eq 0 ]; do
+ local found
+ found=0
+ for i in $instances; do
+ if [ $i -eq $ctr ]; then
+ found=1;
+ break;
+ fi
+ done
+
+ if [ $found -eq 0 ]; then
+ don=1
+ break
+ fi
+ let ctr=ctr+1
+ done
+ let instance=$ctr
+}
+
+
+# Add a domain name and instance number to the DB file
+function add_instance () {
+ local vmname=$1
+ local inst=$2
+
+ if [ ! -f $VTPMDB ]; then
+ echo "#Database for VM to vTPM association" > $VTPMDB
+ echo "#1st column: domain name" >> $VTPMDB
+ echo "#2nd column: TPM instance number" >> $VTPMDB
+ fi
+ validate_entry $vmname $inst
+ if [ $? -eq 0 ]; then
+ echo "$vmname $inst" >> $VTPMDB
+ fi
+}
+
+
+#Validate whether an entry is the same as passed to this
+#function
+function validate_entry () {
+ local rc=0
+ local vmname=$1
+ local inst=$2
+ local res
+ res=`cat $VTPMDB | \
+ gawk -vvmname=$vmname \
+ -vinst=$inst \
+ '{ \
+ if ( 1 == index($1,"#")) {\
+ } else \
+ if ( $1 == vmname && \
+ $2 == inst) { \
+ printf("1"); \
+ exit; \
+ } else \
+ if ( $1 == vmname || \
+ $2 == inst) { \
+ printf("2"); \
+ exit; \
+ } \
+ }'`
+
+ if [ "$res" == "1" ]; then
+ let rc=1
+ elif [ "$res" == "2" ]; then
+ let rc=2
+ fi
+ return $rc
+}
+
+
+#Remove an entry from the vTPM database given its domain name
+function remove_entry () {
+ local vmname=$1
+ local VTPMDB_TMP="$VTPMDB".tmp
+ `cat $VTPMDB | \
+ gawk -vvmname=$vmname \
+ '{ \
+ if ( $1 != vmname ) { \
+ print $0; \
+ } \
+ '} > $VTPMDB_TMP`
+ if [ -e $VTPMDB_TMP ]; then
+ mv -f $VTPMDB_TMP $VTPMDB
+ else
+ log err "Error creating temporary file '$VTPMDB_TMP'."
+ fi
+}
+
+
+#Create a vTPM instance
+# If no entry in the TPM database is found, the instance is
+# created and an entry added to the database.
+function vtpm_create_instance () {
+ local domname=$(xenstore_read "$XENBUS_PATH"/domain)
+ local res
+ set +e
+ find_instance $domname
+ res=$?
+ if [ $res -eq 0 ]; then
+ #Try to give the preferred instance to the domain
+ instance=$(xenstore_read "$XENBUS_PATH"/pref_instance)
+ if [ "$instance" != "" ]; then
+ is_free_instancenum $instance
+ res=$?
+ if [ $res -eq 0 ]; then
+ get_free_instancenum
+ fi
+ else
+ get_free_instancenum
+ fi
+ add_instance $domname $instance
+ if [ "$REASON" == "create" ]; then
+ vtpm_create $instance
+ elif [ "$REASON" == "hibernate" ]; then
+ vtpm_resume $instance $domname
+ else
+ #default case for 'now'
+ vtpm_create $instance
+ fi
+ fi
+ if [ "$REASON" == "create" ]; then
+ vtpm_reset $instance
+ elif [ "$REASON" == "hibernate" ]; then
+ vtpm_setup $instance
+ else
+ #default case for 'now'
+ vtpm_reset $instance
+ fi
+ xenstore_write $XENBUS_PATH/instance $instance
+ set -e
+}
+
+
+#Remove an instance
+function vtpm_remove_instance () {
+ local domname=$(xenstore_read "$XENBUS_PATH"/domain)
+ set +e
+ find_instance $domname
+ res=$?
+ if [ $res -eq 0 ]; then
+ #Something is really wrong with the DB
+ log err "vTPM DB file $VTPMDB has no entry for '$domname'"
+ else
+ if [ "$REASON" == "hibernate" ]; then
+ vtpm_suspend $instance
+ fi
+ fi
+ set -e
+}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|