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