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