xref: /qemu/hw/i386/kvm/xen_xenstore.c (revision f3341e7b91548c38d484285307c23b8f9ce73307)
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