1c08f5d0eSDavid Woodhouse /* 2c08f5d0eSDavid Woodhouse * QEMU Xen emulation: Shared/overlay pages support 3c08f5d0eSDavid Woodhouse * 4c08f5d0eSDavid Woodhouse * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5c08f5d0eSDavid Woodhouse * 6c08f5d0eSDavid Woodhouse * Authors: David Woodhouse <dwmw2@infradead.org> 7c08f5d0eSDavid Woodhouse * 8c08f5d0eSDavid Woodhouse * This work is licensed under the terms of the GNU GPL, version 2 or later. 9c08f5d0eSDavid Woodhouse * See the COPYING file in the top-level directory. 10c08f5d0eSDavid Woodhouse */ 11c08f5d0eSDavid Woodhouse 12c08f5d0eSDavid Woodhouse #include "qemu/osdep.h" 13c08f5d0eSDavid Woodhouse 14c08f5d0eSDavid Woodhouse #include "qemu/host-utils.h" 15c08f5d0eSDavid Woodhouse #include "qemu/module.h" 16c08f5d0eSDavid Woodhouse #include "qemu/main-loop.h" 17c08f5d0eSDavid Woodhouse #include "qemu/cutils.h" 18c08f5d0eSDavid Woodhouse #include "qapi/error.h" 19c08f5d0eSDavid Woodhouse #include "qom/object.h" 20c08f5d0eSDavid Woodhouse #include "migration/vmstate.h" 21c08f5d0eSDavid Woodhouse 22c08f5d0eSDavid Woodhouse #include "hw/sysbus.h" 23c08f5d0eSDavid Woodhouse #include "hw/xen/xen.h" 24c08f5d0eSDavid Woodhouse #include "xen_overlay.h" 25c08f5d0eSDavid Woodhouse #include "xen_evtchn.h" 26c08f5d0eSDavid Woodhouse #include "xen_xenstore.h" 27c08f5d0eSDavid Woodhouse 28c08f5d0eSDavid Woodhouse #include "sysemu/kvm.h" 29c08f5d0eSDavid Woodhouse #include "sysemu/kvm_xen.h" 30c08f5d0eSDavid Woodhouse 31c08f5d0eSDavid Woodhouse #include "hw/xen/interface/io/xs_wire.h" 32c08f5d0eSDavid Woodhouse #include "hw/xen/interface/event_channel.h" 33c08f5d0eSDavid Woodhouse 34c08f5d0eSDavid Woodhouse #define TYPE_XEN_XENSTORE "xen-xenstore" 35c08f5d0eSDavid Woodhouse OBJECT_DECLARE_SIMPLE_TYPE(XenXenstoreState, XEN_XENSTORE) 36c08f5d0eSDavid Woodhouse 37c08f5d0eSDavid Woodhouse #define XEN_PAGE_SHIFT 12 38c08f5d0eSDavid Woodhouse #define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT) 39c08f5d0eSDavid Woodhouse 40c08f5d0eSDavid Woodhouse #define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t)) 41c08f5d0eSDavid Woodhouse #define ENTRIES_PER_FRAME_V2 (XEN_PAGE_SIZE / sizeof(grant_entry_v2_t)) 42c08f5d0eSDavid Woodhouse 43c08f5d0eSDavid Woodhouse #define XENSTORE_HEADER_SIZE ((unsigned int)sizeof(struct xsd_sockmsg)) 44c08f5d0eSDavid Woodhouse 45c08f5d0eSDavid Woodhouse struct XenXenstoreState { 46c08f5d0eSDavid Woodhouse /*< private >*/ 47c08f5d0eSDavid Woodhouse SysBusDevice busdev; 48c08f5d0eSDavid Woodhouse /*< public >*/ 49c08f5d0eSDavid Woodhouse 50c08f5d0eSDavid Woodhouse MemoryRegion xenstore_page; 51c08f5d0eSDavid Woodhouse struct xenstore_domain_interface *xs; 52c08f5d0eSDavid Woodhouse uint8_t req_data[XENSTORE_HEADER_SIZE + XENSTORE_PAYLOAD_MAX]; 53c08f5d0eSDavid Woodhouse uint8_t rsp_data[XENSTORE_HEADER_SIZE + XENSTORE_PAYLOAD_MAX]; 54c08f5d0eSDavid Woodhouse uint32_t req_offset; 55c08f5d0eSDavid Woodhouse uint32_t rsp_offset; 56c08f5d0eSDavid Woodhouse bool rsp_pending; 57c08f5d0eSDavid Woodhouse bool fatal_error; 58c08f5d0eSDavid Woodhouse 59c08f5d0eSDavid Woodhouse evtchn_port_t guest_port; 60c08f5d0eSDavid Woodhouse evtchn_port_t be_port; 61c08f5d0eSDavid Woodhouse struct xenevtchn_handle *eh; 62c08f5d0eSDavid Woodhouse }; 63c08f5d0eSDavid Woodhouse 64c08f5d0eSDavid Woodhouse struct XenXenstoreState *xen_xenstore_singleton; 65c08f5d0eSDavid Woodhouse 66c08f5d0eSDavid Woodhouse static void xen_xenstore_event(void *opaque); 67c08f5d0eSDavid Woodhouse 68c08f5d0eSDavid Woodhouse static void xen_xenstore_realize(DeviceState *dev, Error **errp) 69c08f5d0eSDavid Woodhouse { 70c08f5d0eSDavid Woodhouse XenXenstoreState *s = XEN_XENSTORE(dev); 71c08f5d0eSDavid Woodhouse 72c08f5d0eSDavid Woodhouse if (xen_mode != XEN_EMULATE) { 73c08f5d0eSDavid Woodhouse error_setg(errp, "Xen xenstore support is for Xen emulation"); 74c08f5d0eSDavid Woodhouse return; 75c08f5d0eSDavid Woodhouse } 76c08f5d0eSDavid Woodhouse memory_region_init_ram(&s->xenstore_page, OBJECT(dev), "xen:xenstore_page", 77c08f5d0eSDavid Woodhouse XEN_PAGE_SIZE, &error_abort); 78c08f5d0eSDavid Woodhouse memory_region_set_enabled(&s->xenstore_page, true); 79c08f5d0eSDavid Woodhouse s->xs = memory_region_get_ram_ptr(&s->xenstore_page); 80c08f5d0eSDavid Woodhouse memset(s->xs, 0, XEN_PAGE_SIZE); 81c08f5d0eSDavid Woodhouse 82c08f5d0eSDavid Woodhouse /* We can't map it this early as KVM isn't ready */ 83c08f5d0eSDavid Woodhouse xen_xenstore_singleton = s; 84c08f5d0eSDavid Woodhouse 85c08f5d0eSDavid Woodhouse s->eh = xen_be_evtchn_open(); 86c08f5d0eSDavid Woodhouse if (!s->eh) { 87c08f5d0eSDavid Woodhouse error_setg(errp, "Xenstore evtchn port init failed"); 88c08f5d0eSDavid Woodhouse return; 89c08f5d0eSDavid Woodhouse } 90c08f5d0eSDavid Woodhouse aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), true, 91c08f5d0eSDavid Woodhouse xen_xenstore_event, NULL, NULL, NULL, s); 92c08f5d0eSDavid Woodhouse } 93c08f5d0eSDavid Woodhouse 94c08f5d0eSDavid Woodhouse static bool xen_xenstore_is_needed(void *opaque) 95c08f5d0eSDavid Woodhouse { 96c08f5d0eSDavid Woodhouse return xen_mode == XEN_EMULATE; 97c08f5d0eSDavid Woodhouse } 98c08f5d0eSDavid Woodhouse 99c08f5d0eSDavid Woodhouse static int xen_xenstore_pre_save(void *opaque) 100c08f5d0eSDavid Woodhouse { 101c08f5d0eSDavid Woodhouse XenXenstoreState *s = opaque; 102c08f5d0eSDavid Woodhouse 103c08f5d0eSDavid Woodhouse if (s->eh) { 104c08f5d0eSDavid Woodhouse s->guest_port = xen_be_evtchn_get_guest_port(s->eh); 105c08f5d0eSDavid Woodhouse } 106c08f5d0eSDavid Woodhouse return 0; 107c08f5d0eSDavid Woodhouse } 108c08f5d0eSDavid Woodhouse 109c08f5d0eSDavid Woodhouse static int xen_xenstore_post_load(void *opaque, int ver) 110c08f5d0eSDavid Woodhouse { 111c08f5d0eSDavid Woodhouse XenXenstoreState *s = opaque; 112c08f5d0eSDavid Woodhouse 113c08f5d0eSDavid Woodhouse /* 114c08f5d0eSDavid Woodhouse * As qemu/dom0, rebind to the guest's port. The Windows drivers may 115c08f5d0eSDavid Woodhouse * unbind the XenStore evtchn and rebind to it, having obtained the 116c08f5d0eSDavid Woodhouse * "remote" port through EVTCHNOP_status. In the case that migration 117c08f5d0eSDavid Woodhouse * occurs while it's unbound, the "remote" port needs to be the same 118c08f5d0eSDavid Woodhouse * as before so that the guest can find it, but should remain unbound. 119c08f5d0eSDavid Woodhouse */ 120c08f5d0eSDavid Woodhouse if (s->guest_port) { 121c08f5d0eSDavid Woodhouse int be_port = xen_be_evtchn_bind_interdomain(s->eh, xen_domid, 122c08f5d0eSDavid Woodhouse s->guest_port); 123c08f5d0eSDavid Woodhouse if (be_port < 0) { 124c08f5d0eSDavid Woodhouse return be_port; 125c08f5d0eSDavid Woodhouse } 126c08f5d0eSDavid Woodhouse s->be_port = be_port; 127c08f5d0eSDavid Woodhouse } 128c08f5d0eSDavid Woodhouse return 0; 129c08f5d0eSDavid Woodhouse } 130c08f5d0eSDavid Woodhouse 131c08f5d0eSDavid Woodhouse static const VMStateDescription xen_xenstore_vmstate = { 132c08f5d0eSDavid Woodhouse .name = "xen_xenstore", 133c08f5d0eSDavid Woodhouse .version_id = 1, 134c08f5d0eSDavid Woodhouse .minimum_version_id = 1, 135c08f5d0eSDavid Woodhouse .needed = xen_xenstore_is_needed, 136c08f5d0eSDavid Woodhouse .pre_save = xen_xenstore_pre_save, 137c08f5d0eSDavid Woodhouse .post_load = xen_xenstore_post_load, 138c08f5d0eSDavid Woodhouse .fields = (VMStateField[]) { 139c08f5d0eSDavid Woodhouse VMSTATE_UINT8_ARRAY(req_data, XenXenstoreState, 140c08f5d0eSDavid Woodhouse sizeof_field(XenXenstoreState, req_data)), 141c08f5d0eSDavid Woodhouse VMSTATE_UINT8_ARRAY(rsp_data, XenXenstoreState, 142c08f5d0eSDavid Woodhouse sizeof_field(XenXenstoreState, rsp_data)), 143c08f5d0eSDavid Woodhouse VMSTATE_UINT32(req_offset, XenXenstoreState), 144c08f5d0eSDavid Woodhouse VMSTATE_UINT32(rsp_offset, XenXenstoreState), 145c08f5d0eSDavid Woodhouse VMSTATE_BOOL(rsp_pending, XenXenstoreState), 146c08f5d0eSDavid Woodhouse VMSTATE_UINT32(guest_port, XenXenstoreState), 147c08f5d0eSDavid Woodhouse VMSTATE_BOOL(fatal_error, XenXenstoreState), 148c08f5d0eSDavid Woodhouse VMSTATE_END_OF_LIST() 149c08f5d0eSDavid Woodhouse } 150c08f5d0eSDavid Woodhouse }; 151c08f5d0eSDavid Woodhouse 152c08f5d0eSDavid Woodhouse static void xen_xenstore_class_init(ObjectClass *klass, void *data) 153c08f5d0eSDavid Woodhouse { 154c08f5d0eSDavid Woodhouse DeviceClass *dc = DEVICE_CLASS(klass); 155c08f5d0eSDavid Woodhouse 156c08f5d0eSDavid Woodhouse dc->realize = xen_xenstore_realize; 157c08f5d0eSDavid Woodhouse dc->vmsd = &xen_xenstore_vmstate; 158c08f5d0eSDavid Woodhouse } 159c08f5d0eSDavid Woodhouse 160c08f5d0eSDavid Woodhouse static const TypeInfo xen_xenstore_info = { 161c08f5d0eSDavid Woodhouse .name = TYPE_XEN_XENSTORE, 162c08f5d0eSDavid Woodhouse .parent = TYPE_SYS_BUS_DEVICE, 163c08f5d0eSDavid Woodhouse .instance_size = sizeof(XenXenstoreState), 164c08f5d0eSDavid Woodhouse .class_init = xen_xenstore_class_init, 165c08f5d0eSDavid Woodhouse }; 166c08f5d0eSDavid Woodhouse 167c08f5d0eSDavid Woodhouse void xen_xenstore_create(void) 168c08f5d0eSDavid Woodhouse { 169c08f5d0eSDavid Woodhouse DeviceState *dev = sysbus_create_simple(TYPE_XEN_XENSTORE, -1, NULL); 170c08f5d0eSDavid Woodhouse 171c08f5d0eSDavid Woodhouse xen_xenstore_singleton = XEN_XENSTORE(dev); 172c08f5d0eSDavid Woodhouse 173c08f5d0eSDavid Woodhouse /* 174c08f5d0eSDavid Woodhouse * Defer the init (xen_xenstore_reset()) until KVM is set up and the 175c08f5d0eSDavid Woodhouse * overlay page can be mapped. 176c08f5d0eSDavid Woodhouse */ 177c08f5d0eSDavid Woodhouse } 178c08f5d0eSDavid Woodhouse 179c08f5d0eSDavid Woodhouse static void xen_xenstore_register_types(void) 180c08f5d0eSDavid Woodhouse { 181c08f5d0eSDavid Woodhouse type_register_static(&xen_xenstore_info); 182c08f5d0eSDavid Woodhouse } 183c08f5d0eSDavid Woodhouse 184c08f5d0eSDavid Woodhouse type_init(xen_xenstore_register_types) 185c08f5d0eSDavid Woodhouse 186c08f5d0eSDavid Woodhouse uint16_t xen_xenstore_get_port(void) 187c08f5d0eSDavid Woodhouse { 188c08f5d0eSDavid Woodhouse XenXenstoreState *s = xen_xenstore_singleton; 189c08f5d0eSDavid Woodhouse if (!s) { 190c08f5d0eSDavid Woodhouse return 0; 191c08f5d0eSDavid Woodhouse } 192c08f5d0eSDavid Woodhouse return s->guest_port; 193c08f5d0eSDavid Woodhouse } 194c08f5d0eSDavid Woodhouse 195*f3341e7bSDavid Woodhouse static bool req_pending(XenXenstoreState *s) 196*f3341e7bSDavid Woodhouse { 197*f3341e7bSDavid Woodhouse struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data; 198*f3341e7bSDavid Woodhouse 199*f3341e7bSDavid Woodhouse return s->req_offset == XENSTORE_HEADER_SIZE + req->len; 200*f3341e7bSDavid Woodhouse } 201*f3341e7bSDavid Woodhouse 202*f3341e7bSDavid Woodhouse static void reset_req(XenXenstoreState *s) 203*f3341e7bSDavid Woodhouse { 204*f3341e7bSDavid Woodhouse memset(s->req_data, 0, sizeof(s->req_data)); 205*f3341e7bSDavid Woodhouse s->req_offset = 0; 206*f3341e7bSDavid Woodhouse } 207*f3341e7bSDavid Woodhouse 208*f3341e7bSDavid Woodhouse static void reset_rsp(XenXenstoreState *s) 209*f3341e7bSDavid Woodhouse { 210*f3341e7bSDavid Woodhouse s->rsp_pending = false; 211*f3341e7bSDavid Woodhouse 212*f3341e7bSDavid Woodhouse memset(s->rsp_data, 0, sizeof(s->rsp_data)); 213*f3341e7bSDavid Woodhouse s->rsp_offset = 0; 214*f3341e7bSDavid Woodhouse } 215*f3341e7bSDavid Woodhouse 216*f3341e7bSDavid Woodhouse static void process_req(XenXenstoreState *s) 217*f3341e7bSDavid Woodhouse { 218*f3341e7bSDavid Woodhouse struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data; 219*f3341e7bSDavid Woodhouse struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data; 220*f3341e7bSDavid Woodhouse const char enosys[] = "ENOSYS"; 221*f3341e7bSDavid Woodhouse 222*f3341e7bSDavid Woodhouse assert(req_pending(s)); 223*f3341e7bSDavid Woodhouse assert(!s->rsp_pending); 224*f3341e7bSDavid Woodhouse 225*f3341e7bSDavid Woodhouse rsp->type = XS_ERROR; 226*f3341e7bSDavid Woodhouse rsp->req_id = req->req_id; 227*f3341e7bSDavid Woodhouse rsp->tx_id = req->tx_id; 228*f3341e7bSDavid Woodhouse rsp->len = sizeof(enosys); 229*f3341e7bSDavid Woodhouse memcpy((void *)&rsp[1], enosys, sizeof(enosys)); 230*f3341e7bSDavid Woodhouse 231*f3341e7bSDavid Woodhouse s->rsp_pending = true; 232*f3341e7bSDavid Woodhouse reset_req(s); 233*f3341e7bSDavid Woodhouse } 234*f3341e7bSDavid Woodhouse 235*f3341e7bSDavid Woodhouse static unsigned int copy_from_ring(XenXenstoreState *s, uint8_t *ptr, 236*f3341e7bSDavid Woodhouse unsigned int len) 237*f3341e7bSDavid Woodhouse { 238*f3341e7bSDavid Woodhouse if (!len) { 239*f3341e7bSDavid Woodhouse return 0; 240*f3341e7bSDavid Woodhouse } 241*f3341e7bSDavid Woodhouse 242*f3341e7bSDavid Woodhouse XENSTORE_RING_IDX prod = qatomic_read(&s->xs->req_prod); 243*f3341e7bSDavid Woodhouse XENSTORE_RING_IDX cons = qatomic_read(&s->xs->req_cons); 244*f3341e7bSDavid Woodhouse unsigned int copied = 0; 245*f3341e7bSDavid Woodhouse 246*f3341e7bSDavid Woodhouse /* Ensure the ring contents don't cross the req_prod access. */ 247*f3341e7bSDavid Woodhouse smp_rmb(); 248*f3341e7bSDavid Woodhouse 249*f3341e7bSDavid Woodhouse while (len) { 250*f3341e7bSDavid Woodhouse unsigned int avail = prod - cons; 251*f3341e7bSDavid Woodhouse unsigned int offset = MASK_XENSTORE_IDX(cons); 252*f3341e7bSDavid Woodhouse unsigned int copylen = avail; 253*f3341e7bSDavid Woodhouse 254*f3341e7bSDavid Woodhouse if (avail > XENSTORE_RING_SIZE) { 255*f3341e7bSDavid Woodhouse error_report("XenStore ring handling error"); 256*f3341e7bSDavid Woodhouse s->fatal_error = true; 257*f3341e7bSDavid Woodhouse break; 258*f3341e7bSDavid Woodhouse } else if (avail == 0) { 259*f3341e7bSDavid Woodhouse break; 260*f3341e7bSDavid Woodhouse } 261*f3341e7bSDavid Woodhouse 262*f3341e7bSDavid Woodhouse if (copylen > len) { 263*f3341e7bSDavid Woodhouse copylen = len; 264*f3341e7bSDavid Woodhouse } 265*f3341e7bSDavid Woodhouse if (copylen > XENSTORE_RING_SIZE - offset) { 266*f3341e7bSDavid Woodhouse copylen = XENSTORE_RING_SIZE - offset; 267*f3341e7bSDavid Woodhouse } 268*f3341e7bSDavid Woodhouse 269*f3341e7bSDavid Woodhouse memcpy(ptr, &s->xs->req[offset], copylen); 270*f3341e7bSDavid Woodhouse copied += copylen; 271*f3341e7bSDavid Woodhouse 272*f3341e7bSDavid Woodhouse ptr += copylen; 273*f3341e7bSDavid Woodhouse len -= copylen; 274*f3341e7bSDavid Woodhouse 275*f3341e7bSDavid Woodhouse cons += copylen; 276*f3341e7bSDavid Woodhouse } 277*f3341e7bSDavid Woodhouse 278*f3341e7bSDavid Woodhouse /* 279*f3341e7bSDavid Woodhouse * Not sure this ever mattered except on Alpha, but this barrier 280*f3341e7bSDavid Woodhouse * is to ensure that the update to req_cons is globally visible 281*f3341e7bSDavid Woodhouse * only after we have consumed all the data from the ring, and we 282*f3341e7bSDavid Woodhouse * don't end up seeing data written to the ring *after* the other 283*f3341e7bSDavid Woodhouse * end sees the update and writes more to the ring. Xen's own 284*f3341e7bSDavid Woodhouse * xenstored has the same barrier here (although with no comment 285*f3341e7bSDavid Woodhouse * at all, obviously, because it's Xen code). 286*f3341e7bSDavid Woodhouse */ 287*f3341e7bSDavid Woodhouse smp_mb(); 288*f3341e7bSDavid Woodhouse 289*f3341e7bSDavid Woodhouse qatomic_set(&s->xs->req_cons, cons); 290*f3341e7bSDavid Woodhouse 291*f3341e7bSDavid Woodhouse return copied; 292*f3341e7bSDavid Woodhouse } 293*f3341e7bSDavid Woodhouse 294*f3341e7bSDavid Woodhouse static unsigned int copy_to_ring(XenXenstoreState *s, uint8_t *ptr, 295*f3341e7bSDavid Woodhouse unsigned int len) 296*f3341e7bSDavid Woodhouse { 297*f3341e7bSDavid Woodhouse if (!len) { 298*f3341e7bSDavid Woodhouse return 0; 299*f3341e7bSDavid Woodhouse } 300*f3341e7bSDavid Woodhouse 301*f3341e7bSDavid Woodhouse XENSTORE_RING_IDX cons = qatomic_read(&s->xs->rsp_cons); 302*f3341e7bSDavid Woodhouse XENSTORE_RING_IDX prod = qatomic_read(&s->xs->rsp_prod); 303*f3341e7bSDavid Woodhouse unsigned int copied = 0; 304*f3341e7bSDavid Woodhouse 305*f3341e7bSDavid Woodhouse /* 306*f3341e7bSDavid Woodhouse * This matches the barrier in copy_to_ring() (or the guest's 307*f3341e7bSDavid Woodhouse * equivalent) betweem writing the data to the ring and updating 308*f3341e7bSDavid Woodhouse * rsp_prod. It protects against the pathological case (which 309*f3341e7bSDavid Woodhouse * again I think never happened except on Alpha) where our 310*f3341e7bSDavid Woodhouse * subsequent writes to the ring could *cross* the read of 311*f3341e7bSDavid Woodhouse * rsp_cons and the guest could see the new data when it was 312*f3341e7bSDavid Woodhouse * intending to read the old. 313*f3341e7bSDavid Woodhouse */ 314*f3341e7bSDavid Woodhouse smp_mb(); 315*f3341e7bSDavid Woodhouse 316*f3341e7bSDavid Woodhouse while (len) { 317*f3341e7bSDavid Woodhouse unsigned int avail = cons + XENSTORE_RING_SIZE - prod; 318*f3341e7bSDavid Woodhouse unsigned int offset = MASK_XENSTORE_IDX(prod); 319*f3341e7bSDavid Woodhouse unsigned int copylen = len; 320*f3341e7bSDavid Woodhouse 321*f3341e7bSDavid Woodhouse if (avail > XENSTORE_RING_SIZE) { 322*f3341e7bSDavid Woodhouse error_report("XenStore ring handling error"); 323*f3341e7bSDavid Woodhouse s->fatal_error = true; 324*f3341e7bSDavid Woodhouse break; 325*f3341e7bSDavid Woodhouse } else if (avail == 0) { 326*f3341e7bSDavid Woodhouse break; 327*f3341e7bSDavid Woodhouse } 328*f3341e7bSDavid Woodhouse 329*f3341e7bSDavid Woodhouse if (copylen > avail) { 330*f3341e7bSDavid Woodhouse copylen = avail; 331*f3341e7bSDavid Woodhouse } 332*f3341e7bSDavid Woodhouse if (copylen > XENSTORE_RING_SIZE - offset) { 333*f3341e7bSDavid Woodhouse copylen = XENSTORE_RING_SIZE - offset; 334*f3341e7bSDavid Woodhouse } 335*f3341e7bSDavid Woodhouse 336*f3341e7bSDavid Woodhouse 337*f3341e7bSDavid Woodhouse memcpy(&s->xs->rsp[offset], ptr, copylen); 338*f3341e7bSDavid Woodhouse copied += copylen; 339*f3341e7bSDavid Woodhouse 340*f3341e7bSDavid Woodhouse ptr += copylen; 341*f3341e7bSDavid Woodhouse len -= copylen; 342*f3341e7bSDavid Woodhouse 343*f3341e7bSDavid Woodhouse prod += copylen; 344*f3341e7bSDavid Woodhouse } 345*f3341e7bSDavid Woodhouse 346*f3341e7bSDavid Woodhouse /* Ensure the ring contents are seen before rsp_prod update. */ 347*f3341e7bSDavid Woodhouse smp_wmb(); 348*f3341e7bSDavid Woodhouse 349*f3341e7bSDavid Woodhouse qatomic_set(&s->xs->rsp_prod, prod); 350*f3341e7bSDavid Woodhouse 351*f3341e7bSDavid Woodhouse return copied; 352*f3341e7bSDavid Woodhouse } 353*f3341e7bSDavid Woodhouse 354*f3341e7bSDavid Woodhouse static unsigned int get_req(XenXenstoreState *s) 355*f3341e7bSDavid Woodhouse { 356*f3341e7bSDavid Woodhouse unsigned int copied = 0; 357*f3341e7bSDavid Woodhouse 358*f3341e7bSDavid Woodhouse if (s->fatal_error) { 359*f3341e7bSDavid Woodhouse return 0; 360*f3341e7bSDavid Woodhouse } 361*f3341e7bSDavid Woodhouse 362*f3341e7bSDavid Woodhouse assert(!req_pending(s)); 363*f3341e7bSDavid Woodhouse 364*f3341e7bSDavid Woodhouse if (s->req_offset < XENSTORE_HEADER_SIZE) { 365*f3341e7bSDavid Woodhouse void *ptr = s->req_data + s->req_offset; 366*f3341e7bSDavid Woodhouse unsigned int len = XENSTORE_HEADER_SIZE; 367*f3341e7bSDavid Woodhouse unsigned int copylen = copy_from_ring(s, ptr, len); 368*f3341e7bSDavid Woodhouse 369*f3341e7bSDavid Woodhouse copied += copylen; 370*f3341e7bSDavid Woodhouse s->req_offset += copylen; 371*f3341e7bSDavid Woodhouse } 372*f3341e7bSDavid Woodhouse 373*f3341e7bSDavid Woodhouse if (s->req_offset >= XENSTORE_HEADER_SIZE) { 374*f3341e7bSDavid Woodhouse struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data; 375*f3341e7bSDavid Woodhouse 376*f3341e7bSDavid Woodhouse if (req->len > (uint32_t)XENSTORE_PAYLOAD_MAX) { 377*f3341e7bSDavid Woodhouse error_report("Illegal XenStore request"); 378*f3341e7bSDavid Woodhouse s->fatal_error = true; 379*f3341e7bSDavid Woodhouse return 0; 380*f3341e7bSDavid Woodhouse } 381*f3341e7bSDavid Woodhouse 382*f3341e7bSDavid Woodhouse void *ptr = s->req_data + s->req_offset; 383*f3341e7bSDavid Woodhouse unsigned int len = XENSTORE_HEADER_SIZE + req->len - s->req_offset; 384*f3341e7bSDavid Woodhouse unsigned int copylen = copy_from_ring(s, ptr, len); 385*f3341e7bSDavid Woodhouse 386*f3341e7bSDavid Woodhouse copied += copylen; 387*f3341e7bSDavid Woodhouse s->req_offset += copylen; 388*f3341e7bSDavid Woodhouse } 389*f3341e7bSDavid Woodhouse 390*f3341e7bSDavid Woodhouse return copied; 391*f3341e7bSDavid Woodhouse } 392*f3341e7bSDavid Woodhouse 393*f3341e7bSDavid Woodhouse static unsigned int put_rsp(XenXenstoreState *s) 394*f3341e7bSDavid Woodhouse { 395*f3341e7bSDavid Woodhouse if (s->fatal_error) { 396*f3341e7bSDavid Woodhouse return 0; 397*f3341e7bSDavid Woodhouse } 398*f3341e7bSDavid Woodhouse 399*f3341e7bSDavid Woodhouse assert(s->rsp_pending); 400*f3341e7bSDavid Woodhouse 401*f3341e7bSDavid Woodhouse struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data; 402*f3341e7bSDavid Woodhouse assert(s->rsp_offset < XENSTORE_HEADER_SIZE + rsp->len); 403*f3341e7bSDavid Woodhouse 404*f3341e7bSDavid Woodhouse void *ptr = s->rsp_data + s->rsp_offset; 405*f3341e7bSDavid Woodhouse unsigned int len = XENSTORE_HEADER_SIZE + rsp->len - s->rsp_offset; 406*f3341e7bSDavid Woodhouse unsigned int copylen = copy_to_ring(s, ptr, len); 407*f3341e7bSDavid Woodhouse 408*f3341e7bSDavid Woodhouse s->rsp_offset += copylen; 409*f3341e7bSDavid Woodhouse 410*f3341e7bSDavid Woodhouse /* Have we produced a complete response? */ 411*f3341e7bSDavid Woodhouse if (s->rsp_offset == XENSTORE_HEADER_SIZE + rsp->len) { 412*f3341e7bSDavid Woodhouse reset_rsp(s); 413*f3341e7bSDavid Woodhouse } 414*f3341e7bSDavid Woodhouse 415*f3341e7bSDavid Woodhouse return copylen; 416*f3341e7bSDavid Woodhouse } 417*f3341e7bSDavid Woodhouse 418c08f5d0eSDavid Woodhouse static void xen_xenstore_event(void *opaque) 419c08f5d0eSDavid Woodhouse { 420c08f5d0eSDavid Woodhouse XenXenstoreState *s = opaque; 421c08f5d0eSDavid Woodhouse evtchn_port_t port = xen_be_evtchn_pending(s->eh); 422*f3341e7bSDavid Woodhouse unsigned int copied_to, copied_from; 423*f3341e7bSDavid Woodhouse bool processed, notify = false; 424*f3341e7bSDavid Woodhouse 425c08f5d0eSDavid Woodhouse if (port != s->be_port) { 426c08f5d0eSDavid Woodhouse return; 427c08f5d0eSDavid Woodhouse } 428*f3341e7bSDavid Woodhouse 429c08f5d0eSDavid Woodhouse /* We know this is a no-op. */ 430c08f5d0eSDavid Woodhouse xen_be_evtchn_unmask(s->eh, port); 431*f3341e7bSDavid Woodhouse 432*f3341e7bSDavid Woodhouse do { 433*f3341e7bSDavid Woodhouse copied_to = copied_from = 0; 434*f3341e7bSDavid Woodhouse processed = false; 435*f3341e7bSDavid Woodhouse 436*f3341e7bSDavid Woodhouse if (s->rsp_pending) { 437*f3341e7bSDavid Woodhouse copied_to = put_rsp(s); 438*f3341e7bSDavid Woodhouse } 439*f3341e7bSDavid Woodhouse 440*f3341e7bSDavid Woodhouse if (!req_pending(s)) { 441*f3341e7bSDavid Woodhouse copied_from = get_req(s); 442*f3341e7bSDavid Woodhouse } 443*f3341e7bSDavid Woodhouse 444*f3341e7bSDavid Woodhouse if (req_pending(s) && !s->rsp_pending) { 445*f3341e7bSDavid Woodhouse process_req(s); 446*f3341e7bSDavid Woodhouse processed = true; 447*f3341e7bSDavid Woodhouse } 448*f3341e7bSDavid Woodhouse 449*f3341e7bSDavid Woodhouse notify |= copied_to || copied_from; 450*f3341e7bSDavid Woodhouse } while (copied_to || copied_from || processed); 451*f3341e7bSDavid Woodhouse 452*f3341e7bSDavid Woodhouse if (notify) { 453c08f5d0eSDavid Woodhouse xen_be_evtchn_notify(s->eh, s->be_port); 454c08f5d0eSDavid Woodhouse } 455*f3341e7bSDavid Woodhouse } 456c08f5d0eSDavid Woodhouse 457c08f5d0eSDavid Woodhouse static void alloc_guest_port(XenXenstoreState *s) 458c08f5d0eSDavid Woodhouse { 459c08f5d0eSDavid Woodhouse struct evtchn_alloc_unbound alloc = { 460c08f5d0eSDavid Woodhouse .dom = DOMID_SELF, 461c08f5d0eSDavid Woodhouse .remote_dom = DOMID_QEMU, 462c08f5d0eSDavid Woodhouse }; 463c08f5d0eSDavid Woodhouse 464c08f5d0eSDavid Woodhouse if (!xen_evtchn_alloc_unbound_op(&alloc)) { 465c08f5d0eSDavid Woodhouse s->guest_port = alloc.port; 466c08f5d0eSDavid Woodhouse } 467c08f5d0eSDavid Woodhouse } 468c08f5d0eSDavid Woodhouse 469c08f5d0eSDavid Woodhouse int xen_xenstore_reset(void) 470c08f5d0eSDavid Woodhouse { 471c08f5d0eSDavid Woodhouse XenXenstoreState *s = xen_xenstore_singleton; 472c08f5d0eSDavid Woodhouse int err; 473c08f5d0eSDavid Woodhouse 474c08f5d0eSDavid Woodhouse if (!s) { 475c08f5d0eSDavid Woodhouse return -ENOTSUP; 476c08f5d0eSDavid Woodhouse } 477c08f5d0eSDavid Woodhouse 478c08f5d0eSDavid Woodhouse s->req_offset = s->rsp_offset = 0; 479c08f5d0eSDavid Woodhouse s->rsp_pending = false; 480c08f5d0eSDavid Woodhouse 481c08f5d0eSDavid Woodhouse if (!memory_region_is_mapped(&s->xenstore_page)) { 482c08f5d0eSDavid Woodhouse uint64_t gpa = XEN_SPECIAL_PFN(XENSTORE) << TARGET_PAGE_BITS; 483c08f5d0eSDavid Woodhouse xen_overlay_do_map_page(&s->xenstore_page, gpa); 484c08f5d0eSDavid Woodhouse } 485c08f5d0eSDavid Woodhouse 486c08f5d0eSDavid Woodhouse alloc_guest_port(s); 487c08f5d0eSDavid Woodhouse 488c08f5d0eSDavid Woodhouse /* 489c08f5d0eSDavid Woodhouse * As qemu/dom0, bind to the guest's port. For incoming migration, this 490c08f5d0eSDavid Woodhouse * will be unbound as the guest's evtchn table is overwritten. We then 491c08f5d0eSDavid Woodhouse * rebind to the correct guest port in xen_xenstore_post_load(). 492c08f5d0eSDavid Woodhouse */ 493c08f5d0eSDavid Woodhouse err = xen_be_evtchn_bind_interdomain(s->eh, xen_domid, s->guest_port); 494c08f5d0eSDavid Woodhouse if (err < 0) { 495c08f5d0eSDavid Woodhouse return err; 496c08f5d0eSDavid Woodhouse } 497c08f5d0eSDavid Woodhouse s->be_port = err; 498c08f5d0eSDavid Woodhouse 499c08f5d0eSDavid Woodhouse return 0; 500c08f5d0eSDavid Woodhouse } 501