From patchwork Sun Jul 10 11:47:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emil Condrea X-Patchwork-Id: 9222611 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7CB1460572 for ; Sun, 10 Jul 2016 12:10:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C62425404 for ; Sun, 10 Jul 2016 12:10:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5FB1C2705B; Sun, 10 Jul 2016 12:10:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1E01725404 for ; Sun, 10 Jul 2016 12:10:26 +0000 (UTC) Received: from localhost ([::1]:54383 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMDZ3-0004LL-8O for patchwork-qemu-devel@patchwork.kernel.org; Sun, 10 Jul 2016 08:10:25 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58978) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMDE3-0006L6-4R for qemu-devel@nongnu.org; Sun, 10 Jul 2016 07:48:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bMDE0-0001nZ-5u for qemu-devel@nongnu.org; Sun, 10 Jul 2016 07:48:42 -0400 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:34340) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMDDz-0001nR-Ry for qemu-devel@nongnu.org; Sun, 10 Jul 2016 07:48:40 -0400 Received: by mail-wm0-x241.google.com with SMTP id w75so13127194wmd.1 for ; Sun, 10 Jul 2016 04:48:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=T1GA/u4UdPp2TXEzRtdGhRyCzxSzs3PiPF6vFslDVng=; b=zC2DU4fdyL7/L1EtS9pwASdL57PdnMM3PQNCvZKGC8c9EtsTLlJhdbHuC3VYV2A4lU zc9ugWvQ8J+MjF4JSK3vHzAMAiDwdCoD+L+fdcT3iNMTEt8TOS//TGhK9GdYrWQ/LeJX 6r4mUTBcjS7lMyIeskzX0Afv8pLadquh+XW2rhTZbQV99WuSIuZbcHP8fLvCLP9m8Enr +1dgv/iZuTA6PE0/Ztd7vW8G0MzSRvIOb4ZAoRG7m+cUNilqBvlgaze1C0GzzooaTGn+ DXI1v347BXDvWdr/HJd67OuI8TAnCA4qBRmC+9L/ZkYIcd4UVhc+S570+C8RFwpZCGMX TlFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=T1GA/u4UdPp2TXEzRtdGhRyCzxSzs3PiPF6vFslDVng=; b=CfEM5BaK+H5WoecL+HRPtAZk4x4+RS+OIU/1NLwjveBQzqfLHK+vqvjuVV1GctJGAh kj4+q8Ppd0oyk/tbxYaNFQS2yA9zvmcWZdwmeakhwkqdQroysm/sn3pKSsa2IqvjFXWR 1tFZE9azirLv6G/kxHwDjRXol1anMp/PGsICbk5ydGyXAwet9amNo+Foxh6L7cW37wZS kpo4yFHMUUXRbZaQ4g1TtrUPwZfg1hQD336Tpalo24UW9GuMRptvvTjmRj0P4cRShdzF Yr1/lajiGR1sLsVfwH3zu7odD7IcPknu+9oi4tLRFI2tvvG3nPdg/tmifYlcLpdJUiDy 0XzQ== X-Gm-Message-State: ALyK8tLhykI+arzNtSDxosBJCbB7DN1krcZVMtdPtiYQdBlXVH0h5luU3GgNt45gqY65nw== X-Received: by 10.28.185.202 with SMTP id j193mr7189351wmf.78.1468151318992; Sun, 10 Jul 2016 04:48:38 -0700 (PDT) Received: from localhost.localdomain ([79.112.8.37]) by smtp.gmail.com with ESMTPSA id d137sm6888378wmd.12.2016.07.10.04.48.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 10 Jul 2016 04:48:38 -0700 (PDT) From: Emil Condrea To: qemu-devel@nongnu.org Date: Sun, 10 Jul 2016 14:47:47 +0300 Message-Id: <1468151270-12984-17-git-send-email-emilcondrea@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1468151270-12984-1-git-send-email-emilcondrea@gmail.com> References: <1468151270-12984-1-git-send-email-emilcondrea@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::241 Subject: [Qemu-devel] [PATCH 16/19] Qemu-Xen-vTPM: Register Xen stubdom vTPM frontend driver X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: wei.liu2@citrix.com, stefanb@linux.vnet.ibm.com, stefano.stabellini@eu.citrix.com, xen-devel@lists.xen.org, quan.xu@intel.com, dgdegra@tycho.nsa.gov, emilcondrea@gmail.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This driver transfers any request/repond between TPM xenstubdoms driver and Xen vTPM stubdom, and facilitates communications between Xen vTPM stubdom domain and vTPM xenstubdoms driver. It is a glue for the TPM xenstubdoms driver and Xen stubdom vTPM domain that provides the actual TPM functionality. (Xen) Xen backend driver should run before running this frontend, and initialize XenStore as the following for communication. [XenStore] for example: Domain 0: runs QEMU for guest A Domain 1: vtpmmgr Domain 2: vTPM for guest A Domain 3: HVM guest A [...] local = "" domain = "" 0 = "" frontend = "" vtpm = "" 2 = "" 0 = "" backend = "/local/domain/2/backend/vtpm/0/0" backend-id = "2" state = "*" handle = "0" domain = "Domain3's name" ring-ref = "*" event-channel = "*" feature-protocol-v2 = "1" backend = "" qdisk = "" [...] console = "" vif = "" [...] 2 = "" [...] backend = "" vtpm = "" 0 = "" 0 = "" frontend = "/local/domain/0/frontend/vtpm/2/0" frontend-id = "0" ('0', frontend is running in Domain-0) [...] 3 = "" [...] device = "" (frontend device, the backend is running in QEMU/.etc) vkbd = "" [...] vif = "" [...] .. (QEMU) xen_vtpmdev_ops is initialized with the following process: xen_hvm_init() [...] -->xen_fe_register("vtpm", ...) -->xenstore_fe_scan() -->xen_fe_try_init(ops) --> XenDevOps.init() -->xen_fe_get_xendev() --> XenDevOps.alloc() -->xen_fe_check() -->xen_fe_try_initialise() --> XenDevOps.initialise() -->xen_fe_try_connected() --> XenDevOps.connected() -->xs_watch() [...] Signed-off-by: Quan Xu Signed-off-by: Emil Condrea Reviewed-by: Stefan Berger --- Changed in v9: * instead of xen_frontend.c global variable xenstore_dev, use vtpm specific xenstore_vtpm_dev (since it will be needed just for tpm_xenstubdoms qemu driver) * added xen_vtpm_frontend.h * move vtpm_backend_changed -> xen_fe_backend_changed to xen_frontend.c * use libxengnttab, libxenevtchn stable API instead of xc_* calls: - xc_gntshr_share_pages -> xengntshr_share_pages - xc_gntshr_munmap -> xengntshr_unshare - xc_interface_close -> xengntshr_close - xc_evtchn_unmask -> xenevtchn_unmask --- hw/tpm/Makefile.objs | 1 + hw/tpm/xen_vtpm_frontend.c | 303 ++++++++++++++++++++++++++++++++++++++++++ hw/tpm/xen_vtpm_frontend.h | 10 ++ hw/xen/xen_frontend.c | 20 +++ include/hw/xen/xen_backend.h | 1 + include/hw/xen/xen_frontend.h | 1 + xen-hvm.c | 6 + 7 files changed, 342 insertions(+) create mode 100644 hw/tpm/xen_vtpm_frontend.c create mode 100644 hw/tpm/xen_vtpm_frontend.h diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 64cecc3..b0a821c 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,2 +1,3 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c new file mode 100644 index 0000000..cf3eb5e --- /dev/null +++ b/hw/tpm/xen_vtpm_frontend.c @@ -0,0 +1,303 @@ +/* + * Connect to Xen vTPM stubdom domain + * + * Copyright (c) 2015 Intel Corporation + * Authors: + * Quan Xu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * 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, see + */ + +#include "qemu/osdep.h" + +#include "xen_vtpm_frontend.h" +#include "hw/xen/xen_frontend.h" +#include "hw/xen/xen_backend.h" + +int xenstore_vtpm_dev; +#ifndef XS_STUBDOM_VTPM_ENABLE +#define XS_STUBDOM_VTPM_ENABLE "1" +#endif + +#ifndef VTPM_PAGE_SIZE +#define VTPM_PAGE_SIZE 4096 +#endif + +enum tpmif_state { + /* No contents, vTPM idle, cancel complete */ + TPMIF_STATE_IDLE, + /* Request ready or vTPM working */ + TPMIF_STATE_SUBMIT, + /* Response ready or vTPM idle */ + TPMIF_STATE_FINISH, + /* Cancel requested or vTPM working */ + TPMIF_STATE_CANCEL, +}; + +static AioContext *vtpm_aio_ctx; + +enum status_bits { + VTPM_STATUS_RUNNING = 0x1, + VTPM_STATUS_IDLE = 0x2, + VTPM_STATUS_RESULT = 0x4, + VTPM_STATUS_CANCELED = 0x8, +}; + +struct tpmif_shared_page { + /* Request and response length in bytes */ + uint32_t length; + /* Enum tpmif_state */ + uint8_t state; + /* For the current request */ + uint8_t locality; + /* Should be zero */ + uint8_t pad; + /* Extra pages for long packets; may be zero */ + uint8_t nr_extra_pages; + /* + * Grant IDs, the length is actually nr_extra_pages. + * beyond the extra_pages entries is the actual request + * and response. + */ + uint32_t extra_pages[0]; +}; + +struct xen_vtpm_dev { + struct XenDevice xendev; /* must be first */ + struct tpmif_shared_page *shr; + xengntshr_handle *xen_xcs; + int ring_ref; + int bedomid; + QEMUBH *sr_bh; +}; + +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev) +{ + switch (vtpmdev->shr->state) { + case TPMIF_STATE_IDLE: + case TPMIF_STATE_FINISH: + return VTPM_STATUS_IDLE; + case TPMIF_STATE_SUBMIT: + case TPMIF_STATE_CANCEL: + return VTPM_STATUS_RUNNING; + default: + return 0; + } +} + +static bool vtpm_aio_wait(AioContext *ctx) +{ + return aio_poll(ctx, true); +} + +static void sr_bh_handler(void *opaque) +{ +} + +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + struct tpmif_shared_page *shr = vtpmdev->shr; + unsigned int offset; + size_t length = shr->length; + + if (shr->state == TPMIF_STATE_IDLE) { + return -ECANCELED; + } + + offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages; + if (offset > VTPM_PAGE_SIZE) { + return -EIO; + } + + if (offset + length > VTPM_PAGE_SIZE) { + length = VTPM_PAGE_SIZE - offset; + } + + memcpy(buf, offset + (uint8_t *)shr, length); + *count = length; + + return 0; +} + +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + struct tpmif_shared_page *shr = vtpmdev->shr; + unsigned int offset = sizeof(*shr) + + sizeof(shr->extra_pages[0])*shr->nr_extra_pages; + + if (offset > VTPM_PAGE_SIZE) { + return -EIO; + } + + if (offset + count > VTPM_PAGE_SIZE) { + return -ECANCELED; + } + + while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) { + vtpm_aio_wait(vtpm_aio_ctx); + } + + memcpy(offset + (uint8_t *)shr, buf, count); + shr->length = count; + barrier(); + shr->state = TPMIF_STATE_SUBMIT; + xen_wmb(); + xen_pv_send_notify(&vtpmdev->xendev); + + while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) { + vtpm_aio_wait(vtpm_aio_ctx); + } + + return count; +} + +static int vtpm_initialise(struct XenDevice *xendev) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + xs_transaction_t xbt = XBT_NULL; + unsigned int ring_ref; + + vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev, "frontend"); + if (vtpmdev->xendev.fe == NULL) { + return -1; + } + + /* Get backend domid */ + if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id", + &vtpmdev->bedomid)) { + return -1; + } + + /* Alloc shared page */ + vtpmdev->shr = xengntshr_share_pages(vtpmdev->xen_xcs, vtpmdev->bedomid, 1, + &ring_ref, PROT_READ|PROT_WRITE); + vtpmdev->ring_ref = ring_ref; + if (vtpmdev->shr == NULL) { + return -1; + } + + /* Create event channel */ + if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) { + xengntshr_unshare(vtpmdev->xen_xcs, vtpmdev->shr, 1); + return -1; + } + + xenevtchn_unmask(vtpmdev->xendev.evtchndev, + vtpmdev->xendev.local_port); + +again: + xbt = xs_transaction_start(xenstore); + if (xbt == XBT_NULL) { + goto abort_transaction; + } + + if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref", + vtpmdev->ring_ref)) { + goto abort_transaction; + } + + if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel", + vtpmdev->xendev.local_port)) { + goto abort_transaction; + } + + /* Publish protocol v2 feature */ + if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) { + goto abort_transaction; + } + + if (!xs_transaction_end(xenstore, xbt, 0)) { + if (errno == EAGAIN) { + goto again; + } + } + + return 0; + +abort_transaction: + xengntshr_unshare(vtpmdev->xen_xcs, vtpmdev->shr, 1); + xs_transaction_end(xenstore, xbt, 1); + return -1; +} + +static int vtpm_free(struct XenDevice *xendev) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + + aio_poll(vtpm_aio_ctx, false); + qemu_bh_delete(vtpmdev->sr_bh); + if (vtpmdev->shr) { + xengntshr_unshare(vtpmdev->xen_xcs, vtpmdev->shr, 1); + } + xengntshr_close(vtpmdev->xen_xcs); + return 0; +} + +static int vtpm_init(struct XenDevice *xendev) +{ + char path[XEN_BUFSIZE]; + char *value; + unsigned int stubdom_vtpm = 0; + + snprintf(path, sizeof(path), "/local/domain/%d/platform/acpi_stubdom_vtpm", + xen_domid); + value = xs_read(xenstore, 0, path, &stubdom_vtpm); + if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) { + free(value); + return -1; + } + free(value); + return 0; +} + +static void vtpm_alloc(struct XenDevice *xendev) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + + vtpm_aio_ctx = aio_context_new(NULL); + if (vtpm_aio_ctx == NULL) { + return; + } + vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev); + qemu_bh_schedule(vtpmdev->sr_bh); + vtpmdev->xen_xcs = xengntshr_open(0, 0); + xenstore_vtpm_dev = xendev->dev; +} + +static void vtpm_event(struct XenDevice *xendev) +{ + struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev, + xendev); + + qemu_bh_schedule(vtpmdev->sr_bh); +} + +struct XenDevOps xen_vtpmdev_ops = { + .size = sizeof(struct xen_vtpm_dev), + .flags = DEVOPS_FLAG_IGNORE_STATE | + DEVOPS_FLAG_FE, + .event = vtpm_event, + .free = vtpm_free, + .init = vtpm_init, + .alloc = vtpm_alloc, + .initialise = vtpm_initialise, + .backend_changed = xen_fe_backend_changed, +}; \ No newline at end of file diff --git a/hw/tpm/xen_vtpm_frontend.h b/hw/tpm/xen_vtpm_frontend.h new file mode 100644 index 0000000..72f586b --- /dev/null +++ b/hw/tpm/xen_vtpm_frontend.h @@ -0,0 +1,10 @@ +#ifndef TPM_XEN_VTPM_FRONTEND_H +#define TPM_XEN_VTPM_FRONTEND_H 1 + +struct XenDevice; +extern int xenstore_vtpm_dev; +/* Xen vtpm */ +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count); +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count); + +#endif /* TPM_XEN_VTPM_FRONTEND_H */ diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c index 7b305ce..f110411 100644 --- a/hw/xen/xen_frontend.c +++ b/hw/xen/xen_frontend.c @@ -75,6 +75,26 @@ void xen_fe_frontend_changed(struct XenDevice *xendev, const char *node) } } +void xen_fe_backend_changed(struct XenDevice *xendev, const char *node) +{ + int be_state; + + if (strcmp(node, "state") == 0) { + xenstore_read_be_int(xendev, node, &be_state); + switch (be_state) { + case XenbusStateConnected: + /* TODO */ + break; + case XenbusStateClosing: + case XenbusStateClosed: + xenbus_switch_state(xendev, XenbusStateClosing); + break; + default: + break; + } + } +} + void xenstore_update_fe(char *watch, struct XenDevice *xendev) { char *node; diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h index 71dd158..4a8808e 100644 --- a/include/hw/xen/xen_backend.h +++ b/include/hw/xen/xen_backend.h @@ -35,6 +35,7 @@ extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */ extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */ extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */ extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */ +extern struct XenDevOps xen_vtpmdev_ops; /* xen_vtpm_frontend.c*/ #ifdef CONFIG_USB_LIBUSB extern struct XenDevOps xen_usb_ops; /* xen-usb.c */ #endif diff --git a/include/hw/xen/xen_frontend.h b/include/hw/xen/xen_frontend.h index 8fc0422..912f333 100644 --- a/include/hw/xen/xen_frontend.h +++ b/include/hw/xen/xen_frontend.h @@ -11,6 +11,7 @@ void xenstore_update_fe(char *watch, struct XenDevice *xendev); struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev, char *backend, struct XenDevOps *ops); void xen_fe_frontend_changed(struct XenDevice *xendev, const char *node); +void xen_fe_backend_changed(struct XenDevice *xendev, const char *node); int xen_fe_register(const char *type, struct XenDevOps *ops); int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom); int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus); diff --git a/xen-hvm.c b/xen-hvm.c index eb57792..ef3fc53 100644 --- a/xen-hvm.c +++ b/xen-hvm.c @@ -16,6 +16,7 @@ #include "hw/i386/apic-msidef.h" #include "hw/xen/xen_common.h" #include "hw/xen/xen_backend.h" +#include "hw/xen/xen_frontend.h" #include "qmp-commands.h" #include "sysemu/char.h" @@ -1318,6 +1319,11 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) error_report("xen backend core setup failed"); goto err; } + +#ifdef CONFIG_TPM_XENSTUBDOMS + xen_fe_register("vtpm", &xen_vtpmdev_ops); +#endif + xen_be_register("console", &xen_console_ops); xen_be_register("vkbd", &xen_kbdmouse_ops); xen_be_register("qdisk", &xen_blkdev_ops);