57 changes: 49 additions & 8 deletions hw/char/xen_console.c
Expand Up @@ -173,6 +173,48 @@ static void xencons_send(struct XenConsole *con)

/* -------------------------------------------------------------------- */

static int store_con_info(struct XenConsole *con)
{
Chardev *cs = qemu_chr_fe_get_driver(&con->chr);
char *pts = NULL;
char *dom_path;
GString *path;
int ret = -1;

/* Only continue if we're talking to a pty. */
if (!CHARDEV_IS_PTY(cs)) {
return 0;
}
pts = cs->filename + 4;

dom_path = qemu_xen_xs_get_domain_path(xenstore, xen_domid);
if (!dom_path) {
return 0;
}

path = g_string_new(dom_path);
free(dom_path);

if (con->xendev.dev) {
g_string_append_printf(path, "/device/console/%d", con->xendev.dev);
} else {
g_string_append(path, "/console");
}
g_string_append(path, "/tty");

if (xenstore_write_str(con->console, path->str, pts)) {
fprintf(stderr, "xenstore_write_str for '%s' fail", path->str);
goto out;
}
ret = 0;

out:
g_string_free(path, true);
free(path);

return ret;
}

static int con_init(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
Expand All @@ -181,7 +223,7 @@ static int con_init(struct XenLegacyDevice *xendev)
const char *output;

/* setup */
dom = xs_get_domain_path(xenstore, con->xendev.dom);
dom = qemu_xen_xs_get_domain_path(xenstore, con->xendev.dom);
if (!xendev->dev) {
snprintf(con->console, sizeof(con->console), "%s/console", dom);
} else {
Expand Down Expand Up @@ -215,8 +257,7 @@ static int con_init(struct XenLegacyDevice *xendev)
&error_abort);
}

xenstore_store_pv_console_info(con->xendev.dev,
qemu_chr_fe_get_driver(&con->chr));
store_con_info(con);

out:
g_free(type);
Expand All @@ -237,9 +278,9 @@ static int con_initialise(struct XenLegacyDevice *xendev)

if (!xendev->dev) {
xen_pfn_t mfn = con->ring_ref;
con->sring = xenforeignmemory_map(xen_fmem, con->xendev.dom,
PROT_READ | PROT_WRITE,
1, &mfn, NULL);
con->sring = qemu_xen_foreignmem_map(con->xendev.dom, NULL,
PROT_READ | PROT_WRITE,
1, &mfn, NULL);
} else {
con->sring = xen_be_map_grant_ref(xendev, con->ring_ref,
PROT_READ | PROT_WRITE);
Expand Down Expand Up @@ -269,9 +310,9 @@ static void con_disconnect(struct XenLegacyDevice *xendev)

if (con->sring) {
if (!xendev->dev) {
xenforeignmemory_unmap(xen_fmem, con->sring, 1);
qemu_xen_foreignmem_unmap(con->sring, 1);
} else {
xen_be_unmap_grant_ref(xendev, con->sring);
xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref);
}
con->sring = NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion hw/display/meson.build
Expand Up @@ -14,7 +14,7 @@ softmmu_ss.add(when: 'CONFIG_PL110', if_true: files('pl110.c'))
softmmu_ss.add(when: 'CONFIG_SII9022', if_true: files('sii9022.c'))
softmmu_ss.add(when: 'CONFIG_SSD0303', if_true: files('ssd0303.c'))
softmmu_ss.add(when: 'CONFIG_SSD0323', if_true: files('ssd0323.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xenfb.c'))
softmmu_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xenfb.c'))

softmmu_ss.add(when: 'CONFIG_VGA_PCI', if_true: files('vga-pci.c'))
softmmu_ss.add(when: 'CONFIG_VGA_ISA', if_true: files('vga-isa.c'))
Expand Down
32 changes: 17 additions & 15 deletions hw/display/xenfb.c
Expand Up @@ -98,8 +98,9 @@ static int common_bind(struct common *c)
if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
return -1;

c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
PROT_READ | PROT_WRITE, 1, &mfn, NULL);
c->page = qemu_xen_foreignmem_map(c->xendev.dom, NULL,
PROT_READ | PROT_WRITE, 1, &mfn,
NULL);
if (c->page == NULL)
return -1;

Expand All @@ -115,7 +116,7 @@ static void common_unbind(struct common *c)
{
xen_pv_unbind_evtchn(&c->xendev);
if (c->page) {
xenforeignmemory_unmap(xen_fmem, c->page, 1);
qemu_xen_foreignmem_unmap(c->page, 1);
c->page = NULL;
}
}
Expand Down Expand Up @@ -488,27 +489,28 @@ static int xenfb_map_fb(struct XenFB *xenfb)
}

if (xenfb->pixels) {
munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
munmap(xenfb->pixels, xenfb->fbpages * XEN_PAGE_SIZE);
xenfb->pixels = NULL;
}

xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XEN_PAGE_SIZE);
n_fbdirs = xenfb->fbpages * mode / 8;
n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
n_fbdirs = DIV_ROUND_UP(n_fbdirs, XEN_PAGE_SIZE);

pgmfns = g_new0(xen_pfn_t, n_fbdirs);
fbmfns = g_new0(xen_pfn_t, xenfb->fbpages);

xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
PROT_READ, n_fbdirs, pgmfns, NULL);
map = qemu_xen_foreignmem_map(xenfb->c.xendev.dom, NULL, PROT_READ,
n_fbdirs, pgmfns, NULL);
if (map == NULL)
goto out;
xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
qemu_xen_foreignmem_unmap(map, n_fbdirs);

xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
PROT_READ, xenfb->fbpages, fbmfns, NULL);
xenfb->pixels = qemu_xen_foreignmem_map(xenfb->c.xendev.dom, NULL,
PROT_READ, xenfb->fbpages,
fbmfns, NULL);
if (xenfb->pixels == NULL)
goto out;

Expand All @@ -526,8 +528,8 @@ static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
{
size_t mfn_sz = sizeof_field(struct xenfb_page, pd[0]);
size_t pd_len = sizeof_field(struct xenfb_page, pd) / mfn_sz;
size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
size_t fb_pages = pd_len * XEN_PAGE_SIZE / mfn_sz;
size_t fb_len_max = fb_pages * XEN_PAGE_SIZE;
int max_width, max_height;

if (fb_len_lim > fb_len_max) {
Expand Down Expand Up @@ -927,8 +929,8 @@ static void fb_disconnect(struct XenLegacyDevice *xendev)
* Replacing the framebuffer with anonymous shared memory
* instead. This releases the guest pages and keeps qemu happy.
*/
xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
qemu_xen_foreignmem_unmap(fb->pixels, fb->fbpages);
fb->pixels = mmap(fb->pixels, fb->fbpages * XEN_PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
-1, 0);
if (fb->pixels == MAP_FAILED) {
Expand Down
1 change: 1 addition & 0 deletions hw/i386/kvm/meson.build
Expand Up @@ -9,6 +9,7 @@ i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files(
'xen_evtchn.c',
'xen_gnttab.c',
'xen_xenstore.c',
'xenstore_impl.c',
))

i386_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss)
Expand Down
15 changes: 15 additions & 0 deletions hw/i386/kvm/trace-events
Expand Up @@ -3,3 +3,18 @@ kvm_xen_unmap_pirq(int pirq, int gsi) "pirq %d gsi %d"
kvm_xen_get_free_pirq(int pirq, int type) "pirq %d type %d"
kvm_xen_bind_pirq(int pirq, int port) "pirq %d port %d"
kvm_xen_unmask_pirq(int pirq, char *dev, int vector) "pirq %d dev %s vector %d"
xenstore_error(unsigned int id, unsigned int tx_id, const char *err) "req %u tx %u err %s"
xenstore_read(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_write(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_mkdir(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_directory(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_directory_part(unsigned int tx_id, const char *path, unsigned int offset) "tx %u path %s offset %u"
xenstore_transaction_start(unsigned int new_tx) "new_tx %u"
xenstore_transaction_end(unsigned int tx_id, bool commit) "tx %u commit %d"
xenstore_rm(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_get_perms(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_set_perms(unsigned int tx_id, const char *path) "tx %u path %s"
xenstore_watch(const char *path, const char *token) "path %s token %s"
xenstore_unwatch(const char *path, const char *token) "path %s token %s"
xenstore_reset_watches(void) ""
xenstore_watch_event(const char *path, const char *token) "path %s token %s"
15 changes: 15 additions & 0 deletions hw/i386/kvm/xen_evtchn.c
Expand Up @@ -34,6 +34,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/irq.h"
#include "hw/xen/xen_backend_ops.h"

#include "xen_evtchn.h"
#include "xen_overlay.h"
Expand Down Expand Up @@ -278,6 +279,17 @@ static const TypeInfo xen_evtchn_info = {
.class_init = xen_evtchn_class_init,
};

static struct evtchn_backend_ops emu_evtchn_backend_ops = {
.open = xen_be_evtchn_open,
.bind_interdomain = xen_be_evtchn_bind_interdomain,
.unbind = xen_be_evtchn_unbind,
.close = xen_be_evtchn_close,
.get_fd = xen_be_evtchn_fd,
.notify = xen_be_evtchn_notify,
.unmask = xen_be_evtchn_unmask,
.pending = xen_be_evtchn_pending,
};

static void gsi_assert_bh(void *opaque)
{
struct vcpu_info *vi = kvm_xen_get_vcpu_info_hva(0);
Expand Down Expand Up @@ -318,6 +330,9 @@ void xen_evtchn_create(void)
s->nr_pirq_inuse_words = DIV_ROUND_UP(s->nr_pirqs, 64);
s->pirq_inuse_bitmap = g_new0(uint64_t, s->nr_pirq_inuse_words);
s->pirq = g_new0(struct pirq_info, s->nr_pirqs);

/* Set event channel functions for backend drivers to use */
xen_evtchn_ops = &emu_evtchn_backend_ops;
}

void xen_evtchn_connect_gsis(qemu_irq *system_gsis)
Expand Down
325 changes: 320 additions & 5 deletions hw/i386/kvm/xen_gnttab.c
Expand Up @@ -22,6 +22,7 @@

#include "hw/sysbus.h"
#include "hw/xen/xen.h"
#include "hw/xen/xen_backend_ops.h"
#include "xen_overlay.h"
#include "xen_gnttab.h"

Expand All @@ -34,11 +35,10 @@
#define TYPE_XEN_GNTTAB "xen-gnttab"
OBJECT_DECLARE_SIMPLE_TYPE(XenGnttabState, XEN_GNTTAB)

#define XEN_PAGE_SHIFT 12
#define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT)

#define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t))

static struct gnttab_backend_ops emu_gnttab_backend_ops;

struct XenGnttabState {
/*< private >*/
SysBusDevice busdev;
Expand All @@ -57,6 +57,8 @@ struct XenGnttabState {
MemoryRegion gnt_frames;
MemoryRegion *gnt_aliases;
uint64_t *gnt_frame_gpas;

uint8_t *map_track;
};

struct XenGnttabState *xen_gnttab_singleton;
Expand All @@ -70,13 +72,11 @@ static void xen_gnttab_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Xen grant table support is for Xen emulation");
return;
}
s->nr_frames = 0;
s->max_frames = kvm_xen_get_gnttab_max_frames();
memory_region_init_ram(&s->gnt_frames, OBJECT(dev), "xen:grant_table",
XEN_PAGE_SIZE * s->max_frames, &error_abort);
memory_region_set_enabled(&s->gnt_frames, true);
s->entries.v1 = memory_region_get_ram_ptr(&s->gnt_frames);
memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames);

/* Create individual page-sizes aliases for overlays */
s->gnt_aliases = (void *)g_new0(MemoryRegion, s->max_frames);
Expand All @@ -88,9 +88,18 @@ static void xen_gnttab_realize(DeviceState *dev, Error **errp)
s->gnt_frame_gpas[i] = INVALID_GPA;
}

s->nr_frames = 0;
memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames);
s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags = GTF_permit_access;
s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame = XEN_SPECIAL_PFN(XENSTORE);

qemu_mutex_init(&s->gnt_lock);

xen_gnttab_singleton = s;

s->map_track = g_new0(uint8_t, s->max_frames * ENTRIES_PER_FRAME_V1);

xen_gnttab_ops = &emu_gnttab_backend_ops;
}

static int xen_gnttab_post_load(void *opaque, int version_id)
Expand Down Expand Up @@ -230,3 +239,309 @@ int xen_gnttab_query_size_op(struct gnttab_query_size *size)
size->max_nr_frames = s->max_frames;
return 0;
}

/* Track per-open refs, to allow close() to clean up. */
struct active_ref {
MemoryRegionSection mrs;
void *virtaddr;
uint32_t refcnt;
int prot;
};

static void gnt_unref(XenGnttabState *s, grant_ref_t ref,
MemoryRegionSection *mrs, int prot)
{
if (mrs && mrs->mr) {
if (prot & PROT_WRITE) {
memory_region_set_dirty(mrs->mr, mrs->offset_within_region,
XEN_PAGE_SIZE);
}
memory_region_unref(mrs->mr);
mrs->mr = NULL;
}
assert(s->map_track[ref] != 0);

if (--s->map_track[ref] == 0) {
grant_entry_v1_t *gnt_p = &s->entries.v1[ref];
qatomic_and(&gnt_p->flags, (uint16_t)~(GTF_reading | GTF_writing));
}
}

static uint64_t gnt_ref(XenGnttabState *s, grant_ref_t ref, int prot)
{
uint16_t mask = GTF_type_mask | GTF_sub_page;
grant_entry_v1_t gnt, *gnt_p;
int retries = 0;

if (ref >= s->max_frames * ENTRIES_PER_FRAME_V1 ||
s->map_track[ref] == UINT8_MAX) {
return INVALID_GPA;
}

if (prot & PROT_WRITE) {
mask |= GTF_readonly;
}

gnt_p = &s->entries.v1[ref];

/*
* The guest can legitimately be changing the GTF_readonly flag. Allow
* that, but don't let a malicious guest cause a livelock.
*/
for (retries = 0; retries < 5; retries++) {
uint16_t new_flags;

/* Read the entry before an atomic operation on its flags */
gnt = *(volatile grant_entry_v1_t *)gnt_p;

if ((gnt.flags & mask) != GTF_permit_access ||
gnt.domid != DOMID_QEMU) {
return INVALID_GPA;
}

new_flags = gnt.flags | GTF_reading;
if (prot & PROT_WRITE) {
new_flags |= GTF_writing;
}

if (qatomic_cmpxchg(&gnt_p->flags, gnt.flags, new_flags) == gnt.flags) {
return (uint64_t)gnt.frame << XEN_PAGE_SHIFT;
}
}

return INVALID_GPA;
}

struct xengntdev_handle {
GHashTable *active_maps;
};

static int xen_be_gnttab_set_max_grants(struct xengntdev_handle *xgt,
uint32_t nr_grants)
{
return 0;
}

static void *xen_be_gnttab_map_refs(struct xengntdev_handle *xgt,
uint32_t count, uint32_t domid,
uint32_t *refs, int prot)
{
XenGnttabState *s = xen_gnttab_singleton;
struct active_ref *act;

if (!s) {
errno = ENOTSUP;
return NULL;
}

if (domid != xen_domid) {
errno = EINVAL;
return NULL;
}

if (!count || count > 4096) {
errno = EINVAL;
return NULL;
}

/*
* Making a contiguous mapping from potentially discontiguous grant
* references would be... distinctly non-trivial. We don't support it.
* Even changing the API to return an array of pointers, one per page,
* wouldn't be simple to use in PV backends because some structures
* actually cross page boundaries (e.g. 32-bit blkif_response ring
* entries are 12 bytes).
*/
if (count != 1) {
errno = EINVAL;
return NULL;
}

QEMU_LOCK_GUARD(&s->gnt_lock);

act = g_hash_table_lookup(xgt->active_maps, GINT_TO_POINTER(refs[0]));
if (act) {
if ((prot & PROT_WRITE) && !(act->prot & PROT_WRITE)) {
if (gnt_ref(s, refs[0], prot) == INVALID_GPA) {
return NULL;
}
act->prot |= PROT_WRITE;
}
act->refcnt++;
} else {
uint64_t gpa = gnt_ref(s, refs[0], prot);
if (gpa == INVALID_GPA) {
errno = EINVAL;
return NULL;
}

act = g_new0(struct active_ref, 1);
act->prot = prot;
act->refcnt = 1;
act->mrs = memory_region_find(get_system_memory(), gpa, XEN_PAGE_SIZE);

if (act->mrs.mr &&
!int128_lt(act->mrs.size, int128_make64(XEN_PAGE_SIZE)) &&
memory_region_get_ram_addr(act->mrs.mr) != RAM_ADDR_INVALID) {
act->virtaddr = qemu_map_ram_ptr(act->mrs.mr->ram_block,
act->mrs.offset_within_region);
}
if (!act->virtaddr) {
gnt_unref(s, refs[0], &act->mrs, 0);
g_free(act);
errno = EINVAL;
return NULL;
}

s->map_track[refs[0]]++;
g_hash_table_insert(xgt->active_maps, GINT_TO_POINTER(refs[0]), act);
}

return act->virtaddr;
}

static gboolean do_unmap(gpointer key, gpointer value, gpointer user_data)
{
XenGnttabState *s = user_data;
grant_ref_t gref = GPOINTER_TO_INT(key);
struct active_ref *act = value;

gnt_unref(s, gref, &act->mrs, act->prot);
g_free(act);
return true;
}

static int xen_be_gnttab_unmap(struct xengntdev_handle *xgt,
void *start_address, uint32_t *refs,
uint32_t count)
{
XenGnttabState *s = xen_gnttab_singleton;
struct active_ref *act;

if (!s) {
return -ENOTSUP;
}

if (count != 1) {
return -EINVAL;
}

QEMU_LOCK_GUARD(&s->gnt_lock);

act = g_hash_table_lookup(xgt->active_maps, GINT_TO_POINTER(refs[0]));
if (!act) {
return -ENOENT;
}

if (act->virtaddr != start_address) {
return -EINVAL;
}

if (!--act->refcnt) {
do_unmap(GINT_TO_POINTER(refs[0]), act, s);
g_hash_table_remove(xgt->active_maps, GINT_TO_POINTER(refs[0]));
}

return 0;
}

/*
* This looks a bit like the one for true Xen in xen-operations.c but
* in emulation we don't support multi-page mappings. And under Xen we
* *want* the multi-page mappings so we have fewer bounces through the
* kernel and the hypervisor. So the code paths end up being similar,
* but different.
*/
static int xen_be_gnttab_copy(struct xengntdev_handle *xgt, bool to_domain,
uint32_t domid, XenGrantCopySegment *segs,
uint32_t nr_segs, Error **errp)
{
int prot = to_domain ? PROT_WRITE : PROT_READ;
unsigned int i;

for (i = 0; i < nr_segs; i++) {
XenGrantCopySegment *seg = &segs[i];
void *page;
uint32_t ref = to_domain ? seg->dest.foreign.ref :
seg->source.foreign.ref;

page = xen_be_gnttab_map_refs(xgt, 1, domid, &ref, prot);
if (!page) {
if (errp) {
error_setg_errno(errp, errno,
"xen_be_gnttab_map_refs failed");
}
return -errno;
}

if (to_domain) {
memcpy(page + seg->dest.foreign.offset, seg->source.virt,
seg->len);
} else {
memcpy(seg->dest.virt, page + seg->source.foreign.offset,
seg->len);
}

if (xen_be_gnttab_unmap(xgt, page, &ref, 1)) {
if (errp) {
error_setg_errno(errp, errno, "xen_be_gnttab_unmap failed");
}
return -errno;
}
}

return 0;
}

static struct xengntdev_handle *xen_be_gnttab_open(void)
{
struct xengntdev_handle *xgt = g_new0(struct xengntdev_handle, 1);

xgt->active_maps = g_hash_table_new(g_direct_hash, g_direct_equal);
return xgt;
}

static int xen_be_gnttab_close(struct xengntdev_handle *xgt)
{
XenGnttabState *s = xen_gnttab_singleton;

if (!s) {
return -ENOTSUP;
}

g_hash_table_foreach_remove(xgt->active_maps, do_unmap, s);
g_hash_table_destroy(xgt->active_maps);
g_free(xgt);
return 0;
}

static struct gnttab_backend_ops emu_gnttab_backend_ops = {
.open = xen_be_gnttab_open,
.close = xen_be_gnttab_close,
.grant_copy = xen_be_gnttab_copy,
.set_max_grants = xen_be_gnttab_set_max_grants,
.map_refs = xen_be_gnttab_map_refs,
.unmap = xen_be_gnttab_unmap,
};

int xen_gnttab_reset(void)
{
XenGnttabState *s = xen_gnttab_singleton;

if (!s) {
return -ENOTSUP;
}

QEMU_LOCK_GUARD(&s->gnt_lock);

s->nr_frames = 0;

memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames);

s->entries.v1[GNTTAB_RESERVED_XENSTORE].flags = GTF_permit_access;
s->entries.v1[GNTTAB_RESERVED_XENSTORE].frame = XEN_SPECIAL_PFN(XENSTORE);

memset(s->map_track, 0, s->max_frames * ENTRIES_PER_FRAME_V1);

return 0;
}
1 change: 1 addition & 0 deletions hw/i386/kvm/xen_gnttab.h
Expand Up @@ -13,6 +13,7 @@
#define QEMU_XEN_GNTTAB_H

void xen_gnttab_create(void);
int xen_gnttab_reset(void);
int xen_gnttab_map_page(uint64_t idx, uint64_t gfn);

struct gnttab_set_version;
Expand Down
1,251 changes: 1,239 additions & 12 deletions hw/i386/kvm/xen_xenstore.c

Large diffs are not rendered by default.

1,927 changes: 1,927 additions & 0 deletions hw/i386/kvm/xenstore_impl.c

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions hw/i386/kvm/xenstore_impl.h
@@ -0,0 +1,63 @@
/*
* QEMU Xen emulation: The actual implementation of XenStore
*
* Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Authors: David Woodhouse <dwmw2@infradead.org>
*
* 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 QEMU_XENSTORE_IMPL_H
#define QEMU_XENSTORE_IMPL_H

#include "hw/xen/xen_backend_ops.h"

typedef struct XenstoreImplState XenstoreImplState;

XenstoreImplState *xs_impl_create(unsigned int dom_id);

char *xs_perm_as_string(unsigned int perm, unsigned int domid);

/*
* These functions return *positive* error numbers. This is a little
* unconventional but it helps to keep us honest because there is
* also a very limited set of error numbers that they are permitted
* to return (those in xsd_errors).
*/

int xs_impl_read(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path, GByteArray *data);
int xs_impl_write(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path, GByteArray *data);
int xs_impl_directory(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path,
uint64_t *gencnt, GList **items);
int xs_impl_transaction_start(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t *tx_id);
int xs_impl_transaction_end(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, bool commit);
int xs_impl_rm(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path);
int xs_impl_get_perms(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path, GList **perms);
int xs_impl_set_perms(XenstoreImplState *s, unsigned int dom_id,
xs_transaction_t tx_id, const char *path, GList *perms);

/* This differs from xs_watch_fn because it has the token */
typedef void(xs_impl_watch_fn)(void *opaque, const char *path,
const char *token);
int xs_impl_watch(XenstoreImplState *s, unsigned int dom_id, const char *path,
const char *token, xs_impl_watch_fn fn, void *opaque);
int xs_impl_unwatch(XenstoreImplState *s, unsigned int dom_id,
const char *path, const char *token, xs_impl_watch_fn fn,
void *opaque);
int xs_impl_reset_watches(XenstoreImplState *s, unsigned int dom_id);

GByteArray *xs_impl_serialize(XenstoreImplState *s);
int xs_impl_deserialize(XenstoreImplState *s, GByteArray *bytes,
unsigned int dom_id, xs_impl_watch_fn watch_fn,
void *watch_opaque);

#endif /* QEMU_XENSTORE_IMPL_H */
7 changes: 7 additions & 0 deletions hw/i386/pc.c
Expand Up @@ -102,6 +102,11 @@
#include "trace.h"
#include CONFIG_DEVICES

#ifdef CONFIG_XEN_EMU
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
#endif

/*
* Helper for setting model-id for CPU models that changed model-id
* depending on QEMU versions up to QEMU 2.4.
Expand Down Expand Up @@ -1318,6 +1323,8 @@ void pc_basic_device_init(struct PCMachineState *pcms,
if (pcms->bus) {
pci_create_simple(pcms->bus, -1, "xen-platform");
}
xen_bus_init();
xen_be_init();
}
#endif

Expand Down
4 changes: 2 additions & 2 deletions hw/i386/pc_piix.c
Expand Up @@ -47,8 +47,6 @@
#include "hw/kvm/clock.h"
#include "hw/sysbus.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/xen/xen-x86.h"
#include "hw/xen/xen.h"
#include "exec/memory.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/piix4.h"
Expand All @@ -60,6 +58,8 @@
#include <xen/hvm/hvm_info_table.h>
#include "hw/xen/xen_pt.h"
#endif
#include "hw/xen/xen-x86.h"
#include "hw/xen/xen.h"
#include "migration/global_state.h"
#include "migration/misc.h"
#include "sysemu/numa.h"
Expand Down
38 changes: 21 additions & 17 deletions hw/i386/xen/xen-hvm.c
Expand Up @@ -18,7 +18,7 @@
#include "hw/irq.h"
#include "hw/hw.h"
#include "hw/i386/apic-msidef.h"
#include "hw/xen/xen_common.h"
#include "hw/xen/xen_native.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
#include "hw/xen/xen-x86.h"
Expand Down Expand Up @@ -52,10 +52,11 @@ static bool xen_in_migration;

/* Compatibility with older version */

/* This allows QEMU to build on a system that has Xen 4.5 or earlier
* installed. This here (not in hw/xen/xen_common.h) because xen/hvm/ioreq.h
* needs to be included before this block and hw/xen/xen_common.h needs to
* be included before xen/hvm/ioreq.h
/*
* This allows QEMU to build on a system that has Xen 4.5 or earlier installed.
* This is here (not in hw/xen/xen_native.h) because xen/hvm/ioreq.h needs to
* be included before this block and hw/xen/xen_native.h needs to be included
* before xen/hvm/ioreq.h
*/
#ifndef IOREQ_TYPE_VMWARE_PORT
#define IOREQ_TYPE_VMWARE_PORT 3
Expand Down Expand Up @@ -761,7 +762,7 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state)
int i;
evtchn_port_t port;

port = xenevtchn_pending(state->xce_handle);
port = qemu_xen_evtchn_pending(state->xce_handle);
if (port == state->bufioreq_local_port) {
timer_mod(state->buffered_io_timer,
BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
Expand All @@ -780,7 +781,7 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state)
}

/* unmask the wanted port again */
xenevtchn_unmask(state->xce_handle, port);
qemu_xen_evtchn_unmask(state->xce_handle, port);

/* get the io packet from shared memory */
state->send_vcpu = i;
Expand Down Expand Up @@ -1147,7 +1148,7 @@ static void handle_buffered_io(void *opaque)
BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
} else {
timer_del(state->buffered_io_timer);
xenevtchn_unmask(state->xce_handle, state->bufioreq_local_port);
qemu_xen_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
}
}

Expand Down Expand Up @@ -1196,8 +1197,8 @@ static void cpu_handle_ioreq(void *opaque)
}

req->state = STATE_IORESP_READY;
xenevtchn_notify(state->xce_handle,
state->ioreq_local_port[state->send_vcpu]);
qemu_xen_evtchn_notify(state->xce_handle,
state->ioreq_local_port[state->send_vcpu]);
}
}

Expand All @@ -1206,7 +1207,7 @@ static void xen_main_loop_prepare(XenIOState *state)
int evtchn_fd = -1;

if (state->xce_handle != NULL) {
evtchn_fd = xenevtchn_fd(state->xce_handle);
evtchn_fd = qemu_xen_evtchn_fd(state->xce_handle);
}

state->buffered_io_timer = timer_new_ms(QEMU_CLOCK_REALTIME, handle_buffered_io,
Expand Down Expand Up @@ -1249,7 +1250,7 @@ static void xen_exit_notifier(Notifier *n, void *data)
xenforeignmemory_unmap_resource(xen_fmem, state->fres);
}

xenevtchn_close(state->xce_handle);
qemu_xen_evtchn_close(state->xce_handle);
xs_daemon_close(state->xenstore);
}

Expand Down Expand Up @@ -1397,9 +1398,11 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
xen_pfn_t ioreq_pfn;
XenIOState *state;

setup_xen_backend_ops();

state = g_new0(XenIOState, 1);

state->xce_handle = xenevtchn_open(NULL, 0);
state->xce_handle = qemu_xen_evtchn_open();
if (state->xce_handle == NULL) {
perror("xen: event channel open");
goto err;
Expand Down Expand Up @@ -1463,17 +1466,18 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)

/* FIXME: how about if we overflow the page here? */
for (i = 0; i < max_cpus; i++) {
rc = xenevtchn_bind_interdomain(state->xce_handle, xen_domid,
xen_vcpu_eport(state->shared_page, i));
rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
xen_vcpu_eport(state->shared_page,
i));
if (rc == -1) {
error_report("shared evtchn %d bind error %d", i, errno);
goto err;
}
state->ioreq_local_port[i] = rc;
}

rc = xenevtchn_bind_interdomain(state->xce_handle, xen_domid,
state->bufioreq_remote_port);
rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
state->bufioreq_remote_port);
if (rc == -1) {
error_report("buffered evtchn bind error %d", errno);
goto err;
Expand Down
2 changes: 1 addition & 1 deletion hw/i386/xen/xen-mapcache.c
Expand Up @@ -14,7 +14,7 @@

#include <sys/resource.h>

#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_native.h"
#include "qemu/bitmap.h"

#include "sysemu/runstate.h"
Expand Down
7 changes: 4 additions & 3 deletions hw/i386/xen/xen_platform.c
Expand Up @@ -28,7 +28,6 @@
#include "hw/ide/pci.h"
#include "hw/pci/pci.h"
#include "migration/vmstate.h"
#include "hw/xen/xen.h"
#include "net/net.h"
#include "trace.h"
#include "sysemu/xen.h"
Expand All @@ -38,10 +37,12 @@
#include "qom/object.h"

#ifdef CONFIG_XEN
#include "hw/xen/xen_common.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_native.h"
#endif

/* The rule is that xen_native.h must come first */
#include "hw/xen/xen.h"

//#define DEBUG_PLATFORM

#ifdef DEBUG_PLATFORM
Expand Down
25 changes: 14 additions & 11 deletions hw/net/xen_nic.c
Expand Up @@ -145,7 +145,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
continue;
}

if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
if ((txreq.offset + txreq.size) > XEN_PAGE_SIZE) {
xen_pv_printf(&netdev->xendev, 0, "error: page crossing\n");
net_tx_error(netdev, &txreq, rc);
continue;
Expand All @@ -171,7 +171,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
if (txreq.flags & NETTXF_csum_blank) {
/* have read-only mapping -> can't fill checksum in-place */
if (!tmpbuf) {
tmpbuf = g_malloc(XC_PAGE_SIZE);
tmpbuf = g_malloc(XEN_PAGE_SIZE);
}
memcpy(tmpbuf, page + txreq.offset, txreq.size);
net_checksum_calculate(tmpbuf, txreq.size, CSUM_ALL);
Expand All @@ -181,7 +181,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
qemu_send_packet(qemu_get_queue(netdev->nic),
page + txreq.offset, txreq.size);
}
xen_be_unmap_grant_ref(&netdev->xendev, page);
xen_be_unmap_grant_ref(&netdev->xendev, page, txreq.gref);
net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
}
if (!netdev->tx_work) {
Expand Down Expand Up @@ -243,9 +243,9 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
return 0;
}
if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
if (size > XEN_PAGE_SIZE - NET_IP_ALIGN) {
xen_pv_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
(unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
(unsigned long)size, XEN_PAGE_SIZE - NET_IP_ALIGN);
return -1;
}

Expand All @@ -261,7 +261,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
return -1;
}
memcpy(page + NET_IP_ALIGN, buf, size);
xen_be_unmap_grant_ref(&netdev->xendev, page);
xen_be_unmap_grant_ref(&netdev->xendev, page, rxreq.gref);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);

return size;
Expand Down Expand Up @@ -343,12 +343,13 @@ static int net_connect(struct XenLegacyDevice *xendev)
netdev->rx_ring_ref,
PROT_READ | PROT_WRITE);
if (!netdev->rxs) {
xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs);
xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs,
netdev->tx_ring_ref);
netdev->txs = NULL;
return -1;
}
BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XEN_PAGE_SIZE);
BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XEN_PAGE_SIZE);

xen_be_bind_evtchn(&netdev->xendev);

Expand All @@ -368,11 +369,13 @@ static void net_disconnect(struct XenLegacyDevice *xendev)
xen_pv_unbind_evtchn(&netdev->xendev);

if (netdev->txs) {
xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs);
xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs,
netdev->tx_ring_ref);
netdev->txs = NULL;
}
if (netdev->rxs) {
xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs);
xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs,
netdev->rx_ring_ref);
netdev->rxs = NULL;
}
}
Expand Down
2 changes: 1 addition & 1 deletion hw/usb/meson.build
Expand Up @@ -84,6 +84,6 @@ if libusb.found()
hw_usb_modules += {'host': usbhost_ss}
endif

softmmu_ss.add(when: ['CONFIG_USB', 'CONFIG_XEN', libusb], if_true: files('xen-usb.c'))
softmmu_ss.add(when: ['CONFIG_USB', 'CONFIG_XEN_BUS', libusb], if_true: files('xen-usb.c'))

modules += { 'hw-usb': hw_usb_modules }
29 changes: 20 additions & 9 deletions hw/usb/xen-usb.c
Expand Up @@ -101,6 +101,8 @@ struct usbback_hotplug {
struct usbback_info {
struct XenLegacyDevice xendev; /* must be first */
USBBus bus;
uint32_t urb_ring_ref;
uint32_t conn_ring_ref;
void *urb_sring;
void *conn_sring;
struct usbif_urb_back_ring urb_ring;
Expand Down Expand Up @@ -159,7 +161,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)

for (i = 0; i < nr_segs; i++) {
if ((unsigned)usbback_req->req.seg[i].offset +
(unsigned)usbback_req->req.seg[i].length > XC_PAGE_SIZE) {
(unsigned)usbback_req->req.seg[i].length > XEN_PAGE_SIZE) {
xen_pv_printf(xendev, 0, "segment crosses page boundary\n");
return -EINVAL;
}
Expand All @@ -183,7 +185,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)

for (i = 0; i < usbback_req->nr_buffer_segs; i++) {
seg = usbback_req->req.seg + i;
addr = usbback_req->buffer + i * XC_PAGE_SIZE + seg->offset;
addr = usbback_req->buffer + i * XEN_PAGE_SIZE + seg->offset;
qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length);
}
}
Expand Down Expand Up @@ -277,10 +279,11 @@ static int usbback_init_packet(struct usbback_req *usbback_req)
static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
int32_t actual_length, int32_t error_count)
{
uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST];
struct usbback_info *usbif;
struct usbif_urb_response *res;
struct XenLegacyDevice *xendev;
unsigned int notify;
unsigned int notify, i;

usbif = usbback_req->usbif;
xendev = &usbif->xendev;
Expand All @@ -293,13 +296,19 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
}

if (usbback_req->buffer) {
xen_be_unmap_grant_refs(xendev, usbback_req->buffer,
for (i = 0; i < usbback_req->nr_buffer_segs; i++) {
ref[i] = usbback_req->req.seg[i].gref;
}
xen_be_unmap_grant_refs(xendev, usbback_req->buffer, ref,
usbback_req->nr_buffer_segs);
usbback_req->buffer = NULL;
}

if (usbback_req->isoc_buffer) {
xen_be_unmap_grant_refs(xendev, usbback_req->isoc_buffer,
for (i = 0; i < usbback_req->nr_extra_segs; i++) {
ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref;
}
xen_be_unmap_grant_refs(xendev, usbback_req->isoc_buffer, ref,
usbback_req->nr_extra_segs);
usbback_req->isoc_buffer = NULL;
}
Expand Down Expand Up @@ -832,11 +841,11 @@ static void usbback_disconnect(struct XenLegacyDevice *xendev)
xen_pv_unbind_evtchn(xendev);

if (usbif->urb_sring) {
xen_be_unmap_grant_ref(xendev, usbif->urb_sring);
xen_be_unmap_grant_ref(xendev, usbif->urb_sring, usbif->urb_ring_ref);
usbif->urb_sring = NULL;
}
if (usbif->conn_sring) {
xen_be_unmap_grant_ref(xendev, usbif->conn_sring);
xen_be_unmap_grant_ref(xendev, usbif->conn_sring, usbif->conn_ring_ref);
usbif->conn_sring = NULL;
}

Expand Down Expand Up @@ -889,10 +898,12 @@ static int usbback_connect(struct XenLegacyDevice *xendev)
return -1;
}

usbif->urb_ring_ref = urb_ring_ref;
usbif->conn_ring_ref = conn_ring_ref;
urb_sring = usbif->urb_sring;
conn_sring = usbif->conn_sring;
BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE);
BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE);
BACK_RING_INIT(&usbif->urb_ring, urb_sring, XEN_PAGE_SIZE);
BACK_RING_INIT(&usbif->conn_ring, conn_sring, XEN_PAGE_SIZE);

xen_be_bind_evtchn(xendev);

Expand Down
6 changes: 5 additions & 1 deletion hw/xen/meson.build
@@ -1,4 +1,4 @@
softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
softmmu_ss.add(when: ['CONFIG_XEN_BUS'], if_true: files(
'xen-backend.c',
'xen-bus-helper.c',
'xen-bus.c',
Expand All @@ -7,6 +7,10 @@ softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen_pvdev.c',
))

softmmu_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen-operations.c',
))

xen_specific_ss = ss.source_set()
if have_xen_pci_passthrough
xen_specific_ss.add(files(
Expand Down
2 changes: 1 addition & 1 deletion hw/xen/trace-events
@@ -1,6 +1,6 @@
# See docs/devel/tracing.rst for syntax documentation.

# ../../include/hw/xen/xen_common.h
# ../../include/hw/xen/xen_native.h
xen_default_ioreq_server(void) ""
xen_ioreq_server_create(uint32_t id) "id: %u"
xen_ioreq_server_destroy(uint32_t id) "id: %u"
Expand Down
62 changes: 25 additions & 37 deletions hw/xen/xen-bus-helper.c
Expand Up @@ -10,6 +10,7 @@
#include "hw/xen/xen-bus.h"
#include "hw/xen/xen-bus-helper.h"
#include "qapi/error.h"
#include "trace.h"

#include <glib/gprintf.h>

Expand Down Expand Up @@ -46,34 +47,28 @@ const char *xs_strstate(enum xenbus_state state)
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)
void xs_node_create(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, unsigned int owner, unsigned int domid,
unsigned int perms, Error **errp)
{
trace_xs_node_create(node);

if (!xs_write(xsh, tid, node, "", 0)) {
if (!qemu_xen_xs_create(h, tid, owner, domid, perms, node)) {
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,
void xs_node_destroy(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, Error **errp)
{
trace_xs_node_destroy(node);

if (!xs_rm(xsh, tid, node)) {
if (!qemu_xen_xs_destroy(h, 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,
void xs_node_vprintf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
Expand All @@ -86,7 +81,7 @@ void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,

trace_xs_node_vprintf(path, value);

if (!xs_write(xsh, tid, path, value, len)) {
if (!qemu_xen_xs_write(h, tid, path, value, len)) {
error_setg_errno(errp, errno, "failed to write '%s' to '%s'",
value, path);
}
Expand All @@ -95,18 +90,18 @@ void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
g_free(path);
}

void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
void xs_node_printf(struct qemu_xs_handle *h, 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);
xs_node_vprintf(h, tid, node, key, errp, fmt, ap);
va_end(ap);
}

int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
Expand All @@ -115,7 +110,7 @@ int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,

path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
g_strdup(key);
value = xs_read(xsh, tid, path, NULL);
value = qemu_xen_xs_read(h, tid, path, NULL);

trace_xs_node_vscanf(path, value);

Expand All @@ -133,50 +128,43 @@ int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
return rc;
}

int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
int xs_node_scanf(struct qemu_xs_handle *h, 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);
rc = xs_node_vscanf(h, 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)
struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *node,
const char *key, xs_watch_fn fn,
void *opaque, Error **errp)
{
char *path;
struct qemu_xs_watch *w;

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)) {
w = qemu_xen_xs_watch(h, path, fn, opaque);
if (!w) {
error_setg_errno(errp, errno, "failed to watch node '%s'", path);
}

g_free(path);

return w;
}

void xs_node_unwatch(struct xs_handle *xsh, const char *node,
const char *key, const char *token, Error **errp)
void xs_node_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *w)
{
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);
qemu_xen_xs_unwatch(h, w);
}
411 changes: 64 additions & 347 deletions hw/xen/xen-bus.c

Large diffs are not rendered by default.

254 changes: 80 additions & 174 deletions hw/xen/xen-legacy-backend.c

Large diffs are not rendered by default.

478 changes: 478 additions & 0 deletions hw/xen/xen-operations.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions hw/xen/xen_devconfig.c
Expand Up @@ -11,11 +11,11 @@ static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
{
char *dom;

dom = xs_get_domain_path(xenstore, xen_domid);
dom = qemu_xen_xs_get_domain_path(xenstore, xen_domid);
snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
free(dom);

dom = xs_get_domain_path(xenstore, 0);
dom = qemu_xen_xs_get_domain_path(xenstore, 0);
snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
free(dom);

Expand Down
2 changes: 1 addition & 1 deletion hw/xen/xen_pt.c
Expand Up @@ -60,9 +60,9 @@
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "xen_pt.h"
#include "hw/xen/xen.h"
#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "qemu/range.h"

static bool has_igd_gfx_passthru;
Expand Down
2 changes: 1 addition & 1 deletion hw/xen/xen_pt.h
@@ -1,7 +1,7 @@
#ifndef XEN_PT_H
#define XEN_PT_H

#include "hw/xen/xen_common.h"
#include "hw/xen/xen_native.h"
#include "xen-host-pci-device.h"
#include "qom/object.h"

Expand Down
2 changes: 1 addition & 1 deletion hw/xen/xen_pt_config_init.c
Expand Up @@ -15,8 +15,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/timer.h"
#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "hw/xen/xen-legacy-backend.h"

#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
(((value) & (val_mask)) | ((data) & ~(val_mask)))
Expand Down
1 change: 0 additions & 1 deletion hw/xen/xen_pt_graphics.c
Expand Up @@ -5,7 +5,6 @@
#include "qapi/error.h"
#include "xen_pt.h"
#include "xen-host-pci-device.h"
#include "hw/xen/xen-legacy-backend.h"

static unsigned long igd_guest_opregion;
static unsigned long igd_host_opregion;
Expand Down
4 changes: 2 additions & 2 deletions hw/xen/xen_pt_msi.c
Expand Up @@ -11,9 +11,9 @@

#include "qemu/osdep.h"

#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "hw/i386/apic-msidef.h"
#include "xen_pt.h"
#include "hw/xen/xen-legacy-backend.h"


#define XEN_PT_AUTO_ASSIGN -1
Expand Down
63 changes: 12 additions & 51 deletions hw/xen/xen_pvdev.c
Expand Up @@ -54,31 +54,17 @@ void xen_config_cleanup(void)
struct xs_dirs *d;

QTAILQ_FOREACH(d, &xs_cleanup, list) {
xs_rm(xenstore, 0, d->xs_dir);
qemu_xen_xs_destroy(xenstore, 0, d->xs_dir);
}
}

int xenstore_mkdir(char *path, int p)
{
struct xs_permissions perms[2] = {
{
.id = 0, /* set owner: dom0 */
}, {
.id = xen_domid,
.perms = p,
}
};

if (!xs_mkdir(xenstore, 0, path)) {
if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) {
xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
return -1;
}
xenstore_cleanup_dir(g_strdup(path));

if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
return -1;
}
return 0;
}

Expand All @@ -87,7 +73,7 @@ int xenstore_write_str(const char *base, const char *node, const char *val)
char abspath[XEN_BUFSIZE];

snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) {
return -1;
}
return 0;
Expand All @@ -100,7 +86,7 @@ char *xenstore_read_str(const char *base, const char *node)
char *str, *ret = NULL;

snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
str = xs_read(xenstore, 0, abspath, &len);
str = qemu_xen_xs_read(xenstore, 0, abspath, &len);
if (str != NULL) {
/* move to qemu-allocated memory to make sure
* callers can savely g_free() stuff. */
Expand Down Expand Up @@ -152,29 +138,6 @@ int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
return rc;
}

void xenstore_update(void *unused)
{
char **vec = NULL;
intptr_t type, ops, ptr;
unsigned int dom, count;

vec = xs_read_watch(xenstore, &count);
if (vec == NULL) {
goto cleanup;
}

if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
&type, &dom, &ops) == 3) {
xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)ops);
}
if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
}

cleanup:
free(vec);
}

const char *xenbus_strstate(enum xenbus_state state)
{
static const char *const name[] = {
Expand Down Expand Up @@ -238,14 +201,14 @@ void xen_pv_evtchn_event(void *opaque)
struct XenLegacyDevice *xendev = opaque;
evtchn_port_t port;

port = xenevtchn_pending(xendev->evtchndev);
port = qemu_xen_evtchn_pending(xendev->evtchndev);
if (port != xendev->local_port) {
xen_pv_printf(xendev, 0,
"xenevtchn_pending returned %d (expected %d)\n",
port, xendev->local_port);
return;
}
xenevtchn_unmask(xendev->evtchndev, port);
qemu_xen_evtchn_unmask(xendev->evtchndev, port);

if (xendev->ops->event) {
xendev->ops->event(xendev);
Expand All @@ -257,15 +220,15 @@ void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
if (xendev->local_port == -1) {
return;
}
qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port);
xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
xendev->local_port = -1;
}

int xen_pv_send_notify(struct XenLegacyDevice *xendev)
{
return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port);
}

/* ------------------------------------------------------------- */
Expand Down Expand Up @@ -299,17 +262,15 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
}

if (xendev->fe) {
char token[XEN_BUFSIZE];
snprintf(token, sizeof(token), "fe:%p", xendev);
xs_unwatch(xenstore, xendev->fe, token);
qemu_xen_xs_unwatch(xenstore, xendev->watch);
g_free(xendev->fe);
}

if (xendev->evtchndev != NULL) {
xenevtchn_close(xendev->evtchndev);
qemu_xen_evtchn_close(xendev->evtchndev);
}
if (xendev->gnttabdev != NULL) {
xengnttab_close(xendev->gnttabdev);
qemu_xen_gnttab_close(xendev->gnttabdev);
}

QTAILQ_REMOVE(&xendevs, xendev, next);
Expand Down
26 changes: 13 additions & 13 deletions include/hw/xen/xen-bus-helper.h
Expand Up @@ -8,40 +8,40 @@
#ifndef HW_XEN_BUS_HELPER_H
#define HW_XEN_BUS_HELPER_H

#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend_ops.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,
void xs_node_create(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, unsigned int owner, unsigned int domid,
unsigned int perms, Error **errp);
void xs_node_destroy(struct qemu_xs_handle *h, 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,
void xs_node_vprintf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
G_GNUC_PRINTF(6, 0);
void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
void xs_node_printf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...)
G_GNUC_PRINTF(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,
int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
G_GNUC_SCANF(6, 0);
int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, ...)
G_GNUC_SCANF(6, 7);

/* 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);
struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *node,
const char *key, xs_watch_fn fn,
void *opaque, Error **errp);
void xs_node_unwatch(struct qemu_xs_handle *h, struct qemu_xs_watch *w);

#endif /* HW_XEN_BUS_HELPER_H */
21 changes: 7 additions & 14 deletions include/hw/xen/xen-bus.h
Expand Up @@ -8,31 +8,25 @@
#ifndef HW_XEN_BUS_H
#define HW_XEN_BUS_H

#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend_ops.h"
#include "hw/sysbus.h"
#include "qemu/notify.h"
#include "qom/object.h"

typedef void (*XenWatchHandler)(void *opaque);

typedef struct XenWatchList XenWatchList;
typedef struct XenWatch XenWatch;
typedef struct XenEventChannel XenEventChannel;

struct XenDevice {
DeviceState qdev;
domid_t frontend_id;
char *name;
struct xs_handle *xsh;
XenWatchList *watch_list;
struct qemu_xs_handle *xsh;
char *backend_path, *frontend_path;
enum xenbus_state backend_state, frontend_state;
Notifier exit;
XenWatch *backend_state_watch, *frontend_state_watch;
struct qemu_xs_watch *backend_state_watch, *frontend_state_watch;
bool backend_online;
XenWatch *backend_online_watch;
struct qemu_xs_watch *backend_online_watch;
xengnttab_handle *xgth;
bool feature_grant_copy;
bool inactive;
QLIST_HEAD(, XenEventChannel) event_channels;
QLIST_ENTRY(XenDevice) list;
Expand Down Expand Up @@ -64,10 +58,9 @@ OBJECT_DECLARE_TYPE(XenDevice, XenDeviceClass, XEN_DEVICE)
struct XenBus {
BusState qbus;
domid_t backend_id;
struct xs_handle *xsh;
XenWatchList *watch_list;
struct qemu_xs_handle *xsh;
unsigned int backend_types;
XenWatch **backend_watch;
struct qemu_xs_watch **backend_watch;
QLIST_HEAD(, XenDevice) inactive_devices;
};

Expand Down Expand Up @@ -102,7 +95,7 @@ void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
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,
void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, uint32_t *refs,
unsigned int nr_refs, Error **errp);

typedef struct XenDeviceGrantCopySegment {
Expand Down
24 changes: 5 additions & 19 deletions include/hw/xen/xen-legacy-backend.h
@@ -1,7 +1,7 @@
#ifndef HW_XEN_LEGACY_BACKEND_H
#define HW_XEN_LEGACY_BACKEND_H

#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend_ops.h"
#include "hw/xen/xen_pvdev.h"
#include "net/net.h"
#include "qom/object.h"
Expand All @@ -15,7 +15,7 @@ DECLARE_INSTANCE_CHECKER(XenLegacyDevice, XENBACKEND,
TYPE_XENBACKEND)

/* variables */
extern struct xs_handle *xenstore;
extern struct qemu_xs_handle *xenstore;
extern const char *xen_protocol;
extern DeviceState *xen_sysdev;
extern BusState *xen_sysbus;
Expand All @@ -30,9 +30,6 @@ int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
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 XenLegacyDevice *xendev, const char *node);
int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
int *ival);
Expand All @@ -51,18 +48,7 @@ void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
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 XenLegacyDevice *xendev, void *ptr,
unsigned int nr_refs);

typedef struct XenGrantCopySegment {
union {
void *virt;
struct {
uint32_t ref;
off_t offset;
} foreign;
} source, dest;
size_t len;
} XenGrantCopySegment;
uint32_t *refs, unsigned int nr_refs);

int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain, XenGrantCopySegment segs[],
Expand All @@ -75,9 +61,9 @@ static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev,
}

static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev,
void *ptr)
void *ptr, uint32_t ref)
{
return xen_be_unmap_grant_refs(xendev, ptr, 1);
return xen_be_unmap_grant_refs(xendev, ptr, &ref, 1);
}

/* actual backend drivers */
Expand Down
24 changes: 14 additions & 10 deletions include/hw/xen/xen.h
Expand Up @@ -8,15 +8,21 @@
#define QEMU_HW_XEN_H

/*
* As a temporary measure while the headers are being untangled, define
* __XEN_TOOLS__ here before any Xen headers are included. Otherwise, if
* the Xen toolstack library headers are later included, they will find
* some of the "internal" definitions missing and the build will fail. In
* later commits, we'll end up with a rule that the native libraries have
* to be included first, which will ensure that the libraries get the
* version of Xen libraries that they expect.
* C files using Xen toolstack libraries will have included those headers
* already via xen_native.h, and having __XEM_TOOLS__ defined will have
* automatically set __XEN_INTERFACE_VERSION__ to the latest supported
* by the *system* Xen headers which were transitively included.
*
* C files which are part of the internal emulation, and which did not
* include xen_native.h, may need this defined so that the Xen headers
* imported to include/hw/xen/interface/ will expose the appropriate API
* version.
*
* This is why there's a rule that xen_native.h must be included first.
*/
#define __XEN_TOOLS__ 1
#ifndef __XEN_INTERFACE_VERSION__
#define __XEN_INTERFACE_VERSION__ 0x00040e00
#endif

#include "exec/cpu-common.h"

Expand All @@ -39,8 +45,6 @@ int xen_is_pirq_msi(uint32_t msi_data);

qemu_irq *xen_interrupt_controller_init(void);

void xenstore_store_pv_console_info(int i, Chardev *chr);

void xen_register_framebuffer(struct MemoryRegion *mr);

#endif /* QEMU_HW_XEN_H */
408 changes: 408 additions & 0 deletions include/hw/xen/xen_backend_ops.h

Large diffs are not rendered by default.

75 changes: 7 additions & 68 deletions include/hw/xen/xen_common.h → include/hw/xen/xen_native.h
@@ -1,5 +1,9 @@
#ifndef QEMU_HW_XEN_COMMON_H
#define QEMU_HW_XEN_COMMON_H
#ifndef QEMU_HW_XEN_NATIVE_H
#define QEMU_HW_XEN_NATIVE_H

#ifdef __XEN_INTERFACE_VERSION__
#error In Xen native files, include xen_native.h before other Xen headers
#endif

/*
* If we have new enough libxenctrl then we do not want/need these compat
Expand All @@ -12,7 +16,6 @@

#include <xenctrl.h>
#include <xenstore.h>
#include "hw/xen/interface/io/xenbus.h"

#include "hw/xen/xen.h"
#include "hw/pci/pci_device.h"
Expand All @@ -28,49 +31,12 @@ extern xc_interface *xen_xc;
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40701

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)
#define xenevtchn_fd(h) xc_evtchn_fd(h)
#define xenevtchn_pending(h) xc_evtchn_pending(h)
#define xenevtchn_notify(h, p) xc_evtchn_notify(h, p)
#define xenevtchn_bind_interdomain(h, d, p) xc_evtchn_bind_interdomain(h, d, p)
#define xenevtchn_unmask(h, p) xc_evtchn_unmask(h, p)
#define xenevtchn_unbind(h, p) xc_evtchn_unbind(h, p)

#define xengnttab_open(l, f) xc_gnttab_open(l, f)
#define xengnttab_close(h) xc_gnttab_close(h)
#define xengnttab_set_max_grants(h, n) xc_gnttab_set_max_grants(h, n)
#define xengnttab_map_grant_ref(h, d, r, p) xc_gnttab_map_grant_ref(h, d, r, p)
#define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n)
#define xengnttab_map_grant_refs(h, c, d, r, p) \
xc_gnttab_map_grant_refs(h, c, d, r, p)
#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \
xc_gnttab_map_domain_grant_refs(h, c, d, r, p)

#define xenforeignmemory_open(l, f) xen_xc
#define xenforeignmemory_close(h)

static inline void *xenforeignmemory_map(xc_interface *h, uint32_t dom,
int prot, size_t pages,
const xen_pfn_t arr[/*pages*/],
int err[/*pages*/])
{
if (err)
return xc_map_foreign_bulk(h, dom, prot, arr, err, pages);
else
return xc_map_foreign_pages(h, dom, prot, arr, pages);
}

#define xenforeignmemory_unmap(h, p, s) munmap(p, s * XC_PAGE_SIZE)

#else /* CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40701 */

#include <xenevtchn.h>
#include <xengnttab.h>
#include <xenforeignmemory.h>

#endif
Expand Down Expand Up @@ -660,31 +626,4 @@ static inline int xen_set_ioreq_server_state(domid_t dom,

#endif

/* Xen before 4.8 */

#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800

struct xengnttab_grant_copy_segment {
union xengnttab_copy_ptr {
void *virt;
struct {
uint32_t ref;
uint16_t offset;
uint16_t domid;
} foreign;
} source, dest;
uint16_t len;
uint16_t flags;
int16_t status;
};

typedef struct xengnttab_grant_copy_segment xengnttab_grant_copy_segment_t;

static inline int xengnttab_grant_copy(xengnttab_handle *xgt, uint32_t count,
xengnttab_grant_copy_segment_t *segs)
{
return -ENOSYS;
}
#endif

#endif /* QEMU_HW_XEN_COMMON_H */
#endif /* QEMU_HW_XEN_NATIVE_H */
6 changes: 4 additions & 2 deletions include/hw/xen/xen_pvdev.h
@@ -1,7 +1,9 @@
#ifndef QEMU_HW_XEN_PVDEV_H
#define QEMU_HW_XEN_PVDEV_H

#include "hw/xen/xen_common.h"
#include "hw/qdev-core.h"
#include "hw/xen/xen_backend_ops.h"

/* ------------------------------------------------------------- */

#define XEN_BUFSIZE 1024
Expand Down Expand Up @@ -38,6 +40,7 @@ struct XenLegacyDevice {
char name[64];
int debug;

struct qemu_xs_watch *watch;
enum xenbus_state be_state;
enum xenbus_state fe_state;
int online;
Expand All @@ -63,7 +66,6 @@ int xenstore_write_int64(const char *base, const char *node, int64_t ival);
char *xenstore_read_str(const char *base, const char *node);
int xenstore_read_int(const char *base, const char *node, int *ival);
int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval);
void xenstore_update(void *unused);

const char *xenbus_strstate(enum xenbus_state state);

Expand Down
4 changes: 4 additions & 0 deletions softmmu/globals.c
Expand Up @@ -65,3 +65,7 @@ bool qemu_uuid_set;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_DISABLED;
bool xen_domid_restrict;
struct evtchn_backend_ops *xen_evtchn_ops;
struct gnttab_backend_ops *xen_gnttab_ops;
struct foreignmem_backend_ops *xen_foreignmem_ops;
struct xenstore_backend_ops *xen_xenstore_ops;
5 changes: 5 additions & 0 deletions target/i386/kvm/xen-emu.c
Expand Up @@ -1406,6 +1406,11 @@ int kvm_xen_soft_reset(void)
return err;
}

err = xen_gnttab_reset();
if (err) {
return err;
}

err = xen_xenstore_reset();
if (err) {
return err;
Expand Down
1 change: 1 addition & 0 deletions tests/unit/meson.build
Expand Up @@ -47,6 +47,7 @@ tests = {
'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'],
'test-qapi-util': [],
'test-interval-tree': [],
'test-xs-node': [qom],
}

if have_system or have_tools
Expand Down
871 changes: 871 additions & 0 deletions tests/unit/test-xs-node.c

Large diffs are not rendered by default.