xref: /qemu/hw/xen/xen_pvdev.c (revision 7f6314427e78283f84e6f1b425a122b260a6ac50)
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.1 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 "qemu/main-loop.h"
23 #include "hw/qdev-core.h"
24 #include "hw/xen/xen-legacy-backend.h"
25 #include "hw/xen/xen-bus-helper.h"
26 #include "hw/xen/xen_pvdev.h"
27 
28 /* private */
29 static int debug;
30 
31 struct xs_dirs {
32     char *xs_dir;
33     QTAILQ_ENTRY(xs_dirs) list;
34 };
35 
36 static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
37     QTAILQ_HEAD_INITIALIZER(xs_cleanup);
38 
39 static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
40     QTAILQ_HEAD_INITIALIZER(xendevs);
41 
42 /* ------------------------------------------------------------- */
43 
44 static void xenstore_cleanup_dir(char *dir)
45 {
46     struct xs_dirs *d;
47 
48     d = g_malloc(sizeof(*d));
49     d->xs_dir = dir;
50     QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
51 }
52 
53 void xen_config_cleanup(void)
54 {
55     struct xs_dirs *d;
56 
57     QTAILQ_FOREACH(d, &xs_cleanup, list) {
58         qemu_xen_xs_destroy(xenstore, 0, d->xs_dir);
59     }
60 }
61 
62 int xenstore_mkdir(char *path, int p)
63 {
64     if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) {
65         xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
66         return -1;
67     }
68     xenstore_cleanup_dir(g_strdup(path));
69     return 0;
70 }
71 
72 int xenstore_write_str(const char *base, const char *node, const char *val)
73 {
74     char abspath[XEN_BUFSIZE];
75 
76     snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
77     if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) {
78         return -1;
79     }
80     return 0;
81 }
82 
83 char *xenstore_read_str(const char *base, const char *node)
84 {
85     char *str, *ret = NULL;
86 
87     str = xs_node_read(xenstore, 0, NULL, NULL, "%s/%s", base, node);
88     if (str != NULL) {
89         /* move to qemu-allocated memory to make sure
90          * callers can safely g_free() stuff. */
91         ret = g_strdup(str);
92         free(str);
93     }
94     return ret;
95 }
96 
97 int xenstore_write_int(const char *base, const char *node, int ival)
98 {
99     char val[12];
100 
101     snprintf(val, sizeof(val), "%d", ival);
102     return xenstore_write_str(base, node, val);
103 }
104 
105 int xenstore_write_int64(const char *base, const char *node, int64_t ival)
106 {
107     char val[21];
108 
109     snprintf(val, sizeof(val), "%"PRId64, ival);
110     return xenstore_write_str(base, node, val);
111 }
112 
113 int xenstore_read_int(const char *base, const char *node, int *ival)
114 {
115     char *val;
116     int rc = -1;
117 
118     val = xenstore_read_str(base, node);
119     if (val && 1 == sscanf(val, "%d", ival)) {
120         rc = 0;
121     }
122     g_free(val);
123     return rc;
124 }
125 
126 int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
127 {
128     char *val;
129     int rc = -1;
130 
131     val = xenstore_read_str(base, node);
132     if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
133         rc = 0;
134     }
135     g_free(val);
136     return rc;
137 }
138 
139 const char *xenbus_strstate(enum xenbus_state state)
140 {
141     static const char *const name[] = {
142         [XenbusStateUnknown]       = "Unknown",
143         [XenbusStateInitialising]  = "Initialising",
144         [XenbusStateInitWait]      = "InitWait",
145         [XenbusStateInitialised]   = "Initialised",
146         [XenbusStateConnected]     = "Connected",
147         [XenbusStateClosing]       = "Closing",
148         [XenbusStateClosed]        = "Closed",
149     };
150     return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
151 }
152 
153 /*
154  * msg_level:
155  *  0 == errors (stderr + logfile).
156  *  1 == informative debug messages (logfile only).
157  *  2 == noisy debug messages (logfile only).
158  *  3 == will flood your log (logfile only).
159  */
160 G_GNUC_PRINTF(3, 0)
161 static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
162                               FILE *f, const char *fmt, va_list args)
163 {
164     if (xendev) {
165         fprintf(f, "xen be: %s: ", xendev->name);
166     } else {
167         fprintf(f, "xen be core: ");
168     }
169     vfprintf(f, fmt, args);
170 }
171 
172 void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
173                    const char *fmt, ...)
174 {
175     FILE *logfile;
176     va_list args;
177 
178     if (msg_level > (xendev ? xendev->debug : debug)) {
179         return;
180     }
181 
182     logfile = qemu_log_trylock();
183     if (logfile) {
184         va_start(args, fmt);
185         xen_pv_output_msg(xendev, logfile, fmt, args);
186         va_end(args);
187         qemu_log_unlock(logfile);
188     }
189 
190     if (msg_level == 0) {
191         va_start(args, fmt);
192         xen_pv_output_msg(xendev, stderr, fmt, args);
193         va_end(args);
194     }
195 }
196 
197 void xen_pv_evtchn_event(void *opaque)
198 {
199     struct XenLegacyDevice *xendev = opaque;
200     evtchn_port_t port;
201 
202     port = qemu_xen_evtchn_pending(xendev->evtchndev);
203     if (port != xendev->local_port) {
204         xen_pv_printf(xendev, 0,
205                       "xenevtchn_pending returned %d (expected %d)\n",
206                       port, xendev->local_port);
207         return;
208     }
209     qemu_xen_evtchn_unmask(xendev->evtchndev, port);
210 
211     if (xendev->ops->event) {
212         xendev->ops->event(xendev);
213     }
214 }
215 
216 void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
217 {
218     if (xendev->local_port == -1) {
219         return;
220     }
221     qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
222     qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port);
223     xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
224     xendev->local_port = -1;
225 }
226 
227 int xen_pv_send_notify(struct XenLegacyDevice *xendev)
228 {
229     return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port);
230 }
231 
232 /* ------------------------------------------------------------- */
233 
234 struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
235 {
236     struct XenLegacyDevice *xendev;
237 
238     QTAILQ_FOREACH(xendev, &xendevs, next) {
239         if (xendev->dom != dom) {
240             continue;
241         }
242         if (xendev->dev != dev) {
243             continue;
244         }
245         if (strcmp(xendev->type, type) != 0) {
246             continue;
247         }
248         return xendev;
249     }
250     return NULL;
251 }
252 
253 /*
254  * release xen backend device.
255  */
256 void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
257 {
258     if (xendev->ops->free) {
259         xendev->ops->free(xendev);
260     }
261 
262     if (xendev->fe) {
263         qemu_xen_xs_unwatch(xenstore, xendev->watch);
264         g_free(xendev->fe);
265     }
266 
267     if (xendev->evtchndev != NULL) {
268         qemu_xen_evtchn_close(xendev->evtchndev);
269     }
270     if (xendev->gnttabdev != NULL) {
271         qemu_xen_gnttab_close(xendev->gnttabdev);
272     }
273 
274     QTAILQ_REMOVE(&xendevs, xendev, next);
275 
276     qdev_unplug(&xendev->qdev, NULL);
277 }
278 
279 void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
280 {
281     QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
282 }
283