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 "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 xs_rm(xenstore, 0, d->xs_dir); 58 } 59 } 60 61 int xenstore_mkdir(char *path, int p) 62 { 63 struct xs_permissions perms[2] = { 64 { 65 .id = 0, /* set owner: dom0 */ 66 }, { 67 .id = xen_domid, 68 .perms = p, 69 } 70 }; 71 72 if (!xs_mkdir(xenstore, 0, path)) { 73 xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path); 74 return -1; 75 } 76 xenstore_cleanup_dir(g_strdup(path)); 77 78 if (!xs_set_permissions(xenstore, 0, path, perms, 2)) { 79 xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path); 80 return -1; 81 } 82 return 0; 83 } 84 85 int xenstore_write_str(const char *base, const char *node, const char *val) 86 { 87 char abspath[XEN_BUFSIZE]; 88 89 snprintf(abspath, sizeof(abspath), "%s/%s", base, node); 90 if (!xs_write(xenstore, 0, abspath, val, strlen(val))) { 91 return -1; 92 } 93 return 0; 94 } 95 96 char *xenstore_read_str(const char *base, const char *node) 97 { 98 char abspath[XEN_BUFSIZE]; 99 unsigned int len; 100 char *str, *ret = NULL; 101 102 snprintf(abspath, sizeof(abspath), "%s/%s", base, node); 103 str = xs_read(xenstore, 0, abspath, &len); 104 if (str != NULL) { 105 /* move to qemu-allocated memory to make sure 106 * callers can savely g_free() stuff. */ 107 ret = g_strdup(str); 108 free(str); 109 } 110 return ret; 111 } 112 113 int xenstore_write_int(const char *base, const char *node, int ival) 114 { 115 char val[12]; 116 117 snprintf(val, sizeof(val), "%d", ival); 118 return xenstore_write_str(base, node, val); 119 } 120 121 int xenstore_write_int64(const char *base, const char *node, int64_t ival) 122 { 123 char val[21]; 124 125 snprintf(val, sizeof(val), "%"PRId64, ival); 126 return xenstore_write_str(base, node, val); 127 } 128 129 int xenstore_read_int(const char *base, const char *node, int *ival) 130 { 131 char *val; 132 int rc = -1; 133 134 val = xenstore_read_str(base, node); 135 if (val && 1 == sscanf(val, "%d", ival)) { 136 rc = 0; 137 } 138 g_free(val); 139 return rc; 140 } 141 142 int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval) 143 { 144 char *val; 145 int rc = -1; 146 147 val = xenstore_read_str(base, node); 148 if (val && 1 == sscanf(val, "%"SCNu64, uval)) { 149 rc = 0; 150 } 151 g_free(val); 152 return rc; 153 } 154 155 void xenstore_update(void *unused) 156 { 157 char **vec = NULL; 158 intptr_t type, ops, ptr; 159 unsigned int dom, count; 160 161 vec = xs_read_watch(xenstore, &count); 162 if (vec == NULL) { 163 goto cleanup; 164 } 165 166 if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR, 167 &type, &dom, &ops) == 3) { 168 xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)ops); 169 } 170 if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) { 171 xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr); 172 } 173 174 cleanup: 175 free(vec); 176 } 177 178 const char *xenbus_strstate(enum xenbus_state state) 179 { 180 static const char *const name[] = { 181 [XenbusStateUnknown] = "Unknown", 182 [XenbusStateInitialising] = "Initialising", 183 [XenbusStateInitWait] = "InitWait", 184 [XenbusStateInitialised] = "Initialised", 185 [XenbusStateConnected] = "Connected", 186 [XenbusStateClosing] = "Closing", 187 [XenbusStateClosed] = "Closed", 188 }; 189 return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; 190 } 191 192 /* 193 * msg_level: 194 * 0 == errors (stderr + logfile). 195 * 1 == informative debug messages (logfile only). 196 * 2 == noisy debug messages (logfile only). 197 * 3 == will flood your log (logfile only). 198 */ 199 void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level, 200 const char *fmt, ...) 201 { 202 va_list args; 203 204 if (xendev) { 205 if (msg_level > xendev->debug) { 206 return; 207 } 208 qemu_log("xen be: %s: ", xendev->name); 209 if (msg_level == 0) { 210 fprintf(stderr, "xen be: %s: ", xendev->name); 211 } 212 } else { 213 if (msg_level > debug) { 214 return; 215 } 216 qemu_log("xen be core: "); 217 if (msg_level == 0) { 218 fprintf(stderr, "xen be core: "); 219 } 220 } 221 va_start(args, fmt); 222 qemu_log_vprintf(fmt, args); 223 va_end(args); 224 if (msg_level == 0) { 225 va_start(args, fmt); 226 vfprintf(stderr, fmt, args); 227 va_end(args); 228 } 229 qemu_log_flush(); 230 } 231 232 void xen_pv_evtchn_event(void *opaque) 233 { 234 struct XenLegacyDevice *xendev = opaque; 235 evtchn_port_t port; 236 237 port = xenevtchn_pending(xendev->evtchndev); 238 if (port != xendev->local_port) { 239 xen_pv_printf(xendev, 0, 240 "xenevtchn_pending returned %d (expected %d)\n", 241 port, xendev->local_port); 242 return; 243 } 244 xenevtchn_unmask(xendev->evtchndev, port); 245 246 if (xendev->ops->event) { 247 xendev->ops->event(xendev); 248 } 249 } 250 251 void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev) 252 { 253 if (xendev->local_port == -1) { 254 return; 255 } 256 qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL); 257 xenevtchn_unbind(xendev->evtchndev, xendev->local_port); 258 xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port); 259 xendev->local_port = -1; 260 } 261 262 int xen_pv_send_notify(struct XenLegacyDevice *xendev) 263 { 264 return xenevtchn_notify(xendev->evtchndev, xendev->local_port); 265 } 266 267 /* ------------------------------------------------------------- */ 268 269 struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev) 270 { 271 struct XenLegacyDevice *xendev; 272 273 QTAILQ_FOREACH(xendev, &xendevs, next) { 274 if (xendev->dom != dom) { 275 continue; 276 } 277 if (xendev->dev != dev) { 278 continue; 279 } 280 if (strcmp(xendev->type, type) != 0) { 281 continue; 282 } 283 return xendev; 284 } 285 return NULL; 286 } 287 288 /* 289 * release xen backend device. 290 */ 291 void xen_pv_del_xendev(struct XenLegacyDevice *xendev) 292 { 293 if (xendev->ops->free) { 294 xendev->ops->free(xendev); 295 } 296 297 if (xendev->fe) { 298 char token[XEN_BUFSIZE]; 299 snprintf(token, sizeof(token), "fe:%p", xendev); 300 xs_unwatch(xenstore, xendev->fe, token); 301 g_free(xendev->fe); 302 } 303 304 if (xendev->evtchndev != NULL) { 305 xenevtchn_close(xendev->evtchndev); 306 } 307 if (xendev->gnttabdev != NULL) { 308 xengnttab_close(xendev->gnttabdev); 309 } 310 311 QTAILQ_REMOVE(&xendevs, xendev, next); 312 313 qdev_unplug(&xendev->qdev, NULL); 314 } 315 316 void xen_pv_insert_xendev(struct XenLegacyDevice *xendev) 317 { 318 QTAILQ_INSERT_TAIL(&xendevs, xendev, next); 319 } 320