]> git.proxmox.com Git - mirror_qemu.git/blob - hw/xen/xen_pvdev.c
Merge remote-tracking branch 'sstabellini/tags/xen-20161122-tag' into staging
[mirror_qemu.git] / hw / xen / xen_pvdev.c
1 /*
2 * Xen para-virtualization device
3 *
4 * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>
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 /* private */
27 static int debug;
28
29 struct xs_dirs {
30 char *xs_dir;
31 QTAILQ_ENTRY(xs_dirs) list;
32 };
33
34 static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
35 QTAILQ_HEAD_INITIALIZER(xs_cleanup);
36
37 static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
38 QTAILQ_HEAD_INITIALIZER(xendevs);
39
40 /* ------------------------------------------------------------- */
41
42 static 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
51 void 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
60 int xenstore_mkdir(char *path, int p)
61 {
62 struct xs_permissions perms[2] = {
63 {
64 .id = 0, /* set owner: dom0 */
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
84 int 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
95 char *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 /* move to qemu-allocated memory to make sure
105 * callers can savely g_free() stuff. */
106 ret = g_strdup(str);
107 free(str);
108 }
109 return ret;
110 }
111
112 int 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
120 int 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
128 int 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
141 int 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
154 void 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
173 cleanup:
174 free(vec);
175 }
176
177 const 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 * msg_level:
193 * 0 == errors (stderr + logfile).
194 * 1 == informative debug messages (logfile only).
195 * 2 == noisy debug messages (logfile only).
196 * 3 == will flood your log (logfile only).
197 */
198 void 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
231 void 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
250 void 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
261 int xen_pv_send_notify(struct XenDevice *xendev)
262 {
263 return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
264 }
265
266 /* ------------------------------------------------------------- */
267
268 struct 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 * release xen backend device.
289 */
290 void 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
315 void xen_pv_insert_xendev(struct XenDevice *xendev)
316 {
317 QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
318 }