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
xenstore_cleanup_dir(char * dir)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
xen_config_cleanup(void)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
xenstore_mkdir(char * path,int p)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
xenstore_write_str(const char * base,const char * node,const char * val)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
xenstore_read_str(const char * base,const char * node)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
xenstore_write_int(const char * base,const char * node,int ival)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
xenstore_write_int64(const char * base,const char * node,int64_t ival)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
xenstore_read_int(const char * base,const char * node,int * ival)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
xenstore_read_uint64(const char * base,const char * node,uint64_t * uval)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
xenbus_strstate(enum xenbus_state state)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)
xen_pv_output_msg(struct XenLegacyDevice * xendev,FILE * f,const char * fmt,va_list args)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
xen_pv_printf(struct XenLegacyDevice * xendev,int msg_level,const char * fmt,...)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
xen_pv_evtchn_event(void * opaque)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
xen_pv_unbind_evtchn(struct XenLegacyDevice * xendev)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
xen_pv_send_notify(struct XenLegacyDevice * xendev)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
xen_pv_find_xendev(const char * type,int dom,int dev)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 */
xen_pv_del_xendev(struct XenLegacyDevice * xendev)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(DEVICE(xendev), NULL);
277 }
278
xen_pv_insert_xendev(struct XenLegacyDevice * xendev)279 void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
280 {
281 QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
282 }
283