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