Hello!
The attached patch follows recent changes to the xenbus to now also
work with the split TPM driver. It also adds hotplug scripts for the
vTPM instance to domain (name) association. That association is
maintained in a small database file in /etc/xen/vtpm.db and mintained by
the hotplug scripts. The patch also removes some dead TPM_specific code
in Xend and removes a choice from the TPM directory's Kconfig file.
Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx>
Stefan
Index: root/xen-unstable.hg/tools/examples/Makefile
===================================================================
--- root.orig/xen-unstable.hg/tools/examples/Makefile
+++ root/xen-unstable.hg/tools/examples/Makefile
@@ -26,9 +26,10 @@ XEN_SCRIPTS += network-route vif-route
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
Index: root/xen-unstable.hg/tools/examples/vtpm
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/examples/vtpm
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+dir=$(dirname "$0")
+. "$dir/vtpm-common.sh"
+
+LOGFILE=/tmp/log
+touch $LOGFILE
+echo "REASON=$REASON" >> $LOGFILE
+
+
+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
Index: root/xen-unstable.hg/tools/examples/vtpm-common.sh
===================================================================
--- /dev/null
+++ root/xen-unstable.hg/tools/examples/vtpm-common.sh
@@ -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
+}
Index: root/xen-unstable.hg/tools/examples/xen-backend.agent
===================================================================
--- root.orig/xen-unstable.hg/tools/examples/xen-backend.agent
+++ root/xen-unstable.hg/tools/examples/xen-backend.agent
@@ -6,6 +6,9 @@ case "$XENBUS_TYPE" in
vbd)
/etc/xen/scripts/block "$ACTION"
;;
+ vtpm)
+ /etc/xen/scripts/vtpm "$ACTION"
+ ;;
vif)
[ -n "$script" ] && $script "$ACTION"
;;
Index: root/xen-unstable.hg/tools/examples/xen-backend.rules
===================================================================
--- root.orig/xen-unstable.hg/tools/examples/xen-backend.rules
+++ root/xen-unstable.hg/tools/examples/xen-backend.rules
@@ -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+="/usr/bin/xenstore-rm -t
$env{XENBUS_PATH}"
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
===================================================================
--- root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
@@ -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 @@ struct backend_info
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);
+ 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);
+ be->tpmif = NULL;
+ }
+ kfree(be);
+ dev->data = NULL;
+ return 0;
+}
+
+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);
- tpmif_vtpm_close(be->instance);
+ if (!be) {
+ xenbus_dev_fatal(dev, -ENOMEM,
+ "allocating backend structure");
+ return -ENOMEM;
+ }
- if (be->tpmif)
- tpmif_put(be->tpmif);
+ memset(be, 0, sizeof(*be));
- kfree(be->frontpath);
- kfree(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 frontend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+static void backend_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;
+ long instance;
struct backend_info *be
- = container_of(watch, struct backend_info, watch);
+ = container_of(watch, struct backend_info, backend_watch);
+ struct xenbus_device *dev = be->dev;
- /* If other end is gone, delete ourself. */
- if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
- xenbus_rm(NULL, be->dev->nodename, "");
- device_unregister(&be->dev->dev);
+ err = xenbus_scanf(NULL, dev->nodename,
+ "instance","%li", &instance);
+ if (XENBUS_EXIST_ERR(err)) {
return;
}
- if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading instance");
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);
+ 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;
}
- err = tpmif_map(be->tpmif, ringref, evtchn);
- if (err) {
- xenbus_dev_error(be->dev, err,
- "mapping shared-frame %lu port %u",
- ringref, evtchn);
- 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);
+ 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;
+
+ 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 @@ static void frontend_changed(struct xenb
*/
return;
}
+}
+
+
+static void connect(struct backend_info *be)
+{
+ struct xenbus_transaction *xbt;
+ int err;
+ struct xenbus_device *dev = be->dev;
+ unsigned long ready = 1;
- /*
- * Tell the front-end that we are ready to go -
- * unless something bad happens
- */
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_fatal(be->dev, err, "end of transaction");
}
-
- xenbus_dev_ok(be->dev);
return;
abort:
xenbus_transaction_end(xbt, 1);
}
-static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+static int connect_ring(struct backend_info *be)
{
- int err;
- long int instance;
- struct backend_info *be
- = 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 < 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;
- }
-
- 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;
+ unsigned long ring_ref;
+ unsigned int evtchn;
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);
+ err = xenbus_gather(NULL, dev->otherend,
+ "ring-ref", "%lu", &ring_ref,
+ "event-channel", "%u", &evtchn, NULL);
if (err) {
- be->watch.node = NULL;
xenbus_dev_error(dev, err,
- "adding frontend watch on %s",
- be->frontpath);
- goto free_be;
+ "reading %s/ring-ref and event-channel",
+ dev->otherend);
+ return err;
}
-
- dev->data = be;
- return err;
-
-free_be:
- if (be->backend_watch.node)
- unregister_xenbus_watch(&be->backend_watch);
- kfree(frontend);
- kfree(be);
- 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;
+ }
+ }
+ return 0;
}
@@ -273,6 +309,7 @@ static struct xenbus_driver tpmback = {
.ids = tpmback_ids,
.probe = tpmback_probe,
.remove = tpmback_remove,
+ .otherend_changed = frontend_changed,
};
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
===================================================================
---
root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
@@ -73,7 +73,8 @@ static void tpmif_rx_action(unsigned lon
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 @@ static int tpm_fe_send_upperlayer(const
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;
- }
+ err = xenbus_alloc_evtchn(dev, &tp->evtchn);
+ if (err)
+ goto fail;
- tpmif_connect(op.u.alloc_unbound.port, backend_id);
+ 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 void destroy_tpmring(struct tpmfr
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,36 +299,62 @@ again:
goto abort_transaction;
}
- err = xenbus_transaction_end(xbt, 0);
- if (err == -EAGAIN)
- goto again;
+ err = xenbus_switch_state(dev, xbt, XenbusStateInitialised);
if (err) {
- xenbus_dev_error(dev, err, "completing transaction");
- goto destroy_tpmring;
+ goto abort_transaction;
}
- info->watch.node = backend;
- info->watch.callback = watch_for_status;
- err = register_xenbus_watch(&info->watch);
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
if (err) {
- xenbus_dev_error(dev, err, "registering watch on backend");
+ xenbus_dev_fatal(dev, err, "completing transaction");
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;
+ }
+}
+
static int tpmfront_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
@@ -398,8 +362,6 @@ static int tpmfront_probe(struct xenbus_
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 @@ static int tpmfront_probe(struct xenbus_
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 @@ static int tpmfront_probe(struct xenbus_
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,15 +428,10 @@ tpmfront_suspend(struct xenbus_device *d
/*
* 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 @@ tpmfront_resume(struct xenbus_device *de
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 @@ static struct xenbus_driver tpmfront = {
.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 @@ tpm_xmit(struct tpm_private *tp,
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 @@ static void tpmif_notify_upperlayer(stru
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)
+static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
{
- if (newstate != tp->connected) {
- tp->connected = newstate;
+ /*
+ * 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);
}
}
Index: root/xen-unstable.hg/tools/python/xen/xend/image.py
===================================================================
--- root.orig/xen-unstable.hg/tools/python/xen/xend/image.py
+++ root/xen-unstable.hg/tools/python/xen/xend/image.py
@@ -293,7 +293,7 @@ class VmxImageHandler(ImageHandler):
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
Index: root/xen-unstable.hg/tools/python/xen/xend/server/tpmif.py
===================================================================
--- root.orig/xen-unstable.hg/tools/python/xen/xend/server/tpmif.py
+++ root/xen-unstable.hg/tools/python/xen/xend/server/tpmif.py
@@ -38,10 +38,10 @@ class TPMifController(DevController):
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)
Index: root/xen-unstable.hg/tools/python/xen/xm/create.py
===================================================================
--- root.orig/xen-unstable.hg/tools/python/xen/xm/create.py
+++ root/xen-unstable.hg/tools/python/xen/xm/create.py
@@ -220,11 +220,9 @@ gopts.var('netif', val='no|yes',
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('vif', val="type=TYPE,mac=MAC,
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,34 +467,20 @@ def configure_vtpm(config_devs, vals):
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 @@ def preprocess_vtpm(vals):
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 @@ def preprocess(vals):
preprocess_nfs(vals)
preprocess_vnc(vals)
preprocess_vtpm(vals)
- preprocess_tpmif(vals)
def make_domain(opts, config):
"""Create, build and start a domain.
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
===================================================================
--- root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
@@ -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 @@ extern int num_frontends;
#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__ */
/*
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
===================================================================
---
root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
@@ -127,6 +127,10 @@ tpmif_map(tpmif_t *tpmif, unsigned long
.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_map(tpmif_t *tpmif, unsigned long
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;
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h
===================================================================
---
root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.h
@@ -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 @@ struct tpm_private
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
Index: root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
===================================================================
--- root.orig/xen-unstable.hg/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
+++ root/xen-unstable.hg/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
@@ -18,15 +18,6 @@ config TCG_TPM
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"
depends on TCG_TPM
Index: root/xen-unstable.hg/docs/misc/vtpm.txt
===================================================================
--- root.orig/xen-unstable.hg/docs/misc/vtpm.txt
+++ root/xen-unstable.hg/docs/misc/vtpm.txt
@@ -73,7 +73,14 @@ information about the domain where the v
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.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|