xref: /qemu/hw/i386/kvm/xen_xenstore.c (revision 766804b101d7e452ad85995c231a5c3454f4e25b)
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 
310254c4d1SDavid Woodhouse #include "trace.h"
320254c4d1SDavid Woodhouse 
330254c4d1SDavid Woodhouse #include "xenstore_impl.h"
340254c4d1SDavid Woodhouse 
35c08f5d0eSDavid Woodhouse #include "hw/xen/interface/io/xs_wire.h"
36c08f5d0eSDavid Woodhouse #include "hw/xen/interface/event_channel.h"
37c08f5d0eSDavid Woodhouse 
38c08f5d0eSDavid Woodhouse #define TYPE_XEN_XENSTORE "xen-xenstore"
39c08f5d0eSDavid Woodhouse OBJECT_DECLARE_SIMPLE_TYPE(XenXenstoreState, XEN_XENSTORE)
40c08f5d0eSDavid Woodhouse 
41c08f5d0eSDavid Woodhouse #define XEN_PAGE_SHIFT 12
42c08f5d0eSDavid Woodhouse #define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT)
43c08f5d0eSDavid Woodhouse 
44c08f5d0eSDavid Woodhouse #define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t))
45c08f5d0eSDavid Woodhouse #define ENTRIES_PER_FRAME_V2 (XEN_PAGE_SIZE / sizeof(grant_entry_v2_t))
46c08f5d0eSDavid Woodhouse 
47c08f5d0eSDavid Woodhouse #define XENSTORE_HEADER_SIZE ((unsigned int)sizeof(struct xsd_sockmsg))
48c08f5d0eSDavid Woodhouse 
49c08f5d0eSDavid Woodhouse struct XenXenstoreState {
50c08f5d0eSDavid Woodhouse     /*< private >*/
51c08f5d0eSDavid Woodhouse     SysBusDevice busdev;
52c08f5d0eSDavid Woodhouse     /*< public >*/
53c08f5d0eSDavid Woodhouse 
540254c4d1SDavid Woodhouse     XenstoreImplState *impl;
550254c4d1SDavid Woodhouse     GList *watch_events;
560254c4d1SDavid Woodhouse 
57c08f5d0eSDavid Woodhouse     MemoryRegion xenstore_page;
58c08f5d0eSDavid Woodhouse     struct xenstore_domain_interface *xs;
59c08f5d0eSDavid Woodhouse     uint8_t req_data[XENSTORE_HEADER_SIZE + XENSTORE_PAYLOAD_MAX];
60c08f5d0eSDavid Woodhouse     uint8_t rsp_data[XENSTORE_HEADER_SIZE + XENSTORE_PAYLOAD_MAX];
61c08f5d0eSDavid Woodhouse     uint32_t req_offset;
62c08f5d0eSDavid Woodhouse     uint32_t rsp_offset;
63c08f5d0eSDavid Woodhouse     bool rsp_pending;
64c08f5d0eSDavid Woodhouse     bool fatal_error;
65c08f5d0eSDavid Woodhouse 
66c08f5d0eSDavid Woodhouse     evtchn_port_t guest_port;
67c08f5d0eSDavid Woodhouse     evtchn_port_t be_port;
68c08f5d0eSDavid Woodhouse     struct xenevtchn_handle *eh;
69*766804b1SDavid Woodhouse 
70*766804b1SDavid Woodhouse     uint8_t *impl_state;
71*766804b1SDavid Woodhouse     uint32_t impl_state_size;
72c08f5d0eSDavid Woodhouse };
73c08f5d0eSDavid Woodhouse 
74c08f5d0eSDavid Woodhouse struct XenXenstoreState *xen_xenstore_singleton;
75c08f5d0eSDavid Woodhouse 
76c08f5d0eSDavid Woodhouse static void xen_xenstore_event(void *opaque);
770254c4d1SDavid Woodhouse static void fire_watch_cb(void *opaque, const char *path, const char *token);
78c08f5d0eSDavid Woodhouse 
79c08f5d0eSDavid Woodhouse static void xen_xenstore_realize(DeviceState *dev, Error **errp)
80c08f5d0eSDavid Woodhouse {
81c08f5d0eSDavid Woodhouse     XenXenstoreState *s = XEN_XENSTORE(dev);
82c08f5d0eSDavid Woodhouse 
83c08f5d0eSDavid Woodhouse     if (xen_mode != XEN_EMULATE) {
84c08f5d0eSDavid Woodhouse         error_setg(errp, "Xen xenstore support is for Xen emulation");
85c08f5d0eSDavid Woodhouse         return;
86c08f5d0eSDavid Woodhouse     }
87c08f5d0eSDavid Woodhouse     memory_region_init_ram(&s->xenstore_page, OBJECT(dev), "xen:xenstore_page",
88c08f5d0eSDavid Woodhouse                            XEN_PAGE_SIZE, &error_abort);
89c08f5d0eSDavid Woodhouse     memory_region_set_enabled(&s->xenstore_page, true);
90c08f5d0eSDavid Woodhouse     s->xs = memory_region_get_ram_ptr(&s->xenstore_page);
91c08f5d0eSDavid Woodhouse     memset(s->xs, 0, XEN_PAGE_SIZE);
92c08f5d0eSDavid Woodhouse 
93c08f5d0eSDavid Woodhouse     /* We can't map it this early as KVM isn't ready */
94c08f5d0eSDavid Woodhouse     xen_xenstore_singleton = s;
95c08f5d0eSDavid Woodhouse 
96c08f5d0eSDavid Woodhouse     s->eh = xen_be_evtchn_open();
97c08f5d0eSDavid Woodhouse     if (!s->eh) {
98c08f5d0eSDavid Woodhouse         error_setg(errp, "Xenstore evtchn port init failed");
99c08f5d0eSDavid Woodhouse         return;
100c08f5d0eSDavid Woodhouse     }
101c08f5d0eSDavid Woodhouse     aio_set_fd_handler(qemu_get_aio_context(), xen_be_evtchn_fd(s->eh), true,
102c08f5d0eSDavid Woodhouse                        xen_xenstore_event, NULL, NULL, NULL, s);
1030254c4d1SDavid Woodhouse 
104be1934dfSPaul Durrant     s->impl = xs_impl_create(xen_domid);
105c08f5d0eSDavid Woodhouse }
106c08f5d0eSDavid Woodhouse 
107c08f5d0eSDavid Woodhouse static bool xen_xenstore_is_needed(void *opaque)
108c08f5d0eSDavid Woodhouse {
109c08f5d0eSDavid Woodhouse     return xen_mode == XEN_EMULATE;
110c08f5d0eSDavid Woodhouse }
111c08f5d0eSDavid Woodhouse 
112c08f5d0eSDavid Woodhouse static int xen_xenstore_pre_save(void *opaque)
113c08f5d0eSDavid Woodhouse {
114c08f5d0eSDavid Woodhouse     XenXenstoreState *s = opaque;
115*766804b1SDavid Woodhouse     GByteArray *save;
116c08f5d0eSDavid Woodhouse 
117c08f5d0eSDavid Woodhouse     if (s->eh) {
118c08f5d0eSDavid Woodhouse         s->guest_port = xen_be_evtchn_get_guest_port(s->eh);
119c08f5d0eSDavid Woodhouse     }
120*766804b1SDavid Woodhouse 
121*766804b1SDavid Woodhouse     g_free(s->impl_state);
122*766804b1SDavid Woodhouse     save = xs_impl_serialize(s->impl);
123*766804b1SDavid Woodhouse     s->impl_state = save->data;
124*766804b1SDavid Woodhouse     s->impl_state_size = save->len;
125*766804b1SDavid Woodhouse     g_byte_array_free(save, false);
126*766804b1SDavid Woodhouse 
127c08f5d0eSDavid Woodhouse     return 0;
128c08f5d0eSDavid Woodhouse }
129c08f5d0eSDavid Woodhouse 
130c08f5d0eSDavid Woodhouse static int xen_xenstore_post_load(void *opaque, int ver)
131c08f5d0eSDavid Woodhouse {
132c08f5d0eSDavid Woodhouse     XenXenstoreState *s = opaque;
133*766804b1SDavid Woodhouse     GByteArray *save;
134*766804b1SDavid Woodhouse     int ret;
135c08f5d0eSDavid Woodhouse 
136c08f5d0eSDavid Woodhouse     /*
137c08f5d0eSDavid Woodhouse      * As qemu/dom0, rebind to the guest's port. The Windows drivers may
138c08f5d0eSDavid Woodhouse      * unbind the XenStore evtchn and rebind to it, having obtained the
139c08f5d0eSDavid Woodhouse      * "remote" port through EVTCHNOP_status. In the case that migration
140c08f5d0eSDavid Woodhouse      * occurs while it's unbound, the "remote" port needs to be the same
141c08f5d0eSDavid Woodhouse      * as before so that the guest can find it, but should remain unbound.
142c08f5d0eSDavid Woodhouse      */
143c08f5d0eSDavid Woodhouse     if (s->guest_port) {
144c08f5d0eSDavid Woodhouse         int be_port = xen_be_evtchn_bind_interdomain(s->eh, xen_domid,
145c08f5d0eSDavid Woodhouse                                                      s->guest_port);
146c08f5d0eSDavid Woodhouse         if (be_port < 0) {
147c08f5d0eSDavid Woodhouse             return be_port;
148c08f5d0eSDavid Woodhouse         }
149c08f5d0eSDavid Woodhouse         s->be_port = be_port;
150c08f5d0eSDavid Woodhouse     }
151*766804b1SDavid Woodhouse 
152*766804b1SDavid Woodhouse     save = g_byte_array_new_take(s->impl_state, s->impl_state_size);
153*766804b1SDavid Woodhouse     s->impl_state = NULL;
154*766804b1SDavid Woodhouse     s->impl_state_size = 0;
155*766804b1SDavid Woodhouse 
156*766804b1SDavid Woodhouse     ret = xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s);
157*766804b1SDavid Woodhouse     return ret;
158c08f5d0eSDavid Woodhouse }
159c08f5d0eSDavid Woodhouse 
160c08f5d0eSDavid Woodhouse static const VMStateDescription xen_xenstore_vmstate = {
161c08f5d0eSDavid Woodhouse     .name = "xen_xenstore",
162*766804b1SDavid Woodhouse     .unmigratable = 1, /* The PV back ends don't migrate yet */
163c08f5d0eSDavid Woodhouse     .version_id = 1,
164c08f5d0eSDavid Woodhouse     .minimum_version_id = 1,
165c08f5d0eSDavid Woodhouse     .needed = xen_xenstore_is_needed,
166c08f5d0eSDavid Woodhouse     .pre_save = xen_xenstore_pre_save,
167c08f5d0eSDavid Woodhouse     .post_load = xen_xenstore_post_load,
168c08f5d0eSDavid Woodhouse     .fields = (VMStateField[]) {
169c08f5d0eSDavid Woodhouse         VMSTATE_UINT8_ARRAY(req_data, XenXenstoreState,
170c08f5d0eSDavid Woodhouse                             sizeof_field(XenXenstoreState, req_data)),
171c08f5d0eSDavid Woodhouse         VMSTATE_UINT8_ARRAY(rsp_data, XenXenstoreState,
172c08f5d0eSDavid Woodhouse                             sizeof_field(XenXenstoreState, rsp_data)),
173c08f5d0eSDavid Woodhouse         VMSTATE_UINT32(req_offset, XenXenstoreState),
174c08f5d0eSDavid Woodhouse         VMSTATE_UINT32(rsp_offset, XenXenstoreState),
175c08f5d0eSDavid Woodhouse         VMSTATE_BOOL(rsp_pending, XenXenstoreState),
176c08f5d0eSDavid Woodhouse         VMSTATE_UINT32(guest_port, XenXenstoreState),
177c08f5d0eSDavid Woodhouse         VMSTATE_BOOL(fatal_error, XenXenstoreState),
178*766804b1SDavid Woodhouse         VMSTATE_UINT32(impl_state_size, XenXenstoreState),
179*766804b1SDavid Woodhouse         VMSTATE_VARRAY_UINT32_ALLOC(impl_state, XenXenstoreState,
180*766804b1SDavid Woodhouse                                     impl_state_size, 0,
181*766804b1SDavid Woodhouse                                     vmstate_info_uint8, uint8_t),
182c08f5d0eSDavid Woodhouse         VMSTATE_END_OF_LIST()
183c08f5d0eSDavid Woodhouse     }
184c08f5d0eSDavid Woodhouse };
185c08f5d0eSDavid Woodhouse 
186c08f5d0eSDavid Woodhouse static void xen_xenstore_class_init(ObjectClass *klass, void *data)
187c08f5d0eSDavid Woodhouse {
188c08f5d0eSDavid Woodhouse     DeviceClass *dc = DEVICE_CLASS(klass);
189c08f5d0eSDavid Woodhouse 
190c08f5d0eSDavid Woodhouse     dc->realize = xen_xenstore_realize;
191c08f5d0eSDavid Woodhouse     dc->vmsd = &xen_xenstore_vmstate;
192c08f5d0eSDavid Woodhouse }
193c08f5d0eSDavid Woodhouse 
194c08f5d0eSDavid Woodhouse static const TypeInfo xen_xenstore_info = {
195c08f5d0eSDavid Woodhouse     .name          = TYPE_XEN_XENSTORE,
196c08f5d0eSDavid Woodhouse     .parent        = TYPE_SYS_BUS_DEVICE,
197c08f5d0eSDavid Woodhouse     .instance_size = sizeof(XenXenstoreState),
198c08f5d0eSDavid Woodhouse     .class_init    = xen_xenstore_class_init,
199c08f5d0eSDavid Woodhouse };
200c08f5d0eSDavid Woodhouse 
201c08f5d0eSDavid Woodhouse void xen_xenstore_create(void)
202c08f5d0eSDavid Woodhouse {
203c08f5d0eSDavid Woodhouse     DeviceState *dev = sysbus_create_simple(TYPE_XEN_XENSTORE, -1, NULL);
204c08f5d0eSDavid Woodhouse 
205c08f5d0eSDavid Woodhouse     xen_xenstore_singleton = XEN_XENSTORE(dev);
206c08f5d0eSDavid Woodhouse 
207c08f5d0eSDavid Woodhouse     /*
208c08f5d0eSDavid Woodhouse      * Defer the init (xen_xenstore_reset()) until KVM is set up and the
209c08f5d0eSDavid Woodhouse      * overlay page can be mapped.
210c08f5d0eSDavid Woodhouse      */
211c08f5d0eSDavid Woodhouse }
212c08f5d0eSDavid Woodhouse 
213c08f5d0eSDavid Woodhouse static void xen_xenstore_register_types(void)
214c08f5d0eSDavid Woodhouse {
215c08f5d0eSDavid Woodhouse     type_register_static(&xen_xenstore_info);
216c08f5d0eSDavid Woodhouse }
217c08f5d0eSDavid Woodhouse 
218c08f5d0eSDavid Woodhouse type_init(xen_xenstore_register_types)
219c08f5d0eSDavid Woodhouse 
220c08f5d0eSDavid Woodhouse uint16_t xen_xenstore_get_port(void)
221c08f5d0eSDavid Woodhouse {
222c08f5d0eSDavid Woodhouse     XenXenstoreState *s = xen_xenstore_singleton;
223c08f5d0eSDavid Woodhouse     if (!s) {
224c08f5d0eSDavid Woodhouse         return 0;
225c08f5d0eSDavid Woodhouse     }
226c08f5d0eSDavid Woodhouse     return s->guest_port;
227c08f5d0eSDavid Woodhouse }
228c08f5d0eSDavid Woodhouse 
229f3341e7bSDavid Woodhouse static bool req_pending(XenXenstoreState *s)
230f3341e7bSDavid Woodhouse {
231f3341e7bSDavid Woodhouse     struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data;
232f3341e7bSDavid Woodhouse 
233f3341e7bSDavid Woodhouse     return s->req_offset == XENSTORE_HEADER_SIZE + req->len;
234f3341e7bSDavid Woodhouse }
235f3341e7bSDavid Woodhouse 
236f3341e7bSDavid Woodhouse static void reset_req(XenXenstoreState *s)
237f3341e7bSDavid Woodhouse {
238f3341e7bSDavid Woodhouse     memset(s->req_data, 0, sizeof(s->req_data));
239f3341e7bSDavid Woodhouse     s->req_offset = 0;
240f3341e7bSDavid Woodhouse }
241f3341e7bSDavid Woodhouse 
242f3341e7bSDavid Woodhouse static void reset_rsp(XenXenstoreState *s)
243f3341e7bSDavid Woodhouse {
244f3341e7bSDavid Woodhouse     s->rsp_pending = false;
245f3341e7bSDavid Woodhouse 
246f3341e7bSDavid Woodhouse     memset(s->rsp_data, 0, sizeof(s->rsp_data));
247f3341e7bSDavid Woodhouse     s->rsp_offset = 0;
248f3341e7bSDavid Woodhouse }
249f3341e7bSDavid Woodhouse 
2500254c4d1SDavid Woodhouse static void xs_error(XenXenstoreState *s, unsigned int id,
2510254c4d1SDavid Woodhouse                      xs_transaction_t tx_id, int errnum)
2520254c4d1SDavid Woodhouse {
2530254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
2540254c4d1SDavid Woodhouse     const char *errstr = NULL;
2550254c4d1SDavid Woodhouse 
2560254c4d1SDavid Woodhouse     for (unsigned int i = 0; i < ARRAY_SIZE(xsd_errors); i++) {
2570254c4d1SDavid Woodhouse         struct xsd_errors *xsd_error = &xsd_errors[i];
2580254c4d1SDavid Woodhouse 
2590254c4d1SDavid Woodhouse         if (xsd_error->errnum == errnum) {
2600254c4d1SDavid Woodhouse             errstr = xsd_error->errstring;
2610254c4d1SDavid Woodhouse             break;
2620254c4d1SDavid Woodhouse         }
2630254c4d1SDavid Woodhouse     }
2640254c4d1SDavid Woodhouse     assert(errstr);
2650254c4d1SDavid Woodhouse 
2660254c4d1SDavid Woodhouse     trace_xenstore_error(id, tx_id, errstr);
2670254c4d1SDavid Woodhouse 
2680254c4d1SDavid Woodhouse     rsp->type = XS_ERROR;
2690254c4d1SDavid Woodhouse     rsp->req_id = id;
2700254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
2710254c4d1SDavid Woodhouse     rsp->len = (uint32_t)strlen(errstr) + 1;
2720254c4d1SDavid Woodhouse 
2730254c4d1SDavid Woodhouse     memcpy(&rsp[1], errstr, rsp->len);
2740254c4d1SDavid Woodhouse }
2750254c4d1SDavid Woodhouse 
2760254c4d1SDavid Woodhouse static void xs_ok(XenXenstoreState *s, unsigned int type, unsigned int req_id,
2770254c4d1SDavid Woodhouse                   xs_transaction_t tx_id)
2780254c4d1SDavid Woodhouse {
2790254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
2800254c4d1SDavid Woodhouse     const char *okstr = "OK";
2810254c4d1SDavid Woodhouse 
2820254c4d1SDavid Woodhouse     rsp->type = type;
2830254c4d1SDavid Woodhouse     rsp->req_id = req_id;
2840254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
2850254c4d1SDavid Woodhouse     rsp->len = (uint32_t)strlen(okstr) + 1;
2860254c4d1SDavid Woodhouse 
2870254c4d1SDavid Woodhouse     memcpy(&rsp[1], okstr, rsp->len);
2880254c4d1SDavid Woodhouse }
2890254c4d1SDavid Woodhouse 
2900254c4d1SDavid Woodhouse /*
2910254c4d1SDavid Woodhouse  * The correct request and response formats are documented in xen.git:
2920254c4d1SDavid Woodhouse  * docs/misc/xenstore.txt. A summary is given below for convenience.
2930254c4d1SDavid Woodhouse  * The '|' symbol represents a NUL character.
2940254c4d1SDavid Woodhouse  *
2950254c4d1SDavid Woodhouse  * ---------- Database read, write and permissions operations ----------
2960254c4d1SDavid Woodhouse  *
2970254c4d1SDavid Woodhouse  * READ                    <path>|                 <value|>
2980254c4d1SDavid Woodhouse  * WRITE                   <path>|<value|>
2990254c4d1SDavid Woodhouse  *         Store and read the octet string <value> at <path>.
3000254c4d1SDavid Woodhouse  *         WRITE creates any missing parent paths, with empty values.
3010254c4d1SDavid Woodhouse  *
3020254c4d1SDavid Woodhouse  * MKDIR                   <path>|
3030254c4d1SDavid Woodhouse  *         Ensures that the <path> exists, by necessary by creating
3040254c4d1SDavid Woodhouse  *         it and any missing parents with empty values.  If <path>
3050254c4d1SDavid Woodhouse  *         or any parent already exists, its value is left unchanged.
3060254c4d1SDavid Woodhouse  *
3070254c4d1SDavid Woodhouse  * RM                      <path>|
3080254c4d1SDavid Woodhouse  *         Ensures that the <path> does not exist, by deleting
3090254c4d1SDavid Woodhouse  *         it and all of its children.  It is not an error if <path> does
3100254c4d1SDavid Woodhouse  *         not exist, but it _is_ an error if <path>'s immediate parent
3110254c4d1SDavid Woodhouse  *         does not exist either.
3120254c4d1SDavid Woodhouse  *
3130254c4d1SDavid Woodhouse  * DIRECTORY               <path>|                 <child-leaf-name>|*
3140254c4d1SDavid Woodhouse  *         Gives a list of the immediate children of <path>, as only the
3150254c4d1SDavid Woodhouse  *         leafnames.  The resulting children are each named
3160254c4d1SDavid Woodhouse  *         <path>/<child-leaf-name>.
3170254c4d1SDavid Woodhouse  *
3180254c4d1SDavid Woodhouse  * DIRECTORY_PART          <path>|<offset>         <gencnt>|<child-leaf-name>|*
3190254c4d1SDavid Woodhouse  *         Same as DIRECTORY, but to be used for children lists longer than
3200254c4d1SDavid Woodhouse  *         XENSTORE_PAYLOAD_MAX. Input are <path> and the byte offset into
3210254c4d1SDavid Woodhouse  *         the list of children to return. Return values are the generation
3220254c4d1SDavid Woodhouse  *         count <gencnt> of the node (to be used to ensure the node hasn't
3230254c4d1SDavid Woodhouse  *         changed between two reads: <gencnt> being the same for multiple
3240254c4d1SDavid Woodhouse  *         reads guarantees the node hasn't changed) and the list of children
3250254c4d1SDavid Woodhouse  *         starting at the specified <offset> of the complete list.
3260254c4d1SDavid Woodhouse  *
3270254c4d1SDavid Woodhouse  * GET_PERMS               <path>|                 <perm-as-string>|+
3280254c4d1SDavid Woodhouse  * SET_PERMS               <path>|<perm-as-string>|+?
3290254c4d1SDavid Woodhouse  *         <perm-as-string> is one of the following
3300254c4d1SDavid Woodhouse  *                 w<domid>        write only
3310254c4d1SDavid Woodhouse  *                 r<domid>        read only
3320254c4d1SDavid Woodhouse  *                 b<domid>        both read and write
3330254c4d1SDavid Woodhouse  *                 n<domid>        no access
3340254c4d1SDavid Woodhouse  *         See https://wiki.xen.org/wiki/XenBus section
3350254c4d1SDavid Woodhouse  *         `Permissions' for details of the permissions system.
3360254c4d1SDavid Woodhouse  *         It is possible to set permissions for the special watch paths
3370254c4d1SDavid Woodhouse  *         "@introduceDomain" and "@releaseDomain" to enable receiving those
3380254c4d1SDavid Woodhouse  *         watches in unprivileged domains.
3390254c4d1SDavid Woodhouse  *
3400254c4d1SDavid Woodhouse  * ---------- Watches ----------
3410254c4d1SDavid Woodhouse  *
3420254c4d1SDavid Woodhouse  * WATCH                   <wpath>|<token>|?
3430254c4d1SDavid Woodhouse  *         Adds a watch.
3440254c4d1SDavid Woodhouse  *
3450254c4d1SDavid Woodhouse  *         When a <path> is modified (including path creation, removal,
3460254c4d1SDavid Woodhouse  *         contents change or permissions change) this generates an event
3470254c4d1SDavid Woodhouse  *         on the changed <path>.  Changes made in transactions cause an
3480254c4d1SDavid Woodhouse  *         event only if and when committed.  Each occurring event is
3490254c4d1SDavid Woodhouse  *         matched against all the watches currently set up, and each
3500254c4d1SDavid Woodhouse  *         matching watch results in a WATCH_EVENT message (see below).
3510254c4d1SDavid Woodhouse  *
3520254c4d1SDavid Woodhouse  *         The event's path matches the watch's <wpath> if it is an child
3530254c4d1SDavid Woodhouse  *         of <wpath>.
3540254c4d1SDavid Woodhouse  *
3550254c4d1SDavid Woodhouse  *         <wpath> can be a <path> to watch or @<wspecial>.  In the
3560254c4d1SDavid Woodhouse  *         latter case <wspecial> may have any syntax but it matches
3570254c4d1SDavid Woodhouse  *         (according to the rules above) only the following special
3580254c4d1SDavid Woodhouse  *         events which are invented by xenstored:
3590254c4d1SDavid Woodhouse  *             @introduceDomain    occurs on INTRODUCE
3600254c4d1SDavid Woodhouse  *             @releaseDomain      occurs on any domain crash or
3610254c4d1SDavid Woodhouse  *                                 shutdown, and also on RELEASE
3620254c4d1SDavid Woodhouse  *                                 and domain destruction
3630254c4d1SDavid Woodhouse  *         <wspecial> events are sent to privileged callers or explicitly
3640254c4d1SDavid Woodhouse  *         via SET_PERMS enabled domains only.
3650254c4d1SDavid Woodhouse  *
3660254c4d1SDavid Woodhouse  *         When a watch is first set up it is triggered once straight
3670254c4d1SDavid Woodhouse  *         away, with <path> equal to <wpath>.  Watches may be triggered
3680254c4d1SDavid Woodhouse  *         spuriously.  The tx_id in a WATCH request is ignored.
3690254c4d1SDavid Woodhouse  *
3700254c4d1SDavid Woodhouse  *         Watches are supposed to be restricted by the permissions
3710254c4d1SDavid Woodhouse  *         system but in practice the implementation is imperfect.
3720254c4d1SDavid Woodhouse  *         Applications should not rely on being sent a notification for
3730254c4d1SDavid Woodhouse  *         paths that they cannot read; however, an application may rely
3740254c4d1SDavid Woodhouse  *         on being sent a watch when a path which it _is_ able to read
3750254c4d1SDavid Woodhouse  *         is deleted even if that leaves only a nonexistent unreadable
3760254c4d1SDavid Woodhouse  *         parent.  A notification may omitted if a node's permissions
3770254c4d1SDavid Woodhouse  *         are changed so as to make it unreadable, in which case future
3780254c4d1SDavid Woodhouse  *         notifications may be suppressed (and if the node is later made
3790254c4d1SDavid Woodhouse  *         readable, some notifications may have been lost).
3800254c4d1SDavid Woodhouse  *
3810254c4d1SDavid Woodhouse  * WATCH_EVENT                                     <epath>|<token>|
3820254c4d1SDavid Woodhouse  *         Unsolicited `reply' generated for matching modification events
3830254c4d1SDavid Woodhouse  *         as described above.  req_id and tx_id are both 0.
3840254c4d1SDavid Woodhouse  *
3850254c4d1SDavid Woodhouse  *         <epath> is the event's path, ie the actual path that was
3860254c4d1SDavid Woodhouse  *         modified; however if the event was the recursive removal of an
3870254c4d1SDavid Woodhouse  *         parent of <wpath>, <epath> is just
3880254c4d1SDavid Woodhouse  *         <wpath> (rather than the actual path which was removed).  So
3890254c4d1SDavid Woodhouse  *         <epath> is a child of <wpath>, regardless.
3900254c4d1SDavid Woodhouse  *
3910254c4d1SDavid Woodhouse  *         Iff <wpath> for the watch was specified as a relative pathname,
3920254c4d1SDavid Woodhouse  *         the <epath> path will also be relative (with the same base,
3930254c4d1SDavid Woodhouse  *         obviously).
3940254c4d1SDavid Woodhouse  *
3950254c4d1SDavid Woodhouse  * UNWATCH                 <wpath>|<token>|?
3960254c4d1SDavid Woodhouse  *
3970254c4d1SDavid Woodhouse  * RESET_WATCHES           |
3980254c4d1SDavid Woodhouse  *         Reset all watches and transactions of the caller.
3990254c4d1SDavid Woodhouse  *
4000254c4d1SDavid Woodhouse  * ---------- Transactions ----------
4010254c4d1SDavid Woodhouse  *
4020254c4d1SDavid Woodhouse  * TRANSACTION_START       |                       <transid>|
4030254c4d1SDavid Woodhouse  *         <transid> is an opaque uint32_t allocated by xenstored
4040254c4d1SDavid Woodhouse  *         represented as unsigned decimal.  After this, transaction may
4050254c4d1SDavid Woodhouse  *         be referenced by using <transid> (as 32-bit binary) in the
4060254c4d1SDavid Woodhouse  *         tx_id request header field.  When transaction is started whole
4070254c4d1SDavid Woodhouse  *         db is copied; reads and writes happen on the copy.
4080254c4d1SDavid Woodhouse  *         It is not legal to send non-0 tx_id in TRANSACTION_START.
4090254c4d1SDavid Woodhouse  *
4100254c4d1SDavid Woodhouse  * TRANSACTION_END         T|
4110254c4d1SDavid Woodhouse  * TRANSACTION_END         F|
4120254c4d1SDavid Woodhouse  *         tx_id must refer to existing transaction.  After this
4130254c4d1SDavid Woodhouse  *         request the tx_id is no longer valid and may be reused by
4140254c4d1SDavid Woodhouse  *         xenstore.  If F, the transaction is discarded.  If T,
4150254c4d1SDavid Woodhouse  *         it is committed: if there were any other intervening writes
4160254c4d1SDavid Woodhouse  *         then our END gets get EAGAIN.
4170254c4d1SDavid Woodhouse  *
4180254c4d1SDavid Woodhouse  *         The plan is that in the future only intervening `conflicting'
4190254c4d1SDavid Woodhouse  *         writes cause EAGAIN, meaning only writes or other commits
4200254c4d1SDavid Woodhouse  *         which changed paths which were read or written in the
4210254c4d1SDavid Woodhouse  *         transaction at hand.
4220254c4d1SDavid Woodhouse  *
4230254c4d1SDavid Woodhouse  */
4240254c4d1SDavid Woodhouse 
4250254c4d1SDavid Woodhouse static void xs_read(XenXenstoreState *s, unsigned int req_id,
4260254c4d1SDavid Woodhouse                     xs_transaction_t tx_id, uint8_t *req_data, unsigned int len)
4270254c4d1SDavid Woodhouse {
4280254c4d1SDavid Woodhouse     const char *path = (const char *)req_data;
4290254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
4300254c4d1SDavid Woodhouse     uint8_t *rsp_data = (uint8_t *)&rsp[1];
4310254c4d1SDavid Woodhouse     g_autoptr(GByteArray) data = g_byte_array_new();
4320254c4d1SDavid Woodhouse     int err;
4330254c4d1SDavid Woodhouse 
4340254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
4350254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
4360254c4d1SDavid Woodhouse         return;
4370254c4d1SDavid Woodhouse     }
4380254c4d1SDavid Woodhouse 
4390254c4d1SDavid Woodhouse     trace_xenstore_read(tx_id, path);
4400254c4d1SDavid Woodhouse     err = xs_impl_read(s->impl, xen_domid, tx_id, path, data);
4410254c4d1SDavid Woodhouse     if (err) {
4420254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
4430254c4d1SDavid Woodhouse         return;
4440254c4d1SDavid Woodhouse     }
4450254c4d1SDavid Woodhouse 
4460254c4d1SDavid Woodhouse     rsp->type = XS_READ;
4470254c4d1SDavid Woodhouse     rsp->req_id = req_id;
4480254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
4490254c4d1SDavid Woodhouse     rsp->len = 0;
4500254c4d1SDavid Woodhouse 
4510254c4d1SDavid Woodhouse     len = data->len;
4520254c4d1SDavid Woodhouse     if (len > XENSTORE_PAYLOAD_MAX) {
4530254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, E2BIG);
4540254c4d1SDavid Woodhouse         return;
4550254c4d1SDavid Woodhouse     }
4560254c4d1SDavid Woodhouse 
4570254c4d1SDavid Woodhouse     memcpy(&rsp_data[rsp->len], data->data, len);
4580254c4d1SDavid Woodhouse     rsp->len += len;
4590254c4d1SDavid Woodhouse }
4600254c4d1SDavid Woodhouse 
4610254c4d1SDavid Woodhouse static void xs_write(XenXenstoreState *s, unsigned int req_id,
4620254c4d1SDavid Woodhouse                      xs_transaction_t tx_id, uint8_t *req_data,
4630254c4d1SDavid Woodhouse                      unsigned int len)
4640254c4d1SDavid Woodhouse {
4650254c4d1SDavid Woodhouse     g_autoptr(GByteArray) data = g_byte_array_new();
4660254c4d1SDavid Woodhouse     const char *path;
4670254c4d1SDavid Woodhouse     int err;
4680254c4d1SDavid Woodhouse 
4690254c4d1SDavid Woodhouse     if (len == 0) {
4700254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
4710254c4d1SDavid Woodhouse         return;
4720254c4d1SDavid Woodhouse     }
4730254c4d1SDavid Woodhouse 
4740254c4d1SDavid Woodhouse     path = (const char *)req_data;
4750254c4d1SDavid Woodhouse 
4760254c4d1SDavid Woodhouse     while (len--) {
4770254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
4780254c4d1SDavid Woodhouse             break;
4790254c4d1SDavid Woodhouse         }
4800254c4d1SDavid Woodhouse         if (len == 0) {
4810254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
4820254c4d1SDavid Woodhouse             return;
4830254c4d1SDavid Woodhouse         }
4840254c4d1SDavid Woodhouse     }
4850254c4d1SDavid Woodhouse 
4860254c4d1SDavid Woodhouse     g_byte_array_append(data, req_data, len);
4870254c4d1SDavid Woodhouse 
4880254c4d1SDavid Woodhouse     trace_xenstore_write(tx_id, path);
4890254c4d1SDavid Woodhouse     err = xs_impl_write(s->impl, xen_domid, tx_id, path, data);
4900254c4d1SDavid Woodhouse     if (err) {
4910254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
4920254c4d1SDavid Woodhouse         return;
4930254c4d1SDavid Woodhouse     }
4940254c4d1SDavid Woodhouse 
4950254c4d1SDavid Woodhouse     xs_ok(s, XS_WRITE, req_id, tx_id);
4960254c4d1SDavid Woodhouse }
4970254c4d1SDavid Woodhouse 
4980254c4d1SDavid Woodhouse static void xs_mkdir(XenXenstoreState *s, unsigned int req_id,
4990254c4d1SDavid Woodhouse                      xs_transaction_t tx_id, uint8_t *req_data,
5000254c4d1SDavid Woodhouse                      unsigned int len)
5010254c4d1SDavid Woodhouse {
5020254c4d1SDavid Woodhouse     g_autoptr(GByteArray) data = g_byte_array_new();
5030254c4d1SDavid Woodhouse     const char *path;
5040254c4d1SDavid Woodhouse     int err;
5050254c4d1SDavid Woodhouse 
5060254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
5070254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
5080254c4d1SDavid Woodhouse         return;
5090254c4d1SDavid Woodhouse     }
5100254c4d1SDavid Woodhouse 
5110254c4d1SDavid Woodhouse     path = (const char *)req_data;
5120254c4d1SDavid Woodhouse 
5130254c4d1SDavid Woodhouse     trace_xenstore_mkdir(tx_id, path);
5140254c4d1SDavid Woodhouse     err = xs_impl_read(s->impl, xen_domid, tx_id, path, data);
5150254c4d1SDavid Woodhouse     if (err == ENOENT) {
5160254c4d1SDavid Woodhouse         err = xs_impl_write(s->impl, xen_domid, tx_id, path, data);
5170254c4d1SDavid Woodhouse     }
5180254c4d1SDavid Woodhouse 
5190254c4d1SDavid Woodhouse     if (!err) {
5200254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
5210254c4d1SDavid Woodhouse         return;
5220254c4d1SDavid Woodhouse     }
5230254c4d1SDavid Woodhouse 
5240254c4d1SDavid Woodhouse     xs_ok(s, XS_MKDIR, req_id, tx_id);
5250254c4d1SDavid Woodhouse }
5260254c4d1SDavid Woodhouse 
5270254c4d1SDavid Woodhouse static void xs_append_strings(XenXenstoreState *s, struct xsd_sockmsg *rsp,
5280254c4d1SDavid Woodhouse                               GList *strings, unsigned int start, bool truncate)
5290254c4d1SDavid Woodhouse {
5300254c4d1SDavid Woodhouse     uint8_t *rsp_data = (uint8_t *)&rsp[1];
5310254c4d1SDavid Woodhouse     GList *l;
5320254c4d1SDavid Woodhouse 
5330254c4d1SDavid Woodhouse     for (l = strings; l; l = l->next) {
5340254c4d1SDavid Woodhouse         size_t len = strlen(l->data) + 1; /* Including the NUL termination */
5350254c4d1SDavid Woodhouse         char *str = l->data;
5360254c4d1SDavid Woodhouse 
5370254c4d1SDavid Woodhouse         if (rsp->len + len > XENSTORE_PAYLOAD_MAX) {
5380254c4d1SDavid Woodhouse             if (truncate) {
5390254c4d1SDavid Woodhouse                 len = XENSTORE_PAYLOAD_MAX - rsp->len;
5400254c4d1SDavid Woodhouse                 if (!len) {
5410254c4d1SDavid Woodhouse                     return;
5420254c4d1SDavid Woodhouse                 }
5430254c4d1SDavid Woodhouse             } else {
5440254c4d1SDavid Woodhouse                 xs_error(s, rsp->req_id, rsp->tx_id, E2BIG);
5450254c4d1SDavid Woodhouse                 return;
5460254c4d1SDavid Woodhouse             }
5470254c4d1SDavid Woodhouse         }
5480254c4d1SDavid Woodhouse 
5490254c4d1SDavid Woodhouse         if (start) {
5500254c4d1SDavid Woodhouse             if (start >= len) {
5510254c4d1SDavid Woodhouse                 start -= len;
5520254c4d1SDavid Woodhouse                 continue;
5530254c4d1SDavid Woodhouse             }
5540254c4d1SDavid Woodhouse 
5550254c4d1SDavid Woodhouse             str += start;
5560254c4d1SDavid Woodhouse             len -= start;
5570254c4d1SDavid Woodhouse             start = 0;
5580254c4d1SDavid Woodhouse         }
5590254c4d1SDavid Woodhouse 
5600254c4d1SDavid Woodhouse         memcpy(&rsp_data[rsp->len], str, len);
5610254c4d1SDavid Woodhouse         rsp->len += len;
5620254c4d1SDavid Woodhouse     }
5630254c4d1SDavid Woodhouse     /* XS_DIRECTORY_PART wants an extra NUL to indicate the end */
5640254c4d1SDavid Woodhouse     if (truncate && rsp->len < XENSTORE_PAYLOAD_MAX) {
5650254c4d1SDavid Woodhouse         rsp_data[rsp->len++] = '\0';
5660254c4d1SDavid Woodhouse     }
5670254c4d1SDavid Woodhouse }
5680254c4d1SDavid Woodhouse 
5690254c4d1SDavid Woodhouse static void xs_directory(XenXenstoreState *s, unsigned int req_id,
5700254c4d1SDavid Woodhouse                          xs_transaction_t tx_id, uint8_t *req_data,
5710254c4d1SDavid Woodhouse                          unsigned int len)
5720254c4d1SDavid Woodhouse {
5730254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
5740254c4d1SDavid Woodhouse     GList *items = NULL;
5750254c4d1SDavid Woodhouse     const char *path;
5760254c4d1SDavid Woodhouse     int err;
5770254c4d1SDavid Woodhouse 
5780254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
5790254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
5800254c4d1SDavid Woodhouse         return;
5810254c4d1SDavid Woodhouse     }
5820254c4d1SDavid Woodhouse 
5830254c4d1SDavid Woodhouse     path = (const char *)req_data;
5840254c4d1SDavid Woodhouse 
5850254c4d1SDavid Woodhouse     trace_xenstore_directory(tx_id, path);
5860254c4d1SDavid Woodhouse     err = xs_impl_directory(s->impl, xen_domid, tx_id, path, NULL, &items);
5870254c4d1SDavid Woodhouse     if (err != 0) {
5880254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
5890254c4d1SDavid Woodhouse         return;
5900254c4d1SDavid Woodhouse     }
5910254c4d1SDavid Woodhouse 
5920254c4d1SDavid Woodhouse     rsp->type = XS_DIRECTORY;
5930254c4d1SDavid Woodhouse     rsp->req_id = req_id;
5940254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
5950254c4d1SDavid Woodhouse     rsp->len = 0;
5960254c4d1SDavid Woodhouse 
5970254c4d1SDavid Woodhouse     xs_append_strings(s, rsp, items, 0, false);
5980254c4d1SDavid Woodhouse 
5990254c4d1SDavid Woodhouse     g_list_free_full(items, g_free);
6000254c4d1SDavid Woodhouse }
6010254c4d1SDavid Woodhouse 
6020254c4d1SDavid Woodhouse static void xs_directory_part(XenXenstoreState *s, unsigned int req_id,
6030254c4d1SDavid Woodhouse                               xs_transaction_t tx_id, uint8_t *req_data,
6040254c4d1SDavid Woodhouse                               unsigned int len)
6050254c4d1SDavid Woodhouse {
6060254c4d1SDavid Woodhouse     const char *offset_str, *path = (const char *)req_data;
6070254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
6080254c4d1SDavid Woodhouse     char *rsp_data = (char *)&rsp[1];
6090254c4d1SDavid Woodhouse     uint64_t gencnt = 0;
6100254c4d1SDavid Woodhouse     unsigned int offset;
6110254c4d1SDavid Woodhouse     GList *items = NULL;
6120254c4d1SDavid Woodhouse     int err;
6130254c4d1SDavid Woodhouse 
6140254c4d1SDavid Woodhouse     if (len == 0) {
6150254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
6160254c4d1SDavid Woodhouse         return;
6170254c4d1SDavid Woodhouse     }
6180254c4d1SDavid Woodhouse 
6190254c4d1SDavid Woodhouse     while (len--) {
6200254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
6210254c4d1SDavid Woodhouse             break;
6220254c4d1SDavid Woodhouse         }
6230254c4d1SDavid Woodhouse         if (len == 0) {
6240254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
6250254c4d1SDavid Woodhouse             return;
6260254c4d1SDavid Woodhouse         }
6270254c4d1SDavid Woodhouse     }
6280254c4d1SDavid Woodhouse 
6290254c4d1SDavid Woodhouse     offset_str = (const char *)req_data;
6300254c4d1SDavid Woodhouse     while (len--) {
6310254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
6320254c4d1SDavid Woodhouse             break;
6330254c4d1SDavid Woodhouse         }
6340254c4d1SDavid Woodhouse         if (len == 0) {
6350254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
6360254c4d1SDavid Woodhouse             return;
6370254c4d1SDavid Woodhouse         }
6380254c4d1SDavid Woodhouse     }
6390254c4d1SDavid Woodhouse 
6400254c4d1SDavid Woodhouse     if (len) {
6410254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
6420254c4d1SDavid Woodhouse         return;
6430254c4d1SDavid Woodhouse     }
6440254c4d1SDavid Woodhouse 
6450254c4d1SDavid Woodhouse     if (qemu_strtoui(offset_str, NULL, 10, &offset) < 0) {
6460254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
6470254c4d1SDavid Woodhouse         return;
6480254c4d1SDavid Woodhouse     }
6490254c4d1SDavid Woodhouse 
6500254c4d1SDavid Woodhouse     trace_xenstore_directory_part(tx_id, path, offset);
6510254c4d1SDavid Woodhouse     err = xs_impl_directory(s->impl, xen_domid, tx_id, path, &gencnt, &items);
6520254c4d1SDavid Woodhouse     if (err != 0) {
6530254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
6540254c4d1SDavid Woodhouse         return;
6550254c4d1SDavid Woodhouse     }
6560254c4d1SDavid Woodhouse 
6570254c4d1SDavid Woodhouse     rsp->type = XS_DIRECTORY_PART;
6580254c4d1SDavid Woodhouse     rsp->req_id = req_id;
6590254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
6600254c4d1SDavid Woodhouse     rsp->len = snprintf(rsp_data, XENSTORE_PAYLOAD_MAX, "%" PRIu64, gencnt) + 1;
6610254c4d1SDavid Woodhouse 
6620254c4d1SDavid Woodhouse     xs_append_strings(s, rsp, items, offset, true);
6630254c4d1SDavid Woodhouse 
6640254c4d1SDavid Woodhouse     g_list_free_full(items, g_free);
6650254c4d1SDavid Woodhouse }
6660254c4d1SDavid Woodhouse 
6670254c4d1SDavid Woodhouse static void xs_transaction_start(XenXenstoreState *s, unsigned int req_id,
6680254c4d1SDavid Woodhouse                                  xs_transaction_t tx_id, uint8_t *req_data,
6690254c4d1SDavid Woodhouse                                  unsigned int len)
6700254c4d1SDavid Woodhouse {
6710254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
6720254c4d1SDavid Woodhouse     char *rsp_data = (char *)&rsp[1];
6730254c4d1SDavid Woodhouse     int err;
6740254c4d1SDavid Woodhouse 
6750254c4d1SDavid Woodhouse     if (len != 1 || req_data[0] != '\0') {
6760254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
6770254c4d1SDavid Woodhouse         return;
6780254c4d1SDavid Woodhouse     }
6790254c4d1SDavid Woodhouse 
6800254c4d1SDavid Woodhouse     rsp->type = XS_TRANSACTION_START;
6810254c4d1SDavid Woodhouse     rsp->req_id = req_id;
6820254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
6830254c4d1SDavid Woodhouse     rsp->len = 0;
6840254c4d1SDavid Woodhouse 
6850254c4d1SDavid Woodhouse     err = xs_impl_transaction_start(s->impl, xen_domid, &tx_id);
6860254c4d1SDavid Woodhouse     if (err) {
6870254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
6880254c4d1SDavid Woodhouse         return;
6890254c4d1SDavid Woodhouse     }
6900254c4d1SDavid Woodhouse 
6910254c4d1SDavid Woodhouse     trace_xenstore_transaction_start(tx_id);
6920254c4d1SDavid Woodhouse 
6930254c4d1SDavid Woodhouse     rsp->len = snprintf(rsp_data, XENSTORE_PAYLOAD_MAX, "%u", tx_id);
6940254c4d1SDavid Woodhouse     assert(rsp->len < XENSTORE_PAYLOAD_MAX);
6950254c4d1SDavid Woodhouse     rsp->len++;
6960254c4d1SDavid Woodhouse }
6970254c4d1SDavid Woodhouse 
6980254c4d1SDavid Woodhouse static void xs_transaction_end(XenXenstoreState *s, unsigned int req_id,
6990254c4d1SDavid Woodhouse                                xs_transaction_t tx_id, uint8_t *req_data,
7000254c4d1SDavid Woodhouse                                unsigned int len)
7010254c4d1SDavid Woodhouse {
7020254c4d1SDavid Woodhouse     bool commit;
7030254c4d1SDavid Woodhouse     int err;
7040254c4d1SDavid Woodhouse 
7050254c4d1SDavid Woodhouse     if (len != 2 || req_data[1] != '\0') {
7060254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
7070254c4d1SDavid Woodhouse         return;
7080254c4d1SDavid Woodhouse     }
7090254c4d1SDavid Woodhouse 
7100254c4d1SDavid Woodhouse     switch (req_data[0]) {
7110254c4d1SDavid Woodhouse     case 'T':
7120254c4d1SDavid Woodhouse         commit = true;
7130254c4d1SDavid Woodhouse         break;
7140254c4d1SDavid Woodhouse     case 'F':
7150254c4d1SDavid Woodhouse         commit = false;
7160254c4d1SDavid Woodhouse         break;
7170254c4d1SDavid Woodhouse     default:
7180254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
7190254c4d1SDavid Woodhouse         return;
7200254c4d1SDavid Woodhouse     }
7210254c4d1SDavid Woodhouse 
7220254c4d1SDavid Woodhouse     trace_xenstore_transaction_end(tx_id, commit);
7230254c4d1SDavid Woodhouse     err = xs_impl_transaction_end(s->impl, xen_domid, tx_id, commit);
7240254c4d1SDavid Woodhouse     if (err) {
7250254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
7260254c4d1SDavid Woodhouse         return;
7270254c4d1SDavid Woodhouse     }
7280254c4d1SDavid Woodhouse 
7290254c4d1SDavid Woodhouse     xs_ok(s, XS_TRANSACTION_END, req_id, tx_id);
7300254c4d1SDavid Woodhouse }
7310254c4d1SDavid Woodhouse 
7320254c4d1SDavid Woodhouse static void xs_rm(XenXenstoreState *s, unsigned int req_id,
7330254c4d1SDavid Woodhouse                   xs_transaction_t tx_id, uint8_t *req_data, unsigned int len)
7340254c4d1SDavid Woodhouse {
7350254c4d1SDavid Woodhouse     const char *path = (const char *)req_data;
7360254c4d1SDavid Woodhouse     int err;
7370254c4d1SDavid Woodhouse 
7380254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
7390254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
7400254c4d1SDavid Woodhouse         return;
7410254c4d1SDavid Woodhouse     }
7420254c4d1SDavid Woodhouse 
7430254c4d1SDavid Woodhouse     trace_xenstore_rm(tx_id, path);
7440254c4d1SDavid Woodhouse     err = xs_impl_rm(s->impl, xen_domid, tx_id, path);
7450254c4d1SDavid Woodhouse     if (err) {
7460254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
7470254c4d1SDavid Woodhouse         return;
7480254c4d1SDavid Woodhouse     }
7490254c4d1SDavid Woodhouse 
7500254c4d1SDavid Woodhouse     xs_ok(s, XS_RM, req_id, tx_id);
7510254c4d1SDavid Woodhouse }
7520254c4d1SDavid Woodhouse 
7530254c4d1SDavid Woodhouse static void xs_get_perms(XenXenstoreState *s, unsigned int req_id,
7540254c4d1SDavid Woodhouse                          xs_transaction_t tx_id, uint8_t *req_data,
7550254c4d1SDavid Woodhouse                          unsigned int len)
7560254c4d1SDavid Woodhouse {
7570254c4d1SDavid Woodhouse     const char *path = (const char *)req_data;
7580254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
7590254c4d1SDavid Woodhouse     GList *perms = NULL;
7600254c4d1SDavid Woodhouse     int err;
7610254c4d1SDavid Woodhouse 
7620254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
7630254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
7640254c4d1SDavid Woodhouse         return;
7650254c4d1SDavid Woodhouse     }
7660254c4d1SDavid Woodhouse 
7670254c4d1SDavid Woodhouse     trace_xenstore_get_perms(tx_id, path);
7680254c4d1SDavid Woodhouse     err = xs_impl_get_perms(s->impl, xen_domid, tx_id, path, &perms);
7690254c4d1SDavid Woodhouse     if (err) {
7700254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
7710254c4d1SDavid Woodhouse         return;
7720254c4d1SDavid Woodhouse     }
7730254c4d1SDavid Woodhouse 
7740254c4d1SDavid Woodhouse     rsp->type = XS_GET_PERMS;
7750254c4d1SDavid Woodhouse     rsp->req_id = req_id;
7760254c4d1SDavid Woodhouse     rsp->tx_id = tx_id;
7770254c4d1SDavid Woodhouse     rsp->len = 0;
7780254c4d1SDavid Woodhouse 
7790254c4d1SDavid Woodhouse     xs_append_strings(s, rsp, perms, 0, false);
7800254c4d1SDavid Woodhouse 
7810254c4d1SDavid Woodhouse     g_list_free_full(perms, g_free);
7820254c4d1SDavid Woodhouse }
7830254c4d1SDavid Woodhouse 
7840254c4d1SDavid Woodhouse static void xs_set_perms(XenXenstoreState *s, unsigned int req_id,
7850254c4d1SDavid Woodhouse                          xs_transaction_t tx_id, uint8_t *req_data,
7860254c4d1SDavid Woodhouse                          unsigned int len)
7870254c4d1SDavid Woodhouse {
7880254c4d1SDavid Woodhouse     const char *path = (const char *)req_data;
7890254c4d1SDavid Woodhouse     uint8_t *perm;
7900254c4d1SDavid Woodhouse     GList *perms = NULL;
7910254c4d1SDavid Woodhouse     int err;
7920254c4d1SDavid Woodhouse 
7930254c4d1SDavid Woodhouse     if (len == 0) {
7940254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
7950254c4d1SDavid Woodhouse         return;
7960254c4d1SDavid Woodhouse     }
7970254c4d1SDavid Woodhouse 
7980254c4d1SDavid Woodhouse     while (len--) {
7990254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
8000254c4d1SDavid Woodhouse             break;
8010254c4d1SDavid Woodhouse         }
8020254c4d1SDavid Woodhouse         if (len == 0) {
8030254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
8040254c4d1SDavid Woodhouse             return;
8050254c4d1SDavid Woodhouse         }
8060254c4d1SDavid Woodhouse     }
8070254c4d1SDavid Woodhouse 
8080254c4d1SDavid Woodhouse     perm = req_data;
8090254c4d1SDavid Woodhouse     while (len--) {
8100254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
8110254c4d1SDavid Woodhouse             perms = g_list_append(perms, perm);
8120254c4d1SDavid Woodhouse             perm = req_data;
8130254c4d1SDavid Woodhouse         }
8140254c4d1SDavid Woodhouse     }
8150254c4d1SDavid Woodhouse 
8160254c4d1SDavid Woodhouse     /*
8170254c4d1SDavid Woodhouse      * Note that there may be trailing garbage at the end of the buffer.
8180254c4d1SDavid Woodhouse      * This is explicitly permitted by the '?' at the end of the definition:
8190254c4d1SDavid Woodhouse      *
8200254c4d1SDavid Woodhouse      *    SET_PERMS         <path>|<perm-as-string>|+?
8210254c4d1SDavid Woodhouse      */
8220254c4d1SDavid Woodhouse 
8230254c4d1SDavid Woodhouse     trace_xenstore_set_perms(tx_id, path);
8240254c4d1SDavid Woodhouse     err = xs_impl_set_perms(s->impl, xen_domid, tx_id, path, perms);
8250254c4d1SDavid Woodhouse     g_list_free(perms);
8260254c4d1SDavid Woodhouse     if (err) {
8270254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
8280254c4d1SDavid Woodhouse         return;
8290254c4d1SDavid Woodhouse     }
8300254c4d1SDavid Woodhouse 
8310254c4d1SDavid Woodhouse     xs_ok(s, XS_SET_PERMS, req_id, tx_id);
8320254c4d1SDavid Woodhouse }
8330254c4d1SDavid Woodhouse 
8340254c4d1SDavid Woodhouse static void xs_watch(XenXenstoreState *s, unsigned int req_id,
8350254c4d1SDavid Woodhouse                      xs_transaction_t tx_id, uint8_t *req_data,
8360254c4d1SDavid Woodhouse                      unsigned int len)
8370254c4d1SDavid Woodhouse {
8380254c4d1SDavid Woodhouse     const char *token, *path = (const char *)req_data;
8390254c4d1SDavid Woodhouse     int err;
8400254c4d1SDavid Woodhouse 
8410254c4d1SDavid Woodhouse     if (len == 0) {
8420254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
8430254c4d1SDavid Woodhouse         return;
8440254c4d1SDavid Woodhouse     }
8450254c4d1SDavid Woodhouse 
8460254c4d1SDavid Woodhouse     while (len--) {
8470254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
8480254c4d1SDavid Woodhouse             break;
8490254c4d1SDavid Woodhouse         }
8500254c4d1SDavid Woodhouse         if (len == 0) {
8510254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
8520254c4d1SDavid Woodhouse             return;
8530254c4d1SDavid Woodhouse         }
8540254c4d1SDavid Woodhouse     }
8550254c4d1SDavid Woodhouse 
8560254c4d1SDavid Woodhouse     token = (const char *)req_data;
8570254c4d1SDavid Woodhouse     while (len--) {
8580254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
8590254c4d1SDavid Woodhouse             break;
8600254c4d1SDavid Woodhouse         }
8610254c4d1SDavid Woodhouse         if (len == 0) {
8620254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
8630254c4d1SDavid Woodhouse             return;
8640254c4d1SDavid Woodhouse         }
8650254c4d1SDavid Woodhouse     }
8660254c4d1SDavid Woodhouse 
8670254c4d1SDavid Woodhouse     /*
8680254c4d1SDavid Woodhouse      * Note that there may be trailing garbage at the end of the buffer.
8690254c4d1SDavid Woodhouse      * This is explicitly permitted by the '?' at the end of the definition:
8700254c4d1SDavid Woodhouse      *
8710254c4d1SDavid Woodhouse      *    WATCH             <wpath>|<token>|?
8720254c4d1SDavid Woodhouse      */
8730254c4d1SDavid Woodhouse 
8740254c4d1SDavid Woodhouse     trace_xenstore_watch(path, token);
8750254c4d1SDavid Woodhouse     err = xs_impl_watch(s->impl, xen_domid, path, token, fire_watch_cb, s);
8760254c4d1SDavid Woodhouse     if (err) {
8770254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
8780254c4d1SDavid Woodhouse         return;
8790254c4d1SDavid Woodhouse     }
8800254c4d1SDavid Woodhouse 
8810254c4d1SDavid Woodhouse     xs_ok(s, XS_WATCH, req_id, tx_id);
8820254c4d1SDavid Woodhouse }
8830254c4d1SDavid Woodhouse 
8840254c4d1SDavid Woodhouse static void xs_unwatch(XenXenstoreState *s, unsigned int req_id,
8850254c4d1SDavid Woodhouse                        xs_transaction_t tx_id, uint8_t *req_data,
8860254c4d1SDavid Woodhouse                        unsigned int len)
8870254c4d1SDavid Woodhouse {
8880254c4d1SDavid Woodhouse     const char *token, *path = (const char *)req_data;
8890254c4d1SDavid Woodhouse     int err;
8900254c4d1SDavid Woodhouse 
8910254c4d1SDavid Woodhouse     if (len == 0) {
8920254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
8930254c4d1SDavid Woodhouse         return;
8940254c4d1SDavid Woodhouse     }
8950254c4d1SDavid Woodhouse 
8960254c4d1SDavid Woodhouse     while (len--) {
8970254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
8980254c4d1SDavid Woodhouse             break;
8990254c4d1SDavid Woodhouse         }
9000254c4d1SDavid Woodhouse         if (len == 0) {
9010254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
9020254c4d1SDavid Woodhouse             return;
9030254c4d1SDavid Woodhouse         }
9040254c4d1SDavid Woodhouse     }
9050254c4d1SDavid Woodhouse 
9060254c4d1SDavid Woodhouse     token = (const char *)req_data;
9070254c4d1SDavid Woodhouse     while (len--) {
9080254c4d1SDavid Woodhouse         if (*req_data++ == '\0') {
9090254c4d1SDavid Woodhouse             break;
9100254c4d1SDavid Woodhouse         }
9110254c4d1SDavid Woodhouse         if (len == 0) {
9120254c4d1SDavid Woodhouse             xs_error(s, req_id, tx_id, EINVAL);
9130254c4d1SDavid Woodhouse             return;
9140254c4d1SDavid Woodhouse         }
9150254c4d1SDavid Woodhouse     }
9160254c4d1SDavid Woodhouse 
9170254c4d1SDavid Woodhouse     trace_xenstore_unwatch(path, token);
9180254c4d1SDavid Woodhouse     err = xs_impl_unwatch(s->impl, xen_domid, path, token, fire_watch_cb, s);
9190254c4d1SDavid Woodhouse     if (err) {
9200254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, err);
9210254c4d1SDavid Woodhouse         return;
9220254c4d1SDavid Woodhouse     }
9230254c4d1SDavid Woodhouse 
9240254c4d1SDavid Woodhouse     xs_ok(s, XS_UNWATCH, req_id, tx_id);
9250254c4d1SDavid Woodhouse }
9260254c4d1SDavid Woodhouse 
9270254c4d1SDavid Woodhouse static void xs_reset_watches(XenXenstoreState *s, unsigned int req_id,
9280254c4d1SDavid Woodhouse                              xs_transaction_t tx_id, uint8_t *req_data,
9290254c4d1SDavid Woodhouse                              unsigned int len)
9300254c4d1SDavid Woodhouse {
9310254c4d1SDavid Woodhouse     if (len == 0 || req_data[len - 1] != '\0') {
9320254c4d1SDavid Woodhouse         xs_error(s, req_id, tx_id, EINVAL);
9330254c4d1SDavid Woodhouse         return;
9340254c4d1SDavid Woodhouse     }
9350254c4d1SDavid Woodhouse 
9360254c4d1SDavid Woodhouse     trace_xenstore_reset_watches();
9370254c4d1SDavid Woodhouse     xs_impl_reset_watches(s->impl, xen_domid);
9380254c4d1SDavid Woodhouse 
9390254c4d1SDavid Woodhouse     xs_ok(s, XS_RESET_WATCHES, req_id, tx_id);
9400254c4d1SDavid Woodhouse }
9410254c4d1SDavid Woodhouse 
9420254c4d1SDavid Woodhouse static void xs_priv(XenXenstoreState *s, unsigned int req_id,
9430254c4d1SDavid Woodhouse                     xs_transaction_t tx_id, uint8_t *data,
9440254c4d1SDavid Woodhouse                     unsigned int len)
9450254c4d1SDavid Woodhouse {
9460254c4d1SDavid Woodhouse     xs_error(s, req_id, tx_id, EACCES);
9470254c4d1SDavid Woodhouse }
9480254c4d1SDavid Woodhouse 
9490254c4d1SDavid Woodhouse static void xs_unimpl(XenXenstoreState *s, unsigned int req_id,
9500254c4d1SDavid Woodhouse                       xs_transaction_t tx_id, uint8_t *data,
9510254c4d1SDavid Woodhouse                       unsigned int len)
9520254c4d1SDavid Woodhouse {
9530254c4d1SDavid Woodhouse     xs_error(s, req_id, tx_id, ENOSYS);
9540254c4d1SDavid Woodhouse }
9550254c4d1SDavid Woodhouse 
9560254c4d1SDavid Woodhouse typedef void (*xs_impl)(XenXenstoreState *s, unsigned int req_id,
9570254c4d1SDavid Woodhouse                         xs_transaction_t tx_id, uint8_t *data,
9580254c4d1SDavid Woodhouse                         unsigned int len);
9590254c4d1SDavid Woodhouse 
9600254c4d1SDavid Woodhouse struct xsd_req {
9610254c4d1SDavid Woodhouse     const char *name;
9620254c4d1SDavid Woodhouse     xs_impl fn;
9630254c4d1SDavid Woodhouse };
9640254c4d1SDavid Woodhouse #define XSD_REQ(_type, _fn)                           \
9650254c4d1SDavid Woodhouse     [_type] = { .name = #_type, .fn = _fn }
9660254c4d1SDavid Woodhouse 
9670254c4d1SDavid Woodhouse struct xsd_req xsd_reqs[] = {
9680254c4d1SDavid Woodhouse     XSD_REQ(XS_READ, xs_read),
9690254c4d1SDavid Woodhouse     XSD_REQ(XS_WRITE, xs_write),
9700254c4d1SDavid Woodhouse     XSD_REQ(XS_MKDIR, xs_mkdir),
9710254c4d1SDavid Woodhouse     XSD_REQ(XS_DIRECTORY, xs_directory),
9720254c4d1SDavid Woodhouse     XSD_REQ(XS_DIRECTORY_PART, xs_directory_part),
9730254c4d1SDavid Woodhouse     XSD_REQ(XS_TRANSACTION_START, xs_transaction_start),
9740254c4d1SDavid Woodhouse     XSD_REQ(XS_TRANSACTION_END, xs_transaction_end),
9750254c4d1SDavid Woodhouse     XSD_REQ(XS_RM, xs_rm),
9760254c4d1SDavid Woodhouse     XSD_REQ(XS_GET_PERMS, xs_get_perms),
9770254c4d1SDavid Woodhouse     XSD_REQ(XS_SET_PERMS, xs_set_perms),
9780254c4d1SDavid Woodhouse     XSD_REQ(XS_WATCH, xs_watch),
9790254c4d1SDavid Woodhouse     XSD_REQ(XS_UNWATCH, xs_unwatch),
9800254c4d1SDavid Woodhouse     XSD_REQ(XS_CONTROL, xs_priv),
9810254c4d1SDavid Woodhouse     XSD_REQ(XS_INTRODUCE, xs_priv),
9820254c4d1SDavid Woodhouse     XSD_REQ(XS_RELEASE, xs_priv),
9830254c4d1SDavid Woodhouse     XSD_REQ(XS_IS_DOMAIN_INTRODUCED, xs_priv),
9840254c4d1SDavid Woodhouse     XSD_REQ(XS_RESUME, xs_priv),
9850254c4d1SDavid Woodhouse     XSD_REQ(XS_SET_TARGET, xs_priv),
9860254c4d1SDavid Woodhouse     XSD_REQ(XS_RESET_WATCHES, xs_reset_watches),
9870254c4d1SDavid Woodhouse };
9880254c4d1SDavid Woodhouse 
989f3341e7bSDavid Woodhouse static void process_req(XenXenstoreState *s)
990f3341e7bSDavid Woodhouse {
991f3341e7bSDavid Woodhouse     struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data;
9920254c4d1SDavid Woodhouse     xs_impl handler = NULL;
993f3341e7bSDavid Woodhouse 
994f3341e7bSDavid Woodhouse     assert(req_pending(s));
995f3341e7bSDavid Woodhouse     assert(!s->rsp_pending);
996f3341e7bSDavid Woodhouse 
9970254c4d1SDavid Woodhouse     if (req->type < ARRAY_SIZE(xsd_reqs)) {
9980254c4d1SDavid Woodhouse         handler = xsd_reqs[req->type].fn;
9990254c4d1SDavid Woodhouse     }
10000254c4d1SDavid Woodhouse     if (!handler) {
10010254c4d1SDavid Woodhouse         handler = &xs_unimpl;
10020254c4d1SDavid Woodhouse     }
10030254c4d1SDavid Woodhouse 
10040254c4d1SDavid Woodhouse     handler(s, req->req_id, req->tx_id, (uint8_t *)&req[1], req->len);
1005f3341e7bSDavid Woodhouse 
1006f3341e7bSDavid Woodhouse     s->rsp_pending = true;
1007f3341e7bSDavid Woodhouse     reset_req(s);
1008f3341e7bSDavid Woodhouse }
1009f3341e7bSDavid Woodhouse 
1010f3341e7bSDavid Woodhouse static unsigned int copy_from_ring(XenXenstoreState *s, uint8_t *ptr,
1011f3341e7bSDavid Woodhouse                                    unsigned int len)
1012f3341e7bSDavid Woodhouse {
1013f3341e7bSDavid Woodhouse     if (!len) {
1014f3341e7bSDavid Woodhouse         return 0;
1015f3341e7bSDavid Woodhouse     }
1016f3341e7bSDavid Woodhouse 
1017f3341e7bSDavid Woodhouse     XENSTORE_RING_IDX prod = qatomic_read(&s->xs->req_prod);
1018f3341e7bSDavid Woodhouse     XENSTORE_RING_IDX cons = qatomic_read(&s->xs->req_cons);
1019f3341e7bSDavid Woodhouse     unsigned int copied = 0;
1020f3341e7bSDavid Woodhouse 
1021f3341e7bSDavid Woodhouse     /* Ensure the ring contents don't cross the req_prod access. */
1022f3341e7bSDavid Woodhouse     smp_rmb();
1023f3341e7bSDavid Woodhouse 
1024f3341e7bSDavid Woodhouse     while (len) {
1025f3341e7bSDavid Woodhouse         unsigned int avail = prod - cons;
1026f3341e7bSDavid Woodhouse         unsigned int offset = MASK_XENSTORE_IDX(cons);
1027f3341e7bSDavid Woodhouse         unsigned int copylen = avail;
1028f3341e7bSDavid Woodhouse 
1029f3341e7bSDavid Woodhouse         if (avail > XENSTORE_RING_SIZE) {
1030f3341e7bSDavid Woodhouse             error_report("XenStore ring handling error");
1031f3341e7bSDavid Woodhouse             s->fatal_error = true;
1032f3341e7bSDavid Woodhouse             break;
1033f3341e7bSDavid Woodhouse         } else if (avail == 0) {
1034f3341e7bSDavid Woodhouse             break;
1035f3341e7bSDavid Woodhouse         }
1036f3341e7bSDavid Woodhouse 
1037f3341e7bSDavid Woodhouse         if (copylen > len) {
1038f3341e7bSDavid Woodhouse             copylen = len;
1039f3341e7bSDavid Woodhouse         }
1040f3341e7bSDavid Woodhouse         if (copylen > XENSTORE_RING_SIZE - offset) {
1041f3341e7bSDavid Woodhouse             copylen = XENSTORE_RING_SIZE - offset;
1042f3341e7bSDavid Woodhouse         }
1043f3341e7bSDavid Woodhouse 
1044f3341e7bSDavid Woodhouse         memcpy(ptr, &s->xs->req[offset], copylen);
1045f3341e7bSDavid Woodhouse         copied += copylen;
1046f3341e7bSDavid Woodhouse 
1047f3341e7bSDavid Woodhouse         ptr += copylen;
1048f3341e7bSDavid Woodhouse         len -= copylen;
1049f3341e7bSDavid Woodhouse 
1050f3341e7bSDavid Woodhouse         cons += copylen;
1051f3341e7bSDavid Woodhouse     }
1052f3341e7bSDavid Woodhouse 
1053f3341e7bSDavid Woodhouse     /*
1054f3341e7bSDavid Woodhouse      * Not sure this ever mattered except on Alpha, but this barrier
1055f3341e7bSDavid Woodhouse      * is to ensure that the update to req_cons is globally visible
1056f3341e7bSDavid Woodhouse      * only after we have consumed all the data from the ring, and we
1057f3341e7bSDavid Woodhouse      * don't end up seeing data written to the ring *after* the other
1058f3341e7bSDavid Woodhouse      * end sees the update and writes more to the ring. Xen's own
1059f3341e7bSDavid Woodhouse      * xenstored has the same barrier here (although with no comment
1060f3341e7bSDavid Woodhouse      * at all, obviously, because it's Xen code).
1061f3341e7bSDavid Woodhouse      */
1062f3341e7bSDavid Woodhouse     smp_mb();
1063f3341e7bSDavid Woodhouse 
1064f3341e7bSDavid Woodhouse     qatomic_set(&s->xs->req_cons, cons);
1065f3341e7bSDavid Woodhouse 
1066f3341e7bSDavid Woodhouse     return copied;
1067f3341e7bSDavid Woodhouse }
1068f3341e7bSDavid Woodhouse 
1069f3341e7bSDavid Woodhouse static unsigned int copy_to_ring(XenXenstoreState *s, uint8_t *ptr,
1070f3341e7bSDavid Woodhouse                                  unsigned int len)
1071f3341e7bSDavid Woodhouse {
1072f3341e7bSDavid Woodhouse     if (!len) {
1073f3341e7bSDavid Woodhouse         return 0;
1074f3341e7bSDavid Woodhouse     }
1075f3341e7bSDavid Woodhouse 
1076f3341e7bSDavid Woodhouse     XENSTORE_RING_IDX cons = qatomic_read(&s->xs->rsp_cons);
1077f3341e7bSDavid Woodhouse     XENSTORE_RING_IDX prod = qatomic_read(&s->xs->rsp_prod);
1078f3341e7bSDavid Woodhouse     unsigned int copied = 0;
1079f3341e7bSDavid Woodhouse 
1080f3341e7bSDavid Woodhouse     /*
1081f3341e7bSDavid Woodhouse      * This matches the barrier in copy_to_ring() (or the guest's
1082f3341e7bSDavid Woodhouse      * equivalent) betweem writing the data to the ring and updating
1083f3341e7bSDavid Woodhouse      * rsp_prod. It protects against the pathological case (which
1084f3341e7bSDavid Woodhouse      * again I think never happened except on Alpha) where our
1085f3341e7bSDavid Woodhouse      * subsequent writes to the ring could *cross* the read of
1086f3341e7bSDavid Woodhouse      * rsp_cons and the guest could see the new data when it was
1087f3341e7bSDavid Woodhouse      * intending to read the old.
1088f3341e7bSDavid Woodhouse      */
1089f3341e7bSDavid Woodhouse     smp_mb();
1090f3341e7bSDavid Woodhouse 
1091f3341e7bSDavid Woodhouse     while (len) {
1092f3341e7bSDavid Woodhouse         unsigned int avail = cons + XENSTORE_RING_SIZE - prod;
1093f3341e7bSDavid Woodhouse         unsigned int offset = MASK_XENSTORE_IDX(prod);
1094f3341e7bSDavid Woodhouse         unsigned int copylen = len;
1095f3341e7bSDavid Woodhouse 
1096f3341e7bSDavid Woodhouse         if (avail > XENSTORE_RING_SIZE) {
1097f3341e7bSDavid Woodhouse             error_report("XenStore ring handling error");
1098f3341e7bSDavid Woodhouse             s->fatal_error = true;
1099f3341e7bSDavid Woodhouse             break;
1100f3341e7bSDavid Woodhouse         } else if (avail == 0) {
1101f3341e7bSDavid Woodhouse             break;
1102f3341e7bSDavid Woodhouse         }
1103f3341e7bSDavid Woodhouse 
1104f3341e7bSDavid Woodhouse         if (copylen > avail) {
1105f3341e7bSDavid Woodhouse             copylen = avail;
1106f3341e7bSDavid Woodhouse         }
1107f3341e7bSDavid Woodhouse         if (copylen > XENSTORE_RING_SIZE - offset) {
1108f3341e7bSDavid Woodhouse             copylen = XENSTORE_RING_SIZE - offset;
1109f3341e7bSDavid Woodhouse         }
1110f3341e7bSDavid Woodhouse 
1111f3341e7bSDavid Woodhouse 
1112f3341e7bSDavid Woodhouse         memcpy(&s->xs->rsp[offset], ptr, copylen);
1113f3341e7bSDavid Woodhouse         copied += copylen;
1114f3341e7bSDavid Woodhouse 
1115f3341e7bSDavid Woodhouse         ptr += copylen;
1116f3341e7bSDavid Woodhouse         len -= copylen;
1117f3341e7bSDavid Woodhouse 
1118f3341e7bSDavid Woodhouse         prod += copylen;
1119f3341e7bSDavid Woodhouse     }
1120f3341e7bSDavid Woodhouse 
1121f3341e7bSDavid Woodhouse     /* Ensure the ring contents are seen before rsp_prod update. */
1122f3341e7bSDavid Woodhouse     smp_wmb();
1123f3341e7bSDavid Woodhouse 
1124f3341e7bSDavid Woodhouse     qatomic_set(&s->xs->rsp_prod, prod);
1125f3341e7bSDavid Woodhouse 
1126f3341e7bSDavid Woodhouse     return copied;
1127f3341e7bSDavid Woodhouse }
1128f3341e7bSDavid Woodhouse 
1129f3341e7bSDavid Woodhouse static unsigned int get_req(XenXenstoreState *s)
1130f3341e7bSDavid Woodhouse {
1131f3341e7bSDavid Woodhouse     unsigned int copied = 0;
1132f3341e7bSDavid Woodhouse 
1133f3341e7bSDavid Woodhouse     if (s->fatal_error) {
1134f3341e7bSDavid Woodhouse         return 0;
1135f3341e7bSDavid Woodhouse     }
1136f3341e7bSDavid Woodhouse 
1137f3341e7bSDavid Woodhouse     assert(!req_pending(s));
1138f3341e7bSDavid Woodhouse 
1139f3341e7bSDavid Woodhouse     if (s->req_offset < XENSTORE_HEADER_SIZE) {
1140f3341e7bSDavid Woodhouse         void *ptr = s->req_data + s->req_offset;
1141f3341e7bSDavid Woodhouse         unsigned int len = XENSTORE_HEADER_SIZE;
1142f3341e7bSDavid Woodhouse         unsigned int copylen = copy_from_ring(s, ptr, len);
1143f3341e7bSDavid Woodhouse 
1144f3341e7bSDavid Woodhouse         copied += copylen;
1145f3341e7bSDavid Woodhouse         s->req_offset += copylen;
1146f3341e7bSDavid Woodhouse     }
1147f3341e7bSDavid Woodhouse 
1148f3341e7bSDavid Woodhouse     if (s->req_offset >= XENSTORE_HEADER_SIZE) {
1149f3341e7bSDavid Woodhouse         struct xsd_sockmsg *req = (struct xsd_sockmsg *)s->req_data;
1150f3341e7bSDavid Woodhouse 
1151f3341e7bSDavid Woodhouse         if (req->len > (uint32_t)XENSTORE_PAYLOAD_MAX) {
1152f3341e7bSDavid Woodhouse             error_report("Illegal XenStore request");
1153f3341e7bSDavid Woodhouse             s->fatal_error = true;
1154f3341e7bSDavid Woodhouse             return 0;
1155f3341e7bSDavid Woodhouse         }
1156f3341e7bSDavid Woodhouse 
1157f3341e7bSDavid Woodhouse         void *ptr = s->req_data + s->req_offset;
1158f3341e7bSDavid Woodhouse         unsigned int len = XENSTORE_HEADER_SIZE + req->len - s->req_offset;
1159f3341e7bSDavid Woodhouse         unsigned int copylen = copy_from_ring(s, ptr, len);
1160f3341e7bSDavid Woodhouse 
1161f3341e7bSDavid Woodhouse         copied += copylen;
1162f3341e7bSDavid Woodhouse         s->req_offset += copylen;
1163f3341e7bSDavid Woodhouse     }
1164f3341e7bSDavid Woodhouse 
1165f3341e7bSDavid Woodhouse     return copied;
1166f3341e7bSDavid Woodhouse }
1167f3341e7bSDavid Woodhouse 
1168f3341e7bSDavid Woodhouse static unsigned int put_rsp(XenXenstoreState *s)
1169f3341e7bSDavid Woodhouse {
1170f3341e7bSDavid Woodhouse     if (s->fatal_error) {
1171f3341e7bSDavid Woodhouse         return 0;
1172f3341e7bSDavid Woodhouse     }
1173f3341e7bSDavid Woodhouse 
1174f3341e7bSDavid Woodhouse     assert(s->rsp_pending);
1175f3341e7bSDavid Woodhouse 
1176f3341e7bSDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
1177f3341e7bSDavid Woodhouse     assert(s->rsp_offset < XENSTORE_HEADER_SIZE + rsp->len);
1178f3341e7bSDavid Woodhouse 
1179f3341e7bSDavid Woodhouse     void *ptr = s->rsp_data + s->rsp_offset;
1180f3341e7bSDavid Woodhouse     unsigned int len = XENSTORE_HEADER_SIZE + rsp->len - s->rsp_offset;
1181f3341e7bSDavid Woodhouse     unsigned int copylen = copy_to_ring(s, ptr, len);
1182f3341e7bSDavid Woodhouse 
1183f3341e7bSDavid Woodhouse     s->rsp_offset += copylen;
1184f3341e7bSDavid Woodhouse 
1185f3341e7bSDavid Woodhouse     /* Have we produced a complete response? */
1186f3341e7bSDavid Woodhouse     if (s->rsp_offset == XENSTORE_HEADER_SIZE + rsp->len) {
1187f3341e7bSDavid Woodhouse         reset_rsp(s);
1188f3341e7bSDavid Woodhouse     }
1189f3341e7bSDavid Woodhouse 
1190f3341e7bSDavid Woodhouse     return copylen;
1191f3341e7bSDavid Woodhouse }
1192f3341e7bSDavid Woodhouse 
11930254c4d1SDavid Woodhouse static void deliver_watch(XenXenstoreState *s, const char *path,
11940254c4d1SDavid Woodhouse                           const char *token)
11950254c4d1SDavid Woodhouse {
11960254c4d1SDavid Woodhouse     struct xsd_sockmsg *rsp = (struct xsd_sockmsg *)s->rsp_data;
11970254c4d1SDavid Woodhouse     uint8_t *rsp_data = (uint8_t *)&rsp[1];
11980254c4d1SDavid Woodhouse     unsigned int len;
11990254c4d1SDavid Woodhouse 
12000254c4d1SDavid Woodhouse     assert(!s->rsp_pending);
12010254c4d1SDavid Woodhouse 
12020254c4d1SDavid Woodhouse     trace_xenstore_watch_event(path, token);
12030254c4d1SDavid Woodhouse 
12040254c4d1SDavid Woodhouse     rsp->type = XS_WATCH_EVENT;
12050254c4d1SDavid Woodhouse     rsp->req_id = 0;
12060254c4d1SDavid Woodhouse     rsp->tx_id = 0;
12070254c4d1SDavid Woodhouse     rsp->len = 0;
12080254c4d1SDavid Woodhouse 
12090254c4d1SDavid Woodhouse     len = strlen(path);
12100254c4d1SDavid Woodhouse 
12110254c4d1SDavid Woodhouse     /* XENSTORE_ABS/REL_PATH_MAX should ensure there can be no overflow */
12120254c4d1SDavid Woodhouse     assert(rsp->len + len < XENSTORE_PAYLOAD_MAX);
12130254c4d1SDavid Woodhouse 
12140254c4d1SDavid Woodhouse     memcpy(&rsp_data[rsp->len], path, len);
12150254c4d1SDavid Woodhouse     rsp->len += len;
12160254c4d1SDavid Woodhouse     rsp_data[rsp->len] = '\0';
12170254c4d1SDavid Woodhouse     rsp->len++;
12180254c4d1SDavid Woodhouse 
12190254c4d1SDavid Woodhouse     len = strlen(token);
12200254c4d1SDavid Woodhouse     /*
12210254c4d1SDavid Woodhouse      * It is possible for the guest to have chosen a token that will
12220254c4d1SDavid Woodhouse      * not fit (along with the patch) into a watch event. We have no
12230254c4d1SDavid Woodhouse      * choice but to drop the event if this is the case.
12240254c4d1SDavid Woodhouse      */
12250254c4d1SDavid Woodhouse     if (rsp->len + len >= XENSTORE_PAYLOAD_MAX) {
12260254c4d1SDavid Woodhouse         return;
12270254c4d1SDavid Woodhouse     }
12280254c4d1SDavid Woodhouse 
12290254c4d1SDavid Woodhouse     memcpy(&rsp_data[rsp->len], token, len);
12300254c4d1SDavid Woodhouse     rsp->len += len;
12310254c4d1SDavid Woodhouse     rsp_data[rsp->len] = '\0';
12320254c4d1SDavid Woodhouse     rsp->len++;
12330254c4d1SDavid Woodhouse 
12340254c4d1SDavid Woodhouse     s->rsp_pending = true;
12350254c4d1SDavid Woodhouse }
12360254c4d1SDavid Woodhouse 
12370254c4d1SDavid Woodhouse struct watch_event {
12380254c4d1SDavid Woodhouse     char *path;
12390254c4d1SDavid Woodhouse     char *token;
12400254c4d1SDavid Woodhouse };
12410254c4d1SDavid Woodhouse 
12420254c4d1SDavid Woodhouse static void queue_watch(XenXenstoreState *s, const char *path,
12430254c4d1SDavid Woodhouse                         const char *token)
12440254c4d1SDavid Woodhouse {
12450254c4d1SDavid Woodhouse     struct watch_event *ev = g_new0(struct watch_event, 1);
12460254c4d1SDavid Woodhouse 
12470254c4d1SDavid Woodhouse     ev->path = g_strdup(path);
12480254c4d1SDavid Woodhouse     ev->token = g_strdup(token);
12490254c4d1SDavid Woodhouse 
12500254c4d1SDavid Woodhouse     s->watch_events = g_list_append(s->watch_events, ev);
12510254c4d1SDavid Woodhouse }
12520254c4d1SDavid Woodhouse 
12530254c4d1SDavid Woodhouse static void fire_watch_cb(void *opaque, const char *path, const char *token)
12540254c4d1SDavid Woodhouse {
12550254c4d1SDavid Woodhouse     XenXenstoreState *s = opaque;
12560254c4d1SDavid Woodhouse 
12570254c4d1SDavid Woodhouse     assert(qemu_mutex_iothread_locked());
12580254c4d1SDavid Woodhouse 
12590254c4d1SDavid Woodhouse     /*
12600254c4d1SDavid Woodhouse      * If there's a response pending, we obviously can't scribble over
12610254c4d1SDavid Woodhouse      * it. But if there's a request pending, it has dibs on the buffer
12620254c4d1SDavid Woodhouse      * too.
12630254c4d1SDavid Woodhouse      *
12640254c4d1SDavid Woodhouse      * In the common case of a watch firing due to backend activity
12650254c4d1SDavid Woodhouse      * when the ring was otherwise idle, we should be able to copy the
12660254c4d1SDavid Woodhouse      * strings directly into the rsp_data and thence the actual ring,
12670254c4d1SDavid Woodhouse      * without needing to perform any allocations and queue them.
12680254c4d1SDavid Woodhouse      */
12690254c4d1SDavid Woodhouse     if (s->rsp_pending || req_pending(s)) {
12700254c4d1SDavid Woodhouse         queue_watch(s, path, token);
12710254c4d1SDavid Woodhouse     } else {
12720254c4d1SDavid Woodhouse         deliver_watch(s, path, token);
12730254c4d1SDavid Woodhouse         /*
12740254c4d1SDavid Woodhouse          * If the message was queued because there was already ring activity,
12750254c4d1SDavid Woodhouse          * no need to wake the guest. But if not, we need to send the evtchn.
12760254c4d1SDavid Woodhouse          */
12770254c4d1SDavid Woodhouse         xen_be_evtchn_notify(s->eh, s->be_port);
12780254c4d1SDavid Woodhouse     }
12790254c4d1SDavid Woodhouse }
12800254c4d1SDavid Woodhouse 
12810254c4d1SDavid Woodhouse static void process_watch_events(XenXenstoreState *s)
12820254c4d1SDavid Woodhouse {
12830254c4d1SDavid Woodhouse     struct watch_event *ev = s->watch_events->data;
12840254c4d1SDavid Woodhouse 
12850254c4d1SDavid Woodhouse     deliver_watch(s, ev->path, ev->token);
12860254c4d1SDavid Woodhouse 
12870254c4d1SDavid Woodhouse     s->watch_events = g_list_remove(s->watch_events, ev);
12880254c4d1SDavid Woodhouse     g_free(ev->path);
12890254c4d1SDavid Woodhouse     g_free(ev->token);
12900254c4d1SDavid Woodhouse     g_free(ev);
12910254c4d1SDavid Woodhouse }
12920254c4d1SDavid Woodhouse 
1293c08f5d0eSDavid Woodhouse static void xen_xenstore_event(void *opaque)
1294c08f5d0eSDavid Woodhouse {
1295c08f5d0eSDavid Woodhouse     XenXenstoreState *s = opaque;
1296c08f5d0eSDavid Woodhouse     evtchn_port_t port = xen_be_evtchn_pending(s->eh);
1297f3341e7bSDavid Woodhouse     unsigned int copied_to, copied_from;
1298f3341e7bSDavid Woodhouse     bool processed, notify = false;
1299f3341e7bSDavid Woodhouse 
1300c08f5d0eSDavid Woodhouse     if (port != s->be_port) {
1301c08f5d0eSDavid Woodhouse         return;
1302c08f5d0eSDavid Woodhouse     }
1303f3341e7bSDavid Woodhouse 
1304c08f5d0eSDavid Woodhouse     /* We know this is a no-op. */
1305c08f5d0eSDavid Woodhouse     xen_be_evtchn_unmask(s->eh, port);
1306f3341e7bSDavid Woodhouse 
1307f3341e7bSDavid Woodhouse     do {
1308f3341e7bSDavid Woodhouse         copied_to = copied_from = 0;
1309f3341e7bSDavid Woodhouse         processed = false;
1310f3341e7bSDavid Woodhouse 
13110254c4d1SDavid Woodhouse         if (!s->rsp_pending && s->watch_events) {
13120254c4d1SDavid Woodhouse             process_watch_events(s);
13130254c4d1SDavid Woodhouse         }
13140254c4d1SDavid Woodhouse 
1315f3341e7bSDavid Woodhouse         if (s->rsp_pending) {
1316f3341e7bSDavid Woodhouse             copied_to = put_rsp(s);
1317f3341e7bSDavid Woodhouse         }
1318f3341e7bSDavid Woodhouse 
1319f3341e7bSDavid Woodhouse         if (!req_pending(s)) {
1320f3341e7bSDavid Woodhouse             copied_from = get_req(s);
1321f3341e7bSDavid Woodhouse         }
1322f3341e7bSDavid Woodhouse 
13230254c4d1SDavid Woodhouse         if (req_pending(s) && !s->rsp_pending && !s->watch_events) {
1324f3341e7bSDavid Woodhouse             process_req(s);
1325f3341e7bSDavid Woodhouse             processed = true;
1326f3341e7bSDavid Woodhouse         }
1327f3341e7bSDavid Woodhouse 
1328f3341e7bSDavid Woodhouse         notify |= copied_to || copied_from;
1329f3341e7bSDavid Woodhouse     } while (copied_to || copied_from || processed);
1330f3341e7bSDavid Woodhouse 
1331f3341e7bSDavid Woodhouse     if (notify) {
1332c08f5d0eSDavid Woodhouse         xen_be_evtchn_notify(s->eh, s->be_port);
1333c08f5d0eSDavid Woodhouse     }
1334f3341e7bSDavid Woodhouse }
1335c08f5d0eSDavid Woodhouse 
1336c08f5d0eSDavid Woodhouse static void alloc_guest_port(XenXenstoreState *s)
1337c08f5d0eSDavid Woodhouse {
1338c08f5d0eSDavid Woodhouse     struct evtchn_alloc_unbound alloc = {
1339c08f5d0eSDavid Woodhouse         .dom = DOMID_SELF,
1340c08f5d0eSDavid Woodhouse         .remote_dom = DOMID_QEMU,
1341c08f5d0eSDavid Woodhouse     };
1342c08f5d0eSDavid Woodhouse 
1343c08f5d0eSDavid Woodhouse     if (!xen_evtchn_alloc_unbound_op(&alloc)) {
1344c08f5d0eSDavid Woodhouse         s->guest_port = alloc.port;
1345c08f5d0eSDavid Woodhouse     }
1346c08f5d0eSDavid Woodhouse }
1347c08f5d0eSDavid Woodhouse 
1348c08f5d0eSDavid Woodhouse int xen_xenstore_reset(void)
1349c08f5d0eSDavid Woodhouse {
1350c08f5d0eSDavid Woodhouse     XenXenstoreState *s = xen_xenstore_singleton;
1351c08f5d0eSDavid Woodhouse     int err;
1352c08f5d0eSDavid Woodhouse 
1353c08f5d0eSDavid Woodhouse     if (!s) {
1354c08f5d0eSDavid Woodhouse         return -ENOTSUP;
1355c08f5d0eSDavid Woodhouse     }
1356c08f5d0eSDavid Woodhouse 
1357c08f5d0eSDavid Woodhouse     s->req_offset = s->rsp_offset = 0;
1358c08f5d0eSDavid Woodhouse     s->rsp_pending = false;
1359c08f5d0eSDavid Woodhouse 
1360c08f5d0eSDavid Woodhouse     if (!memory_region_is_mapped(&s->xenstore_page)) {
1361c08f5d0eSDavid Woodhouse         uint64_t gpa = XEN_SPECIAL_PFN(XENSTORE) << TARGET_PAGE_BITS;
1362c08f5d0eSDavid Woodhouse         xen_overlay_do_map_page(&s->xenstore_page, gpa);
1363c08f5d0eSDavid Woodhouse     }
1364c08f5d0eSDavid Woodhouse 
1365c08f5d0eSDavid Woodhouse     alloc_guest_port(s);
1366c08f5d0eSDavid Woodhouse 
1367c08f5d0eSDavid Woodhouse     /*
1368c08f5d0eSDavid Woodhouse      * As qemu/dom0, bind to the guest's port. For incoming migration, this
1369c08f5d0eSDavid Woodhouse      * will be unbound as the guest's evtchn table is overwritten. We then
1370c08f5d0eSDavid Woodhouse      * rebind to the correct guest port in xen_xenstore_post_load().
1371c08f5d0eSDavid Woodhouse      */
1372c08f5d0eSDavid Woodhouse     err = xen_be_evtchn_bind_interdomain(s->eh, xen_domid, s->guest_port);
1373c08f5d0eSDavid Woodhouse     if (err < 0) {
1374c08f5d0eSDavid Woodhouse         return err;
1375c08f5d0eSDavid Woodhouse     }
1376c08f5d0eSDavid Woodhouse     s->be_port = err;
1377c08f5d0eSDavid Woodhouse 
1378c08f5d0eSDavid Woodhouse     return 0;
1379c08f5d0eSDavid Woodhouse }
1380