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 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 G_GNUC_PRINTF(3, 0) 200 static void xen_pv_output_msg(struct XenLegacyDevice *xendev, 201 FILE *f, const char *fmt, va_list args) 202 { 203 if (xendev) { 204 fprintf(f, "xen be: %s: ", xendev->name); 205 } else { 206 fprintf(f, "xen be core: "); 207 } 208 vfprintf(f, fmt, args); 209 } 210 211 void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level, 212 const char *fmt, ...) 213 { 214 FILE *logfile; 215 va_list args; 216 217 if (msg_level > (xendev ? xendev->debug : debug)) { 218 return; 219 } 220 221 logfile = qemu_log_trylock(); 222 if (logfile) { 223 va_start(args, fmt); 224 xen_pv_output_msg(xendev, logfile, fmt, args); 225 va_end(args); 226 qemu_log_unlock(logfile); 227 } 228 229 if (msg_level == 0) { 230 va_start(args, fmt); 231 xen_pv_output_msg(xendev, stderr, fmt, args); 232 va_end(args); 233 } 234 } 235 236 void xen_pv_evtchn_event(void *opaque) 237 { 238 struct XenLegacyDevice *xendev = opaque; 239 evtchn_port_t port; 240 241 port = xenevtchn_pending(xendev->evtchndev); 242 if (port != xendev->local_port) { 243 xen_pv_printf(xendev, 0, 244 "xenevtchn_pending returned %d (expected %d)\n", 245 port, xendev->local_port); 246 return; 247 } 248 xenevtchn_unmask(xendev->evtchndev, port); 249 250 if (xendev->ops->event) { 251 xendev->ops->event(xendev); 252 } 253 } 254 255 void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev) 256 { 257 if (xendev->local_port == -1) { 258 return; 259 } 260 qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL); 261 xenevtchn_unbind(xendev->evtchndev, xendev->local_port); 262 xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port); 263 xendev->local_port = -1; 264 } 265 266 int xen_pv_send_notify(struct XenLegacyDevice *xendev) 267 { 268 return xenevtchn_notify(xendev->evtchndev, xendev->local_port); 269 } 270 271 /* ------------------------------------------------------------- */ 272 273 struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev) 274 { 275 struct XenLegacyDevice *xendev; 276 277 QTAILQ_FOREACH(xendev, &xendevs, next) { 278 if (xendev->dom != dom) { 279 continue; 280 } 281 if (xendev->dev != dev) { 282 continue; 283 } 284 if (strcmp(xendev->type, type) != 0) { 285 continue; 286 } 287 return xendev; 288 } 289 return NULL; 290 } 291 292 /* 293 * release xen backend device. 294 */ 295 void xen_pv_del_xendev(struct XenLegacyDevice *xendev) 296 { 297 if (xendev->ops->free) { 298 xendev->ops->free(xendev); 299 } 300 301 if (xendev->fe) { 302 char token[XEN_BUFSIZE]; 303 snprintf(token, sizeof(token), "fe:%p", xendev); 304 xs_unwatch(xenstore, xendev->fe, token); 305 g_free(xendev->fe); 306 } 307 308 if (xendev->evtchndev != NULL) { 309 xenevtchn_close(xendev->evtchndev); 310 } 311 if (xendev->gnttabdev != NULL) { 312 xengnttab_close(xendev->gnttabdev); 313 } 314 315 QTAILQ_REMOVE(&xendevs, xendev, next); 316 317 qdev_unplug(&xendev->qdev, NULL); 318 } 319 320 void xen_pv_insert_xendev(struct XenLegacyDevice *xendev) 321 { 322 QTAILQ_INSERT_TAIL(&xendevs, xendev, next); 323 } 324