1 #include "qemu/osdep.h" 2 #include "trace.h" 3 #include "ui/qemu-spice.h" 4 #include "chardev/char.h" 5 #include "qapi/error.h" 6 #include "qemu/error-report.h" 7 #include "qemu/option.h" 8 #include <spice.h> 9 #include <spice/protocol.h> 10 11 12 typedef struct SpiceChardev { 13 Chardev parent; 14 15 SpiceCharDeviceInstance sin; 16 bool active; 17 bool blocked; 18 const uint8_t *datapos; 19 int datalen; 20 QLIST_ENTRY(SpiceChardev) next; 21 } SpiceChardev; 22 23 #define TYPE_CHARDEV_SPICE "chardev-spice" 24 #define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc" 25 #define TYPE_CHARDEV_SPICEPORT "chardev-spiceport" 26 27 #define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE) 28 29 typedef struct SpiceCharSource { 30 GSource source; 31 SpiceChardev *scd; 32 } SpiceCharSource; 33 34 static QLIST_HEAD(, SpiceChardev) spice_chars = 35 QLIST_HEAD_INITIALIZER(spice_chars); 36 37 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) 38 { 39 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 40 Chardev *chr = CHARDEV(scd); 41 ssize_t out = 0; 42 ssize_t last_out; 43 uint8_t* p = (uint8_t*)buf; 44 45 while (len > 0) { 46 int can_write = qemu_chr_be_can_write(chr); 47 last_out = MIN(len, can_write); 48 if (last_out <= 0) { 49 break; 50 } 51 qemu_chr_be_write(chr, p, last_out); 52 out += last_out; 53 len -= last_out; 54 p += last_out; 55 } 56 57 trace_spice_vmc_write(out, len + out); 58 return out; 59 } 60 61 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) 62 { 63 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 64 int bytes = MIN(len, scd->datalen); 65 66 if (bytes > 0) { 67 memcpy(buf, scd->datapos, bytes); 68 scd->datapos += bytes; 69 scd->datalen -= bytes; 70 assert(scd->datalen >= 0); 71 } 72 if (scd->datalen == 0) { 73 scd->datapos = 0; 74 scd->blocked = false; 75 } 76 trace_spice_vmc_read(bytes, len); 77 return bytes; 78 } 79 80 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) 81 { 82 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 83 Chardev *chr = CHARDEV(scd); 84 int chr_event; 85 86 switch (event) { 87 case SPICE_PORT_EVENT_BREAK: 88 chr_event = CHR_EVENT_BREAK; 89 break; 90 default: 91 return; 92 } 93 94 trace_spice_vmc_event(chr_event); 95 qemu_chr_be_event(chr, chr_event); 96 } 97 98 static void vmc_state(SpiceCharDeviceInstance *sin, int connected) 99 { 100 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 101 Chardev *chr = CHARDEV(scd); 102 103 if ((chr->be_open && connected) || 104 (!chr->be_open && !connected)) { 105 return; 106 } 107 108 qemu_chr_be_event(chr, 109 connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED); 110 } 111 112 static SpiceCharDeviceInterface vmc_interface = { 113 .base.type = SPICE_INTERFACE_CHAR_DEVICE, 114 .base.description = "spice virtual channel char device", 115 .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, 116 .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, 117 .state = vmc_state, 118 .write = vmc_write, 119 .read = vmc_read, 120 .event = vmc_event, 121 #if SPICE_SERVER_VERSION >= 0x000c06 122 .flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE, 123 #endif 124 }; 125 126 127 static void vmc_register_interface(SpiceChardev *scd) 128 { 129 if (scd->active) { 130 return; 131 } 132 scd->sin.base.sif = &vmc_interface.base; 133 qemu_spice_add_interface(&scd->sin.base); 134 scd->active = true; 135 trace_spice_vmc_register_interface(scd); 136 } 137 138 static void vmc_unregister_interface(SpiceChardev *scd) 139 { 140 if (!scd->active) { 141 return; 142 } 143 spice_server_remove_interface(&scd->sin.base); 144 scd->active = false; 145 trace_spice_vmc_unregister_interface(scd); 146 } 147 148 static gboolean spice_char_source_prepare(GSource *source, gint *timeout) 149 { 150 SpiceCharSource *src = (SpiceCharSource *)source; 151 152 *timeout = -1; 153 154 return !src->scd->blocked; 155 } 156 157 static gboolean spice_char_source_check(GSource *source) 158 { 159 SpiceCharSource *src = (SpiceCharSource *)source; 160 161 return !src->scd->blocked; 162 } 163 164 static gboolean spice_char_source_dispatch(GSource *source, 165 GSourceFunc callback, gpointer user_data) 166 { 167 GIOFunc func = (GIOFunc)callback; 168 169 return func(NULL, G_IO_OUT, user_data); 170 } 171 172 static GSourceFuncs SpiceCharSourceFuncs = { 173 .prepare = spice_char_source_prepare, 174 .check = spice_char_source_check, 175 .dispatch = spice_char_source_dispatch, 176 }; 177 178 static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond) 179 { 180 SpiceChardev *scd = SPICE_CHARDEV(chr); 181 SpiceCharSource *src; 182 183 assert(cond & G_IO_OUT); 184 185 src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs, 186 sizeof(SpiceCharSource)); 187 src->scd = scd; 188 189 return (GSource *)src; 190 } 191 192 static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len) 193 { 194 SpiceChardev *s = SPICE_CHARDEV(chr); 195 int read_bytes; 196 197 assert(s->datalen == 0); 198 s->datapos = buf; 199 s->datalen = len; 200 spice_server_char_device_wakeup(&s->sin); 201 read_bytes = len - s->datalen; 202 if (read_bytes != len) { 203 /* We'll get passed in the unconsumed data with the next call */ 204 s->datalen = 0; 205 s->datapos = NULL; 206 s->blocked = true; 207 } 208 return read_bytes; 209 } 210 211 static void char_spice_finalize(Object *obj) 212 { 213 SpiceChardev *s = SPICE_CHARDEV(obj); 214 215 vmc_unregister_interface(s); 216 217 if (s->next.le_prev) { 218 QLIST_REMOVE(s, next); 219 } 220 221 g_free((char *)s->sin.subtype); 222 g_free((char *)s->sin.portname); 223 } 224 225 static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open) 226 { 227 SpiceChardev *s = SPICE_CHARDEV(chr); 228 if (fe_open) { 229 vmc_register_interface(s); 230 } else { 231 vmc_unregister_interface(s); 232 } 233 } 234 235 static void spice_port_set_fe_open(struct Chardev *chr, int fe_open) 236 { 237 SpiceChardev *s = SPICE_CHARDEV(chr); 238 239 if (fe_open) { 240 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED); 241 } else { 242 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED); 243 } 244 } 245 246 static void spice_chr_accept_input(struct Chardev *chr) 247 { 248 SpiceChardev *s = SPICE_CHARDEV(chr); 249 250 spice_server_char_device_wakeup(&s->sin); 251 } 252 253 static void chr_open(Chardev *chr, const char *subtype) 254 { 255 SpiceChardev *s = SPICE_CHARDEV(chr); 256 257 s->active = false; 258 s->sin.subtype = g_strdup(subtype); 259 260 QLIST_INSERT_HEAD(&spice_chars, s, next); 261 } 262 263 static void qemu_chr_open_spice_vmc(Chardev *chr, 264 ChardevBackend *backend, 265 bool *be_opened, 266 Error **errp) 267 { 268 ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data; 269 const char *type = spicevmc->type; 270 const char **psubtype = spice_server_char_device_recognized_subtypes(); 271 272 for (; *psubtype != NULL; ++psubtype) { 273 if (strcmp(type, *psubtype) == 0) { 274 break; 275 } 276 } 277 if (*psubtype == NULL) { 278 char *subtypes = g_strjoinv(", ", 279 (gchar **)spice_server_char_device_recognized_subtypes()); 280 281 error_setg(errp, "unsupported type name: %s", type); 282 error_append_hint(errp, "allowed spice char type names: %s\n", 283 subtypes); 284 285 g_free(subtypes); 286 return; 287 } 288 289 *be_opened = false; 290 chr_open(chr, type); 291 } 292 293 static void qemu_chr_open_spice_port(Chardev *chr, 294 ChardevBackend *backend, 295 bool *be_opened, 296 Error **errp) 297 { 298 ChardevSpicePort *spiceport = backend->u.spiceport.data; 299 const char *name = spiceport->fqdn; 300 SpiceChardev *s; 301 302 if (name == NULL) { 303 error_setg(errp, "missing name parameter"); 304 return; 305 } 306 307 chr_open(chr, "port"); 308 309 *be_opened = false; 310 s = SPICE_CHARDEV(chr); 311 s->sin.portname = g_strdup(name); 312 } 313 314 void qemu_spice_register_ports(void) 315 { 316 SpiceChardev *s; 317 318 QLIST_FOREACH(s, &spice_chars, next) { 319 if (s->sin.portname == NULL) { 320 continue; 321 } 322 vmc_register_interface(s); 323 } 324 } 325 326 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, 327 Error **errp) 328 { 329 const char *name = qemu_opt_get(opts, "name"); 330 ChardevSpiceChannel *spicevmc; 331 332 if (name == NULL) { 333 error_setg(errp, "chardev: spice channel: no name given"); 334 return; 335 } 336 backend->type = CHARDEV_BACKEND_KIND_SPICEVMC; 337 spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1); 338 qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc)); 339 spicevmc->type = g_strdup(name); 340 } 341 342 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, 343 Error **errp) 344 { 345 const char *name = qemu_opt_get(opts, "name"); 346 ChardevSpicePort *spiceport; 347 348 if (name == NULL) { 349 error_setg(errp, "chardev: spice port: no name given"); 350 return; 351 } 352 backend->type = CHARDEV_BACKEND_KIND_SPICEPORT; 353 spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1); 354 qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport)); 355 spiceport->fqdn = g_strdup(name); 356 } 357 358 static void char_spice_class_init(ObjectClass *oc, void *data) 359 { 360 ChardevClass *cc = CHARDEV_CLASS(oc); 361 362 cc->chr_write = spice_chr_write; 363 cc->chr_add_watch = spice_chr_add_watch; 364 cc->chr_accept_input = spice_chr_accept_input; 365 } 366 367 static const TypeInfo char_spice_type_info = { 368 .name = TYPE_CHARDEV_SPICE, 369 .parent = TYPE_CHARDEV, 370 .instance_size = sizeof(SpiceChardev), 371 .instance_finalize = char_spice_finalize, 372 .class_init = char_spice_class_init, 373 .abstract = true, 374 }; 375 376 static void char_spicevmc_class_init(ObjectClass *oc, void *data) 377 { 378 ChardevClass *cc = CHARDEV_CLASS(oc); 379 380 cc->parse = qemu_chr_parse_spice_vmc; 381 cc->open = qemu_chr_open_spice_vmc; 382 cc->chr_set_fe_open = spice_vmc_set_fe_open; 383 } 384 385 static const TypeInfo char_spicevmc_type_info = { 386 .name = TYPE_CHARDEV_SPICEVMC, 387 .parent = TYPE_CHARDEV_SPICE, 388 .class_init = char_spicevmc_class_init, 389 }; 390 391 static void char_spiceport_class_init(ObjectClass *oc, void *data) 392 { 393 ChardevClass *cc = CHARDEV_CLASS(oc); 394 395 cc->parse = qemu_chr_parse_spice_port; 396 cc->open = qemu_chr_open_spice_port; 397 cc->chr_set_fe_open = spice_port_set_fe_open; 398 } 399 400 static const TypeInfo char_spiceport_type_info = { 401 .name = TYPE_CHARDEV_SPICEPORT, 402 .parent = TYPE_CHARDEV_SPICE, 403 .class_init = char_spiceport_class_init, 404 }; 405 406 static void register_types(void) 407 { 408 type_register_static(&char_spice_type_info); 409 type_register_static(&char_spicevmc_type_info); 410 type_register_static(&char_spiceport_type_info); 411 } 412 413 type_init(register_types); 414