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