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 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 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 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 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 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 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 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 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 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 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) 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 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 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 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 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 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 */ 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(&xendev->qdev, NULL); 277 } 278 279 void xen_pv_insert_xendev(struct XenLegacyDevice *xendev) 280 { 281 QTAILQ_INSERT_TAIL(&xendevs, xendev, next); 282 } 283