Merge remote-tracking branch 'spice/spice.v66' into staging

* spice/spice.v66:
  docs: add spice-port-fqdn.txt
  spice-qemu-char: register spicevmc ports during qemu_spice_init()
  spice-qemu-char: keep a list of spice chardev
  spice-qemu-char: add spiceport chardev
  spice-qemu-char: factor out CharDriverState creation
  spice-qemu-char: write to chardev whatever amount it can read
  qxl+vnc: register a vm state change handler for dummy spice_server
  qxl: save qemu_create_displaysurface_from result

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2012-12-18 15:41:21 -06:00
commit 510981a097
8 changed files with 141 additions and 23 deletions

19
docs/spice-port-fqdn.txt Normal file
View File

@ -0,0 +1,19 @@
A Spice port channel is an arbitrary communication between the Spice
server host side and the client side.
Thanks to the associated reverse fully qualified domain name (fqdn),
a Spice client can handle the various ports appropriately.
The following fqdn names are reserved by the QEMU project:
org.qemu.monitor.hmp.0
QEMU human monitor
org.qemu.monitor.qmp.0:
QEMU control monitor
org.qemu.console.serial.0
QEMU virtual serial port
org.qemu.console.debug.0
QEMU debug console

View File

@ -113,11 +113,12 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
qxl->guest_primary.bits_pp); qxl->guest_primary.bits_pp);
if (qxl->guest_primary.qxl_stride > 0) { if (qxl->guest_primary.qxl_stride > 0) {
qemu_free_displaysurface(vga->ds); qemu_free_displaysurface(vga->ds);
qemu_create_displaysurface_from(qxl->guest_primary.surface.width, vga->ds->surface = qemu_create_displaysurface_from
qxl->guest_primary.surface.height, (qxl->guest_primary.surface.width,
qxl->guest_primary.bits_pp, qxl->guest_primary.surface.height,
qxl->guest_primary.abs_stride, qxl->guest_primary.bits_pp,
qxl->guest_primary.data); qxl->guest_primary.abs_stride,
qxl->guest_primary.data);
} else { } else {
qemu_resize_displaysurface(vga->ds, qemu_resize_displaysurface(vga->ds,
qxl->guest_primary.surface.width, qxl->guest_primary.surface.width,

View File

@ -2762,6 +2762,9 @@ static const struct {
#endif #endif
#ifdef CONFIG_SPICE #ifdef CONFIG_SPICE
{ .name = "spicevmc", .open = qemu_chr_open_spice }, { .name = "spicevmc", .open = qemu_chr_open_spice },
#if SPICE_SERVER_VERSION >= 0x000c02
{ .name = "spiceport", .open = qemu_chr_open_spice_port },
#endif
#endif #endif
}; };

View File

@ -1749,6 +1749,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
#endif #endif
#if defined(CONFIG_SPICE) #if defined(CONFIG_SPICE)
"-chardev spicevmc,id=id,name=name[,debug=debug]\n" "-chardev spicevmc,id=id,name=name[,debug=debug]\n"
"-chardev spiceport,id=id,name=name[,debug=debug]\n"
#endif #endif
, QEMU_ARCH_ALL , QEMU_ARCH_ALL
) )
@ -1776,6 +1777,7 @@ Backend is one of:
@option{tty}, @option{tty},
@option{parport}, @option{parport},
@option{spicevmc}. @option{spicevmc}.
@option{spiceport}.
The specific backend will determine the applicable options. The specific backend will determine the applicable options.
All devices must have an id, which can be any string up to 127 characters long. All devices must have an id, which can be any string up to 127 characters long.
@ -1961,6 +1963,17 @@ required.
Connect to a spice virtual machine channel, such as vdiport. Connect to a spice virtual machine channel, such as vdiport.
@item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name}
@option{spiceport} is only available when spice support is built in.
@option{debug} debug level for spicevmc
@option{name} name of spice port to connect to
Connect to a spice port, allowing a Spice client to handle the traffic
identified by a name (preferably a fqdn).
@end table @end table
ETEXI ETEXI

View File

@ -3,6 +3,7 @@
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
#include <spice.h> #include <spice.h>
#include <spice-experimental.h> #include <spice-experimental.h>
#include <spice/protocol.h>
#include "osdep.h" #include "osdep.h"
@ -14,8 +15,6 @@
} \ } \
} while (0) } while (0)
#define VMC_MAX_HOST_WRITE 2048
typedef struct SpiceCharDriver { typedef struct SpiceCharDriver {
CharDriverState* chr; CharDriverState* chr;
SpiceCharDeviceInstance sin; SpiceCharDeviceInstance sin;
@ -25,8 +24,12 @@ typedef struct SpiceCharDriver {
uint8_t *datapos; uint8_t *datapos;
ssize_t bufsize, datalen; ssize_t bufsize, datalen;
uint32_t debug; uint32_t debug;
QLIST_ENTRY(SpiceCharDriver) next;
} SpiceCharDriver; } SpiceCharDriver;
static QLIST_HEAD(, SpiceCharDriver) spice_chars =
QLIST_HEAD_INITIALIZER(spice_chars);
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
{ {
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
@ -35,8 +38,8 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
uint8_t* p = (uint8_t*)buf; uint8_t* p = (uint8_t*)buf;
while (len > 0) { while (len > 0) {
last_out = MIN(len, VMC_MAX_HOST_WRITE); last_out = MIN(len, qemu_chr_be_can_write(scd->chr));
if (qemu_chr_be_can_write(scd->chr) < last_out) { if (last_out <= 0) {
break; break;
} }
qemu_chr_be_write(scd->chr, p, last_out); qemu_chr_be_write(scd->chr, p, last_out);
@ -69,6 +72,27 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
return bytes; return bytes;
} }
#if SPICE_SERVER_VERSION >= 0x000c02
static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
{
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
int chr_event;
switch (event) {
case SPICE_PORT_EVENT_BREAK:
chr_event = CHR_EVENT_BREAK;
break;
default:
dprintf(scd, 2, "%s: unknown %d\n", __func__, event);
return;
}
dprintf(scd, 2, "%s: %d\n", __func__, event);
trace_spice_vmc_event(chr_event);
qemu_chr_be_event(scd->chr, chr_event);
}
#endif
static void vmc_state(SpiceCharDeviceInstance *sin, int connected) static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
{ {
SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
@ -105,6 +129,9 @@ static SpiceCharDeviceInterface vmc_interface = {
.state = vmc_state, .state = vmc_state,
.write = vmc_write, .write = vmc_write,
.read = vmc_read, .read = vmc_read,
#if SPICE_SERVER_VERSION >= 0x000c02
.event = vmc_event,
#endif
}; };
@ -156,6 +183,7 @@ static void spice_chr_close(struct CharDriverState *chr)
printf("%s\n", __func__); printf("%s\n", __func__);
vmc_unregister_interface(s); vmc_unregister_interface(s);
QLIST_REMOVE(s, next);
g_free(s); g_free(s);
} }
@ -188,13 +216,34 @@ static void print_allowed_subtypes(void)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
CharDriverState *qemu_chr_open_spice(QemuOpts *opts) static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
{ {
CharDriverState *chr; CharDriverState *chr;
SpiceCharDriver *s; SpiceCharDriver *s;
const char* name = qemu_opt_get(opts, "name");
uint32_t debug = qemu_opt_get_number(opts, "debug", 0); uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
const char** psubtype = spice_server_char_device_recognized_subtypes();
chr = g_malloc0(sizeof(CharDriverState));
s = g_malloc0(sizeof(SpiceCharDriver));
s->chr = chr;
s->debug = debug;
s->active = false;
s->sin.subtype = subtype;
chr->opaque = s;
chr->chr_write = spice_chr_write;
chr->chr_close = spice_chr_close;
chr->chr_guest_open = spice_chr_guest_open;
chr->chr_guest_close = spice_chr_guest_close;
QLIST_INSERT_HEAD(&spice_chars, s, next);
return chr;
}
CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
{
CharDriverState *chr;
const char *name = qemu_opt_get(opts, "name");
const char **psubtype = spice_server_char_device_recognized_subtypes();
const char *subtype = NULL; const char *subtype = NULL;
if (name == NULL) { if (name == NULL) {
@ -214,17 +263,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
return NULL; return NULL;
} }
chr = g_malloc0(sizeof(CharDriverState)); chr = chr_open(opts, subtype);
s = g_malloc0(sizeof(SpiceCharDriver));
s->chr = chr;
s->debug = debug;
s->active = false;
s->sin.subtype = subtype;
chr->opaque = s;
chr->chr_write = spice_chr_write;
chr->chr_close = spice_chr_close;
chr->chr_guest_open = spice_chr_guest_open;
chr->chr_guest_close = spice_chr_guest_close;
#if SPICE_SERVER_VERSION < 0x000901 #if SPICE_SERVER_VERSION < 0x000901
/* See comment in vmc_state() */ /* See comment in vmc_state() */
@ -235,3 +274,35 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
return chr; return chr;
} }
#if SPICE_SERVER_VERSION >= 0x000c02
CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts)
{
CharDriverState *chr;
SpiceCharDriver *s;
const char *name = qemu_opt_get(opts, "name");
if (name == NULL) {
fprintf(stderr, "spice-qemu-char: missing name parameter\n");
return NULL;
}
chr = chr_open(opts, "port");
s = chr->opaque;
s->sin.portname = name;
return chr;
}
void qemu_spice_register_ports(void)
{
SpiceCharDriver *s;
QLIST_FOREACH(s, &spice_chars, next) {
if (s->sin.portname == NULL) {
continue;
}
vmc_register_interface(s);
}
}
#endif

View File

@ -535,6 +535,7 @@ spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d"
spice_vmc_read(int bytes, int len) "spice read %d of requested %d" spice_vmc_read(int bytes, int len) "spice read %d of requested %d"
spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p" spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
spice_vmc_event(int event) "spice vmc event %d"
# hw/lm32_pic.c # hw/lm32_pic.c
lm32_pic_raise_irq(void) "Raise CPU interrupt" lm32_pic_raise_irq(void) "Raise CPU interrupt"

View File

@ -46,6 +46,10 @@ void do_info_spice_print(Monitor *mon, const QObject *data);
void do_info_spice(Monitor *mon, QObject **ret_data); void do_info_spice(Monitor *mon, QObject **ret_data);
CharDriverState *qemu_chr_open_spice(QemuOpts *opts); CharDriverState *qemu_chr_open_spice(QemuOpts *opts);
#if SPICE_SERVER_VERSION >= 0x000c02
CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts);
void qemu_spice_register_ports(void);
#endif
#else /* CONFIG_SPICE */ #else /* CONFIG_SPICE */
#include "monitor.h" #include "monitor.h"

View File

@ -714,6 +714,10 @@ void qemu_spice_init(void)
g_free(x509_key_file); g_free(x509_key_file);
g_free(x509_cert_file); g_free(x509_cert_file);
g_free(x509_cacert_file); g_free(x509_cacert_file);
#if SPICE_SERVER_VERSION >= 0x000c02
qemu_spice_register_ports();
#endif
} }
int qemu_spice_add_interface(SpiceBaseInstance *sin) int qemu_spice_add_interface(SpiceBaseInstance *sin)
@ -732,6 +736,8 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
*/ */
spice_server = spice_server_new(); spice_server = spice_server_new();
spice_server_init(spice_server, &core_interface); spice_server_init(spice_server, &core_interface);
qemu_add_vm_change_state_handler(vm_change_state_handler,
&spice_server);
} }
return spice_server_add_interface(spice_server, sin); return spice_server_add_interface(spice_server, sin);