1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "qemu/log.h"
22#include "hw/qdev-core.h"
23#include "hw/xen/xen_backend.h"
24#include "hw/xen/xen_pvdev.h"
25
26
27static int debug;
28
29struct xs_dirs {
30 char *xs_dir;
31 QTAILQ_ENTRY(xs_dirs) list;
32};
33
34static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
35 QTAILQ_HEAD_INITIALIZER(xs_cleanup);
36
37static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
38 QTAILQ_HEAD_INITIALIZER(xendevs);
39
40
41
42static void xenstore_cleanup_dir(char *dir)
43{
44 struct xs_dirs *d;
45
46 d = g_malloc(sizeof(*d));
47 d->xs_dir = dir;
48 QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
49}
50
51void xen_config_cleanup(void)
52{
53 struct xs_dirs *d;
54
55 QTAILQ_FOREACH(d, &xs_cleanup, list) {
56 xs_rm(xenstore, 0, d->xs_dir);
57 }
58}
59
60int xenstore_mkdir(char *path, int p)
61{
62 struct xs_permissions perms[2] = {
63 {
64 .id = 0,
65 }, {
66 .id = xen_domid,
67 .perms = p,
68 }
69 };
70
71 if (!xs_mkdir(xenstore, 0, path)) {
72 xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
73 return -1;
74 }
75 xenstore_cleanup_dir(g_strdup(path));
76
77 if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
78 xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
79 return -1;
80 }
81 return 0;
82}
83
84int xenstore_write_str(const char *base, const char *node, const char *val)
85{
86 char abspath[XEN_BUFSIZE];
87
88 snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
89 if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
90 return -1;
91 }
92 return 0;
93}
94
95char *xenstore_read_str(const char *base, const char *node)
96{
97 char abspath[XEN_BUFSIZE];
98 unsigned int len;
99 char *str, *ret = NULL;
100
101 snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
102 str = xs_read(xenstore, 0, abspath, &len);
103 if (str != NULL) {
104
105
106 ret = g_strdup(str);
107 free(str);
108 }
109 return ret;
110}
111
112int xenstore_write_int(const char *base, const char *node, int ival)
113{
114 char val[12];
115
116 snprintf(val, sizeof(val), "%d", ival);
117 return xenstore_write_str(base, node, val);
118}
119
120int xenstore_write_int64(const char *base, const char *node, int64_t ival)
121{
122 char val[21];
123
124 snprintf(val, sizeof(val), "%"PRId64, ival);
125 return xenstore_write_str(base, node, val);
126}
127
128int xenstore_read_int(const char *base, const char *node, int *ival)
129{
130 char *val;
131 int rc = -1;
132
133 val = xenstore_read_str(base, node);
134 if (val && 1 == sscanf(val, "%d", ival)) {
135 rc = 0;
136 }
137 g_free(val);
138 return rc;
139}
140
141int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
142{
143 char *val;
144 int rc = -1;
145
146 val = xenstore_read_str(base, node);
147 if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
148 rc = 0;
149 }
150 g_free(val);
151 return rc;
152}
153
154void xenstore_update(void *unused)
155{
156 char **vec = NULL;
157 intptr_t type, ops, ptr;
158 unsigned int dom, count;
159
160 vec = xs_read_watch(xenstore, &count);
161 if (vec == NULL) {
162 goto cleanup;
163 }
164
165 if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
166 &type, &dom, &ops) == 3) {
167 xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)ops);
168 }
169 if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
170 xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
171 }
172
173cleanup:
174 free(vec);
175}
176
177const char *xenbus_strstate(enum xenbus_state state)
178{
179 static const char *const name[] = {
180 [XenbusStateUnknown] = "Unknown",
181 [XenbusStateInitialising] = "Initialising",
182 [XenbusStateInitWait] = "InitWait",
183 [XenbusStateInitialised] = "Initialised",
184 [XenbusStateConnected] = "Connected",
185 [XenbusStateClosing] = "Closing",
186 [XenbusStateClosed] = "Closed",
187 };
188 return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
189}
190
191
192
193
194
195
196
197
198void xen_pv_printf(struct XenDevice *xendev, int msg_level,
199 const char *fmt, ...)
200{
201 va_list args;
202
203 if (xendev) {
204 if (msg_level > xendev->debug) {
205 return;
206 }
207 qemu_log("xen be: %s: ", xendev->name);
208 if (msg_level == 0) {
209 fprintf(stderr, "xen be: %s: ", xendev->name);
210 }
211 } else {
212 if (msg_level > debug) {
213 return;
214 }
215 qemu_log("xen be core: ");
216 if (msg_level == 0) {
217 fprintf(stderr, "xen be core: ");
218 }
219 }
220 va_start(args, fmt);
221 qemu_log_vprintf(fmt, args);
222 va_end(args);
223 if (msg_level == 0) {
224 va_start(args, fmt);
225 vfprintf(stderr, fmt, args);
226 va_end(args);
227 }
228 qemu_log_flush();
229}
230
231void xen_pv_evtchn_event(void *opaque)
232{
233 struct XenDevice *xendev = opaque;
234 evtchn_port_t port;
235
236 port = xenevtchn_pending(xendev->evtchndev);
237 if (port != xendev->local_port) {
238 xen_pv_printf(xendev, 0,
239 "xenevtchn_pending returned %d (expected %d)\n",
240 port, xendev->local_port);
241 return;
242 }
243 xenevtchn_unmask(xendev->evtchndev, port);
244
245 if (xendev->ops->event) {
246 xendev->ops->event(xendev);
247 }
248}
249
250void xen_pv_unbind_evtchn(struct XenDevice *xendev)
251{
252 if (xendev->local_port == -1) {
253 return;
254 }
255 qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
256 xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
257 xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
258 xendev->local_port = -1;
259}
260
261int xen_pv_send_notify(struct XenDevice *xendev)
262{
263 return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
264}
265
266
267
268struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
269{
270 struct XenDevice *xendev;
271
272 QTAILQ_FOREACH(xendev, &xendevs, next) {
273 if (xendev->dom != dom) {
274 continue;
275 }
276 if (xendev->dev != dev) {
277 continue;
278 }
279 if (strcmp(xendev->type, type) != 0) {
280 continue;
281 }
282 return xendev;
283 }
284 return NULL;
285}
286
287
288
289
290void xen_pv_del_xendev(struct XenDevice *xendev)
291{
292 if (xendev->ops->free) {
293 xendev->ops->free(xendev);
294 }
295
296 if (xendev->fe) {
297 char token[XEN_BUFSIZE];
298 snprintf(token, sizeof(token), "fe:%p", xendev);
299 xs_unwatch(xenstore, xendev->fe, token);
300 g_free(xendev->fe);
301 }
302
303 if (xendev->evtchndev != NULL) {
304 xenevtchn_close(xendev->evtchndev);
305 }
306 if (xendev->gnttabdev != NULL) {
307 xengnttab_close(xendev->gnttabdev);
308 }
309
310 QTAILQ_REMOVE(&xendevs, xendev, next);
311
312 qdev_unplug(&xendev->qdev, NULL);
313}
314
315void xen_pv_insert_xendev(struct XenDevice *xendev)
316{
317 QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
318}
319