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