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