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