From 52f3dde83b45d9e4e84dc68d5c62b96bfd8c70cc Mon Sep 17 00:00:00 2001 From: Yaniv Kamay <yaniv@qumranet.com> Date: Sun, 21 Dec 2008 13:32:08 +0200 Subject: [PATCH 10/54] qxl: add qxl device + support libspice [ehabkost: use pkgconfig to probe for spice] RH-Type: improvement(qxl) RH-Upstream-status: pending --- qemu/Makefile | 5 + qemu/Makefile.target | 13 + qemu/configure | 52 ++++- qemu/console.h | 1 + qemu/hw/pc.c | 13 + qemu/hw/pc.h | 18 ++ qemu/hw/ps2.c | 217 ++++++++++++++++++- qemu/hw/qxl.c | 508 ++++++++++++++++++++++++++++++------------- qemu/hw/qxl_interface.h | 54 +++-- qemu/hw/qxl_native_worker.c | 151 +++++++++++++ qemu/hw/usb-hid.c | 96 ++++++++- qemu/hw/vga.c | 17 ++ qemu/interface.c | 232 ++++++++++++++++++++ qemu/interface.h | 12 + qemu/monitor.c | 210 ++++++++++++++++-- qemu/vl.c | 99 ++++++++- 16 files changed, 1488 insertions(+), 210 deletions(-) create mode 100644 qemu/hw/qxl_native_worker.c create mode 100644 qemu/interface.c create mode 100644 qemu/interface.h diff --git a/qemu/Makefile b/qemu/Makefile index 8293bf9..f277379 100644 --- a/qemu/Makefile +++ b/qemu/Makefile @@ -151,6 +151,11 @@ ifdef CONFIG_COCOA OBJS+=cocoa.o endif +ifdef CONFIG_SPICE +CFLAGS+=$(SPICE_CFLAGS) +LIBS+=$(SPICE_LIBS) +endif + ifdef CONFIG_SLIRP CPPFLAGS+=-I$(SRC_PATH)/slirp SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \ diff --git a/qemu/Makefile.target b/qemu/Makefile.target index 5cf1dda..806fdb5 100644 --- a/qemu/Makefile.target +++ b/qemu/Makefile.target @@ -231,6 +231,11 @@ LIBOBJS+=qemu-kvm-helper.o endif endif +ifeq ($(CONFIG_SPICE),yes) +CFLAGS+=$(SPICE_CFLAGS) +LIBS+=$(SPICE_LIBS) +endif + LIBOBJS+= op_helper.o ifneq ($(TARGET_ARCH), ia64) @@ -710,6 +715,14 @@ OBJS+= extboot.o # virtio support OBJS+= virtio.o virtio-blk.o virtio-balloon.o OBJS += virtio-net.o + +ifeq ($(CONFIG_QXL),yes) +OBJS+=qxl.o qxl_native_worker.o +endif +ifeq ($(CONFIG_SPICE),yes) +OBJS+=interface.o +endif + ifeq ($(USE_KVM_PIT), 1) OBJS+= i8254-kvm.o endif diff --git a/qemu/configure b/qemu/configure index f405b86..3276832 100755 --- a/qemu/configure +++ b/qemu/configure @@ -184,6 +184,8 @@ fdt="yes" signalfd="no" eventfd="no" cpu_emulation="yes" +qxl="yes" +spice="no" # OS specific if check_define __linux__ ; then @@ -391,6 +393,10 @@ for opt do ;; --disable-vde) vde="no" ;; + --disable-qxl) qxl="no" + ;; + --enable-spice) spice="yes" + ;; --disable-kqemu) kqemu="no" ;; --disable-brlapi) brlapi="no" @@ -569,6 +575,8 @@ echo " --disable-aio disable AIO support" echo " --disable-blobs disable installing provided firmware blobs" echo " --kerneldir=PATH look for kernel includes in PATH" echo " --disable-cpu-emulation disables use of qemu cpu emulation code" +echo " --disable-qxl disable qxl" +echo " --enable-spice use spice" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -1140,6 +1148,26 @@ if [ -x "`which texi2html 2>/dev/null`" ] && \ fi ########################################## +# spice probe +if test "$spice" = "yes" ; then + `pkg-config spice` || spice="no" +fi +if test "$spice" = "yes" ; then + cat > $TMPC << EOF +#include <spice.h> +int main(void) { CoreInterface ci; spice_init(&ci); return 0; } +EOF + spice_cflags=`pkg-config --cflags spice` + spice_libs=`pkg-config --libs spice` + if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $spice_cflags $TMPC \ + $spice_libs > /dev/null 2> /dev/null ; then + : + else + spice="no" + fi +fi + +########################################## # Do we need librt cat > $TMPC <<EOF #include <signal.h> @@ -1233,9 +1261,8 @@ echo "uname -r $uname_release" echo "NPTL support $nptl" echo "vde support $vde" echo "AIO support $aio" -echo "Install blobs $blobs" -echo "KVM support $kvm" -echo "fdt support $fdt" +echo "QXL $qxl" +echo "Spice $spice" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -1543,6 +1570,23 @@ if test "$eventfd" = "yes" ; then echo "#define CONFIG_eventfd 1" >> $config_h fi +if test "$qxl" = "yes" ; then + echo "CONFIG_QXL=yes" >> $config_mak + echo "#define CONFIG_QXL 1" >> $config_h +fi + +if test "$spice" = "yes" ; then + if test "$qxl" = "no" ; then + echo "ERROR: Spice requires QXL device" + exit 1; + fi + + echo "CONFIG_SPICE=yes" >> $config_mak + echo "SPICE_CFLAGS=$spice_cflags" >> $config_mak + echo "SPICE_LIBS=$spice_libs" >> $config_mak + echo "#define CONFIG_SPICE 1" >> $config_h +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "#define O_LARGEFILE 0" >> $config_h @@ -1623,7 +1667,7 @@ case "$target" in esac if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ - -a "$sdl" = "no" -a "$cocoa" = "no" ; then + -a "$sdl" = "no" -a "$cocoa" = "no" -a "$qxl" = "no" ; then echo "ERROR: QEMU requires SDL or Cocoa for graphical output" echo "To build QEMU without graphical output configure with --disable-gfx-check" echo "Note that this will disable all output from the virtual graphics card" diff --git a/qemu/console.h b/qemu/console.h index 6ee40cc..791d32a 100644 --- a/qemu/console.h +++ b/qemu/console.h @@ -191,6 +191,7 @@ extern uint8_t _translate_keycode(const int key); /* FIXME: term_printf et al should probably go elsewhere so everything does not need to include console.h */ /* monitor.c */ +void init_monitor_commands(); void monitor_init(CharDriverState *hd, int show_banner); void term_puts(const char *str); void term_vprintf(const char *fmt, va_list ap); diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c index 3038cd3..51f78e1 100644 --- a/qemu/hw/pc.c +++ b/qemu/hw/pc.c @@ -1006,6 +1006,19 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } +#ifdef CONFIG_QXL + } else if (using_qxl) { + if (!pci_enabled) { + fprintf(stderr, "%s: can't use qxl without pci\n", __FUNCTION__); + exit(-1); + } + isa_vga_init(ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); + for (i = 0; i < num_qxl_device; i++) { + ram_addr_t qxl_ram = qemu_ram_alloc(QXL_MEM_SIZE); + qxl_init(pci_bus, phys_ram_base + qxl_ram, qxl_ram, QXL_MEM_SIZE); + } +#endif } else if (vmsvga_enabled) { if (pci_enabled) pci_vmsvga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h index e9ddd4d..a4aede5 100644 --- a/qemu/hw/pc.h +++ b/qemu/hw/pc.h @@ -158,6 +158,24 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, ram_addr_t vga_ram_offset, int vga_ram_size); +/*qxl.c*/ +#ifdef CONFIG_QXL + +#define QXL_MEM_SIZE (1024 * 1024 * (32 + 9)) +#define QXL_MAX_MONITORS 4 + +extern int using_qxl; +extern int num_qxl_device; + +void qxl_init(PCIBus *bus, uint8_t *vram, + unsigned long vram_offset, + uint32_t vram_size); +void qxl_init_display(DisplayState *ds); +int qxl_vga_touch(void); +void qxl_do_set_log_level(int log_level); + +#endif + /* ide.c */ void isa_ide_init(int iobase, int iobase2, qemu_irq irq, BlockDriverState *hd0, BlockDriverState *hd1); diff --git a/qemu/hw/ps2.c b/qemu/hw/ps2.c index 054b92f..405b9c3 100644 --- a/qemu/hw/ps2.c +++ b/qemu/hw/ps2.c @@ -24,6 +24,9 @@ #include "hw.h" #include "ps2.h" #include "console.h" +#ifdef CONFIG_SPICE +#include "interface.h" +#endif /* debug PC keyboard */ //#define DEBUG_KBD @@ -92,6 +95,7 @@ typedef struct { not the keyboard controller. */ int translate; int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ + uint8_t leds; //bit 0 scroll lock, bit 1 num lock and bit 2 caps lock } PS2KbdState; typedef struct { @@ -181,10 +185,101 @@ uint32_t ps2_read_data(void *opaque) return val; } +#ifdef CONFIG_SPICE + +typedef struct KBDLedNotifier KBDLedNotifier; +struct KBDLedNotifier { + void *opaque; + keyborad_leads_notifier_t proc; + int refs; + KBDLedNotifier *next; +}; + +static KBDLedNotifier *kbd_leds_notifiers = NULL; + +static KBDLedNotifier *register_leds_notifier(keyborad_leads_notifier_t proc, void *opaque) +{ + KBDLedNotifier *notifier; + + if (!proc) { + return NULL; + } + + if (!(notifier = (KBDLedNotifier *)malloc(sizeof(*notifier)))) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + notifier->opaque = opaque; + notifier->proc = proc; + notifier->refs = 1; + notifier->next = kbd_leds_notifiers; + kbd_leds_notifiers = notifier; + return notifier; +} + +static void hold_led_notifier(KBDLedNotifier* notifier) +{ + notifier->refs++; +} + +static void releas_led_notifier(KBDLedNotifier* notifier) +{ + if (--notifier->refs) { + return; + } + KBDLedNotifier **now = &kbd_leds_notifiers; + + while (*now != notifier) { + now = &(*now)->next; + } + *now = notifier->next; + free(notifier); +} + +static void unregister_leds_notifier(KBDLedNotifier *notifier) +{ + KBDLedNotifier **now = &kbd_leds_notifiers; + for (;;) { + if (*now == notifier) { + notifier->proc = NULL; + releas_led_notifier(notifier); + return; + } + now = &(*now)->next; + } +} + +static void on_leds_change(uint8_t leds) +{ + KBDLedNotifier *notifier = kbd_leds_notifiers; + KBDLedNotifier *temp; + + while (notifier) { + hold_led_notifier(notifier); + notifier->proc(notifier->opaque, leds); + temp = notifier; + notifier = notifier->next; + releas_led_notifier(temp); + } +} +#endif + +static void ps2_set_keyboard_leds(PS2KbdState *s, uint8_t new_val) +{ + if (new_val == s->leds) { + return; + } + s->leds = new_val; +#ifdef CONFIG_SPICE + on_leds_change(new_val); +#endif +} + static void ps2_reset_keyboard(PS2KbdState *s) { s->scan_enabled = 1; s->scancode_set = 2; + ps2_set_keyboard_leds(s, 0); } void ps2_write_keyboard(void *opaque, int val) @@ -259,6 +354,7 @@ void ps2_write_keyboard(void *opaque, int val) s->common.write_cmd = -1; break; case KBD_CMD_SET_LEDS: + ps2_set_keyboard_leds(s, val); ps2_queue(&s->common, KBD_REPLY_ACK); s->common.write_cmd = -1; break; @@ -497,6 +593,7 @@ static void ps2_reset(void *opaque) q->rptr = 0; q->wptr = 0; q->count = 0; + s->update_irq(s->update_arg, 0); } static void ps2_common_save (QEMUFile *f, PS2State *s) @@ -525,6 +622,7 @@ static void ps2_kbd_save(QEMUFile* f, void* opaque) qemu_put_be32(f, s->scan_enabled); qemu_put_be32(f, s->translate); qemu_put_be32(f, s->scancode_set); + qemu_put_byte(f, s->leds); } static void ps2_mouse_save(QEMUFile* f, void* opaque) @@ -548,16 +646,21 @@ static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; - if (version_id != 2 && version_id != 3) + if (version_id < 2 || version_id > 4) return -EINVAL; ps2_common_load (f, &s->common); s->scan_enabled=qemu_get_be32(f); s->translate=qemu_get_be32(f); - if (version_id == 3) + if (version_id >= 3) s->scancode_set=qemu_get_be32(f); else s->scancode_set=2; + if (version_id >= 4) { + ps2_set_keyboard_leds(s, qemu_get_byte(f)); + } else { + ps2_set_keyboard_leds(s, 0); + } return 0; } @@ -582,6 +685,108 @@ static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) return 0; } +#ifdef CONFIG_SPICE + +typedef struct KbdInterface { + KeyboardInterface vd_interface; + PS2KbdState *keyboard_state; +} KbdInterface; + +static void interface_push_scan_freg(KeyboardInterface *keyboard, uint8_t frag) +{ + KbdInterface *interface = (KbdInterface *)keyboard; + ps2_put_keycode(interface->keyboard_state, frag); +} + +static uint8_t interface_get_leds(KeyboardInterface *keyboard) +{ + KbdInterface *interface = (KbdInterface *)keyboard; + return interface->keyboard_state->leds; +} + +static VDObjectRef interface_register_leds_notifier(KeyboardInterface *keyboard, + keyborad_leads_notifier_t notifier, + void *opaque) +{ + if (!notifier) { + return 0; + } + return (VDObjectRef)register_leds_notifier(notifier, opaque); +} + +static void interface_unregister_leds_notifier(KeyboardInterface *keyboard, VDObjectRef notifier) +{ + if (!notifier) { + return; + } + unregister_leds_notifier((KBDLedNotifier *)notifier); +} + +static void regitser_keyboard(PS2KbdState *s) +{ + KbdInterface *interface = (KbdInterface *)qemu_mallocz(sizeof(*interface)); + static int keyboard_interface_id = 0; + + if (!interface) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION; + interface->vd_interface.base.type = VD_INTERFACE_KEYBOARD; + interface->vd_interface.base.id = ++keyboard_interface_id; + interface->vd_interface.base.description = "ps2 keyboard"; + interface->vd_interface.base.major_vertion = VD_INTERFACE_KEYBOARD_MAJOR; + interface->vd_interface.base.minor_vertion = VD_INTERFACE_KEYBOARD_MINOR; + interface->vd_interface.push_scan_freg = interface_push_scan_freg; + interface->vd_interface.get_leds = interface_get_leds; + interface->vd_interface.register_leds_notifier = interface_register_leds_notifier; + interface->vd_interface.unregister_leds_notifayer = interface_unregister_leds_notifier; + interface->keyboard_state = s; + add_interface(&interface->vd_interface.base); +} + +typedef struct PS2MouseInterface { + MouseInterface vd_interface; + PS2MouseState *mouse_state; +} PS2MouseInterface; + +static void interface_moution(MouseInterface* mouse, int dx, int dy, int dz, + uint32_t buttons_state) +{ + PS2MouseInterface *interface = (PS2MouseInterface *)mouse; + ps2_mouse_event(interface->mouse_state, dx, dy, dz, buttons_state); +} + +static void interface_buttons(MouseInterface* mouse, uint32_t buttons_state) +{ + PS2MouseInterface *interface = (PS2MouseInterface *)mouse; + ps2_mouse_event(interface->mouse_state, 0, 0, 0, buttons_state); +} + +static void regitser_mouse(PS2MouseState *s) +{ + PS2MouseInterface *interface = (PS2MouseInterface *)qemu_mallocz(sizeof(*interface)); + static int mouse_interface_id = 0; + if (!interface) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION; + interface->vd_interface.base.type = VD_INTERFACE_MOUSE; + interface->vd_interface.base.id = mouse_interface_id++; + interface->vd_interface.base.description = "ps2 mouse"; + interface->vd_interface.base.major_vertion = VD_INTERFACE_MOUSE_MAJOR; + interface->vd_interface.base.minor_vertion = VD_INTERFACE_MOUSE_MINOR; + + interface->vd_interface.moution = interface_moution; + interface->vd_interface.buttons = interface_buttons; + + interface->mouse_state = s; + add_interface(&interface->vd_interface.base); +} + +#endif + void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) { PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState)); @@ -590,9 +795,12 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_arg = update_arg; s->scancode_set = 2; ps2_reset(&s->common); - register_savevm("ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s); + register_savevm("ps2kbd", 0, 4, ps2_kbd_save, ps2_kbd_load, s); qemu_add_kbd_event_handler(ps2_put_keycode, s); qemu_register_reset(ps2_reset, &s->common); +#ifdef CONFIG_SPICE + regitser_keyboard(s); +#endif return s; } @@ -606,5 +814,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); qemu_register_reset(ps2_reset, &s->common); +#ifdef CONFIG_SPICE + regitser_mouse(s); +#endif return s; } diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c index e37def9..9ce2072 100644 --- a/qemu/hw/qxl.c +++ b/qemu/hw/qxl.c @@ -2,35 +2,31 @@ #include <signal.h> #include "qemu-common.h" -#include "hw.h" -#include "pc.h" -#include "pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci.h" #include "console.h" -#include "vga_int.h" +#include "hw/vga_int.h" #include "qemu-timer.h" #include "sysemu.h" #include "qxl_dev.h" -#include "qxl_interface.h" - -#include "qemu-kvm.h" - -#define KVM_MEM_ALIAS_QXL_RAM 0 -#define KVM_MEM_ALIAS_QXL_VRAM 1 -#define KVM_MEM_ALIAS_QXL_ROM 2 +#ifdef CONFIG_SPICE +#include "interface.h" +#endif +#include "qxl_interface.h" //#define QXL_IO_MEM #define QXL_RAM_SIZE (32 * 1024 * 1024) -#define QXL_DEFAULT_COMPRESSION_LEVEL 2 +#define QXL_DEFAULT_COMPRESSION_LEVEL 0 #define QXL_SHARED_VGA_MODE FALSE #define QXL_SAVE_VERSION 3 - -#define ASSERT(x) if (!(x)) { \ +#define ASSERT(x) if (!(x)) { \ printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \ - exit(-1); \ + exit(-1); \ } #undef ALIGN @@ -99,7 +95,6 @@ typedef struct QXLState { #endif int num_free_res; QXLReleaseInfo *last_release; - QXLWorkerRef worker; void *worker_data; int worker_data_size; int mode; @@ -108,7 +103,20 @@ typedef struct QXLState { int running; } QXLState; -typedef struct PCIQXLDevice { +typedef struct PCIQXLDevice PCIQXLDevice; + +#ifdef CONFIG_SPICE +typedef struct QXLModeNotifier QXLModeNotifier; +struct QXLModeNotifier { + void *opaque; + qxl_mode_change_notifier_t proc; + PCIQXLDevice *d; + int refs; + QXLModeNotifier *next; +}; +#endif + +struct PCIQXLDevice { PCIDevice pci_dev; QXLState state; int id; @@ -116,11 +124,14 @@ typedef struct PCIQXLDevice { struct PCIQXLDevice *dev_next; struct PCIQXLDevice *vga_next; int pipe_fd[2]; -} PCIQXLDevice; + QXLWorker* worker; +#ifdef CONFIG_SPICE + QXLModeNotifier *mode_notifiers; +#endif +}; static PCIQXLDevice *dev_list = NULL; static pthread_t main_thread; -static int compression_level = QXL_DEFAULT_COMPRESSION_LEVEL; #define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" @@ -180,8 +191,6 @@ static void qxl_reset_state(PCIQXLDevice *d); static QXLVga qxl_vga; -static QXLModeChangeNotifier qxl_mode_change_notifier = NULL; - inline void atomic_or(uint32_t *var, uint32_t add) { __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory"); @@ -239,18 +248,7 @@ void qxl_update_irq() } } -void qxl_set_compression_level(int new_compression_level) -{ - PCIQXLDevice *d = dev_list; - - compression_level = new_compression_level; - while (d) { - d->state.rom->compression_level = compression_level; - d = d->dev_next; - } -} - -void do_set_qxl_log_level(int log_level) +void qxl_do_set_log_level(int log_level) { PCIQXLDevice *d = dev_list; while (d) { @@ -272,7 +270,9 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) } else { //dummy write in order to wake up the main thread //to update the irq line - write(d->pipe_fd[1], d, 1); + if (write(d->pipe_fd[1], d, 1) != 1) { + printf("%s: write to pipe failed\n", __FUNCTION__); + } } } @@ -287,9 +287,8 @@ static void set_dreaw_area(PCIQXLDevice *d, QXLDevInfo *info) info->draw_area.heigth = info->y_res; } -void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) +static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLState *state = &d->state; QXLMode *mode; @@ -297,6 +296,7 @@ void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) info->x_res = qxl_vga.ds->width; info->y_res = qxl_vga.ds->height; info->bits = qxl_vga.ds->depth; + info->use_hardware_cursor = FALSE; info->phys_start = 0; info->phys_end = ~info->phys_start; @@ -310,6 +310,7 @@ void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) info->x_res = mode->x_res; info->y_res = mode->y_res; info->bits = mode->bits; + info->use_hardware_cursor = TRUE; info->phys_start = (unsigned long)state->ram_start + state->rom->pages_offset; info->phys_end = (unsigned long)state->ram_start + state->ram_size; @@ -322,9 +323,8 @@ static QXLCommandRing *qxl_active_ring(PCIQXLDevice *d) return (d->state.mode == QXL_MODE_VGA) ? &d->state.vga_ring : &d->state.ram->cmd_ring; } -int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd) +static int _qxl_get_command(PCIQXLDevice *d, QXLCommand *cmd) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLCommandRing *ring = qxl_active_ring(d); int notify; @@ -339,16 +339,14 @@ int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd) return TRUE; } -int qxl_has_command(QXLDevRef dev_ref) +static int _qxl_has_command(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLCommandRing *ring = qxl_active_ring(d); return !RING_IS_EMPTY(ring); } -int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd) +static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLCursorRing *ring; int notify; @@ -369,24 +367,20 @@ int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd) return 1; } -const Rect *qxl_get_update_area(QXLDevRef dev_ref) +static const Rect *_qxl_get_update_area(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; return &d->state.ram->update_area; } -int qxl_req_cmd_notification(QXLDevRef dev_ref) +static int _qxl_req_cmd_notification(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; int wait; - RING_CONS_WAIT(qxl_active_ring(d), wait); return wait; } -int qxl_req_cursor_notification(QXLDevRef dev_ref) +static int _qxl_req_cursor_notification(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; int wait; if (d->state.mode == QXL_MODE_VGA) { @@ -419,9 +413,8 @@ static inline void qxl_push_free_res(PCIQXLDevice *d) } } -void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info) +static void _qxl_release_resource(PCIQXLDevice *d, QXLReleaseInfo *release_info) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; UINT64 id = release_info->id; QXLState *state = &d->state; QXLReleaseRing *ring; @@ -448,9 +441,8 @@ void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info) qxl_push_free_res(d); } -void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size) +static void _qxl_set_save_data(PCIQXLDevice *d, void *data, int size) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLState *state = &d->state; free(state->worker_data); @@ -458,20 +450,15 @@ void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size) state->worker_data_size = size; } -void *qxl_get_save_data(QXLDevRef dev_ref) +static void *_qxl_get_save_data(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; QXLState *state = &d->state; - return state->worker_data; - } -int qxl_flush_resources(QXLDevRef dev_ref) +static int _qxl_flush_resources(PCIQXLDevice *d) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; int ret; - if (d->state.mode == QXL_MODE_VGA) { return 0; } @@ -482,10 +469,8 @@ int qxl_flush_resources(QXLDevRef dev_ref) return ret; } -void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id) +static void _qxl_notify_update(PCIQXLDevice *d, uint32_t update_id) { - PCIQXLDevice *d = (PCIQXLDevice *)dev_ref; - if (d->state.mode == QXL_MODE_VGA) { return; } @@ -501,7 +486,7 @@ static void qxl_detach(PCIQXLDevice *d) return; } - qxl_worker_detach(d->state.worker); + d->worker->detach(d->worker); if (d->state.mode != QXL_MODE_VGA) { RING_INIT(&d->state.ram->cmd_ring); RING_INIT(&d->state.ram->cursor_ring); @@ -523,44 +508,42 @@ static void qxl_detach(PCIQXLDevice *d) } } -static void qxl_notify_mode_change() +#ifdef CONFIG_SPICE + +static void hold_mode_notifier(QXLModeNotifier* notifier) { - PCIQXLDevice *d = dev_list; - int qxl_mode_native_counter = 0; - int mode = 0; + notifier->refs++; +} - if (!qxl_mode_change_notifier){ - return; - } - if (qxl_vga.active_clients > 0) { - qxl_mode_change_notifier(FALSE, 0, 0); +static void release_mode_notifier(QXLModeNotifier* notifier) +{ + if (--notifier->refs) { return; } - while (d && qxl_mode_native_counter < 2) { - if (d->state.mode == QXL_MODE_NATIVE && ++qxl_mode_native_counter == 1) { - mode = d->state.rom->mode; - } - d = d->dev_next; - } - if (qxl_mode_native_counter == 1) { - qxl_mode_change_notifier(TRUE, qxl_modes[mode].x_res, qxl_modes[mode].y_res); - } else { - qxl_mode_change_notifier(FALSE, 0, 0); + QXLModeNotifier **now = ¬ifier->d->mode_notifiers; + while (*now != notifier) { + now = &(*now)->next; } + *now = notifier->next; + free(notifier); } -void qxl_register_mode_change(QXLModeChangeNotifier notifier){ - qxl_mode_change_notifier = notifier; - qxl_notify_mode_change(); -} +#endif -void qxl_set_mm_time(uint32_t stamp) +static void qxl_notify_mode_change(PCIQXLDevice *d) { - PCIQXLDevice *d = dev_list; - while (d) { - d->state.rom->mm_clock = stamp; - d = d->dev_next; +#ifdef CONFIG_SPICE + QXLModeNotifier *now = d->mode_notifiers; + QXLModeNotifier *tmp; + + while (now) { + hold_mode_notifier(now); + now->proc(now->opaque); + tmp = now; + now = now->next; + release_mode_notifier(tmp); } +#endif } static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode) @@ -579,15 +562,8 @@ static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode) d->state.rom->mode = mode; memset(d->state.vram, 0, d->state.vram_size); d->state.mode = QXL_MODE_NATIVE; - qxl_notify_mode_change(); - qxl_worker_attach(d->state.worker); -} - -void *vga_context = NULL; - -void qxl_set_vga_context(void *context) -{ - vga_context = context; + qxl_notify_mode_change(d); + d->worker->attach(d->worker); } static void qxl_add_vga_client() @@ -610,9 +586,8 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) printf("%u: %s\n", d->id, __FUNCTION__); d->state.rom->mode = ~0; d->state.mode = QXL_MODE_VGA; - qxl_notify_mode_change(); + qxl_notify_mode_change(d); qxl_add_vga_client(); - vga_on_qxl_enter_vga(vga_context); } /* reset the state (assuming the worker is detached) */ @@ -645,10 +620,10 @@ static void qxl_reset(PCIQXLDevice *d) qxl_reset_state(d); if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); - qxl_worker_attach(d->state.worker); + d->worker->attach(d->worker); } else { d->state.mode = QXL_MODE_UNDEFINED; - qxl_notify_mode_change(); + qxl_notify_mode_change(d); } } @@ -665,13 +640,13 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) } switch (io_port) { case QXL_IO_UPDATE_AREA: - qxl_worker_update_area(d->state.worker); + d->worker->update_area(d->worker); break; case QXL_IO_NOTIFY_CMD: - qxl_worker_wakeup(d->state.worker); + d->worker->wakeup(d->worker); break; case QXL_IO_NOTIFY_CURSOR: - qxl_worker_wakeup(d->state.worker); + d->worker->wakeup(d->worker); break; case QXL_IO_UPDATE_IRQ: qemu_set_irq(d->pci_dev.irq[0], irq_level(d)); @@ -685,7 +660,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) if (!RING_IS_EMPTY(&d->state.ram->release_ring)) { break; } - qxl_worker_oom(d->state.worker); + d->worker->oom(d->worker); break; case QXL_IO_LOG: printf("%u: %s", d->id, d->state.ram->log_buf); @@ -732,13 +707,6 @@ static void rom_map(PCIDevice *d, int region_num, ASSERT(size == s->rom_size); cpu_register_physical_memory(addr, size, s->rom_offset | IO_MEM_ROM); - if (kvm_enabled() && kvm_create_memory_alias(kvm_context, - addr, - size, - s->rom_offset)) { - printf("%s: create memory alias failed\n", __FUNCTION__); - exit(-1); - } } static void ram_map(PCIDevice *d, int region_num, @@ -754,13 +722,6 @@ static void ram_map(PCIDevice *d, int region_num, ASSERT((size & ~TARGET_PAGE_MASK) == 0); s->ram_phys_addr = addr; cpu_register_physical_memory(addr, size, s->ram_offset | IO_MEM_RAM); - if (kvm_enabled() && kvm_create_memory_alias(kvm_context, - addr, - size, - s->ram_offset)) { - printf("%s: create memory alias failed\n", __FUNCTION__); - exit(-1); - } } static void vram_map(PCIDevice *d, int region_num, @@ -779,13 +740,6 @@ static void vram_map(PCIDevice *d, int region_num, #else cpu_register_physical_memory(addr, size, s->vram_offset | IO_MEM_RAM); #endif - if (kvm_enabled() && kvm_create_memory_alias(kvm_context, - addr, - size, - s->vram_offset)) { - printf("%s: create memory alias failed\n", __FUNCTION__); - exit(-1); - } } @@ -852,7 +806,7 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size, rom->mode = 0; rom->modes_offset = sizeof(QXLRom); rom->draw_area_size =qxl_max_x_res() * sizeof(uint32_t) * qxl_max_y_res(); - rom->compression_level = compression_level; + rom->compression_level = QXL_DEFAULT_COMPRESSION_LEVEL; rom->log_level = 0; *max_fb = 0; @@ -968,7 +922,7 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int cmd->data = (PHYSICAL)drawable; RING_PUSH(ring, notify); if (notify) { - qxl_worker_wakeup(client->state.worker); + client->worker->wakeup(client->worker); } } client = client->vga_next; @@ -1040,7 +994,6 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) printf("%s\n", __FUNCTION__); qxl_remove_vga_client(); d->state.mode = QXL_MODE_UNDEFINED; - vga_on_qxl_exit_vga(vga_context); } int qxl_vga_touch(void) @@ -1063,7 +1016,7 @@ static void qxl_save(QEMUFile* f, void* opaque) QXLState* s=&d->state; uint32_t last_release_offset; - qxl_worker_save(d->state.worker); + d->worker->save(d->worker); pci_device_save(&d->pci_dev, f); qemu_put_be32(f, s->rom->mode); @@ -1105,7 +1058,7 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id) } if (d->state.mode != QXL_MODE_UNDEFINED) { - qxl_worker_detach(d->state.worker); + d->worker->detach(d->worker); } if (s->mode == QXL_MODE_VGA) { @@ -1149,10 +1102,10 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id) qxl_add_vga_client(); } if (s->mode != QXL_MODE_UNDEFINED) { - qxl_worker_attach(d->state.worker); - qxl_worker_load(d->state.worker); + d->worker->attach(d->worker); + d->worker->load(d->worker); } - qxl_notify_mode_change(); + qxl_notify_mode_change(d); return 0; } @@ -1183,14 +1136,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running) if (running) { d->state.running = TRUE; qemu_set_fd_handler(d->pipe_fd[0], qxl_pipe_read, NULL, d); - qxl_worker_start(d->state.worker); + d->worker->start(d->worker); qemu_set_irq(d->pci_dev.irq[0], irq_level(d)); if (qxl_vga.active_clients) { qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock)); } } else { qemu_del_timer(qxl_vga.timer); - qxl_worker_stop(d->state.worker); + d->worker->stop(d->worker); qemu_set_fd_handler(d->pipe_fd[0], NULL, NULL, d); d->state.running = FALSE; } @@ -1215,7 +1168,259 @@ static void reset_handler(void *opaque) } } -static int channel_id = 0; +void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) +{ + _qxl_get_info((PCIQXLDevice *)dev_ref, info); +} + +int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd) +{ + return _qxl_get_command((PCIQXLDevice *)dev_ref, cmd); +} + +void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info) +{ + _qxl_release_resource((PCIQXLDevice *)dev_ref, release_info); +} + +void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id) +{ + _qxl_notify_update((PCIQXLDevice *)dev_ref, update_id); +} + +int qxl_req_cmd_notification(QXLDevRef dev_ref) +{ + return _qxl_req_cmd_notification((PCIQXLDevice *)dev_ref); +} + +int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd) +{ + return _qxl_get_cursor_command((PCIQXLDevice *)dev_ref, cmd); +} + +int qxl_req_cursor_notification(QXLDevRef dev_ref) +{ + return _qxl_req_cursor_notification((PCIQXLDevice *)dev_ref); +} + +int qxl_has_command(QXLDevRef dev_ref) +{ + return _qxl_has_command((PCIQXLDevice *)dev_ref); +} + +const Rect *qxl_get_update_area(QXLDevRef dev_ref) +{ + return _qxl_get_update_area((PCIQXLDevice *)dev_ref); +} + +int qxl_flush_resources(QXLDevRef dev_ref) +{ + return _qxl_flush_resources((PCIQXLDevice *)dev_ref); +} + +void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size) +{ + _qxl_set_save_data((PCIQXLDevice *)dev_ref, data, size); +} + +void *qxl_get_save_data(QXLDevRef dev_ref) +{ + return _qxl_get_save_data((PCIQXLDevice *)dev_ref); +} + +#ifdef CONFIG_SPICE + +typedef struct Interface { + QXLInterface vd_interface; + PCIQXLDevice *d; +} Interface; + +static void interface_attache_worker(QXLInterface *qxl, QXLWorker *qxl_worker) +{ + Interface *interface = (Interface *)qxl; + if (interface->d->worker) { + printf("%s: has worker\n", __FUNCTION__); + exit(-1); + } + interface->d->worker = qxl_worker; +} + +void interface_set_compression_level(QXLInterface *qxl, int level) +{ + PCIQXLDevice *d = ((Interface *)qxl)->d; + d->state.rom->compression_level = level; +} + +void interface_set_mm_time(QXLInterface *qxl, uint32_t mm_time) +{ + PCIQXLDevice *d = ((Interface *)qxl)->d; + d->state.rom->mm_clock = mm_time; +} + +static QXLModeNotifier *register_mode_notifier(PCIQXLDevice *d, qxl_mode_change_notifier_t proc, + void *opaque) +{ + QXLModeNotifier *notifier; + + if (!proc) { + return NULL; + } + + if (!(notifier = (QXLModeNotifier *)malloc(sizeof(*notifier)))) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + notifier->opaque = opaque; + notifier->proc = proc; + notifier->refs = 1; + notifier->next = d->mode_notifiers; + d->mode_notifiers = notifier; + return notifier; +} + +static void unregister_mode_notifier(PCIQXLDevice *d, QXLModeNotifier *notifier) +{ + QXLModeNotifier **now = &d->mode_notifiers; + for (;;) { + if (*now == notifier) { + notifier->proc = NULL; + release_mode_notifier(notifier); + return; + } + now = &(*now)->next; + } +} + +static VDObjectRef interface_register_mode_change(QXLInterface *qxl, qxl_mode_change_notifier_t notifier, void *opaque) +{ + PCIQXLDevice *d = ((Interface *)qxl)->d; + + if (!notifier) { + return 0; + } + return (VDObjectRef)register_mode_notifier(d, notifier, opaque); +} + +static void interface_unregister_mode_change(QXLInterface *qxl, VDObjectRef notifier) +{ + PCIQXLDevice *d = ((Interface *)qxl)->d; + if (!notifier) { + return; + } + unregister_mode_notifier(d, (QXLModeNotifier *)notifier); +} + +static void interface_get_info(QXLInterface *qxl, QXLDevInfo *info) +{ + _qxl_get_info(((Interface *)qxl)->d, info); +} + +static int interface_get_command(QXLInterface *qxl, struct QXLCommand *cmd) +{ + return _qxl_get_command(((Interface *)qxl)->d, cmd); +} + +static int interface_req_cmd_notification(QXLInterface *qxl) +{ + return _qxl_req_cmd_notification(((Interface *)qxl)->d); +} + +static int interface_has_command(QXLInterface *qxl) +{ + return _qxl_has_command(((Interface *)qxl)->d); +} + +static void interface_release_resource(QXLInterface *qxl, union QXLReleaseInfo *release_info) +{ + _qxl_release_resource(((Interface *)qxl)->d, release_info); +} + +static int interface_get_cursor_command(QXLInterface *qxl, struct QXLCommand *cmd) +{ + return _qxl_get_cursor_command(((Interface *)qxl)->d, cmd); +} + +static int interface_req_cursor_notification(QXLInterface *qxl) +{ + return _qxl_req_cursor_notification(((Interface *)qxl)->d); +} + +static const struct Rect *interface_get_update_area(QXLInterface *qxl) +{ + return _qxl_get_update_area(((Interface *)qxl)->d); +} + +static void interface_notify_update(QXLInterface *qxl, uint32_t update_id) +{ + _qxl_notify_update(((Interface *)qxl)->d, update_id); +} + +static void interface_set_save_data(QXLInterface *qxl, void *data, int size) +{ + _qxl_set_save_data(((Interface *)qxl)->d, data, size); +} + +static void *interface_get_save_data(QXLInterface *qxl) +{ + return _qxl_get_save_data(((Interface *)qxl)->d); +} + +static int interface_flush_resources(QXLInterface *qxl) +{ + return _qxl_flush_resources(((Interface *)qxl)->d); +} + +static void regitser_interface(PCIQXLDevice *d) +{ + Interface *interface = (Interface *)qemu_mallocz(sizeof(*interface)); + + if (!interface) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION; + interface->vd_interface.base.type = VD_INTERFACE_QXL; + interface->vd_interface.base.id = d->id; + interface->vd_interface.base.description = "QXL GPU"; + interface->vd_interface.base.major_vertion = VD_INTERFACE_QXL_MAJOR; + interface->vd_interface.base.minor_vertion = VD_INTERFACE_QXL_MINOR; + + interface->vd_interface.pci_vendor = QUMRANET_PCI_VENDOR_ID; + interface->vd_interface.pci_id = QXL_DEVICE_ID; + interface->vd_interface.pci_revision = QXL_REVISION; + + interface->vd_interface.attache_worker = interface_attache_worker; + interface->vd_interface.set_compression_level = interface_set_compression_level; + interface->vd_interface.set_mm_time = interface_set_mm_time; + interface->vd_interface.register_mode_change = interface_register_mode_change; + interface->vd_interface.unregister_mode_change = interface_unregister_mode_change; + + interface->vd_interface.get_info = interface_get_info; + interface->vd_interface.get_command = interface_get_command; + interface->vd_interface.req_cmd_notification = interface_req_cmd_notification; + interface->vd_interface.has_command = interface_has_command; + interface->vd_interface.release_resource = interface_release_resource; + interface->vd_interface.get_cursor_command = interface_get_cursor_command; + interface->vd_interface.req_cursor_notification = interface_req_cursor_notification; + interface->vd_interface.get_update_area = interface_get_update_area; + interface->vd_interface.notify_update = interface_notify_update; + interface->vd_interface.set_save_data = interface_set_save_data; + interface->vd_interface.get_save_data = interface_get_save_data; + interface->vd_interface.flush_resources = interface_flush_resources; + + interface->d = d; + add_interface(&interface->vd_interface.base); +} + +#endif + +static void creat_native_worker(PCIQXLDevice *d, int id) +{ + d->worker = qxl_interface_create_worker((QXLDevRef)d, id); + ASSERT(d->worker); +} + +static int device_id = 0; void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, uint32_t vram_size) @@ -1229,13 +1434,13 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, sizeof(PCIQXLDevice), -1, NULL, NULL); - d->id = channel_id; + d->id = device_id; d->state.mode = QXL_MODE_UNDEFINED; - if (!channel_id) { + if (!device_id) { qxl_init_modes(); } - register_savevm(QXL_DEV_NAME, channel_id, QXL_SAVE_VERSION, qxl_save, qxl_load, d); + register_savevm(QXL_DEV_NAME, device_id, QXL_SAVE_VERSION, qxl_save, qxl_load, d); qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, d); pci_conf = (PCIConf *)d->pci_dev.config; @@ -1309,19 +1514,26 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, #else pci_register_io_region(&d->pci_dev, QXL_VRAM_RANGE_INDEX, d->state.vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vram_map); -#endif - d->state.worker = qxl_worker_init((QXLDevRef) d, channel_id++); +#endif d->dev_next = dev_list; dev_list = d; d->vga_next = qxl_vga.clients; qxl_vga.clients = d; main_thread = pthread_self(); qxl_reset_state(d); + init_pipe_signaling(d); + +#ifdef CONFIG_SPICE + regitser_interface(d); +#endif + if (!d->worker) { + creat_native_worker(d, device_id); + } if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); - qxl_worker_attach(d->state.worker); + d->worker->attach(d->worker); } - init_pipe_signaling(d); qemu_register_reset(reset_handler, d); + device_id++; } diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h index 19ee2f9..15ee9c2 100644 --- a/qemu/hw/qxl_interface.h +++ b/qemu/hw/qxl_interface.h @@ -3,11 +3,13 @@ #include <stdint.h> -union QXLReleaseInfo; -struct QXLCommand; +#include "qxl_dev.h" -typedef unsigned long QXLWorkerRef; -typedef unsigned long QXLDevRef; +#ifdef CONFIG_SPICE + +#include "vd_interface.h" + +#else typedef struct DrawArea{ uint8_t *buf; @@ -22,39 +24,43 @@ typedef struct QXLDevInfo { long phys_delta; unsigned long phys_start; unsigned long phys_end; - uint32_t x_res; uint32_t y_res; + int use_hardware_cursor; uint32_t bits; - DrawArea draw_area; - } QXLDevInfo; +typedef struct QXLWorker QXLWorker; +struct QXLWorker { + void (*attach)(QXLWorker *worker); + void (*detach)(QXLWorker *worker); + void (*wakeup)(QXLWorker *worker); + void (*oom)(QXLWorker *worker); + void (*save)(QXLWorker *worker); + void (*load)(QXLWorker *worker); + void (*start)(QXLWorker *worker); + void (*stop)(QXLWorker *worker); + void (*update_area)(QXLWorker *worker); +}; +#endif + +typedef unsigned long QXLDevRef; + void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info); -int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd); -int qxl_has_command(QXLDevRef dev_ref); -int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd); -const struct Rect *qxl_get_update_area(QXLDevRef dev_ref); +int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd); +void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info); +void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id); int qxl_req_cmd_notification(QXLDevRef dev_ref); +int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd); int qxl_req_cursor_notification(QXLDevRef dev_ref); -void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info); +int qxl_has_command(QXLDevRef dev_ref); +const Rect *qxl_get_update_area(QXLDevRef dev_ref); int qxl_flush_resources(QXLDevRef dev_ref); -void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id); void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size); void *qxl_get_save_data(QXLDevRef dev_ref); - -QXLWorkerRef qxl_worker_init(QXLDevRef dev_ref, int channel_id); -void qxl_worker_attach(QXLWorkerRef worker_ref); -void qxl_worker_detach(QXLWorkerRef worker_ref); -void qxl_worker_wakeup(QXLWorkerRef worker_ref); -void qxl_worker_oom(QXLWorkerRef worker_ref); -void qxl_worker_save(QXLWorkerRef worker_ref); -void qxl_worker_load(QXLWorkerRef worker_ref); -void qxl_worker_start(QXLWorkerRef worker_ref); -void qxl_worker_stop(QXLWorkerRef worker_ref); -void qxl_worker_update_area(QXLWorkerRef worker_ref); +QXLWorker *qxl_interface_create_worker(QXLDevRef dev, int id); #endif diff --git a/qemu/hw/qxl_native_worker.c b/qemu/hw/qxl_native_worker.c new file mode 100644 index 0000000..91eefb1 --- /dev/null +++ b/qemu/hw/qxl_native_worker.c @@ -0,0 +1,151 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "qemu-common.h" + +#include "qxl_interface.h" +#include "qxl_dev.h" + +#define qxl_error(format, ...) { \ + printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \ + exit(-1); \ +} + +#define qxl_printf(format, ...) \ + printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ) + +typedef struct QxlDispatcher { + QXLWorker base; + int id; + QXLDevRef dev_ref; + QXLDevInfo dev_info; +} QxlDispatcher; + +static void native_qxl_worker_wakeup(QXLWorker *worker) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + QXLCommand cmd; + + qxl_printf(""); + + for (;;) { + if (qxl_get_command(dispatcher->dev_ref, &cmd)) { + switch (cmd.type) { + case QXL_CMD_DRAW: { + QXLDrawable *draw_cmd = (QXLDrawable *)(cmd.data + dispatcher->dev_info.phys_delta); + qxl_release_resource(dispatcher->dev_ref, &draw_cmd->release_info); + break; + } + case QXL_CMD_UPDATE: { + QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)(cmd.data + dispatcher->dev_info.phys_delta); + qxl_notify_update(dispatcher->dev_ref, update_cmd->update_id); + qxl_release_resource(dispatcher->dev_ref, &update_cmd->release_info); + break; + } + case QXL_CMD_MESSAGE: { + QXLMessage *message = (QXLMessage *)(cmd.data + dispatcher->dev_info.phys_delta); + qxl_printf("MESSAGE: %s", message->data); + qxl_release_resource(dispatcher->dev_ref, &message->release_info); + break; + } + default: + qxl_error("bad command type"); + } + continue; + } + if (qxl_req_cmd_notification(dispatcher->dev_ref)) { + break; + } + } + for (;;) { + if (qxl_get_cursor_command(dispatcher->dev_ref, &cmd)) { + switch (cmd.type) { + case QXL_CMD_CURSOR: { + QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)(cmd.data + dispatcher->dev_info.phys_delta); + qxl_release_resource(dispatcher->dev_ref, &cursor_cmd->release_info); + break; + } + default: + qxl_error("bad command type"); + } + continue; + } + if (qxl_req_cursor_notification(dispatcher->dev_ref)) { + break; + } + } +} + +static void native_qxl_worker_attach(QXLWorker *worker) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + qxl_printf(""); + + qxl_get_info(dispatcher->dev_ref, &dispatcher->dev_info); + native_qxl_worker_wakeup(worker); +} + +static void native_qxl_worker_detach(QXLWorker *worker) +{ + qxl_printf(""); + native_qxl_worker_wakeup(worker); +} + +static void native_qxl_worker_update_area(QXLWorker *worker) +{ + qxl_printf(""); + native_qxl_worker_wakeup(worker); +} + +static void native_qxl_worker_oom(QXLWorker *worker) +{ + qxl_printf(""); + native_qxl_worker_wakeup(worker); +} + +static void native_qxl_worker_start(QXLWorker *worker) +{ + qxl_printf(""); +} + +static void native_qxl_worker_stop(QXLWorker *worker) +{ + qxl_printf(""); +} + +static void native_qxl_worker_save(QXLWorker *worker) +{ + qxl_printf(""); +} + +static void native_qxl_worker_load(QXLWorker *worker) +{ + qxl_printf(""); +} + +QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) +{ + QxlDispatcher *dispatcher; + + if (!(dispatcher = malloc(sizeof(QxlDispatcher)))) { + qxl_error("malloc failed"); + } + memset(dispatcher, 0, sizeof(*dispatcher)); + dispatcher->id = device_id; + dispatcher->dev_ref = dev_ref; + + dispatcher->base.attach = native_qxl_worker_attach; + dispatcher->base.detach = native_qxl_worker_detach; + dispatcher->base.wakeup = native_qxl_worker_wakeup; + dispatcher->base.oom = native_qxl_worker_oom; + dispatcher->base.save = native_qxl_worker_save; + dispatcher->base.load = native_qxl_worker_load; + dispatcher->base.start = native_qxl_worker_start; + dispatcher->base.stop = native_qxl_worker_stop; + dispatcher->base.update_area = native_qxl_worker_update_area; + + return &dispatcher->base; +} + diff --git a/qemu/hw/usb-hid.c b/qemu/hw/usb-hid.c index 76fdce6..b23de50 100644 --- a/qemu/hw/usb-hid.c +++ b/qemu/hw/usb-hid.c @@ -26,6 +26,10 @@ #include "console.h" #include "usb.h" +#ifdef CONFIG_SPICE +#include "interface.h" +#endif + /* HID interface requests */ #define GET_REPORT 0xa101 #define GET_IDLE 0xa102 @@ -47,6 +51,11 @@ typedef struct USBMouseState { int dx, dy, dz, buttons_state; int x, y; int mouse_grabbed; +#ifdef CONFIG_SPICE + TabletInterface interface; + int logical_width; + int logical_height; +#endif QEMUPutMouseEntry *eh_entry; } USBMouseState; @@ -510,9 +519,9 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) USBMouseState *s = &hs->ptr; if (!s->mouse_grabbed) { - s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs, + s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs, 0, "QEMU USB Mouse"); - s->mouse_grabbed = 1; + s->mouse_grabbed = 1; } dx = int_clamp(s->dx, -127, 127); @@ -546,15 +555,77 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) return l; } + +#ifdef CONFIG_SPICE + +static void interface_set_logical_size(TabletInterface* interface, int width, int height) +{ + USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface); + hs->ptr.logical_width = width; + hs->ptr.logical_height = height; +} + +static void interface_position(TabletInterface *interface, int x, int y, + uint32_t buttons_state) +{ + USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface); + + x = (x + 1) * 0x7FFF / (hs->ptr.logical_width + 1 /*why + 1*/); + y = (y + 1) * 0x7FFF / (hs->ptr.logical_height + 1 /*why + 1*/); + usb_tablet_event(hs, x, y, 0, buttons_state); +} + + +static void interface_wheel(TabletInterface *interface, int wheel, + uint32_t buttons_state) +{ + USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface); + usb_tablet_event(hs, hs->ptr.x, hs->ptr.y, wheel, buttons_state); +} + +static void interface_buttons(TabletInterface *interface, + uint32_t buttons_state) +{ + USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface); + usb_tablet_event(hs, hs->ptr.x, hs->ptr.y, 0, buttons_state); +} + +static void regitser_tablet(USBMouseState *s) +{ + TabletInterface *interface = &s->interface; + static int tablet_interface_id = 0; + + interface->base.base_vertion = VM_INTERFACE_VERTION; + interface->base.type = VD_INTERFACE_TABLET; + interface->base.id = ++tablet_interface_id; + interface->base.description = "usb tablet"; + interface->base.major_vertion = VD_INTERFACE_TABLET_MAJOR; + interface->base.minor_vertion = VD_INTERFACE_TABLET_MINOR; + + + interface->set_logical_size = interface_set_logical_size; + interface->position = interface_position; + interface->wheel = interface_wheel; + interface->buttons = interface_buttons; + + add_interface(&interface->base); +} + + +#endif + static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) { int dz, b, l; USBMouseState *s = &hs->ptr; if (!s->mouse_grabbed) { - s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs, + s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs, 1, "QEMU USB Tablet"); - s->mouse_grabbed = 1; + s->mouse_grabbed = 1; +#ifdef CONFIG_SPICE + regitser_tablet(s); +#endif } dz = int_clamp(s->dz, -127, 127); @@ -840,12 +911,25 @@ static void usb_hid_handle_destroy(USBDevice *dev) { USBHIDState *s = (USBHIDState *)dev; - if (s->kind != USB_KEYBOARD) + if (s->kind != USB_KEYBOARD && s->ptr.mouse_grabbed) qemu_remove_mouse_event_handler(s->ptr.eh_entry); /* TODO: else */ qemu_free(s); } + +static void usb_tablet_handle_destroy(USBDevice *dev) +{ + USBHIDState *s = (USBHIDState *)dev; + if (s->ptr.mouse_grabbed) { +#ifdef CONFIG_SPICE + remove_interface(&s->ptr.interface.base); +#endif + qemu_remove_mouse_event_handler(s->ptr.eh_entry); + } + qemu_free(s); +} + USBDevice *usb_tablet_init(void) { USBHIDState *s; @@ -859,7 +943,7 @@ USBDevice *usb_tablet_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_hid_handle_control; s->dev.handle_data = usb_hid_handle_data; - s->dev.handle_destroy = usb_hid_handle_destroy; + s->dev.handle_destroy = usb_tablet_handle_destroy; s->kind = USB_TABLET; /* Force poll routine to be run and grab input the first time. */ s->changed = 1; diff --git a/qemu/hw/vga.c b/qemu/hw/vga.c index 3cde818..f1eb2bb 100644 --- a/qemu/hw/vga.c +++ b/qemu/hw/vga.c @@ -151,6 +151,7 @@ static uint16_t expand2[256]; static uint8_t expand4to8[16]; static void vga_screen_dump(void *opaque, const char *filename); +static void vga_invalidate_display(void *opaque); static void vga_dumb_update_retrace_info(VGAState *s) { @@ -389,6 +390,12 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); #endif +#ifdef CONFIG_QXL + if(using_qxl && qxl_vga_touch()) { + vga_invalidate_display(opaque); + } +#endif + switch(addr) { case 0x3c0: if (s->ar_flip_flop == 0) { @@ -564,6 +571,12 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) { VGAState *s = opaque; +#ifdef CONFIG_QXL + if(using_qxl && qxl_vga_touch()) { + vga_invalidate_display(opaque); + } +#endif + if (s->vbe_index <= VBE_DISPI_INDEX_NB) { #ifdef DEBUG_BOCHS_VBE printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); @@ -2587,6 +2600,10 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, /* XXX: use optimized standard vga accesses */ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, vga_ram_offset); + if (kvm_enabled()) { + kvm_qemu_log_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, 1); + } + s->map_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS; #endif return 0; } diff --git a/qemu/interface.c b/qemu/interface.c new file mode 100644 index 0000000..847573f --- /dev/null +++ b/qemu/interface.c @@ -0,0 +1,232 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "interface.h" +#include "qemu-common.h" +#include "qemu-timer.h" +#include "console.h" + +typedef struct InterfacesNotifier InterfacesNotifier; + +struct InterfacesNotifier { + vd_interface_change_notifier_t notifier; + void *opaque; + int refs; + InterfacesNotifier *next; +}; + +InterfacesNotifier *notifiers = NULL; + +typedef struct VDInterfaceLink VDInterfaceLink; + +struct VDInterfaceLink { + VDInterface *interface; + VDInterfaceLink *next; +}; + +VDInterfaceLink* interfaces = NULL; + +static void hold_notifier(InterfacesNotifier* notifier) +{ + notifier->refs++; +} + +static void releas_notifier(InterfacesNotifier* notifier) +{ + if (--notifier->refs) { + return; + } + InterfacesNotifier **now = ¬ifiers; + + while (*now != notifier) { + now = &(*now)->next; + } + *now = notifier->next; + free(notifier); +} + +static void run_notifiers(VDInterface *interface, VDInterfaceChangeType type) +{ + InterfacesNotifier *now; + InterfacesNotifier *prev; + + now = notifiers; + while (now) { + hold_notifier(now); + if (now->notifier) { + now->notifier(now->opaque, interface, type); + } + prev = now; + now = now->next; + releas_notifier(prev); + } +} + +void add_interface(VDInterface *interface) +{ + VDInterfaceLink *holder; + + if (!interface) { + return; + } + + if (!(holder = malloc(sizeof(*holder)))) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + memset(holder, 0, sizeof(*holder)); + holder->interface = interface; + holder->next = interfaces; + interfaces = holder; + run_notifiers(interface, VD_INTERFACE_ADDING); +} + +void remove_interface(VDInterface *interface) +{ + VDInterfaceLink **now; + + if (!interface) { + return; + } + now = &interfaces; + while (*now) { + if ((*now)->interface == interface) { + VDInterfaceLink *found = *now; + *now = found->next; + free(found); + run_notifiers(interface, VD_INTERFACE_REMOVING); + return; + } + now = &(*now)->next; + } + printf("%s: not found\n", __FUNCTION__); +} + +static VDInterface *firest_valid_interface(VDInterfaceLink* interface_holder) +{ + while (interface_holder) { + if (interface_holder->interface) { + return interface_holder->interface; + } + interface_holder = interface_holder->next; + } + return NULL; +} + +static VDInterface *core_next(CoreInterface *core, VDInterface *prev) +{ + VDInterfaceLink* now; + + if (!interfaces) { + return NULL; + } + + if (!prev) { + return firest_valid_interface(interfaces); + } + + now = interfaces; + while (now->next) { + if (now->interface == prev) { + return firest_valid_interface(now->next); + } + } + return NULL; +} + +static void core_unregister_change_notifiers(CoreInterface *core, VDObjectRef notifier) +{ + InterfacesNotifier *to_remove = (InterfacesNotifier *)notifier; + InterfacesNotifier *now; + + if (!to_remove) { + return; + } + now = notifiers; + while (now) { + if (now == to_remove && now->notifier) { + now->notifier = NULL; + releas_notifier(now); + return; + } + now = now->next; + } + printf("%s: not found\n", __FUNCTION__); +} + +static VDObjectRef core_register_change_notifiers(CoreInterface *core, void *opaque, + vd_interface_change_notifier_t notifier) +{ + InterfacesNotifier *_notifie; + + if (!notifier) { + printf("%s: invalid args\n", __FUNCTION__); + return 0; + } + + _notifie = malloc(sizeof(*_notifie)); + if (!_notifie) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + memset(_notifie, 0, sizeof(*_notifie)); + _notifie->refs = 1; + _notifie->opaque = opaque; + _notifie->notifier = notifier; + _notifie->next = notifiers; + notifiers = _notifie; + + return (VDObjectRef)_notifie; +} + +static VDObjectRef core_create_timer(CoreInterface *core, timer_callback_t callback, void *opaue) +{ + return (VDObjectRef)qemu_new_timer(rt_clock, callback, opaue); +} + +static void core_arm_timer(CoreInterface *core, VDObjectRef timer, uint32_t ms) +{ + qemu_mod_timer((QEMUTimer *)timer, qemu_get_clock(rt_clock) + ms); +} + +static void core_disarm_timer(CoreInterface *core, VDObjectRef timer) +{ + qemu_del_timer((QEMUTimer *)timer); +} + +static void core_destroy_timer(CoreInterface *core, VDObjectRef timer) +{ + qemu_del_timer((QEMUTimer *)timer); + qemu_free_timer((QEMUTimer *)timer); +} + +static int core_set_file_handlers(CoreInterface *core, int fd, + void (*on_read)(void *), + void (*on_write)(void *), + void *opaque) +{ + return qemu_set_fd_handler(fd, on_read, on_write, opaque); +} + +static void core_term_printf(CoreInterface *core, const char* format, ...) +{ + va_list ap; + + va_start(ap, format); + term_vprintf(format, ap); + va_end(ap); +} + +CoreInterface core_interface = { + {VM_INTERFACE_VERTION, VD_INTERFACE_CORE, 0, "qwnu core services", VD_INTERFACE_CORE_MAJOR, VD_INTERFACE_CORE_MINOR}, + core_next, + core_register_change_notifiers, + core_unregister_change_notifiers, + core_create_timer, + core_arm_timer, + core_disarm_timer, + core_destroy_timer, + core_set_file_handlers, + core_term_printf, +}; diff --git a/qemu/interface.h b/qemu/interface.h new file mode 100644 index 0000000..aa01926 --- /dev/null +++ b/qemu/interface.h @@ -0,0 +1,12 @@ +#ifndef _H_INTERFACE +#define _H_INTERFACE + +#include "vd_interface.h" + +void add_interface(VDInterface *interface); +void remove_interface(VDInterface *interface); + +extern CoreInterface core_interface; + +#endif + diff --git a/qemu/monitor.c b/qemu/monitor.c index 1bc46f4..6cfa0fa 100644 --- a/qemu/monitor.c +++ b/qemu/monitor.c @@ -42,6 +42,11 @@ #include "qemu-kvm.h" +#ifdef CONFIG_SPICE +#include "vd_interface.h" +#include "interface.h" +#endif + //#define DEBUG //#define DEBUG_COMPLETION @@ -59,20 +64,24 @@ * */ -typedef struct term_cmd_t { + +typedef struct term_cmd_t term_cmd_t; +struct term_cmd_t { const char *name; const char *args_type; void *handler; const char *params; const char *help; -} term_cmd_t; + term_cmd_t* next; +}; #define MAX_MON 4 static CharDriverState *monitor_hd[MAX_MON]; static int hide_banner; -static const term_cmd_t term_cmds[]; -static const term_cmd_t info_cmds[]; + +static term_cmd_t *action_commands = NULL; +static term_cmd_t *info_commands = NULL; static uint8_t term_outbuf[1024]; static int term_outbuf_index; @@ -182,20 +191,22 @@ static int compare_cmd(const char *name, const char *list) static void help_cmd1(const term_cmd_t *cmds, const char *prefix, const char *name) { - const term_cmd_t *cmd; + const term_cmd_t *cmd = cmds; - for(cmd = cmds; cmd->name != NULL; cmd++) { - if (!name || !strcmp(name, cmd->name)) + while (cmd) { + if (!name || !strcmp(name, cmd->name)) { term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help); + } + cmd = cmd->next; } } static void help_cmd(const char *name) { if (name && !strcmp(name, "info")) { - help_cmd1(info_cmds, "info ", NULL); + help_cmd1(info_commands, "info ", NULL); } else { - help_cmd1(term_cmds, "", name); + help_cmd1(action_commands, "", name); if (name && !strcmp(name, "log")) { const CPULogItem *item; term_printf("Log items (comma separated):\n"); @@ -231,9 +242,12 @@ static void do_info(const char *item) if (!item) goto help; - for(cmd = info_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(item, cmd->name)) + cmd = info_commands; + while (cmd) { + if (compare_cmd(item, cmd->name)) { goto found; + } + cmd = cmd->next; } help: help_cmd("info"); @@ -1456,7 +1470,7 @@ static void do_info_balloon(void) term_printf("balloon: actual=%d\n", (int)(actual >> 20)); } -static const term_cmd_t term_cmds[] = { +static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, { "commit", "s", do_commit, @@ -1554,10 +1568,13 @@ static const term_cmd_t term_cmds[] = { { "pci_add", "iss", device_hot_add, "bus nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", "hot-add PCI device" }, { "pci_del", "ii", device_hot_remove, "bus slot-number", "hot remove PCI device" }, #endif +#ifdef CONFIG_QXL + { "set_qxl_log_level", "i", qxl_do_set_log_level, "", "set qxl log level" }, +#endif { NULL, NULL, }, }; -static const term_cmd_t info_cmds[] = { +static term_cmd_t info_cmds[] = { { "version", "", do_info_version, "", "show the version of qemu" }, { "network", "", do_info_network, @@ -2315,10 +2332,13 @@ static void monitor_handle_command(const char *cmdline) cmdname[len] = '\0'; /* find the command */ - for(cmd = term_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(cmdname, cmd->name)) + cmd = action_commands; + while (cmd) { + if (compare_cmd(cmdname, cmd->name)) { goto found; - } + } + cmd = cmd->next; + } term_printf("unknown command: '%s'\n", cmdname); return; found: @@ -2708,6 +2728,126 @@ static void parse_cmdline(const char *cmdline, *pnb_args = nb_args; } +#ifdef CONFIG_SPICE + +static term_cmd_t* add_command_common(const char *module_name, + const char *name, + const char *args_type, + void *handler, + const char *params, + const char *help, + term_cmd_t** command_list) +{ + const char *seperator = "."; + term_cmd_t *cmd; + char *pos ; + + int malloc_size = sizeof(*cmd) + strlen(module_name) + strlen(seperator) + strlen(name) + + strlen(args_type) + strlen(params) + strlen(help) + 4 /*str term*/; + + if (!(cmd = malloc(malloc_size))) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + + pos = (char *)(cmd + 1); + strcpy(pos, module_name); + strcat(pos, seperator); + strcat(pos, name); + cmd->name = pos; + pos += strlen(pos) + 1; + + strcpy(pos, args_type); + cmd->args_type = pos; + pos += strlen(pos) + 1; + + strcpy(pos, params); + cmd->params = pos; + pos += strlen(pos) + 1; + + strcpy(pos, help); + cmd->help = pos; + + cmd->handler = handler; + cmd->next = NULL; + while (*command_list) { + command_list = &(*command_list)->next; + } + *command_list = cmd; + return cmd; +} + +static VDObjectRef monitor_add_action_command(QTermInterface *term, const char *module_name, + const char *name, + const char *args_type, + void *handler, + const char *params, + const char *help) +{ + if (!module_name || !name || !args_type || !handler || !params || !help) { + return INVALID_VD_OBJECT_REF; + } + + return (VDObjectRef)add_command_common(module_name, name, args_type, handler, params, help, &action_commands); +} + +static VDObjectRef monitor_add_info_command(QTermInterface *term, const char *module_name, + const char *name, + void *handler, + const char *help) +{ + if (!module_name || !name || !handler || !help) { + return INVALID_VD_OBJECT_REF; + } + + return (VDObjectRef)add_command_common(module_name, name, "", handler, "", help, &info_commands); +} + +static void remove_command(term_cmd_t *command, term_cmd_t** command_list) +{ + while (*command_list) { + if (*command_list == command) { + *command_list = command->next; + free(command); + return; + } + command_list = &(*command_list)->next; + } +} + +static void monitor_remove_action(QTermInterface *term, VDObjectRef command_ref) +{ + remove_command((term_cmd_t *)command_ref, &action_commands); +} + +static void monitor_remove_info(QTermInterface *term, VDObjectRef command_ref) +{ + remove_command((term_cmd_t *)command_ref, &info_commands); +} + +static void regitser_interface() +{ + QTermInterface *interface = (QTermInterface *)qemu_mallocz(sizeof(*interface)); + + if (!interface) { + printf("%s: malloc failed\n", __FUNCTION__); + exit(-1); + } + interface->base.base_vertion = VM_INTERFACE_VERTION; + interface->base.type = VD_INTERFACE_QTERM; + interface->base.id = 0; + interface->base.description = "qemue terminal"; + interface->base.major_vertion = VD_INTERFACE_QTERM_MAJOR; + interface->base.minor_vertion = VD_INTERFACE_QTERM_MINOR; + interface->add_action_command_handler = monitor_add_action_command; + interface->remove_action_command_handler = monitor_remove_action; + interface->add_info_command_handler = monitor_add_info_command; + interface->remove_info_command_handler = monitor_remove_info; + add_interface(&interface->base); +} + +#endif + void readline_find_completion(const char *cmdline) { const char *cmdname; @@ -2739,14 +2879,19 @@ void readline_find_completion(const char *cmdline) else cmdname = args[0]; completion_index = strlen(cmdname); - for(cmd = term_cmds; cmd->name != NULL; cmd++) { + cmd = action_commands; + while (cmd) { cmd_completion(cmdname, cmd->name); + cmd = cmd->next; } } else { /* find the command */ - for(cmd = term_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(args[0], cmd->name)) - goto found; + cmd = action_commands; + while (cmd) { + if (compare_cmd(args[0], cmd->name)) { + goto found; + } + cmd = cmd->next; } return; found: @@ -2774,8 +2919,10 @@ void readline_find_completion(const char *cmdline) /* XXX: more generic ? */ if (!strcmp(cmd->name, "info")) { completion_index = strlen(str); - for(cmd = info_cmds; cmd->name != NULL; cmd++) { + cmd = info_commands; + while (cmd) { cmd_completion(str, cmd->name); + cmd = cmd->next; } } else if (!strcmp(cmd->name, "sendkey")) { completion_index = strlen(str); @@ -2843,10 +2990,29 @@ static void term_event(void *opaque, int event) monitor_start_input(); } -static int is_first_init = 1; +static void init_commands(term_cmd_t *init_array, term_cmd_t **pos) +{ + term_cmd_t *now = init_array; + while (now->name) { + now->next = NULL; + *pos = now; + pos = &now->next; + now++; + } +} + +void init_monitor_commands() +{ + init_commands(term_cmds, &action_commands); + init_commands(info_cmds, &info_commands); +#ifdef CONFIG_SPICE + regitser_interface(); +#endif +} void monitor_init(CharDriverState *hd, int show_banner) { + static int is_first_init = 1; int i; if (is_first_init) { diff --git a/qemu/vl.c b/qemu/vl.c index 7a36870..1034240 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -153,6 +153,11 @@ #include "qemu-kvm.h" +#ifdef CONFIG_SPICE +#include "spice.h" +#include "interface.h" +#endif + //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT //#define DEBUG_NET @@ -263,6 +268,16 @@ static int64_t qemu_icount_bias; static QEMUTimer *icount_rt_timer; static QEMUTimer *icount_vm_timer; +#ifdef CONFIG_QXL +int using_qxl = 0; +int num_qxl_device = 0; +#endif + +#ifdef CONFIG_SPICE +int using_spice = 0; +const char *spice_args = NULL; +#endif + uint8_t qemu_uuid[16]; /* KVM runs the main loop in a separate thread. If we update one of the lists @@ -4007,6 +4022,13 @@ static void help(int exitcode) #endif "-name string set the name of the guest\n" "-uuid %%08x-%%04x-%%04x-%%04x-%%012x specify machine UUID\n" +#ifdef CONFIG_QXL + "-qxl <num> use qxl display device\n" +#endif +#ifdef CONFIG_SPICE + "-spice <args> use spice\n" + "-spice-help show spice usage\n" +#endif "\n" "Network options:\n" "-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str]\n" @@ -4246,6 +4268,13 @@ enum { QEMU_OPTION_tdf, QEMU_OPTION_kvm_shadow_memory, QEMU_OPTION_mempath, +#ifdef CONFIG_QXL + QEMU_OPTION_qxl, +#endif +#ifdef CONFIG_SPICE + QEMU_OPTION_spice, + QEMU_OPTION_spice_help, +#endif }; typedef struct QEMUOption { @@ -4381,6 +4410,13 @@ static const QEMUOption qemu_options[] = { { "icount", HAS_ARG, QEMU_OPTION_icount }, { "incoming", HAS_ARG, QEMU_OPTION_incoming }, { "mem-path", HAS_ARG, QEMU_OPTION_mempath }, +#ifdef CONFIG_QXL + { "qxl", HAS_ARG, QEMU_OPTION_qxl }, +#endif +#ifdef CONFIG_SPICE + { "spice", HAS_ARG, QEMU_OPTION_spice }, + { "spice-help", 0, QEMU_OPTION_spice_help }, +#endif { NULL }, }; @@ -4635,7 +4671,6 @@ void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const cha *opt_incoming = incoming; } - static int gethugepagesize(void) { int ret, fd; @@ -4815,7 +4850,7 @@ int main(int argc, char **argv, char **envp) } } #endif - + init_monitor_commands(); register_machines(); machine = first_machine; cpu_model = NULL; @@ -5316,6 +5351,37 @@ int main(int argc, char **argv, char **envp) break; #endif #endif +#ifdef CONFIG_QXL + case QEMU_OPTION_qxl: { + int devices = strtol(optarg, NULL, 0); + if (devices < 0 || devices > QXL_MAX_MONITORS ) { + fprintf(stderr, "qemu: invalid number of qxl devices, use 0 to %d\n", + QXL_MAX_MONITORS); + exit(-1); + } + num_qxl_device = devices; + using_qxl = (num_qxl_device > 0) ? 1 : 0; + break; + } +#endif +#ifdef CONFIG_SPICE + case QEMU_OPTION_spice: + using_spice = 1; + if (!spice_parse_args(optarg)) { + fprintf(stderr, "qemu: spice parse args failed\n"); + exit(1); + } + break; + case QEMU_OPTION_spice_help: { + const char **spice_line = spice_usage_str; + printf("\nSpice options\n"); + for (; *spice_line; spice_line++) { + printf(" %s\n", *spice_line); + } + exit(0); + break; + } +#endif case QEMU_OPTION_usb: usb_enabled = 1; break; @@ -5465,6 +5531,13 @@ int main(int argc, char **argv, char **envp) } } +#ifdef CONFIG_QXL + if(using_qxl) { + cirrus_vga_enabled = 0; + vmsvga_enabled = 0; + } +#endif + #if defined(CONFIG_KVM) && defined(USE_KQEMU) if (kvm_allowed && kqemu_allowed) { fprintf(stderr, @@ -5672,6 +5745,12 @@ int main(int argc, char **argv, char **envp) phys_ram_size += ram_size; } +#ifdef CONFIG_QXL + if (using_qxl) { + phys_ram_size += num_qxl_device * QXL_MEM_SIZE; + } +#endif + /* Initialize kvm */ #if defined(TARGET_I386) || defined(TARGET_X86_64) #define KVM_EXTRA_PAGES 3 @@ -5732,6 +5811,10 @@ int main(int argc, char **argv, char **envp) } /* nearly nothing to do */ dumb_display_init(ds); +#ifdef CONFIG_QXL + } else if (using_qxl) { + qxl_init_display(ds); +#endif } else if (vnc_display != NULL) { vnc_display_init(ds); if (vnc_display_open(ds, vnc_display) < 0) @@ -5812,8 +5895,14 @@ int main(int argc, char **argv, char **envp) } } +#ifdef CONFIG_SPICE + if(using_spice) { + spice_init(&core_interface); + } +#endif + if (kvm_enabled()) - kvm_init_ap(); + kvm_init_ap(); #ifdef KVM_UPSTREAM if (kvm_enabled()) { @@ -5853,7 +5942,11 @@ int main(int argc, char **argv, char **envp) } } +#ifdef CONFIG_QXL + if(!using_qxl && display_state.dpy_refresh) { +#else if (display_state.dpy_refresh) { +#endif display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state); qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock)); } -- 1.6.1