Xen queue

* Xen PV backend 'qdevification'.
   Starting with xen_disk.
 * Performance improvements for xen-block.
 * Remove of the Xen PV domain builder.
 * bug fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQFOBAABCgA4FiEE+AwAYwjiLP2KkueYDPVXL9f7Va8FAlw8krkaHGFudGhvbnku
 cGVyYXJkQGNpdHJpeC5jb20ACgkQDPVXL9f7Va81vQf/XH0vIHytB0xM9qd06Svi
 axW6grfLfHipSIjQwdv8xeJjLJUQxZCV3Q1kg8sHDAioj9LVc0jAiJKMMUkQdnHT
 Ad98PbKrPNdEZJf+dydzFmibuehqD8OHL0Nu4U/k3+PKp/QjWJZvr7SspVxJPvz3
 K29n5HTjfA4QntahSEHKndmbQ9sxPd+Pz8+qZEXBLtogOW0xhK6WAVwkPG4XwhFz
 6wXySfuruSM0v5F3wkdA7FS1rmcdW/prty81MT7zg6h8hcYLo49pbXrRTuB6Psuz
 UWsbNhegevYWpxZAZZv9TvCY6d/5X733wDhENCTD8am+GBoDVV4Dh9YljTTjG4S0
 tA==
 =88n2
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/aperard/tags/pull-xen-20190114' into staging

Xen queue

* Xen PV backend 'qdevification'.
  Starting with xen_disk.
* Performance improvements for xen-block.
* Remove of the Xen PV domain builder.
* bug fixes.

# gpg: Signature made Mon 14 Jan 2019 13:46:33 GMT
# gpg:                using RSA key 0CF5572FD7FB55AF
# gpg: Good signature from "Anthony PERARD <anthony.perard@gmail.com>"
# gpg:                 aka "Anthony PERARD <anthony.perard@citrix.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 5379 2F71 024C 600F 778A  7161 D8D5 7199 DF83 42C8
#      Subkey fingerprint: F80C 0063 08E2 2CFD 8A92  E798 0CF5 572F D7FB 55AF

* remotes/aperard/tags/pull-xen-20190114: (25 commits)
  xen-block: avoid repeated memory allocation
  xen-block: improve response latency
  xen-block: improve batching behaviour
  xen: Replace few mentions of xend by libxl
  Remove broken Xen PV domain builder
  xen: remove the legacy 'xen_disk' backend
  MAINTAINERS: add myself as a Xen maintainer
  xen: automatically create XenBlockDevice-s
  xen: add a mechanism to automatically create XenDevice-s...
  xen: add implementations of xen-block connect and disconnect functions...
  xen: purge 'blk' and 'ioreq' from function names in dataplane/xen-block.c
  xen: remove 'ioreq' struct/varable/field names from dataplane/xen-block.c
  xen: remove 'XenBlkDev' and 'blkdev' names from dataplane/xen-block
  xen: add header and build dataplane/xen-block.c
  xen: remove unnecessary code from dataplane/xen-block.c
  xen: duplicate xen_disk.c as basis of dataplane/xen-block.c
  xen: add event channel interface for XenDevice-s
  xen: add grant table interface for XenDevice-s
  xen: add xenstore watcher infrastructure
  xen: create xenstore areas for XenDevice-s
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2019-01-14 13:54:17 +00:00
commit c9d18c1c15
45 changed files with 3923 additions and 1536 deletions

View File

@ -407,6 +407,7 @@ Guest CPU Cores (Xen):
X86
M: Stefano Stabellini <sstabellini@kernel.org>
M: Anthony Perard <anthony.perard@citrix.com>
M: Paul Durrant <paul.durrant@citrix.com>
L: xen-devel@lists.xenproject.org
S: Supported
F: */xen*
@ -414,10 +415,12 @@ F: hw/9pfs/xen-9p-backend.c
F: hw/char/xen_console.c
F: hw/display/xenfb.c
F: hw/net/xen_nic.c
F: hw/block/xen_*
F: hw/block/xen*
F: hw/block/dataplane/xen*
F: hw/xen/
F: hw/xenpv/
F: hw/i386/xen/
F: include/hw/block/dataplane/xen*
F: include/hw/xen/
F: include/sysemu/xen-mapcache.h

17
configure vendored
View File

@ -357,7 +357,6 @@ vnc_png=""
xkbcommon=""
xen=""
xen_ctrl_version=""
xen_pv_domain_build="no"
xen_pci_passthrough=""
linux_aio=""
cap_ng=""
@ -1119,10 +1118,6 @@ for opt do
;;
--enable-xen-pci-passthrough) xen_pci_passthrough="yes"
;;
--disable-xen-pv-domain-build) xen_pv_domain_build="no"
;;
--enable-xen-pv-domain-build) xen_pv_domain_build="yes"
;;
--disable-brlapi) brlapi="no"
;;
--enable-brlapi) brlapi="yes"
@ -1685,8 +1680,6 @@ Advanced options (experts only):
--tls-priority default TLS protocol/cipher priority string
--enable-gprof QEMU profiling with gprof
--enable-profiler profiler support
--enable-xen-pv-domain-build
xen pv domain builder
--enable-debug-stack-usage
track the maximum stack usage of stacks created by qemu_alloc_stack
@ -2678,12 +2671,6 @@ if test "$xen_pci_passthrough" != "no"; then
fi
fi
if test "$xen_pv_domain_build" = "yes" &&
test "$xen" != "yes"; then
error_exit "User requested Xen PV domain builder support" \
"which requires Xen support."
fi
##########################################
# Windows Hypervisor Platform accelerator (WHPX) check
if test "$whpx" != "no" ; then
@ -6069,7 +6056,6 @@ fi
echo "xen support $xen"
if test "$xen" = "yes" ; then
echo "xen ctrl version $xen_ctrl_version"
echo "pv dom build $xen_pv_domain_build"
fi
echo "brlapi support $brlapi"
echo "bluez support $bluez"
@ -6539,9 +6525,6 @@ fi
if test "$xen" = "yes" ; then
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
if test "$xen_pv_domain_build" = "yes" ; then
echo "CONFIG_XEN_PV_DOMAIN_BUILD=y" >> $config_host_mak
fi
fi
if test "$linux_aio" = "yes" ; then
echo "CONFIG_LINUX_AIO=y" >> $config_host_mak

View File

@ -12,7 +12,7 @@
#include "hw/hw.h"
#include "hw/9pfs/9p.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/9pfs/xen-9pfs.h"
#include "qapi/error.h"
#include "qemu/config-file.h"
@ -45,7 +45,7 @@ typedef struct Xen9pfsRing {
} Xen9pfsRing;
typedef struct Xen9pfsDev {
struct XenDevice xendev; /* must be first */
struct XenLegacyDevice xendev; /* must be first */
V9fsState state;
char *path;
char *security_model;
@ -56,7 +56,7 @@ typedef struct Xen9pfsDev {
Xen9pfsRing *rings;
} Xen9pfsDev;
static void xen_9pfs_disconnect(struct XenDevice *xendev);
static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
struct iovec *in_sg,
@ -243,7 +243,7 @@ static const V9fsTransport xen_9p_transport = {
.push_and_notify = xen_9pfs_push_and_notify,
};
static int xen_9pfs_init(struct XenDevice *xendev)
static int xen_9pfs_init(struct XenLegacyDevice *xendev)
{
return 0;
}
@ -305,7 +305,7 @@ static void xen_9pfs_evtchn_event(void *opaque)
qemu_bh_schedule(ring->bh);
}
static void xen_9pfs_disconnect(struct XenDevice *xendev)
static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
{
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
int i;
@ -321,7 +321,7 @@ static void xen_9pfs_disconnect(struct XenDevice *xendev)
}
}
static int xen_9pfs_free(struct XenDevice *xendev)
static int xen_9pfs_free(struct XenLegacyDevice *xendev)
{
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
int i;
@ -354,7 +354,7 @@ static int xen_9pfs_free(struct XenDevice *xendev)
return 0;
}
static int xen_9pfs_connect(struct XenDevice *xendev)
static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
{
Error *err = NULL;
int i;
@ -467,7 +467,7 @@ out:
return -1;
}
static void xen_9pfs_alloc(struct XenDevice *xendev)
static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
{
xenstore_write_be_str(xendev, "versions", VERSIONS);
xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);

View File

@ -4,7 +4,7 @@ common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
common-obj-$(CONFIG_NAND) += nand.o
common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
common-obj-$(CONFIG_XEN) += xen_disk.o
common-obj-$(CONFIG_XEN) += xen-block.o
common-obj-$(CONFIG_ECC) += ecc.o
common-obj-$(CONFIG_ONENAND) += onenand.o
common-obj-$(CONFIG_NVME_PCI) += nvme.o

View File

@ -1 +1,2 @@
obj-y += virtio-blk.o
obj-$(CONFIG_XEN) += xen-block.o

View File

@ -0,0 +1,827 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
* (c) Gerd Hoffmann <kraxel@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; under version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/xen/xen_common.h"
#include "hw/block/xen_blkif.h"
#include "sysemu/block-backend.h"
#include "sysemu/iothread.h"
#include "xen-block.h"
typedef struct XenBlockRequest {
blkif_request_t req;
int16_t status;
off_t start;
QEMUIOVector v;
void *buf;
size_t size;
int presync;
int aio_inflight;
int aio_errors;
XenBlockDataPlane *dataplane;
QLIST_ENTRY(XenBlockRequest) list;
BlockAcctCookie acct;
} XenBlockRequest;
struct XenBlockDataPlane {
XenDevice *xendev;
XenEventChannel *event_channel;
unsigned int *ring_ref;
unsigned int nr_ring_ref;
void *sring;
int64_t file_blk;
int64_t file_size;
int protocol;
blkif_back_rings_t rings;
int more_work;
QLIST_HEAD(inflight_head, XenBlockRequest) inflight;
QLIST_HEAD(freelist_head, XenBlockRequest) freelist;
int requests_total;
int requests_inflight;
unsigned int max_requests;
BlockBackend *blk;
QEMUBH *bh;
IOThread *iothread;
AioContext *ctx;
};
static void reset_request(XenBlockRequest *request)
{
memset(&request->req, 0, sizeof(request->req));
request->status = 0;
request->start = 0;
request->size = 0;
request->presync = 0;
request->aio_inflight = 0;
request->aio_errors = 0;
request->dataplane = NULL;
memset(&request->list, 0, sizeof(request->list));
memset(&request->acct, 0, sizeof(request->acct));
qemu_iovec_reset(&request->v);
}
static XenBlockRequest *xen_block_start_request(XenBlockDataPlane *dataplane)
{
XenBlockRequest *request = NULL;
if (QLIST_EMPTY(&dataplane->freelist)) {
if (dataplane->requests_total >= dataplane->max_requests) {
goto out;
}
/* allocate new struct */
request = g_malloc0(sizeof(*request));
request->dataplane = dataplane;
/*
* We cannot need more pages per requests than this, and since we
* re-use requests, allocate the memory once here. It will be freed
* xen_block_dataplane_destroy() when the request list is freed.
*/
request->buf = qemu_memalign(XC_PAGE_SIZE,
BLKIF_MAX_SEGMENTS_PER_REQUEST *
XC_PAGE_SIZE);
dataplane->requests_total++;
qemu_iovec_init(&request->v, 1);
} else {
/* get one from freelist */
request = QLIST_FIRST(&dataplane->freelist);
QLIST_REMOVE(request, list);
}
QLIST_INSERT_HEAD(&dataplane->inflight, request, list);
dataplane->requests_inflight++;
out:
return request;
}
static void xen_block_finish_request(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
QLIST_REMOVE(request, list);
dataplane->requests_inflight--;
}
static void xen_block_release_request(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
QLIST_REMOVE(request, list);
reset_request(request);
request->dataplane = dataplane;
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
dataplane->requests_inflight--;
}
/*
* translate request into iovec + start offset
* do sanity checks along the way
*/
static int xen_block_parse_request(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
size_t len;
int i;
switch (request->req.operation) {
case BLKIF_OP_READ:
break;
case BLKIF_OP_FLUSH_DISKCACHE:
request->presync = 1;
if (!request->req.nr_segments) {
return 0;
}
/* fall through */
case BLKIF_OP_WRITE:
break;
case BLKIF_OP_DISCARD:
return 0;
default:
error_report("error: unknown operation (%d)", request->req.operation);
goto err;
};
if (request->req.operation != BLKIF_OP_READ &&
blk_is_read_only(dataplane->blk)) {
error_report("error: write req for ro device");
goto err;
}
request->start = request->req.sector_number * dataplane->file_blk;
for (i = 0; i < request->req.nr_segments; i++) {
if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
error_report("error: nr_segments too big");
goto err;
}
if (request->req.seg[i].first_sect > request->req.seg[i].last_sect) {
error_report("error: first > last sector");
goto err;
}
if (request->req.seg[i].last_sect * dataplane->file_blk >=
XC_PAGE_SIZE) {
error_report("error: page crossing");
goto err;
}
len = (request->req.seg[i].last_sect -
request->req.seg[i].first_sect + 1) * dataplane->file_blk;
request->size += len;
}
if (request->start + request->size > dataplane->file_size) {
error_report("error: access beyond end of file");
goto err;
}
return 0;
err:
request->status = BLKIF_RSP_ERROR;
return -1;
}
static int xen_block_copy_request(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
XenDevice *xendev = dataplane->xendev;
XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int i, count;
int64_t file_blk = dataplane->file_blk;
bool to_domain = (request->req.operation == BLKIF_OP_READ);
void *virt = request->buf;
Error *local_err = NULL;
if (request->req.nr_segments == 0) {
return 0;
}
count = request->req.nr_segments;
for (i = 0; i < count; i++) {
if (to_domain) {
segs[i].dest.foreign.ref = request->req.seg[i].gref;
segs[i].dest.foreign.offset = request->req.seg[i].first_sect *
file_blk;
segs[i].source.virt = virt;
} else {
segs[i].source.foreign.ref = request->req.seg[i].gref;
segs[i].source.foreign.offset = request->req.seg[i].first_sect *
file_blk;
segs[i].dest.virt = virt;
}
segs[i].len = (request->req.seg[i].last_sect -
request->req.seg[i].first_sect + 1) * file_blk;
virt += segs[i].len;
}
xen_device_copy_grant_refs(xendev, to_domain, segs, count, &local_err);
if (local_err) {
error_reportf_err(local_err, "failed to copy data: ");
request->aio_errors++;
return -1;
}
return 0;
}
static int xen_block_do_aio(XenBlockRequest *request);
static int xen_block_send_response(XenBlockRequest *request);
static void xen_block_complete_aio(void *opaque, int ret)
{
XenBlockRequest *request = opaque;
XenBlockDataPlane *dataplane = request->dataplane;
aio_context_acquire(dataplane->ctx);
if (ret != 0) {
error_report("%s I/O error",
request->req.operation == BLKIF_OP_READ ?
"read" : "write");
request->aio_errors++;
}
request->aio_inflight--;
if (request->presync) {
request->presync = 0;
xen_block_do_aio(request);
goto done;
}
if (request->aio_inflight > 0) {
goto done;
}
switch (request->req.operation) {
case BLKIF_OP_READ:
/* in case of failure request->aio_errors is increased */
if (ret == 0) {
xen_block_copy_request(request);
}
break;
case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE:
if (!request->req.nr_segments) {
break;
}
break;
default:
break;
}
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
xen_block_finish_request(request);
switch (request->req.operation) {
case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE:
if (!request->req.nr_segments) {
break;
}
case BLKIF_OP_READ:
if (request->status == BLKIF_RSP_OKAY) {
block_acct_done(blk_get_stats(dataplane->blk), &request->acct);
} else {
block_acct_failed(blk_get_stats(dataplane->blk), &request->acct);
}
break;
case BLKIF_OP_DISCARD:
default:
break;
}
if (xen_block_send_response(request)) {
Error *local_err = NULL;
xen_device_notify_event_channel(dataplane->xendev,
dataplane->event_channel,
&local_err);
if (local_err) {
error_report_err(local_err);
}
}
xen_block_release_request(request);
qemu_bh_schedule(dataplane->bh);
done:
aio_context_release(dataplane->ctx);
}
static bool xen_block_split_discard(XenBlockRequest *request,
blkif_sector_t sector_number,
uint64_t nr_sectors)
{
XenBlockDataPlane *dataplane = request->dataplane;
int64_t byte_offset;
int byte_chunk;
uint64_t byte_remaining, limit;
uint64_t sec_start = sector_number;
uint64_t sec_count = nr_sectors;
/* Wrap around, or overflowing byte limit? */
if (sec_start + sec_count < sec_count ||
sec_start + sec_count > INT64_MAX / dataplane->file_blk) {
return false;
}
limit = BDRV_REQUEST_MAX_SECTORS * dataplane->file_blk;
byte_offset = sec_start * dataplane->file_blk;
byte_remaining = sec_count * dataplane->file_blk;
do {
byte_chunk = byte_remaining > limit ? limit : byte_remaining;
request->aio_inflight++;
blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk,
xen_block_complete_aio, request);
byte_remaining -= byte_chunk;
byte_offset += byte_chunk;
} while (byte_remaining > 0);
return true;
}
static int xen_block_do_aio(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
if (request->req.nr_segments &&
(request->req.operation == BLKIF_OP_WRITE ||
request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
xen_block_copy_request(request)) {
goto err;
}
request->aio_inflight++;
if (request->presync) {
blk_aio_flush(request->dataplane->blk, xen_block_complete_aio,
request);
return 0;
}
switch (request->req.operation) {
case BLKIF_OP_READ:
qemu_iovec_add(&request->v, request->buf, request->size);
block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
request->v.size, BLOCK_ACCT_READ);
request->aio_inflight++;
blk_aio_preadv(dataplane->blk, request->start, &request->v, 0,
xen_block_complete_aio, request);
break;
case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE:
if (!request->req.nr_segments) {
break;
}
qemu_iovec_add(&request->v, request->buf, request->size);
block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
request->v.size,
request->req.operation == BLKIF_OP_WRITE ?
BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
request->aio_inflight++;
blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0,
xen_block_complete_aio, request);
break;
case BLKIF_OP_DISCARD:
{
struct blkif_request_discard *req = (void *)&request->req;
if (!xen_block_split_discard(request, req->sector_number,
req->nr_sectors)) {
goto err;
}
break;
}
default:
/* unknown operation (shouldn't happen -- parse catches this) */
goto err;
}
xen_block_complete_aio(request, 0);
return 0;
err:
xen_block_finish_request(request);
request->status = BLKIF_RSP_ERROR;
return -1;
}
static int xen_block_send_response(XenBlockRequest *request)
{
XenBlockDataPlane *dataplane = request->dataplane;
int send_notify = 0;
int have_requests = 0;
blkif_response_t *resp;
/* Place on the response ring for the relevant domain. */
switch (dataplane->protocol) {
case BLKIF_PROTOCOL_NATIVE:
resp = (blkif_response_t *)RING_GET_RESPONSE(
&dataplane->rings.native,
dataplane->rings.native.rsp_prod_pvt);
break;
case BLKIF_PROTOCOL_X86_32:
resp = (blkif_response_t *)RING_GET_RESPONSE(
&dataplane->rings.x86_32_part,
dataplane->rings.x86_32_part.rsp_prod_pvt);
break;
case BLKIF_PROTOCOL_X86_64:
resp = (blkif_response_t *)RING_GET_RESPONSE(
&dataplane->rings.x86_64_part,
dataplane->rings.x86_64_part.rsp_prod_pvt);
break;
default:
return 0;
}
resp->id = request->req.id;
resp->operation = request->req.operation;
resp->status = request->status;
dataplane->rings.common.rsp_prod_pvt++;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&dataplane->rings.common,
send_notify);
if (dataplane->rings.common.rsp_prod_pvt ==
dataplane->rings.common.req_cons) {
/*
* Tail check for pending requests. Allows frontend to avoid
* notifications if requests are already in flight (lower
* overheads and promotes batching).
*/
RING_FINAL_CHECK_FOR_REQUESTS(&dataplane->rings.common,
have_requests);
} else if (RING_HAS_UNCONSUMED_REQUESTS(&dataplane->rings.common)) {
have_requests = 1;
}
if (have_requests) {
dataplane->more_work++;
}
return send_notify;
}
static int xen_block_get_request(XenBlockDataPlane *dataplane,
XenBlockRequest *request, RING_IDX rc)
{
switch (dataplane->protocol) {
case BLKIF_PROTOCOL_NATIVE: {
blkif_request_t *req =
RING_GET_REQUEST(&dataplane->rings.native, rc);
memcpy(&request->req, req, sizeof(request->req));
break;
}
case BLKIF_PROTOCOL_X86_32: {
blkif_x86_32_request_t *req =
RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc);
blkif_get_x86_32_req(&request->req, req);
break;
}
case BLKIF_PROTOCOL_X86_64: {
blkif_x86_64_request_t *req =
RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc);
blkif_get_x86_64_req(&request->req, req);
break;
}
}
/* Prevent the compiler from accessing the on-ring fields instead. */
barrier();
return 0;
}
/*
* Threshold of in-flight requests above which we will start using
* blk_io_plug()/blk_io_unplug() to batch requests.
*/
#define IO_PLUG_THRESHOLD 1
static void xen_block_handle_requests(XenBlockDataPlane *dataplane)
{
RING_IDX rc, rp;
XenBlockRequest *request;
int inflight_atstart = dataplane->requests_inflight;
int batched = 0;
dataplane->more_work = 0;
rc = dataplane->rings.common.req_cons;
rp = dataplane->rings.common.sring->req_prod;
xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
/*
* If there was more than IO_PLUG_THRESHOLD requests in flight
* when we got here, this is an indication that there the bottleneck
* is below us, so it's worth beginning to batch up I/O requests
* rather than submitting them immediately. The maximum number
* of requests we're willing to batch is the number already in
* flight, so it can grow up to max_requests when the bottleneck
* is below us.
*/
if (inflight_atstart > IO_PLUG_THRESHOLD) {
blk_io_plug(dataplane->blk);
}
while (rc != rp) {
/* pull request from ring */
if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) {
break;
}
request = xen_block_start_request(dataplane);
if (request == NULL) {
dataplane->more_work++;
break;
}
xen_block_get_request(dataplane, request, rc);
dataplane->rings.common.req_cons = ++rc;
/* parse them */
if (xen_block_parse_request(request) != 0) {
switch (request->req.operation) {
case BLKIF_OP_READ:
block_acct_invalid(blk_get_stats(dataplane->blk),
BLOCK_ACCT_READ);
break;
case BLKIF_OP_WRITE:
block_acct_invalid(blk_get_stats(dataplane->blk),
BLOCK_ACCT_WRITE);
break;
case BLKIF_OP_FLUSH_DISKCACHE:
block_acct_invalid(blk_get_stats(dataplane->blk),
BLOCK_ACCT_FLUSH);
default:
break;
};
if (xen_block_send_response(request)) {
Error *local_err = NULL;
xen_device_notify_event_channel(dataplane->xendev,
dataplane->event_channel,
&local_err);
if (local_err) {
error_report_err(local_err);
}
}
xen_block_release_request(request);
continue;
}
if (inflight_atstart > IO_PLUG_THRESHOLD &&
batched >= inflight_atstart) {
blk_io_unplug(dataplane->blk);
}
xen_block_do_aio(request);
if (inflight_atstart > IO_PLUG_THRESHOLD) {
if (batched >= inflight_atstart) {
blk_io_plug(dataplane->blk);
batched = 0;
} else {
batched++;
}
}
}
if (inflight_atstart > IO_PLUG_THRESHOLD) {
blk_io_unplug(dataplane->blk);
}
if (dataplane->more_work &&
dataplane->requests_inflight < dataplane->max_requests) {
qemu_bh_schedule(dataplane->bh);
}
}
static void xen_block_dataplane_bh(void *opaque)
{
XenBlockDataPlane *dataplane = opaque;
aio_context_acquire(dataplane->ctx);
xen_block_handle_requests(dataplane);
aio_context_release(dataplane->ctx);
}
static void xen_block_dataplane_event(void *opaque)
{
XenBlockDataPlane *dataplane = opaque;
qemu_bh_schedule(dataplane->bh);
}
XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
BlockConf *conf,
IOThread *iothread)
{
XenBlockDataPlane *dataplane = g_new0(XenBlockDataPlane, 1);
dataplane->xendev = xendev;
dataplane->file_blk = conf->logical_block_size;
dataplane->blk = conf->blk;
dataplane->file_size = blk_getlength(dataplane->blk);
QLIST_INIT(&dataplane->inflight);
QLIST_INIT(&dataplane->freelist);
if (iothread) {
dataplane->iothread = iothread;
object_ref(OBJECT(dataplane->iothread));
dataplane->ctx = iothread_get_aio_context(dataplane->iothread);
} else {
dataplane->ctx = qemu_get_aio_context();
}
dataplane->bh = aio_bh_new(dataplane->ctx, xen_block_dataplane_bh,
dataplane);
return dataplane;
}
void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
{
XenBlockRequest *request;
if (!dataplane) {
return;
}
while (!QLIST_EMPTY(&dataplane->freelist)) {
request = QLIST_FIRST(&dataplane->freelist);
QLIST_REMOVE(request, list);
qemu_iovec_destroy(&request->v);
qemu_vfree(request->buf);
g_free(request);
}
qemu_bh_delete(dataplane->bh);
if (dataplane->iothread) {
object_unref(OBJECT(dataplane->iothread));
}
g_free(dataplane);
}
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
{
XenDevice *xendev;
if (!dataplane) {
return;
}
aio_context_acquire(dataplane->ctx);
blk_set_aio_context(dataplane->blk, qemu_get_aio_context());
aio_context_release(dataplane->ctx);
xendev = dataplane->xendev;
if (dataplane->event_channel) {
Error *local_err = NULL;
xen_device_unbind_event_channel(xendev, dataplane->event_channel,
&local_err);
dataplane->event_channel = NULL;
if (local_err) {
error_report_err(local_err);
}
}
if (dataplane->sring) {
Error *local_err = NULL;
xen_device_unmap_grant_refs(xendev, dataplane->sring,
dataplane->nr_ring_ref, &local_err);
dataplane->sring = NULL;
if (local_err) {
error_report_err(local_err);
}
}
g_free(dataplane->ring_ref);
dataplane->ring_ref = NULL;
}
void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
const unsigned int ring_ref[],
unsigned int nr_ring_ref,
unsigned int event_channel,
unsigned int protocol,
Error **errp)
{
XenDevice *xendev = dataplane->xendev;
Error *local_err = NULL;
unsigned int ring_size;
unsigned int i;
dataplane->nr_ring_ref = nr_ring_ref;
dataplane->ring_ref = g_new(unsigned int, nr_ring_ref);
for (i = 0; i < nr_ring_ref; i++) {
dataplane->ring_ref[i] = ring_ref[i];
}
dataplane->protocol = protocol;
ring_size = XC_PAGE_SIZE * dataplane->nr_ring_ref;
switch (dataplane->protocol) {
case BLKIF_PROTOCOL_NATIVE:
{
dataplane->max_requests = __CONST_RING_SIZE(blkif, ring_size);
break;
}
case BLKIF_PROTOCOL_X86_32:
{
dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
break;
}
case BLKIF_PROTOCOL_X86_64:
{
dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
break;
}
default:
error_setg(errp, "unknown protocol %u", dataplane->protocol);
return;
}
xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
goto stop;
}
dataplane->sring = xen_device_map_grant_refs(xendev,
dataplane->ring_ref,
dataplane->nr_ring_ref,
PROT_READ | PROT_WRITE,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
goto stop;
}
switch (dataplane->protocol) {
case BLKIF_PROTOCOL_NATIVE:
{
blkif_sring_t *sring_native = dataplane->sring;
BACK_RING_INIT(&dataplane->rings.native, sring_native, ring_size);
break;
}
case BLKIF_PROTOCOL_X86_32:
{
blkif_x86_32_sring_t *sring_x86_32 = dataplane->sring;
BACK_RING_INIT(&dataplane->rings.x86_32_part, sring_x86_32,
ring_size);
break;
}
case BLKIF_PROTOCOL_X86_64:
{
blkif_x86_64_sring_t *sring_x86_64 = dataplane->sring;
BACK_RING_INIT(&dataplane->rings.x86_64_part, sring_x86_64,
ring_size);
break;
}
}
dataplane->event_channel =
xen_device_bind_event_channel(xendev, event_channel,
xen_block_dataplane_event, dataplane,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
goto stop;
}
aio_context_acquire(dataplane->ctx);
blk_set_aio_context(dataplane->blk, dataplane->ctx);
aio_context_release(dataplane->ctx);
return;
stop:
xen_block_dataplane_stop(dataplane);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_BLOCK_DATAPLANE_XEN_BLOCK_H
#define HW_BLOCK_DATAPLANE_XEN_BLOCK_H
#include "hw/block/block.h"
#include "hw/xen/xen-bus.h"
#include "sysemu/iothread.h"
typedef struct XenBlockDataPlane XenBlockDataPlane;
XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
BlockConf *conf,
IOThread *iothread);
void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane);
void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
const unsigned int ring_ref[],
unsigned int nr_ring_ref,
unsigned int event_channel,
unsigned int protocol,
Error **errp);
void xen_block_dataplane_stop(XenBlockDataPlane *dataplane);
#endif /* HW_BLOCK_DATAPLANE_XEN_BLOCK_H */

View File

@ -127,3 +127,17 @@ xen_disk_init(char *name) "%s"
xen_disk_connect(char *name) "%s"
xen_disk_disconnect(char *name) "%s"
xen_disk_free(char *name) "%s"
# hw/block/xen-block.c
xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
xen_block_disconnect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
xen_disk_realize(void) ""
xen_disk_unrealize(void) ""
xen_cdrom_realize(void) ""
xen_cdrom_unrealize(void) ""
xen_block_blockdev_add(char *str) "%s"
xen_block_blockdev_del(const char *node_name) "%s"
xen_block_device_create(unsigned int number) "%u"
xen_block_device_destroy(unsigned int number) "%u"

963
hw/block/xen-block.c Normal file
View File

@ -0,0 +1,963 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/visitor.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
#include "hw/hw.h"
#include "hw/xen/xen_common.h"
#include "hw/block/xen_blkif.h"
#include "hw/xen/xen-block.h"
#include "hw/xen/xen-backend.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "sysemu/iothread.h"
#include "dataplane/xen-block.h"
#include "trace.h"
static char *xen_block_get_name(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
XenBlockVdev *vdev = &blockdev->props.vdev;
return g_strdup_printf("%lu", vdev->number);
}
static void xen_block_disconnect(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
const char *type = object_get_typename(OBJECT(blockdev));
XenBlockVdev *vdev = &blockdev->props.vdev;
trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
xen_block_dataplane_stop(blockdev->dataplane);
}
static void xen_block_connect(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
const char *type = object_get_typename(OBJECT(blockdev));
XenBlockVdev *vdev = &blockdev->props.vdev;
unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
char *str;
trace_xen_block_connect(type, vdev->disk, vdev->partition);
if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
&order) != 1) {
nr_ring_ref = 1;
ring_ref = g_new(unsigned int, nr_ring_ref);
if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
&ring_ref[0]) != 1) {
error_setg(errp, "failed to read ring-ref");
g_free(ring_ref);
return;
}
} else if (order <= blockdev->props.max_ring_page_order) {
unsigned int i;
nr_ring_ref = 1 << order;
ring_ref = g_new(unsigned int, nr_ring_ref);
for (i = 0; i < nr_ring_ref; i++) {
const char *key = g_strdup_printf("ring-ref%u", i);
if (xen_device_frontend_scanf(xendev, key, "%u",
&ring_ref[i]) != 1) {
error_setg(errp, "failed to read %s", key);
g_free((gpointer)key);
g_free(ring_ref);
return;
}
g_free((gpointer)key);
}
} else {
error_setg(errp, "invalid ring-page-order (%d)", order);
return;
}
if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
&event_channel) != 1) {
error_setg(errp, "failed to read event-channel");
g_free(ring_ref);
return;
}
if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
&str) != 1) {
protocol = BLKIF_PROTOCOL_NATIVE;
} else {
if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
protocol = BLKIF_PROTOCOL_X86_32;
} else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
protocol = BLKIF_PROTOCOL_X86_64;
} else {
protocol = BLKIF_PROTOCOL_NATIVE;
}
free(str);
}
xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
event_channel, protocol, errp);
g_free(ring_ref);
}
static void xen_block_unrealize(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
XenBlockDeviceClass *blockdev_class =
XEN_BLOCK_DEVICE_GET_CLASS(xendev);
const char *type = object_get_typename(OBJECT(blockdev));
XenBlockVdev *vdev = &blockdev->props.vdev;
if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
return;
}
trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
/* Disconnect from the frontend in case this has not already happened */
xen_block_disconnect(xendev, NULL);
xen_block_dataplane_destroy(blockdev->dataplane);
blockdev->dataplane = NULL;
if (blockdev_class->unrealize) {
blockdev_class->unrealize(blockdev, errp);
}
}
static void xen_block_realize(XenDevice *xendev, Error **errp)
{
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
XenBlockDeviceClass *blockdev_class =
XEN_BLOCK_DEVICE_GET_CLASS(xendev);
const char *type = object_get_typename(OBJECT(blockdev));
XenBlockVdev *vdev = &blockdev->props.vdev;
BlockConf *conf = &blockdev->props.conf;
Error *local_err = NULL;
if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
error_setg(errp, "vdev property not set");
return;
}
trace_xen_block_realize(type, vdev->disk, vdev->partition);
if (blockdev_class->realize) {
blockdev_class->realize(blockdev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
/*
* The blkif protocol does not deal with removable media, so it must
* always be present, even for CDRom devices.
*/
assert(conf->blk);
if (!blk_is_inserted(conf->blk)) {
error_setg(errp, "device needs media, but drive is empty");
return;
}
if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
false, errp)) {
return;
}
if (!(blockdev->info & VDISK_CDROM) &&
!blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
return;
}
blkconf_blocksizes(conf);
if (conf->logical_block_size > conf->physical_block_size) {
error_setg(
errp, "logical_block_size > physical_block_size not supported");
return;
}
blk_set_guest_block_size(conf->blk, conf->logical_block_size);
if (conf->discard_granularity > 0) {
xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
}
xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
blockdev->props.max_ring_page_order);
xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
xen_device_frontend_printf(xendev, "virtual-device", "%lu",
vdev->number);
xen_device_frontend_printf(xendev, "device-type", "%s",
blockdev->device_type);
xen_device_backend_printf(xendev, "sector-size", "%u",
conf->logical_block_size);
xen_device_backend_printf(xendev, "sectors", "%lu",
blk_getlength(conf->blk) /
conf->logical_block_size);
blockdev->dataplane =
xen_block_dataplane_create(xendev, conf, blockdev->props.iothread);
}
static void xen_block_frontend_changed(XenDevice *xendev,
enum xenbus_state frontend_state,
Error **errp)
{
enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
Error *local_err = NULL;
switch (frontend_state) {
case XenbusStateInitialised:
case XenbusStateConnected:
if (backend_state == XenbusStateConnected) {
break;
}
xen_block_disconnect(xendev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
break;
}
xen_block_connect(xendev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
break;
}
xen_device_backend_set_state(xendev, XenbusStateConnected);
break;
case XenbusStateClosing:
xen_device_backend_set_state(xendev, XenbusStateClosing);
break;
case XenbusStateClosed:
xen_block_disconnect(xendev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
break;
}
xen_device_backend_set_state(xendev, XenbusStateClosed);
break;
default:
break;
}
}
static char *disk_to_vbd_name(unsigned int disk)
{
char *name, *prefix = (disk >= 26) ?
disk_to_vbd_name((disk / 26) - 1) : g_strdup("");
name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26);
g_free(prefix);
return name;
}
static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
char *str;
switch (vdev->type) {
case XEN_BLOCK_VDEV_TYPE_DP:
str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition);
break;
case XEN_BLOCK_VDEV_TYPE_XVD:
case XEN_BLOCK_VDEV_TYPE_HD:
case XEN_BLOCK_VDEV_TYPE_SD: {
char *name = disk_to_vbd_name(vdev->disk);
str = g_strdup_printf("%s%s%lu",
(vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ?
"xvd" :
(vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ?
"hd" :
"sd",
name, vdev->partition);
g_free(name);
break;
}
default:
error_setg(errp, "invalid vdev type");
return;
}
visit_type_str(v, name, &str, errp);
g_free(str);
}
static unsigned int vbd_name_to_disk(const char *name, const char **endp)
{
unsigned int disk = 0;
while (*name != '\0') {
if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) {
break;
}
disk *= 26;
disk += *name++ - 'a' + 1;
}
*endp = name;
return disk - 1;
}
static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
char *str, *p;
const char *end;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_str(v, name, &str, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
p = strchr(str, 'd');
if (!p) {
goto invalid;
}
*p++ = '\0';
if (*str == '\0') {
vdev->type = XEN_BLOCK_VDEV_TYPE_DP;
} else if (strcmp(str, "xv") == 0) {
vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
} else if (strcmp(str, "h") == 0) {
vdev->type = XEN_BLOCK_VDEV_TYPE_HD;
} else if (strcmp(str, "s") == 0) {
vdev->type = XEN_BLOCK_VDEV_TYPE_SD;
} else {
goto invalid;
}
if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) {
if (qemu_strtoul(p, &end, 10, &vdev->disk)) {
goto invalid;
}
if (*end == 'p') {
p = (char *) ++end;
if (*end == '\0') {
goto invalid;
}
}
} else {
vdev->disk = vbd_name_to_disk(p, &end);
}
if (*end != '\0') {
p = (char *)end;
if (qemu_strtoul(p, &end, 10, &vdev->partition)) {
goto invalid;
}
if (*end != '\0') {
goto invalid;
}
} else {
vdev->partition = 0;
}
switch (vdev->type) {
case XEN_BLOCK_VDEV_TYPE_DP:
case XEN_BLOCK_VDEV_TYPE_XVD:
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
vdev->number = (202 << 8) | (vdev->disk << 4) |
vdev->partition;
} else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
vdev->number = (1 << 28) | (vdev->disk << 8) |
vdev->partition;
} else {
goto invalid;
}
break;
case XEN_BLOCK_VDEV_TYPE_HD:
if ((vdev->disk == 0 || vdev->disk == 1) &&
vdev->partition < (1 << 6)) {
vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
} else if ((vdev->disk == 2 || vdev->disk == 3) &&
vdev->partition < (1 << 6)) {
vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
vdev->partition;
} else {
goto invalid;
}
break;
case XEN_BLOCK_VDEV_TYPE_SD:
if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
} else {
goto invalid;
}
break;
default:
goto invalid;
}
g_free(str);
return;
invalid:
error_setg(errp, "invalid virtual disk specifier");
vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID;
g_free(str);
}
/*
* This property deals with 'vdev' names adhering to the Xen VBD naming
* scheme described in:
*
* https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
*/
const PropertyInfo xen_block_prop_vdev = {
.name = "str",
.description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
.get = xen_block_get_vdev,
.set = xen_block_set_vdev,
};
static Property xen_block_props[] = {
DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
xen_block_prop_vdev, XenBlockVdev),
DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
props.max_ring_page_order, 4),
DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
TYPE_IOTHREAD, IOThread *),
DEFINE_PROP_END_OF_LIST()
};
static void xen_block_class_init(ObjectClass *class, void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
xendev_class->backend = "qdisk";
xendev_class->device = "vbd";
xendev_class->get_name = xen_block_get_name;
xendev_class->realize = xen_block_realize;
xendev_class->frontend_changed = xen_block_frontend_changed;
xendev_class->unrealize = xen_block_unrealize;
dev_class->props = xen_block_props;
}
static const TypeInfo xen_block_type_info = {
.name = TYPE_XEN_BLOCK_DEVICE,
.parent = TYPE_XEN_DEVICE,
.instance_size = sizeof(XenBlockDevice),
.abstract = true,
.class_size = sizeof(XenBlockDeviceClass),
.class_init = xen_block_class_init,
};
static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
{
trace_xen_disk_unrealize();
}
static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
{
BlockConf *conf = &blockdev->props.conf;
trace_xen_disk_realize();
blockdev->device_type = "disk";
if (!conf->blk) {
error_setg(errp, "drive property not set");
return;
}
blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
}
static void xen_disk_class_init(ObjectClass *class, void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
blockdev_class->realize = xen_disk_realize;
blockdev_class->unrealize = xen_disk_unrealize;
dev_class->desc = "Xen Disk Device";
}
static const TypeInfo xen_disk_type_info = {
.name = TYPE_XEN_DISK_DEVICE,
.parent = TYPE_XEN_BLOCK_DEVICE,
.instance_size = sizeof(XenDiskDevice),
.class_init = xen_disk_class_init,
};
static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
{
trace_xen_cdrom_unrealize();
}
static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
{
BlockConf *conf = &blockdev->props.conf;
trace_xen_cdrom_realize();
blockdev->device_type = "cdrom";
if (!conf->blk) {
int rc;
/* Set up an empty drive */
conf->blk = blk_new(0, BLK_PERM_ALL);
rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
if (!rc) {
error_setg_errno(errp, -rc, "failed to create drive");
return;
}
}
blockdev->info = VDISK_READONLY | VDISK_CDROM;
}
static void xen_cdrom_class_init(ObjectClass *class, void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
blockdev_class->realize = xen_cdrom_realize;
blockdev_class->unrealize = xen_cdrom_unrealize;
dev_class->desc = "Xen CD-ROM Device";
}
static const TypeInfo xen_cdrom_type_info = {
.name = TYPE_XEN_CDROM_DEVICE,
.parent = TYPE_XEN_BLOCK_DEVICE,
.instance_size = sizeof(XenCDRomDevice),
.class_init = xen_cdrom_class_init,
};
static void xen_block_register_types(void)
{
type_register_static(&xen_block_type_info);
type_register_static(&xen_disk_type_info);
type_register_static(&xen_cdrom_type_info);
}
type_init(xen_block_register_types)
static void xen_block_blockdev_del(const char *node_name, Error **errp)
{
trace_xen_block_blockdev_del(node_name);
qmp_blockdev_del(node_name, errp);
}
static char *xen_block_blockdev_add(const char *id, QDict *qdict,
Error **errp)
{
const char *driver = qdict_get_try_str(qdict, "driver");
BlockdevOptions *options = NULL;
Error *local_err = NULL;
char *node_name;
Visitor *v;
if (!driver) {
error_setg(errp, "no 'driver' parameter");
return NULL;
}
node_name = g_strdup_printf("%s-%s", id, driver);
qdict_put_str(qdict, "node-name", node_name);
trace_xen_block_blockdev_add(node_name);
v = qobject_input_visitor_new(QOBJECT(qdict));
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
qmp_blockdev_add(options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
qapi_free_BlockdevOptions(options);
return node_name;
fail:
if (options) {
qapi_free_BlockdevOptions(options);
}
g_free(node_name);
return NULL;
}
static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
{
char *node_name = drive->node_name;
if (node_name) {
Error *local_err = NULL;
xen_block_blockdev_del(node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
g_free(node_name);
drive->node_name = NULL;
}
g_free(drive->id);
g_free(drive);
}
static XenBlockDrive *xen_block_drive_create(const char *id,
const char *device_type,
QDict *opts, Error **errp)
{
const char *params = qdict_get_try_str(opts, "params");
const char *mode = qdict_get_try_str(opts, "mode");
const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
char *driver = NULL;
char *filename = NULL;
XenBlockDrive *drive = NULL;
Error *local_err = NULL;
QDict *file_layer;
QDict *driver_layer;
if (params) {
char **v = g_strsplit(params, ":", 2);
if (v[1] == NULL) {
filename = g_strdup(v[0]);
driver = g_strdup("raw");
} else {
if (strcmp(v[0], "aio") == 0) {
driver = g_strdup("raw");
} else if (strcmp(v[0], "vhd") == 0) {
driver = g_strdup("vpc");
} else {
driver = g_strdup(v[0]);
}
filename = g_strdup(v[1]);
}
g_strfreev(v);
}
if (!filename) {
error_setg(errp, "no filename");
goto done;
}
assert(driver);
drive = g_new0(XenBlockDrive, 1);
drive->id = g_strdup(id);
file_layer = qdict_new();
qdict_put_str(file_layer, "driver", "file");
qdict_put_str(file_layer, "filename", filename);
if (mode && *mode != 'w') {
qdict_put_bool(file_layer, "read-only", true);
}
if (direct_io_safe) {
unsigned long value;
if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) {
QDict *cache_qdict = qdict_new();
qdict_put_bool(cache_qdict, "direct", true);
qdict_put_obj(file_layer, "cache", QOBJECT(cache_qdict));
qdict_put_str(file_layer, "aio", "native");
}
}
if (discard_enable) {
unsigned long value;
if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) {
qdict_put_str(file_layer, "discard", "unmap");
}
}
/*
* It is necessary to turn file locking off as an emulated device
* may have already opened the same image file.
*/
qdict_put_str(file_layer, "locking", "off");
driver_layer = qdict_new();
qdict_put_str(driver_layer, "driver", driver);
qdict_put_obj(driver_layer, "file", QOBJECT(file_layer));
g_assert(!drive->node_name);
drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
&local_err);
done:
g_free(driver);
g_free(filename);
if (local_err) {
error_propagate(errp, local_err);
xen_block_drive_destroy(drive, NULL);
return NULL;
}
return drive;
}
static const char *xen_block_drive_get_node_name(XenBlockDrive *drive)
{
return drive->node_name ? drive->node_name : "";
}
static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
Error **errp)
{
qmp_object_del(iothread->id, errp);
g_free(iothread->id);
g_free(iothread);
}
static XenBlockIOThread *xen_block_iothread_create(const char *id,
Error **errp)
{
XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
Error *local_err = NULL;
iothread->id = g_strdup(id);
qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(iothread->id);
g_free(iothread);
return NULL;
}
return iothread;
}
static void xen_block_device_create(XenBackendInstance *backend,
QDict *opts, Error **errp)
{
XenBus *xenbus = xen_backend_get_bus(backend);
const char *name = xen_backend_get_name(backend);
unsigned long number;
const char *vdev, *device_type;
XenBlockDrive *drive = NULL;
XenBlockIOThread *iothread = NULL;
XenDevice *xendev = NULL;
Error *local_err = NULL;
const char *type;
XenBlockDevice *blockdev;
if (qemu_strtoul(name, NULL, 10, &number)) {
error_setg(errp, "failed to parse name '%s'", name);
goto fail;
}
trace_xen_block_device_create(number);
vdev = qdict_get_try_str(opts, "dev");
if (!vdev) {
error_setg(errp, "no dev parameter");
goto fail;
}
device_type = qdict_get_try_str(opts, "device-type");
if (!device_type) {
error_setg(errp, "no device-type parameter");
goto fail;
}
if (!strcmp(device_type, "disk")) {
type = TYPE_XEN_DISK_DEVICE;
} else if (!strcmp(device_type, "cdrom")) {
type = TYPE_XEN_CDROM_DEVICE;
} else {
error_setg(errp, "invalid device-type parameter '%s'", device_type);
goto fail;
}
drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
if (!drive) {
error_propagate_prepend(errp, local_err, "failed to create drive: ");
goto fail;
}
iothread = xen_block_iothread_create(vdev, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
"failed to create iothread: ");
goto fail;
}
xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
blockdev = XEN_BLOCK_DEVICE(xendev);
object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
goto fail;
}
object_property_set_str(OBJECT(xendev),
xen_block_drive_get_node_name(drive), "drive",
&local_err);
if (local_err) {
error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
goto fail;
}
object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
&local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
"failed to set 'iothread': ");
goto fail;
}
blockdev->iothread = iothread;
blockdev->drive = drive;
object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
"realization of device %s failed: ",
type);
goto fail;
}
xen_backend_set_device(backend, xendev);
return;
fail:
if (xendev) {
object_unparent(OBJECT(xendev));
}
if (iothread) {
xen_block_iothread_destroy(iothread, NULL);
}
if (drive) {
xen_block_drive_destroy(drive, NULL);
}
}
static void xen_block_device_destroy(XenBackendInstance *backend,
Error **errp)
{
XenDevice *xendev = xen_backend_get_device(backend);
XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
XenBlockVdev *vdev = &blockdev->props.vdev;
XenBlockDrive *drive = blockdev->drive;
XenBlockIOThread *iothread = blockdev->iothread;
trace_xen_block_device_destroy(vdev->number);
object_unparent(OBJECT(xendev));
if (iothread) {
Error *local_err = NULL;
xen_block_iothread_destroy(iothread, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
"failed to destroy iothread: ");
return;
}
}
if (drive) {
Error *local_err = NULL;
xen_block_drive_destroy(drive, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
"failed to destroy drive: ");
}
}
}
static const XenBackendInfo xen_block_backend_info = {
.type = "qdisk",
.create = xen_block_device_create,
.destroy = xen_block_device_destroy,
};
static void xen_block_register_backend(void)
{
xen_backend_register(&xen_block_backend_info);
}
xen_backend_init(xen_block_register_backend);

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
#include "qapi/error.h"
#include "hw/hw.h"
#include "chardev/char-fe.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include <xen/io/console.h>
@ -39,7 +39,7 @@ struct buffer {
};
struct XenConsole {
struct XenDevice xendev; /* must be first */
struct XenLegacyDevice xendev; /* must be first */
struct buffer buffer;
char console[XEN_BUFSIZE];
int ring_ref;
@ -173,7 +173,7 @@ static void xencons_send(struct XenConsole *con)
/* -------------------------------------------------------------------- */
static int con_init(struct XenDevice *xendev)
static int con_init(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
char *type, *dom, label[32];
@ -222,7 +222,7 @@ out:
return ret;
}
static int con_initialise(struct XenDevice *xendev)
static int con_initialise(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
int limit;
@ -259,7 +259,7 @@ static int con_initialise(struct XenDevice *xendev)
return 0;
}
static void con_disconnect(struct XenDevice *xendev)
static void con_disconnect(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
@ -276,7 +276,7 @@ static void con_disconnect(struct XenDevice *xendev)
}
}
static void con_event(struct XenDevice *xendev)
static void con_event(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);

View File

@ -30,7 +30,7 @@
#include "hw/hw.h"
#include "ui/input.h"
#include "ui/console.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include <xen/event_channel.h>
#include <xen/io/fbif.h>
@ -46,7 +46,7 @@
/* -------------------------------------------------------------------- */
struct common {
struct XenDevice xendev; /* must be first */
struct XenLegacyDevice xendev; /* must be first */
void *page;
};
@ -342,14 +342,14 @@ static QemuInputHandler xenfb_rel_mouse = {
.sync = xenfb_mouse_sync,
};
static int input_init(struct XenDevice *xendev)
static int input_init(struct XenLegacyDevice *xendev)
{
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
xenstore_write_be_int(xendev, "feature-raw-pointer", 1);
return 0;
}
static int input_initialise(struct XenDevice *xendev)
static int input_initialise(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
int rc;
@ -361,7 +361,7 @@ static int input_initialise(struct XenDevice *xendev)
return 0;
}
static void input_connected(struct XenDevice *xendev)
static void input_connected(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
@ -395,7 +395,7 @@ static void input_connected(struct XenDevice *xendev)
}
}
static void input_disconnect(struct XenDevice *xendev)
static void input_disconnect(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
@ -410,7 +410,7 @@ static void input_disconnect(struct XenDevice *xendev)
common_unbind(&in->c);
}
static void input_event(struct XenDevice *xendev)
static void input_event(struct XenLegacyDevice *xendev)
{
struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
struct xenkbd_page *page = xenfb->c.page;
@ -867,7 +867,7 @@ static void xenfb_handle_events(struct XenFB *xenfb)
page->out_cons = cons;
}
static int fb_init(struct XenDevice *xendev)
static int fb_init(struct XenLegacyDevice *xendev)
{
#ifdef XENFB_TYPE_RESIZE
xenstore_write_be_int(xendev, "feature-resize", 1);
@ -875,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
return 0;
}
static int fb_initialise(struct XenDevice *xendev)
static int fb_initialise(struct XenLegacyDevice *xendev)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
struct xenfb_page *fb_page;
@ -912,7 +912,7 @@ static int fb_initialise(struct XenDevice *xendev)
return 0;
}
static void fb_disconnect(struct XenDevice *xendev)
static void fb_disconnect(struct XenLegacyDevice *xendev)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
@ -935,7 +935,8 @@ static void fb_disconnect(struct XenDevice *xendev)
fb->bug_trigger = 0;
}
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
static void fb_frontend_changed(struct XenLegacyDevice *xendev,
const char *node)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
@ -953,7 +954,7 @@ static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
}
}
static void fb_event(struct XenDevice *xendev)
static void fb_event(struct XenLegacyDevice *xendev)
{
struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);

View File

@ -16,7 +16,8 @@
#include "hw/i386/pc.h"
#include "hw/i386/apic-msidef.h"
#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-misc.h"
#include "qemu/error-report.h"
@ -1484,6 +1485,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
QLIST_INIT(&state->dev_list);
device_listener_register(&state->device_listener);
xen_bus_init();
/* Initialize backend core & drivers */
if (xen_be_init() != 0) {
error_report("xen backend core setup failed");

View File

@ -14,7 +14,7 @@
#include <sys/resource.h>
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "qemu/bitmap.h"
#include <xen/hvm/params.h>

View File

@ -30,7 +30,7 @@
#include "hw/pci/pci.h"
#include "hw/irq.h"
#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "trace.h"
#include "exec/address-spaces.h"
#include "sysemu/block-backend.h"

View File

@ -28,14 +28,14 @@
#include "net/net.h"
#include "net/checksum.h"
#include "net/util.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include <xen/io/netif.h>
/* ------------------------------------------------------------- */
struct XenNetDev {
struct XenDevice xendev; /* must be first */
struct XenLegacyDevice xendev; /* must be first */
char *mac;
int tx_work;
int tx_ring_ref;
@ -276,7 +276,7 @@ static NetClientInfo net_xen_info = {
.receive = net_rx_packet,
};
static int net_init(struct XenDevice *xendev)
static int net_init(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
@ -308,7 +308,7 @@ static int net_init(struct XenDevice *xendev)
return 0;
}
static int net_connect(struct XenDevice *xendev)
static int net_connect(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
int rx_copy;
@ -363,7 +363,7 @@ static int net_connect(struct XenDevice *xendev)
return 0;
}
static void net_disconnect(struct XenDevice *xendev)
static void net_disconnect(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
@ -379,14 +379,14 @@ static void net_disconnect(struct XenDevice *xendev)
}
}
static void net_event(struct XenDevice *xendev)
static void net_event(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
net_tx_packets(netdev);
qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
}
static int net_free(struct XenDevice *xendev)
static int net_free(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);

View File

@ -27,7 +27,7 @@
#include "qemu/option.h"
#include "hw/sysbus.h"
#include "hw/usb.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "monitor/qdev.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
@ -99,7 +99,7 @@ struct usbback_hotplug {
};
struct usbback_info {
struct XenDevice xendev; /* must be first */
struct XenLegacyDevice xendev; /* must be first */
USBBus bus;
void *urb_sring;
void *conn_sring;
@ -142,7 +142,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
unsigned int nr_segs, i, prot;
uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST];
struct usbback_info *usbif = usbback_req->usbif;
struct XenDevice *xendev = &usbif->xendev;
struct XenLegacyDevice *xendev = &usbif->xendev;
struct usbif_request_segment *seg;
void *addr;
@ -220,7 +220,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
static int usbback_init_packet(struct usbback_req *usbback_req)
{
struct XenDevice *xendev = &usbback_req->usbif->xendev;
struct XenLegacyDevice *xendev = &usbback_req->usbif->xendev;
USBPacket *packet = &usbback_req->packet;
USBDevice *dev = usbback_req->stub->dev;
USBEndpoint *ep;
@ -279,7 +279,7 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
{
struct usbback_info *usbif;
struct usbif_urb_response *res;
struct XenDevice *xendev;
struct XenLegacyDevice *xendev;
unsigned int notify;
usbif = usbback_req->usbif;
@ -824,7 +824,7 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port)
g_free(busid);
}
static void usbback_disconnect(struct XenDevice *xendev)
static void usbback_disconnect(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
unsigned int i;
@ -853,7 +853,7 @@ static void usbback_disconnect(struct XenDevice *xendev)
TR_BUS(xendev, "finished\n");
}
static int usbback_connect(struct XenDevice *xendev)
static int usbback_connect(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
struct usbif_urb_sring *urb_sring;
@ -913,7 +913,8 @@ static int usbback_connect(struct XenDevice *xendev)
return 0;
}
static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
static void usbback_backend_changed(struct XenLegacyDevice *xendev,
const char *node)
{
struct usbback_info *usbif;
unsigned int i;
@ -926,7 +927,7 @@ static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
}
}
static int usbback_init(struct XenDevice *xendev)
static int usbback_init(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
@ -1005,7 +1006,7 @@ static USBPortOps xen_usb_port_ops = {
static USBBusOps xen_usb_bus_ops = {
};
static void usbback_alloc(struct XenDevice *xendev)
static void usbback_alloc(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
USBPort *p;
@ -1027,7 +1028,7 @@ static void usbback_alloc(struct XenDevice *xendev)
usbif->bh = qemu_bh_new(usbback_bh, usbif);
}
static int usbback_free(struct XenDevice *xendev)
static int usbback_free(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
struct usbback_req *usbback_req;
@ -1066,7 +1067,7 @@ static int usbback_free(struct XenDevice *xendev)
return 0;
}
static void usbback_event(struct XenDevice *xendev)
static void usbback_event(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;

View File

@ -1,5 +1,5 @@
# xen backend driver support
common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o xen_pvdev.o xen-common.o
common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o xen-backend.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o

View File

@ -12,3 +12,29 @@ xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id:
xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
xen_domid_restrict(int err) "err: %u"
# include/hw/xen/xen-bus.c
xen_bus_realize(void) ""
xen_bus_unrealize(void) ""
xen_bus_enumerate(void) ""
xen_bus_type_enumerate(const char *type) "type: %s"
xen_bus_backend_create(const char *type, const char *path) "type: %s path: %s"
xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
xen_bus_watch(const char *token) "token: %s"
xen_device_realize(const char *type, char *name) "type: %s name: %s"
xen_device_unrealize(const char *type, char *name) "type: %s name: %s"
xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u"
xen_device_backend_changed(const char *type, char *name) "type: %s name: %s"
xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s"
xen_device_unplug(const char *type, char *name) "type: %s name: %s"
# include/hw/xen/xen-bus-helper.c
xs_node_create(const char *node) "%s"
xs_node_destroy(const char *node) "%s"
xs_node_vprintf(char *path, char *value) "%s %s"
xs_node_vscanf(char *path, char *value) "%s %s"
xs_node_watch(char *path) "%s"
xs_node_unwatch(char *path) "%s"

165
hw/xen/xen-backend.c Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/xen/xen-backend.h"
#include "hw/xen/xen-bus.h"
typedef struct XenBackendImpl {
const char *type;
XenBackendDeviceCreate create;
XenBackendDeviceDestroy destroy;
} XenBackendImpl;
struct XenBackendInstance {
QLIST_ENTRY(XenBackendInstance) entry;
const XenBackendImpl *impl;
XenBus *xenbus;
char *name;
XenDevice *xendev;
};
static GHashTable *xen_backend_table_get(void)
{
static GHashTable *table;
if (table == NULL) {
table = g_hash_table_new(g_str_hash, g_str_equal);
}
return table;
}
static void xen_backend_table_add(XenBackendImpl *impl)
{
g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl);
}
static const XenBackendImpl *xen_backend_table_lookup(const char *type)
{
return g_hash_table_lookup(xen_backend_table_get(), type);
}
void xen_backend_register(const XenBackendInfo *info)
{
XenBackendImpl *impl = g_new0(XenBackendImpl, 1);
g_assert(info->type);
if (xen_backend_table_lookup(info->type)) {
error_report("attempt to register duplicate Xen backend type '%s'",
info->type);
abort();
}
if (!info->create) {
error_report("backend type '%s' has no creator", info->type);
abort();
}
impl->type = info->type;
impl->create = info->create;
impl->destroy = info->destroy;
xen_backend_table_add(impl);
}
static QLIST_HEAD(, XenBackendInstance) backend_list;
static void xen_backend_list_add(XenBackendInstance *backend)
{
QLIST_INSERT_HEAD(&backend_list, backend, entry);
}
static XenBackendInstance *xen_backend_list_find(XenDevice *xendev)
{
XenBackendInstance *backend;
QLIST_FOREACH(backend, &backend_list, entry) {
if (backend->xendev == xendev) {
return backend;
}
}
return NULL;
}
static void xen_backend_list_remove(XenBackendInstance *backend)
{
QLIST_REMOVE(backend, entry);
}
void xen_backend_device_create(XenBus *xenbus, const char *type,
const char *name, QDict *opts, Error **errp)
{
const XenBackendImpl *impl = xen_backend_table_lookup(type);
XenBackendInstance *backend;
Error *local_error = NULL;
if (!impl) {
return;
}
backend = g_new0(XenBackendInstance, 1);
backend->xenbus = xenbus;
backend->name = g_strdup(name);
impl->create(backend, opts, &local_error);
if (local_error) {
error_propagate(errp, local_error);
g_free(backend->name);
g_free(backend);
return;
}
backend->impl = impl;
xen_backend_list_add(backend);
}
XenBus *xen_backend_get_bus(XenBackendInstance *backend)
{
return backend->xenbus;
}
const char *xen_backend_get_name(XenBackendInstance *backend)
{
return backend->name;
}
void xen_backend_set_device(XenBackendInstance *backend,
XenDevice *xendev)
{
g_assert(!backend->xendev);
backend->xendev = xendev;
}
XenDevice *xen_backend_get_device(XenBackendInstance *backend)
{
return backend->xendev;
}
bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp)
{
XenBackendInstance *backend = xen_backend_list_find(xendev);
const XenBackendImpl *impl;
if (!backend) {
return false;
}
impl = backend->impl;
impl->destroy(backend, errp);
xen_backend_list_remove(backend);
g_free(backend->name);
g_free(backend);
return true;
}

184
hw/xen/xen-bus-helper.c Normal file
View File

@ -0,0 +1,184 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/xen/xen.h"
#include "hw/xen/xen-bus.h"
#include "hw/xen/xen-bus-helper.h"
#include "qapi/error.h"
#include <glib/gprintf.h>
struct xs_state {
enum xenbus_state statenum;
const char *statestr;
};
#define XS_STATE(state) { state, #state }
static struct xs_state xs_state[] = {
XS_STATE(XenbusStateUnknown),
XS_STATE(XenbusStateInitialising),
XS_STATE(XenbusStateInitWait),
XS_STATE(XenbusStateInitialised),
XS_STATE(XenbusStateConnected),
XS_STATE(XenbusStateClosing),
XS_STATE(XenbusStateClosed),
XS_STATE(XenbusStateReconfiguring),
XS_STATE(XenbusStateReconfigured),
};
#undef XS_STATE
const char *xs_strstate(enum xenbus_state state)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(xs_state); i++) {
if (xs_state[i].statenum == state) {
return xs_state[i].statestr;
}
}
return "INVALID";
}
void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, struct xs_permissions perms[],
unsigned int nr_perms, Error **errp)
{
trace_xs_node_create(node);
if (!xs_write(xsh, tid, node, "", 0)) {
error_setg_errno(errp, errno, "failed to create node '%s'", node);
return;
}
if (!xs_set_permissions(xsh, tid, node, perms, nr_perms)) {
error_setg_errno(errp, errno, "failed to set node '%s' permissions",
node);
}
}
void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, Error **errp)
{
trace_xs_node_destroy(node);
if (!xs_rm(xsh, tid, node)) {
error_setg_errno(errp, errno, "failed to destroy node '%s'", node);
}
}
void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
char *path, *value;
int len;
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
g_strdup(key);
len = g_vasprintf(&value, fmt, ap);
trace_xs_node_vprintf(path, value);
if (!xs_write(xsh, tid, path, value, len)) {
error_setg_errno(errp, errno, "failed to write '%s' to '%s'",
value, path);
}
g_free(value);
g_free(path);
}
void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xs_node_vprintf(xsh, tid, node, key, errp, fmt, ap);
va_end(ap);
}
int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
char *path, *value;
int rc;
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
g_strdup(key);
value = xs_read(xsh, tid, path, NULL);
trace_xs_node_vscanf(path, value);
if (value) {
rc = vsscanf(value, fmt, ap);
} else {
error_setg_errno(errp, errno, "failed to read from '%s'",
path);
rc = EOF;
}
free(value);
g_free(path);
return rc;
}
int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = xs_node_vscanf(xsh, tid, node, key, errp, fmt, ap);
va_end(ap);
return rc;
}
void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
char *token, Error **errp)
{
char *path;
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
g_strdup(key);
trace_xs_node_watch(path);
if (!xs_watch(xsh, path, token)) {
error_setg_errno(errp, errno, "failed to watch node '%s'", path);
}
g_free(path);
}
void xs_node_unwatch(struct xs_handle *xsh, const char *node,
const char *key, const char *token, Error **errp)
{
char *path;
path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
g_strdup(key);
trace_xs_node_unwatch(path);
if (!xs_unwatch(xsh, path, token)) {
error_setg_errno(errp, errno, "failed to unwatch node '%s'", path);
}
g_free(path);
}

1199
hw/xen/xen-bus.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "chardev/char.h"
#include "sysemu/accel.h"
#include "migration/misc.h"

View File

@ -30,7 +30,7 @@
#include "hw/boards.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pvdev.h"
#include "monitor/qdev.h"
@ -42,49 +42,54 @@ BusState *xen_sysbus;
/* ------------------------------------------------------------- */
/* public */
struct xs_handle *xenstore = NULL;
struct xs_handle *xenstore;
const char *xen_protocol;
/* private */
static bool xen_feature_grant_copy;
static int debug;
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
const char *val)
{
return xenstore_write_str(xendev->be, node, val);
}
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
int ival)
{
return xenstore_write_int(xendev->be, node, ival);
}
int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
int64_t ival)
{
return xenstore_write_int64(xendev->be, node, ival);
}
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node)
{
return xenstore_read_str(xendev->be, node);
}
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
int *ival)
{
return xenstore_read_int(xendev->be, node, ival);
}
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node)
{
return xenstore_read_str(xendev->fe, node);
}
int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
int *ival)
{
return xenstore_read_int(xendev->fe, node, ival);
}
int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
uint64_t *uval)
{
return xenstore_read_uint64(xendev->fe, node, uval);
@ -92,7 +97,7 @@ int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
/* ------------------------------------------------------------- */
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state)
{
int rc;
@ -106,7 +111,7 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
return 0;
}
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
@ -117,7 +122,7 @@ void xen_be_set_max_grant_refs(struct XenDevice *xendev,
}
}
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot)
{
void *ptr;
@ -135,7 +140,7 @@ void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
return ptr;
}
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
@ -146,7 +151,7 @@ void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
}
}
static int compat_copy_grant_refs(struct XenDevice *xendev,
static int compat_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain,
XenGrantCopySegment segs[],
unsigned int nr_segs)
@ -195,7 +200,7 @@ static int compat_copy_grant_refs(struct XenDevice *xendev,
return 0;
}
int xen_be_copy_grant_refs(struct XenDevice *xendev,
int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain,
XenGrantCopySegment segs[],
unsigned int nr_segs)
@ -259,10 +264,11 @@ int xen_be_copy_grant_refs(struct XenDevice *xendev,
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
struct XenDevOps *ops)
static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
int dev,
struct XenDevOps *ops)
{
struct XenDevice *xendev;
struct XenLegacyDevice *xendev;
xendev = xen_pv_find_xendev(type, dom, dev);
if (xendev) {
@ -314,7 +320,8 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
* Node specifies the changed field. node = NULL means
* update all fields (used for initialization).
*/
static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
static void xen_be_backend_changed(struct XenLegacyDevice *xendev,
const char *node)
{
if (node == NULL || strcmp(node, "online") == 0) {
if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
@ -330,7 +337,8 @@ static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
}
}
static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
static void xen_be_frontend_changed(struct XenLegacyDevice *xendev,
const char *node)
{
int fe_state;
@ -373,7 +381,7 @@ static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
* only affects the xendev->be_state variable as xenbus should
* already be put into that state by xend.
*/
static int xen_be_try_setup(struct XenDevice *xendev)
static int xen_be_try_setup(struct XenLegacyDevice *xendev)
{
char token[XEN_BUFSIZE];
int be_state;
@ -417,7 +425,7 @@ static int xen_be_try_setup(struct XenDevice *xendev)
*
* Goes to InitWait on success.
*/
static int xen_be_try_init(struct XenDevice *xendev)
static int xen_be_try_init(struct XenLegacyDevice *xendev)
{
int rc = 0;
@ -446,7 +454,7 @@ static int xen_be_try_init(struct XenDevice *xendev)
*
* Goes to Connected on success.
*/
static int xen_be_try_initialise(struct XenDevice *xendev)
static int xen_be_try_initialise(struct XenLegacyDevice *xendev)
{
int rc = 0;
@ -487,7 +495,7 @@ static int xen_be_try_initialise(struct XenDevice *xendev)
* frontend being Connected. Note that this may be called more
* than once since the backend state is not modified.
*/
static void xen_be_try_connected(struct XenDevice *xendev)
static void xen_be_try_connected(struct XenLegacyDevice *xendev)
{
if (!xendev->ops->connected) {
return;
@ -510,7 +518,8 @@ static void xen_be_try_connected(struct XenDevice *xendev)
*
* Goes to Closed when done.
*/
static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
static void xen_be_disconnect(struct XenLegacyDevice *xendev,
enum xenbus_state state)
{
if (xendev->be_state != XenbusStateClosing &&
xendev->be_state != XenbusStateClosed &&
@ -529,7 +538,7 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
/*
* Try to reset xendev, for reconnection by another frontend instance.
*/
static int xen_be_try_reset(struct XenDevice *xendev)
static int xen_be_try_reset(struct XenLegacyDevice *xendev)
{
if (xendev->fe_state != XenbusStateInitialising) {
return -1;
@ -543,7 +552,7 @@ static int xen_be_try_reset(struct XenDevice *xendev)
/*
* state change dispatcher function
*/
void xen_be_check_state(struct XenDevice *xendev)
void xen_be_check_state(struct XenLegacyDevice *xendev)
{
int rc = 0;
@ -587,7 +596,7 @@ void xen_be_check_state(struct XenDevice *xendev)
static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
{
struct XenDevice *xendev;
struct XenLegacyDevice *xendev;
char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
char **dev = NULL;
unsigned int cdev, j;
@ -620,7 +629,7 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops)
{
struct XenDevice *xendev;
struct XenLegacyDevice *xendev;
char path[XEN_BUFSIZE], *bepath;
unsigned int len, dev;
@ -628,9 +637,9 @@ void xenstore_update_be(char *watch, char *type, int dom,
if (strncmp(path, watch, len) != 0) {
return;
}
if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
if (sscanf(watch + len, "/%u/%255s", &dev, path) != 2) {
strcpy(path, "");
if (sscanf(watch+len, "/%u", &dev) != 1) {
if (sscanf(watch + len, "/%u", &dev) != 1) {
dev = -1;
}
}
@ -651,7 +660,7 @@ void xenstore_update_be(char *watch, char *type, int dom,
}
}
void xenstore_update_fe(char *watch, struct XenDevice *xendev)
void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev)
{
char *node;
unsigned int len;
@ -744,7 +753,6 @@ void xen_be_register_common(void)
xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
xen_be_register("qdisk", &xen_blkdev_ops);
#ifdef CONFIG_VIRTFS
xen_be_register("9pfs", &xen_9pfs_ops);
#endif
@ -753,7 +761,7 @@ void xen_be_register_common(void)
#endif
}
int xen_be_bind_evtchn(struct XenDevice *xendev)
int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
{
if (xendev->local_port != -1) {
return 0;
@ -789,7 +797,7 @@ static const TypeInfo xendev_type_info = {
.name = TYPE_XENBACKEND,
.parent = TYPE_XENSYSDEV,
.class_init = xendev_class_init,
.instance_size = sizeof(struct XenDevice),
.instance_size = sizeof(struct XenLegacyDevice),
};
static void xen_sysbus_class_init(ObjectClass *klass, void *data)

View File

@ -1,5 +1,5 @@
#include "qemu/osdep.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "qemu/option.h"
#include "sysemu/blockdev.h"

View File

@ -59,7 +59,7 @@
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
#include "hw/i386/pc.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "qemu/range.h"
#include "exec/address-spaces.h"
@ -847,6 +847,12 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
}
machine_irq = s->real_device.irq;
if (machine_irq == 0) {
XEN_PT_LOG(d, "machine irq is 0\n");
cmd |= PCI_COMMAND_INTX_DISABLE;
goto out;
}
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
if (rc < 0) {
error_setg_errno(errp, errno, "Mapping machine irq %u to"

View File

@ -15,7 +15,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/timer.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
@ -300,7 +300,9 @@ static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
XenPTRegInfo *reg, uint32_t real_offset,
uint32_t *data)
{
*data = xen_pt_pci_read_intx(s);
if (s->real_device.irq) {
*data = xen_pt_pci_read_intx(s);
}
return 0;
}

View File

@ -5,7 +5,7 @@
#include "qapi/error.h"
#include "xen_pt.h"
#include "xen-host-pci-device.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
static unsigned long igd_guest_opregion;
static unsigned long igd_host_opregion;
@ -185,8 +185,19 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
return;
}
if (bios_size < sizeof(struct rom_header)) {
error_setg(errp, "VGA: VBIOS image corrupt (too small)");
return;
}
/* Currently we fixed this address as a primary. */
rom = (struct rom_header *)bios;
if (rom->pcioffset + sizeof(struct pci_data) > bios_size) {
error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)");
return;
}
pd = (void *)(bios + (unsigned char)rom->pcioffset);
/* We may need to fixup Device Identification. */
@ -194,6 +205,11 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
pd->device = s->real_device.device_id;
len = rom->size * 512;
if (len > bios_size) {
error_setg(errp, "VGA: VBIOS image corrupt (bad size field)");
return;
}
/* Then adjust the bios checksum */
for (c = (char *)bios; c < ((char *)bios + len); c++) {
checksum += *c;

View File

@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "hw/i386/apic-msidef.h"

View File

@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-core.h"
#include "hw/xen/xen_backend.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pvdev.h"
/* private */
@ -34,7 +34,7 @@ struct xs_dirs {
static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
QTAILQ_HEAD_INITIALIZER(xs_cleanup);
static QTAILQ_HEAD(, XenDevice) xendevs =
static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
QTAILQ_HEAD_INITIALIZER(xendevs);
/* ------------------------------------------------------------- */
@ -195,7 +195,7 @@ const char *xenbus_strstate(enum xenbus_state state)
* 2 == noisy debug messages (logfile only).
* 3 == will flood your log (logfile only).
*/
void xen_pv_printf(struct XenDevice *xendev, int msg_level,
void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
const char *fmt, ...)
{
va_list args;
@ -230,7 +230,7 @@ void xen_pv_printf(struct XenDevice *xendev, int msg_level,
void xen_pv_evtchn_event(void *opaque)
{
struct XenDevice *xendev = opaque;
struct XenLegacyDevice *xendev = opaque;
evtchn_port_t port;
port = xenevtchn_pending(xendev->evtchndev);
@ -247,7 +247,7 @@ void xen_pv_evtchn_event(void *opaque)
}
}
void xen_pv_unbind_evtchn(struct XenDevice *xendev)
void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
{
if (xendev->local_port == -1) {
return;
@ -258,16 +258,16 @@ void xen_pv_unbind_evtchn(struct XenDevice *xendev)
xendev->local_port = -1;
}
int xen_pv_send_notify(struct XenDevice *xendev)
int xen_pv_send_notify(struct XenLegacyDevice *xendev)
{
return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
}
/* ------------------------------------------------------------- */
struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
{
struct XenDevice *xendev;
struct XenLegacyDevice *xendev;
QTAILQ_FOREACH(xendev, &xendevs, next) {
if (xendev->dom != dom) {
@ -287,7 +287,7 @@ struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
/*
* release xen backend device.
*/
void xen_pv_del_xendev(struct XenDevice *xendev)
void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
{
if (xendev->ops->free) {
xendev->ops->free(xendev);
@ -312,7 +312,7 @@ void xen_pv_del_xendev(struct XenDevice *xendev)
qdev_unplug(&xendev->qdev, NULL);
}
void xen_pv_insert_xendev(struct XenDevice *xendev)
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
{
QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
}

View File

@ -1,4 +1,2 @@
# Xen PV machine support
obj-$(CONFIG_XEN) += xen_machine_pv.o
# Xen PV machine builder support
obj-$(CONFIG_XEN_PV_DOMAIN_BUILD) += xen_domainbuild.o

View File

@ -1,299 +0,0 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/xen/xen_backend.h"
#include "xen_domainbuild.h"
#include "qemu/timer.h"
#include "qemu/log.h"
#include <xenguest.h>
static int xenstore_domain_mkdir(char *path)
{
struct xs_permissions perms_ro[] = {{
.id = 0, /* set owner: dom0 */
},{
.id = xen_domid,
.perms = XS_PERM_READ,
}};
struct xs_permissions perms_rw[] = {{
.id = 0, /* set owner: dom0 */
},{
.id = xen_domid,
.perms = XS_PERM_READ | XS_PERM_WRITE,
}};
const char *writable[] = { "device", "control", "error", NULL };
char subpath[256];
int i;
if (!xs_mkdir(xenstore, 0, path)) {
fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, path);
return -1;
}
if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
return -1;
}
for (i = 0; writable[i]; i++) {
snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
if (!xs_mkdir(xenstore, 0, subpath)) {
fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, subpath);
return -1;
}
if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
return -1;
}
}
return 0;
}
int xenstore_domain_init1(const char *kernel, const char *ramdisk,
const char *cmdline)
{
char *dom, uuid_string[42], vm[256], path[256];
int i;
qemu_uuid_unparse(&qemu_uuid, uuid_string);
dom = xs_get_domain_path(xenstore, xen_domid);
snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
xenstore_domain_mkdir(dom);
xenstore_write_str(vm, "image/ostype", "linux");
if (kernel)
xenstore_write_str(vm, "image/kernel", kernel);
if (ramdisk)
xenstore_write_str(vm, "image/ramdisk", ramdisk);
if (cmdline)
xenstore_write_str(vm, "image/cmdline", cmdline);
/* name + id */
xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
xenstore_write_str(vm, "uuid", uuid_string);
xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
xenstore_write_int(dom, "domid", xen_domid);
xenstore_write_str(dom, "vm", vm);
/* memory */
xenstore_write_int(dom, "memory/target", ram_size / KiB);
xenstore_write_int(vm, "memory", ram_size / MiB);
xenstore_write_int(vm, "maxmem", ram_size / MiB);
/* cpus */
for (i = 0; i < smp_cpus; i++) {
snprintf(path, sizeof(path), "cpu/%d/availability",i);
xenstore_write_str(dom, path, "online");
}
xenstore_write_int(vm, "vcpu_avail", smp_cpus);
xenstore_write_int(vm, "vcpus", smp_cpus);
/* vnc password */
xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
free(dom);
return 0;
}
int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
int console_port, int console_mfn)
{
char *dom;
dom = xs_get_domain_path(xenstore, xen_domid);
/* signal new domain */
xs_introduce_domain(xenstore,
xen_domid,
xenstore_mfn,
xenstore_port);
/* xenstore */
xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
xenstore_write_int(dom, "store/port", xenstore_port);
/* console */
xenstore_write_str(dom, "console/type", "ioemu");
xenstore_write_int(dom, "console/limit", 128 * KiB);
xenstore_write_int(dom, "console/ring-ref", console_mfn);
xenstore_write_int(dom, "console/port", console_port);
xen_config_dev_console(0);
free(dom);
return 0;
}
/* ------------------------------------------------------------- */
static QEMUTimer *xen_poll;
/* check domain state once per second */
static void xen_domain_poll(void *opaque)
{
struct xc_dominfo info;
int rc;
rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
if ((rc != 1) || (info.domid != xen_domid)) {
qemu_log("xen: domain %d is gone\n", xen_domid);
goto quit;
}
if (info.dying) {
qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
info.crashed ? "crashed" : "",
info.shutdown ? "shutdown" : "");
goto quit;
}
timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
return;
quit:
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
static int xen_domain_watcher(void)
{
int qemu_running = 1;
int fd[2], i, n, rc;
char byte;
if (pipe(fd) != 0) {
qemu_log("%s: Huh? pipe error: %s\n", __func__, strerror(errno));
return -1;
}
if (fork() != 0)
return 0; /* not child */
/* close all file handles, except stdio/out/err,
* our watch pipe and the xen interface handle */
n = getdtablesize();
for (i = 3; i < n; i++) {
if (i == fd[0])
continue;
close(i);
}
/*
* Reopen xc interface, since the original is unsafe after fork
* and was closed above.
*/
xen_xc = xc_interface_open(0, 0, 0);
/* ignore term signals */
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
/* wait for qemu exiting */
while (qemu_running) {
rc = read(fd[0], &byte, 1);
switch (rc) {
case -1:
if (errno == EINTR)
continue;
qemu_log("%s: Huh? read error: %s\n", __func__, strerror(errno));
qemu_running = 0;
break;
case 0:
/* EOF -> qemu exited */
qemu_running = 0;
break;
default:
qemu_log("%s: Huh? data on the watch pipe?\n", __func__);
break;
}
}
/* cleanup */
qemu_log("%s: destroy domain %d\n", __func__, xen_domid);
xc_domain_destroy(xen_xc, xen_domid);
_exit(0);
}
/* normal cleanup */
static void xen_domain_cleanup(void)
{
char *dom;
dom = xs_get_domain_path(xenstore, xen_domid);
if (dom) {
xs_rm(xenstore, 0, dom);
free(dom);
}
xs_release_domain(xenstore, xen_domid);
}
int xen_domain_build_pv(const char *kernel, const char *ramdisk,
const char *cmdline)
{
uint32_t ssidref = 0;
uint32_t flags = 0;
xen_domain_handle_t uuid;
unsigned int xenstore_port = 0, console_port = 0;
unsigned long xenstore_mfn = 0, console_mfn = 0;
int rc;
memcpy(uuid, &qemu_uuid, sizeof(uuid));
rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_create() failed\n");
goto err;
}
qemu_log("xen: created domain %d\n", xen_domid);
atexit(xen_domain_cleanup);
if (xen_domain_watcher() == -1) {
goto err;
}
xenstore_domain_init1(kernel, ramdisk, cmdline);
rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
goto err;
}
#if 0
rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
goto err;
}
#endif
rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size / KiB);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
goto err;
}
xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
rc = xc_linux_build(xen_xc, xen_domid, ram_size / MiB,
kernel, ramdisk, cmdline,
0, flags,
xenstore_port, &xenstore_mfn,
console_port, &console_mfn);
if (rc < 0) {
fprintf(stderr, "xen: xc_linux_build() failed\n");
goto err;
}
xenstore_domain_init2(xenstore_port, xenstore_mfn,
console_port, console_mfn);
qemu_log("xen: unpausing domain %d\n", xen_domid);
rc = xc_domain_unpause(xen_xc, xen_domid);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_unpause() failed\n");
goto err;
}
xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL);
timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
return 0;
err:
return -1;
}

View File

@ -1,13 +0,0 @@
#ifndef QEMU_HW_XEN_DOMAINBUILD_H
#define QEMU_HW_XEN_DOMAINBUILD_H
#include "hw/xen/xen_common.h"
int xenstore_domain_init1(const char *kernel, const char *ramdisk,
const char *cmdline);
int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
int console_port, int console_mfn);
int xen_domain_build_pv(const char *kernel, const char *ramdisk,
const char *cmdline);
#endif /* QEMU_HW_XEN_DOMAINBUILD_H */

View File

@ -26,8 +26,8 @@
#include "qemu/error-report.h"
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/xen/xen_backend.h"
#include "xen_domainbuild.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
#include "sysemu/block-backend.h"
static void xen_init_pv(MachineState *machine)
@ -43,21 +43,8 @@ static void xen_init_pv(MachineState *machine)
switch (xen_mode) {
case XEN_ATTACH:
/* nothing to do, xend handles everything */
/* nothing to do, libxl handles everything */
break;
#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
case XEN_CREATE: {
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
if (xen_domain_build_pv(kernel_filename, initrd_filename,
kernel_cmdline) < 0) {
error_report("xen pv domain creation failed");
exit(1);
}
break;
}
#endif
case XEN_EMULATE:
error_report("xen emulation not implemented (yet)");
exit(1);
@ -93,6 +80,8 @@ static void xen_init_pv(MachineState *machine)
xen_config_dev_nic(nd_table + i);
}
xen_bus_init();
/* config cleanup hook */
atexit(xen_config_cleanup);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_XEN_BACKEND_H
#define HW_XEN_BACKEND_H
#include "hw/xen/xen-bus.h"
typedef struct XenBackendInstance XenBackendInstance;
typedef void (*XenBackendDeviceCreate)(XenBackendInstance *backend,
QDict *opts, Error **errp);
typedef void (*XenBackendDeviceDestroy)(XenBackendInstance *backend,
Error **errp);
typedef struct XenBackendInfo {
const char *type;
XenBackendDeviceCreate create;
XenBackendDeviceDestroy destroy;
} XenBackendInfo;
XenBus *xen_backend_get_bus(XenBackendInstance *backend);
const char *xen_backend_get_name(XenBackendInstance *backend);
void xen_backend_set_device(XenBackendInstance *backend,
XenDevice *xendevice);
XenDevice *xen_backend_get_device(XenBackendInstance *backend);
void xen_backend_register(const XenBackendInfo *info);
void xen_backend_device_create(XenBus *xenbus, const char *type,
const char *name, QDict *opts, Error **errp);
bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp);
#endif /* HW_XEN_BACKEND_H */

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_XEN_BLOCK_H
#define HW_XEN_BLOCK_H
#include "hw/xen/xen-bus.h"
#include "hw/block/block.h"
#include "hw/block/dataplane/xen-block.h"
#include "sysemu/iothread.h"
typedef enum XenBlockVdevType {
XEN_BLOCK_VDEV_TYPE_INVALID,
XEN_BLOCK_VDEV_TYPE_DP,
XEN_BLOCK_VDEV_TYPE_XVD,
XEN_BLOCK_VDEV_TYPE_HD,
XEN_BLOCK_VDEV_TYPE_SD,
XEN_BLOCK_VDEV_TYPE__MAX
} XenBlockVdevType;
typedef struct XenBlockVdev {
XenBlockVdevType type;
unsigned long disk;
unsigned long partition;
unsigned long number;
} XenBlockVdev;
typedef struct XenBlockProperties {
XenBlockVdev vdev;
BlockConf conf;
unsigned int max_ring_page_order;
IOThread *iothread;
} XenBlockProperties;
typedef struct XenBlockDrive {
char *id;
char *node_name;
} XenBlockDrive;
typedef struct XenBlockIOThread {
char *id;
} XenBlockIOThread;
typedef struct XenBlockDevice {
XenDevice xendev;
XenBlockProperties props;
const char *device_type;
unsigned int info;
XenBlockDataPlane *dataplane;
XenBlockDrive *drive;
XenBlockIOThread *iothread;
} XenBlockDevice;
typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp);
typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev, Error **errp);
typedef struct XenBlockDeviceClass {
/*< private >*/
XenDeviceClass parent_class;
/*< public >*/
XenBlockDeviceRealize realize;
XenBlockDeviceUnrealize unrealize;
} XenBlockDeviceClass;
#define TYPE_XEN_BLOCK_DEVICE "xen-block"
#define XEN_BLOCK_DEVICE(obj) \
OBJECT_CHECK(XenBlockDevice, (obj), TYPE_XEN_BLOCK_DEVICE)
#define XEN_BLOCK_DEVICE_CLASS(class) \
OBJECT_CLASS_CHECK(XenBlockDeviceClass, (class), TYPE_XEN_BLOCK_DEVICE)
#define XEN_BLOCK_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(XenBlockDeviceClass, (obj), TYPE_XEN_BLOCK_DEVICE)
typedef struct XenDiskDevice {
XenBlockDevice blockdev;
} XenDiskDevice;
#define TYPE_XEN_DISK_DEVICE "xen-disk"
#define XEN_DISK_DEVICE(obj) \
OBJECT_CHECK(XenDiskDevice, (obj), TYPE_XEN_DISK_DEVICE)
typedef struct XenCDRomDevice {
XenBlockDevice blockdev;
} XenCDRomDevice;
#define TYPE_XEN_CDROM_DEVICE "xen-cdrom"
#define XEN_CDROM_DEVICE(obj) \
OBJECT_CHECK(XenCDRomDevice, (obj), TYPE_XEN_CDROM_DEVICE)
#endif /* HW_XEN_BLOCK_H */

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_XEN_BUS_HELPER_H
#define HW_XEN_BUS_HELPER_H
#include "hw/xen/xen_common.h"
const char *xs_strstate(enum xenbus_state state);
void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, struct xs_permissions perms[],
unsigned int nr_perms, Error **errp);
void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, Error **errp);
/* Write to node/key unless node is empty, in which case write to key */
void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
GCC_FMT_ATTR(6, 0);
void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...)
GCC_FMT_ATTR(6, 7);
/* Read from node/key unless node is empty, in which case read from key */
int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap);
int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...);
/* Watch node/key unless node is empty, in which case watch key */
void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
char *token, Error **errp);
void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *key,
const char *token, Error **errp);
#endif /* HW_XEN_BUS_HELPER_H */

137
include/hw/xen/xen-bus.h Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2018 Citrix Systems Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_XEN_BUS_H
#define HW_XEN_BUS_H
#include "hw/xen/xen_common.h"
#include "hw/sysbus.h"
#include "qemu/notify.h"
typedef void (*XenWatchHandler)(void *opaque);
typedef struct XenWatch XenWatch;
typedef struct XenDevice {
DeviceState qdev;
domid_t frontend_id;
char *name;
char *backend_path, *frontend_path;
enum xenbus_state backend_state, frontend_state;
Notifier exit;
XenWatch *backend_state_watch, *frontend_state_watch;
bool backend_online;
XenWatch *backend_online_watch;
xengnttab_handle *xgth;
bool feature_grant_copy;
xenevtchn_handle *xeh;
NotifierList event_notifiers;
} XenDevice;
typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp);
typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp);
typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev,
enum xenbus_state frontend_state,
Error **errp);
typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp);
typedef struct XenDeviceClass {
/*< private >*/
DeviceClass parent_class;
/*< public >*/
const char *backend;
const char *device;
XenDeviceGetName get_name;
XenDeviceRealize realize;
XenDeviceFrontendChanged frontend_changed;
XenDeviceUnrealize unrealize;
} XenDeviceClass;
#define TYPE_XEN_DEVICE "xen-device"
#define XEN_DEVICE(obj) \
OBJECT_CHECK(XenDevice, (obj), TYPE_XEN_DEVICE)
#define XEN_DEVICE_CLASS(class) \
OBJECT_CLASS_CHECK(XenDeviceClass, (class), TYPE_XEN_DEVICE)
#define XEN_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(XenDeviceClass, (obj), TYPE_XEN_DEVICE)
typedef struct XenBus {
BusState qbus;
domid_t backend_id;
struct xs_handle *xsh;
NotifierList watch_notifiers;
XenWatch *backend_watch;
} XenBus;
typedef struct XenBusClass {
/*< private >*/
BusClass parent_class;
} XenBusClass;
#define TYPE_XEN_BUS "xen-bus"
#define XEN_BUS(obj) \
OBJECT_CHECK(XenBus, (obj), TYPE_XEN_BUS)
#define XEN_BUS_CLASS(class) \
OBJECT_CLASS_CHECK(XenBusClass, (class), TYPE_XEN_BUS)
#define XEN_BUS_GET_CLASS(obj) \
OBJECT_GET_CLASS(XenBusClass, (obj), TYPE_XEN_BUS)
void xen_bus_init(void);
void xen_device_backend_set_state(XenDevice *xendev,
enum xenbus_state state);
enum xenbus_state xen_device_backend_get_state(XenDevice *xendev);
void xen_device_backend_printf(XenDevice *xendev, const char *key,
const char *fmt, ...)
GCC_FMT_ATTR(3, 4);
void xen_device_frontend_printf(XenDevice *xendev, const char *key,
const char *fmt, ...)
GCC_FMT_ATTR(3, 4);
int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
const char *fmt, ...);
void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
Error **errp);
void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot,
Error **errp);
void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
unsigned int nr_refs, Error **errp);
typedef struct XenDeviceGrantCopySegment {
union {
void *virt;
struct {
uint32_t ref;
off_t offset;
} foreign;
} source, dest;
size_t len;
} XenDeviceGrantCopySegment;
void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
XenDeviceGrantCopySegment segs[],
unsigned int nr_segs, Error **errp);
typedef struct XenEventChannel XenEventChannel;
typedef void (*XenEventHandler)(void *opaque);
XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
unsigned int port,
XenEventHandler handler,
void *opaque, Error **errp);
void xen_device_notify_event_channel(XenDevice *xendev,
XenEventChannel *channel,
Error **errp);
void xen_device_unbind_event_channel(XenDevice *xendev,
XenEventChannel *channel,
Error **errp);
#endif /* HW_XEN_BUS_H */

View File

@ -11,7 +11,7 @@
#define TYPE_XENBACKEND "xen-backend"
#define XENBACKEND_DEVICE(obj) \
OBJECT_CHECK(XenDevice, (obj), TYPE_XENBACKEND)
OBJECT_CHECK(XenLegacyDevice, (obj), TYPE_XENBACKEND)
/* variables */
extern struct xs_handle *xenstore;
@ -20,32 +20,37 @@ extern DeviceState *xen_sysdev;
extern BusState *xen_sysbus;
int xenstore_mkdir(char *path, int p);
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival);
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
void xenstore_update_fe(char *watch, struct XenDevice *xendev);
int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
const char *val);
int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
int ival);
int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
int64_t ival);
char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node);
int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
int *ival);
void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev);
void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops);
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node);
int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
int *ival);
int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
uint64_t *uval);
void xen_be_check_state(struct XenDevice *xendev);
void xen_be_check_state(struct XenLegacyDevice *xendev);
/* xen backend driver bits */
int xen_be_init(void);
void xen_be_register_common(void);
int xen_be_register(const char *type, struct XenDevOps *ops);
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
int xen_be_bind_evtchn(struct XenDevice *xendev);
void xen_be_set_max_grant_refs(struct XenDevice *xendev,
int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state);
int xen_be_bind_evtchn(struct XenLegacyDevice *xendev);
void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
unsigned int nr_refs);
void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot);
void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
unsigned int nr_refs);
typedef struct XenGrantCopySegment {
@ -59,17 +64,17 @@ typedef struct XenGrantCopySegment {
size_t len;
} XenGrantCopySegment;
int xen_be_copy_grant_refs(struct XenDevice *xendev,
int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain, XenGrantCopySegment segs[],
unsigned int nr_segs);
static inline void *xen_be_map_grant_ref(struct XenDevice *xendev,
static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev,
uint32_t ref, int prot)
{
return xen_be_map_grant_refs(xendev, &ref, 1, prot);
}
static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev,
static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev,
void *ptr)
{
return xen_be_unmap_grant_refs(xendev, ptr, 1);

View File

@ -15,8 +15,7 @@
/* xen-machine.c */
enum xen_mode {
XEN_EMULATE = 0, // xen emulation, using xenner (default)
XEN_CREATE, // create xen domain
XEN_ATTACH // attach to xen domain created by xend
XEN_ATTACH // attach to xen domain created by libxl
};
extern uint32_t xen_domid;

View File

@ -32,6 +32,7 @@ extern xc_interface *xen_xc;
typedef xc_interface xenforeignmemory_handle;
typedef xc_evtchn xenevtchn_handle;
typedef xc_gnttab xengnttab_handle;
typedef evtchn_port_or_error_t xenevtchn_port_or_error_t;
#define xenevtchn_open(l, f) xc_evtchn_open(l, f);
#define xenevtchn_close(h) xc_evtchn_close(h)
@ -661,24 +662,6 @@ static inline int xen_set_ioreq_server_state(domid_t dom,
#endif
#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40700
static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
xen_domain_handle_t handle, uint32_t flags,
uint32_t *pdomid)
{
return xc_domain_create(xc, ssidref, handle, flags, pdomid);
}
#else
static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
xen_domain_handle_t handle, uint32_t flags,
uint32_t *pdomid)
{
return xc_domain_create(xc, ssidref, handle, flags, pdomid, NULL);
}
#endif
#endif
/* Xen before 4.8 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800

View File

@ -6,7 +6,7 @@
#define XEN_BUFSIZE 1024
struct XenDevice;
struct XenLegacyDevice;
/* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */
#define DEVOPS_FLAG_NEED_GNTDEV 1
@ -16,19 +16,21 @@ struct XenDevice;
struct XenDevOps {
size_t size;
uint32_t flags;
void (*alloc)(struct XenDevice *xendev);
int (*init)(struct XenDevice *xendev);
int (*initialise)(struct XenDevice *xendev);
void (*connected)(struct XenDevice *xendev);
void (*event)(struct XenDevice *xendev);
void (*disconnect)(struct XenDevice *xendev);
int (*free)(struct XenDevice *xendev);
void (*backend_changed)(struct XenDevice *xendev, const char *node);
void (*frontend_changed)(struct XenDevice *xendev, const char *node);
void (*alloc)(struct XenLegacyDevice *xendev);
int (*init)(struct XenLegacyDevice *xendev);
int (*initialise)(struct XenLegacyDevice *xendev);
void (*connected)(struct XenLegacyDevice *xendev);
void (*event)(struct XenLegacyDevice *xendev);
void (*disconnect)(struct XenLegacyDevice *xendev);
int (*free)(struct XenLegacyDevice *xendev);
void (*backend_changed)(struct XenLegacyDevice *xendev,
const char *node);
void (*frontend_changed)(struct XenLegacyDevice *xendev,
const char *node);
int (*backend_register)(void);
};
struct XenDevice {
struct XenLegacyDevice {
DeviceState qdev;
const char *type;
int dom;
@ -49,7 +51,7 @@ struct XenDevice {
xengnttab_handle *gnttabdev;
struct XenDevOps *ops;
QTAILQ_ENTRY(XenDevice) next;
QTAILQ_ENTRY(XenLegacyDevice) next;
};
/* ------------------------------------------------------------- */
@ -66,14 +68,14 @@ void xenstore_update(void *unused);
const char *xenbus_strstate(enum xenbus_state state);
void xen_pv_evtchn_event(void *opaque);
void xen_pv_insert_xendev(struct XenDevice *xendev);
void xen_pv_del_xendev(struct XenDevice *xendev);
struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev);
void xen_pv_del_xendev(struct XenLegacyDevice *xendev);
struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
void xen_pv_unbind_evtchn(struct XenDevice *xendev);
int xen_pv_send_notify(struct XenDevice *xendev);
void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev);
int xen_pv_send_notify(struct XenLegacyDevice *xendev);
void xen_pv_printf(struct XenDevice *xendev, int msg_level,
void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#endif /* QEMU_HW_XEN_PVDEV_H */

View File

@ -44,6 +44,7 @@ typedef enum {
MODULE_INIT_OPTS,
MODULE_INIT_QOM,
MODULE_INIT_TRACE,
MODULE_INIT_XEN_BACKEND,
MODULE_INIT_MAX
} module_init_type;
@ -51,6 +52,8 @@ typedef enum {
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
#define xen_backend_init(function) module_init(function, \
MODULE_INIT_XEN_BACKEND)
#define block_module_load_one(lib) module_load_one("block-", lib)
#define ui_module_load_one(lib) module_load_one("ui-", lib)

View File

@ -3394,13 +3394,9 @@ ETEXI
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
DEF("xen-create", 0, QEMU_OPTION_xen_create,
"-xen-create create domain using xen hypercalls, bypassing xend\n"
" warning: should not be used when xend is in use\n",
QEMU_ARCH_ALL)
DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
"-xen-attach attach to existing xen domain\n"
" xend will use this when starting QEMU\n",
" libxl will use this when starting QEMU\n",
QEMU_ARCH_ALL)
DEF("xen-domid-restrict", 0, QEMU_OPTION_xen_domid_restrict,
"-xen-domid-restrict restrict set of available xen operations\n"
@ -3411,14 +3407,10 @@ STEXI
@item -xen-domid @var{id}
@findex -xen-domid
Specify xen guest domain @var{id} (XEN only).
@item -xen-create
@findex -xen-create
Create domain using xen hypercalls, bypassing xend.
Warning: should not be used when xend is in use (XEN only).
@item -xen-attach
@findex -xen-attach
Attach to existing xen domain.
xend will use this when starting QEMU (XEN only).
libxl will use this when starting QEMU (XEN only).
@findex -xen-domid-restrict
Restrict set of available xen operations to specified domain id (XEN only).
ETEXI

7
vl.c
View File

@ -3856,13 +3856,6 @@ int main(int argc, char **argv, char **envp)
}
xen_domid = atoi(optarg);
break;
case QEMU_OPTION_xen_create:
if (!(xen_available())) {
error_report("Option not supported for this target");
exit(1);
}
xen_mode = XEN_CREATE;
break;
case QEMU_OPTION_xen_attach:
if (!(xen_available())) {
error_report("Option not supported for this target");