xref: /openbmc/qemu/hw/xen/xen_pvdev.c (revision fcf5ef2a)
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 }
319