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