diff options
63 files changed, 1974 insertions, 704 deletions
diff --git a/.gitignore b/.gitignore index f5aab2cb07..c72955aad1 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,8 @@ QMP/qmp-commands.txt test-coroutine test-qmp-input-visitor test-qmp-output-visitor +test-string-input-visitor +test-string-output-visitor fsdev/virtfs-proxy-helper.1 fsdev/virtfs-proxy-helper.pod .gdbinit diff --git a/MAINTAINERS b/MAINTAINERS index 647c41363d..0b3b3d8dc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -420,11 +420,16 @@ F: hw/pci* F: hw/piix* SCSI +M: Paolo Bonzini <pbonzini@redhat.com> +S: Supported +F: hw/virtio-scsi.* +F: hw/scsi* +T: git://github.com/bonzini/qemu.git scsi-next + +LSI53C895A M: Paul Brook <paul@codesourcery.com> -M: Kevin Wolf <kwolf@redhat.com> S: Odd Fixes F: hw/lsi53c895a.c -F: hw/scsi* USB M: Gerd Hoffmann <kraxel@redhat.com> @@ -159,6 +159,7 @@ qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o +qemu-bridge-helper.o: $(GENERATED_HEADERS) fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y) fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap diff --git a/Makefile.objs b/Makefile.objs index 391e524525..67ee3df828 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -250,6 +250,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o # MIPS devices hw-obj-$(CONFIG_PIIX4) += piix4.o hw-obj-$(CONFIG_G364FB) += g364fb.o +hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o # PCI watchdog devices hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o @@ -412,8 +413,9 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o ###################################################################### # qapi -qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o -qapi-nested-y += qmp-registry.o qmp-dispatch.o +qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o +qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +qapi-nested-y += string-input-visitor.o string-output-visitor.o qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y)) common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y) diff --git a/Makefile.target b/Makefile.target index eef4accb27..68a5641183 100644 --- a/Makefile.target +++ b/Makefile.target @@ -242,6 +242,7 @@ obj-i386-y += vmport.o obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o +obj-i386-y += pc_sysfw.o obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o @@ -300,7 +301,6 @@ obj-lm32-y += framebuffer.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o -obj-mips-y += jazz_led.o obj-mips-y += gt64xxx.o mc146818rtc.o obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o diff --git a/QMP/qmp.py b/QMP/qmp.py index c7dbea076d..36ecc1dfae 100644 --- a/QMP/qmp.py +++ b/QMP/qmp.py @@ -128,6 +128,12 @@ class QEMUMonitorProtocol: qmp_cmd['id'] = id return self.cmd_obj(qmp_cmd) + def command(self, cmd, **kwds): + ret = self.cmd(cmd, kwds) + if ret.has_key('error'): + raise Exception(ret['error']['desc']) + return ret['return'] + def get_events(self, wait=False): """ Get a list of available QMP events. diff --git a/QMP/qom-get b/QMP/qom-get new file mode 100755 index 0000000000..0172c69441 --- /dev/null +++ b/QMP/qom-get @@ -0,0 +1,67 @@ +#!/usr/bin/python +## +# QEMU Object Model test tools +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori <aliguori@us.ibm.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. See +# the COPYING file in the top-level directory. +## + +import sys +import os +from qmp import QEMUMonitorProtocol + +cmd, args = sys.argv[0], sys.argv[1:] +socket_path = None +path = None +prop = None + +def usage(): + return '''environment variables: + QMP_SOCKET=<path | addr:port> +usage: + %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> +''' % cmd + +def usage_error(error_msg = "unspecified error"): + sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) + exit(1) + +if len(args) > 0: + if args[0] == "-h": + print usage() + exit(0); + elif args[0] == "-s": + try: + socket_path = args[1] + except: + usage_error("missing argument: QMP socket path or address"); + args = args[2:] + +if not socket_path: + if os.environ.has_key('QMP_SOCKET'): + socket_path = os.environ['QMP_SOCKET'] + else: + usage_error("no QMP socket path or address given"); + +if len(args) > 0: + try: + path, prop = args[0].rsplit('.', 1) + except: + usage_error("invalid format for path/property/value") +else: + usage_error("not enough arguments") + +srv = QEMUMonitorProtocol(socket_path) +srv.connect() + +rsp = srv.command('qom-get', path=path, property=prop) +if type(rsp) == dict: + for i in rsp.keys(): + print '%s: %s' % (i, rsp[i]) +else: + print rsp diff --git a/QMP/qom-list b/QMP/qom-list new file mode 100755 index 0000000000..1e7cc6cb2d --- /dev/null +++ b/QMP/qom-list @@ -0,0 +1,64 @@ +#!/usr/bin/python +## +# QEMU Object Model test tools +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori <aliguori@us.ibm.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. See +# the COPYING file in the top-level directory. +## + +import sys +import os +from qmp import QEMUMonitorProtocol + +cmd, args = sys.argv[0], sys.argv[1:] +socket_path = None +path = None +prop = None + +def usage(): + return '''environment variables: + QMP_SOCKET=<path | addr:port> +usage: + %s [-h] [-s <QMP socket path | addr:port>] [<path>] +''' % cmd + +def usage_error(error_msg = "unspecified error"): + sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) + exit(1) + +if len(args) > 0: + if args[0] == "-h": + print usage() + exit(0); + elif args[0] == "-s": + try: + socket_path = args[1] + except: + usage_error("missing argument: QMP socket path or address"); + args = args[2:] + +if not socket_path: + if os.environ.has_key('QMP_SOCKET'): + socket_path = os.environ['QMP_SOCKET'] + else: + usage_error("no QMP socket path or address given"); + +srv = QEMUMonitorProtocol(socket_path) +srv.connect() + +if len(args) == 0: + print '/' + sys.exit(0) + +for item in srv.command('qom-list', path=args[0]): + if item['type'].startswith('child<'): + print '%s/' % item['name'] + elif item['type'].startswith('link<'): + print '@%s/' % item['name'] + else: + print '%s' % item['name'] diff --git a/QMP/qom-set b/QMP/qom-set new file mode 100755 index 0000000000..54ecfecc53 --- /dev/null +++ b/QMP/qom-set @@ -0,0 +1,64 @@ +#!/usr/bin/python +## +# QEMU Object Model test tools +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori <aliguori@us.ibm.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. See +# the COPYING file in the top-level directory. +## + +import sys +import os +from qmp import QEMUMonitorProtocol + +cmd, args = sys.argv[0], sys.argv[1:] +socket_path = None +path = None +prop = None +value = None + +def usage(): + return '''environment variables: + QMP_SOCKET=<path | addr:port> +usage: + %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value> +''' % cmd + +def usage_error(error_msg = "unspecified error"): + sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) + exit(1) + +if len(args) > 0: + if args[0] == "-h": + print usage() + exit(0); + elif args[0] == "-s": + try: + socket_path = args[1] + except: + usage_error("missing argument: QMP socket path or address"); + args = args[2:] + +if not socket_path: + if os.environ.has_key('QMP_SOCKET'): + socket_path = os.environ['QMP_SOCKET'] + else: + usage_error("no QMP socket path or address given"); + +if len(args) > 1: + try: + path, prop = args[0].rsplit('.', 1) + except: + usage_error("invalid format for path/property/value") + value = args[1] +else: + usage_error("not enough arguments") + +srv = QEMUMonitorProtocol(socket_path) +srv.connect() + +print srv.command('qom-set', path=path, property=prop, value=sys.argv[2]) diff --git a/blockdev.c b/blockdev.c index 7a6613a2d2..2c132a308b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -595,7 +595,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) /* CDROM is fine for any interface, don't check. */ ro = 1; } else if (ro == 1) { - if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) { + if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && + type != IF_NONE && type != IF_PFLASH) { error_report("readonly not supported by this bus type"); goto err; } @@ -1441,9 +1441,6 @@ void console_color_init(DisplayState *ds) } } -static int n_text_consoles; -static CharDriverState *text_consoles[128]; - static void text_console_set_echo(CharDriverState *chr, bool echo) { TextConsole *s = chr->opaque; @@ -1510,7 +1507,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -int text_console_init(QemuOpts *opts, CharDriverState **_chr) +CharDriverState *text_console_init(QemuOpts *opts) { CharDriverState *chr; TextConsole *s; @@ -1519,13 +1516,6 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) chr = g_malloc0(sizeof(CharDriverState)); - if (n_text_consoles == 128) { - fprintf(stderr, "Too many text consoles\n"); - exit(1); - } - text_consoles[n_text_consoles] = chr; - n_text_consoles++; - width = qemu_opt_get_number(opts, "width", 0); if (width == 0) width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; @@ -1542,7 +1532,7 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) if (!s) { g_free(chr); - return -EBUSY; + return NULL; } s->chr = chr; @@ -1550,20 +1540,18 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr) s->g_height = height; chr->opaque = s; chr->chr_set_echo = text_console_set_echo; - - *_chr = chr; - return 0; + return chr; } void text_consoles_set_display(DisplayState *ds) { int i; - for (i = 0; i < n_text_consoles; i++) { - text_console_do_init(text_consoles[i], ds); + for (i = 0; i < nb_consoles; i++) { + if (consoles[i]->console_type != GRAPHIC_CONSOLE) { + text_console_do_init(consoles[i]->chr, ds); + } } - - n_text_consoles = 0; } void qemu_console_resize(DisplayState *ds, int width, int height) @@ -356,7 +356,7 @@ void vga_hw_text_update(console_ch_t *chardata); int is_graphic_console(void); int is_fixedsize_console(void); -int text_console_init(QemuOpts *opts, CharDriverState **_chr); +CharDriverState *text_console_init(QemuOpts *opts); void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); void console_color_init(DisplayState *ds); diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 662348ef11..2c78175ae7 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -24,3 +24,4 @@ CONFIG_SOUND=y CONFIG_HPET=y CONFIG_APPLESMC=y CONFIG_I8259=y +CONFIG_PFLASH_CFI01=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index 308d04aeab..a271b1c6da 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -30,3 +30,4 @@ CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_G364FB=y CONFIG_I8259=y +CONFIG_JAZZ_LED=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index f1b92da8a3..0510bb6a53 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -30,3 +30,4 @@ CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_G364FB=y CONFIG_I8259=y +CONFIG_JAZZ_LED=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 567396c84f..ed3bed3b8d 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -32,3 +32,4 @@ CONFIG_PFLASH_CFI01=y CONFIG_FULONG=y CONFIG_G364FB=y CONFIG_I8259=y +CONFIG_JAZZ_LED=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index a8e421b151..fa3a2cacdd 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -30,3 +30,4 @@ CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_G364FB=y CONFIG_I8259=y +CONFIG_JAZZ_LED=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index b445be2059..233a8564eb 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -24,3 +24,4 @@ CONFIG_SOUND=y CONFIG_HPET=y CONFIG_APPLESMC=y CONFIG_I8259=y +CONFIG_PFLASH_CFI01=y @@ -562,7 +562,7 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -int chr_baum_init(QemuOpts *opts, CharDriverState **_chr) +CharDriverState *chr_baum_init(QemuOpts *opts) { BaumDriverState *baum; CharDriverState *chr; @@ -614,8 +614,7 @@ int chr_baum_init(QemuOpts *opts, CharDriverState **_chr) qemu_chr_generic_open(chr); - *_chr = chr; - return 0; + return chr; fail: qemu_free_timer(baum->cellCount_timer); @@ -624,5 +623,5 @@ fail_handle: g_free(handle); g_free(chr); g_free(baum); - return -EIO; + return NULL; } @@ -23,4 +23,4 @@ */ /* char device */ -int chr_baum_init(QemuOpts *opts, CharDriverState **_chr); +CharDriverState *chr_baum_init(QemuOpts *opts); diff --git a/hw/boards.h b/hw/boards.h index f6d3784cf1..667177d76d 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -32,6 +32,7 @@ typedef struct QEMUMachine { } QEMUMachine; int qemu_register_machine(QEMUMachine *m); +QEMUMachine *find_default_machine(void); extern QEMUMachine *current_machine; diff --git a/hw/jazz_led.c b/hw/jazz_led.c index f8a218252c..5d8040be30 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -1,7 +1,7 @@ /* * QEMU JAZZ LED emulator. * - * Copyright (c) 2007 Hervé Poussineau + * Copyright (c) 2007-2012 Herve Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,131 +22,53 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" #include "console.h" #include "pixel_ops.h" - -//#define DEBUG_LED - -#ifdef DEBUG_LED -#define DPRINTF(fmt, ...) \ -do { printf("jazz led: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif -#define BADF(fmt, ...) \ -do { fprintf(stderr, "jazz led ERROR: " fmt , ## __VA_ARGS__);} while (0) +#include "trace.h" +#include "sysbus.h" typedef enum { REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, } screen_state_t; typedef struct LedState { + SysBusDevice busdev; MemoryRegion iomem; uint8_t segments; DisplayState *ds; screen_state_t state; } LedState; -static uint32_t led_readb(void *opaque, target_phys_addr_t addr) +static uint64_t jazz_led_read(void *opaque, target_phys_addr_t addr, + unsigned int size) { LedState *s = opaque; - uint32_t val; - - switch (addr) { - case 0: - val = s->segments; - break; - default: - BADF("invalid read at [" TARGET_FMT_plx "]\n", addr); - val = 0; - } + uint8_t val; - DPRINTF("read addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val); + val = s->segments; + trace_jazz_led_read(addr, val); return val; } -static uint32_t led_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = led_readb(opaque, addr) << 8; - v |= led_readb(opaque, addr + 1); -#else - v = led_readb(opaque, addr); - v |= led_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t led_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = led_readb(opaque, addr) << 24; - v |= led_readb(opaque, addr + 1) << 16; - v |= led_readb(opaque, addr + 2) << 8; - v |= led_readb(opaque, addr + 3); -#else - v = led_readb(opaque, addr); - v |= led_readb(opaque, addr + 1) << 8; - v |= led_readb(opaque, addr + 2) << 16; - v |= led_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void jazz_led_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) { LedState *s = opaque; + uint8_t new_val = val & 0xff; - DPRINTF("write addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val); + trace_jazz_led_write(addr, new_val); - switch (addr) { - case 0: - s->segments = val; - s->state |= REDRAW_SEGMENTS; - break; - default: - BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr); - break; - } -} - -static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - led_writeb(opaque, addr, (val >> 8) & 0xff); - led_writeb(opaque, addr + 1, val & 0xff); -#else - led_writeb(opaque, addr, val & 0xff); - led_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - led_writeb(opaque, addr, (val >> 24) & 0xff); - led_writeb(opaque, addr + 1, (val >> 16) & 0xff); - led_writeb(opaque, addr + 2, (val >> 8) & 0xff); - led_writeb(opaque, addr + 3, val & 0xff); -#else - led_writeb(opaque, addr, val & 0xff); - led_writeb(opaque, addr + 1, (val >> 8) & 0xff); - led_writeb(opaque, addr + 2, (val >> 16) & 0xff); - led_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif + s->segments = new_val; + s->state |= REDRAW_SEGMENTS; } static const MemoryRegionOps led_ops = { - .old_mmio = { - .read = { led_readb, led_readw, led_readl, }, - .write = { led_writeb, led_writew, led_writel, }, - }, + .read = jazz_led_read, + .write = jazz_led_write, .endianness = DEVICE_NATIVE_ENDIAN, + .impl.min_access_size = 1, + .impl.max_access_size = 1, }; /***********************************************************/ @@ -304,20 +226,71 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) dpy_update(s->ds, 0, 0, 2, 1); } -void jazz_led_init(MemoryRegion *address_space, target_phys_addr_t base) +static int jazz_led_post_load(void *opaque, int version_id) { - LedState *s; + /* force refresh */ + jazz_led_invalidate_display(opaque); + + return 0; +} - s = g_malloc0(sizeof(LedState)); +static const VMStateDescription vmstate_jazz_led = { + .name = "jazz-led", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = jazz_led_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(segments, LedState), + VMSTATE_END_OF_LIST() + } +}; - s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; +static int jazz_led_init(SysBusDevice *dev) +{ + LedState *s = FROM_SYSBUS(LedState, dev); memory_region_init_io(&s->iomem, &led_ops, s, "led", 1); - memory_region_add_subregion(address_space, base, &s->iomem); + sysbus_init_mmio(dev, &s->iomem); s->ds = graphic_console_init(jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, jazz_led_text_update, s); + + return 0; +} + +static void jazz_led_reset(DeviceState *d) +{ + LedState *s = DO_UPCAST(LedState, busdev.qdev, d); + + s->segments = 0; + s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; qemu_console_resize(s->ds, 60, 80); } + +static void jazz_led_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = jazz_led_init; + dc->desc = "Jazz LED display", + dc->vmsd = &vmstate_jazz_led; + dc->reset = jazz_led_reset; +} + +static TypeInfo jazz_led_info = { + .name = "jazz-led", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LedState), + .class_init = jazz_led_class_init, +}; + +static void jazz_led_register(void) +{ + type_register_static(&jazz_led_info); +} + +type_init(jazz_led_register); @@ -10,9 +10,6 @@ PCIBus *gt64120_register(qemu_irq *pic); /* bonito.c */ PCIBus *bonito_init(qemu_irq *pic); -/* jazz_led.c */ -void jazz_led_init(MemoryRegion *address_space, target_phys_addr_t base); - /* rc4030.c */ typedef struct rc4030DMAState *rc4030_dma; void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 65608dc644..2b4678e170 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -295,7 +295,7 @@ static void mips_jazz_init(MemoryRegion *address_space, sysbus_mmio_map(sysbus, 0, 0x80009000); /* LED indicator */ - jazz_led_init(address_space, 0x8000f000); + sysbus_create_simple("jazz-led", 0x8000f000, NULL); } static diff --git a/hw/msmouse.c b/hw/msmouse.c index c3b57ea31c..9c492a4637 100644 --- a/hw/msmouse.c +++ b/hw/msmouse.c @@ -64,7 +64,7 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr) +CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) { CharDriverState *chr; @@ -74,6 +74,5 @@ int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr) qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse"); - *_chr = chr; - return 0; + return chr; } diff --git a/hw/msmouse.h b/hw/msmouse.h index 8b853b35bf..456cb21424 100644 --- a/hw/msmouse.h +++ b/hw/msmouse.h @@ -1,2 +1,2 @@ /* msmouse.c */ -int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr); +CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); @@ -60,10 +60,6 @@ #define DPRINTF(fmt, ...) #endif -#define BIOS_FILENAME "bios.bin" - -#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) - /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ #define ACPI_DATA_SIZE 0x10000 #define BIOS_CFG_IOPORT 0x510 @@ -990,11 +986,9 @@ void pc_memory_init(MemoryRegion *system_memory, MemoryRegion *rom_memory, MemoryRegion **ram_memory) { - char *filename; - int ret, linux_boot, i; - MemoryRegion *ram, *bios, *isa_bios, *option_rom_mr; + int linux_boot, i; + MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; - int bios_size, isa_bios_size; void *fw_cfg; linux_boot = (kernel_filename != NULL); @@ -1020,44 +1014,9 @@ void pc_memory_init(MemoryRegion *system_memory, ram_above_4g); } - /* BIOS load */ - if (bios_name == NULL) - bios_name = BIOS_FILENAME; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = get_image_size(filename); - } else { - bios_size = -1; - } - if (bios_size <= 0 || - (bios_size % 65536) != 0) { - goto bios_error; - } - bios = g_malloc(sizeof(*bios)); - memory_region_init_ram(bios, "pc.bios", bios_size); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); - if (ret != 0) { - bios_error: - fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); - exit(1); - } - if (filename) { - g_free(filename); - } - /* map the last 128KB of the BIOS in ISA space */ - isa_bios_size = bios_size; - if (isa_bios_size > (128 * 1024)) - isa_bios_size = 128 * 1024; - isa_bios = g_malloc(sizeof(*isa_bios)); - memory_region_init_alias(isa_bios, "isa-bios", bios, - bios_size - isa_bios_size, isa_bios_size); - memory_region_add_subregion_overlap(rom_memory, - 0x100000 - isa_bios_size, - isa_bios, - 1); - memory_region_set_readonly(isa_bios, true); + + /* Initialize PC system firmware */ + pc_system_firmware_init(rom_memory); option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE); @@ -1067,11 +1026,6 @@ void pc_memory_init(MemoryRegion *system_memory, option_rom_mr, 1); - /* map all the bios at the top of memory */ - memory_region_add_subregion(rom_memory, - (uint32_t)(-bios_size), - bios); - fw_cfg = bochs_bios_init(); rom_set_fw(fw_cfg); @@ -216,6 +216,9 @@ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) return true; } +/* pc_sysfw.c */ +void pc_system_firmware_init(MemoryRegion *rom_memory); + /* e820 types */ #define E820_RAM 1 #define E820_RESERVED 2 diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 17f8d5d593..fe7a729472 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -371,8 +371,8 @@ static void pc_xen_hvm_init(ram_addr_t ram_size, } #endif -static QEMUMachine pc_machine_v1_0 = { - .name = "pc-1.0", +static QEMUMachine pc_machine_v1_1 = { + .name = "pc-1.1", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci, @@ -380,12 +380,34 @@ static QEMUMachine pc_machine_v1_0 = { .is_default = 1, }; +static QEMUMachine pc_machine_v1_0 = { + .name = "pc-1.0", + .desc = "Standard PC", + .init = pc_init_pci, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, + { /* end of list */ } + }, +}; + static QEMUMachine pc_machine_v0_15 = { .name = "pc-0.15", .desc = "Standard PC", .init = pc_init_pci, .max_cpus = 255, - .is_default = 1, + .compat_props = (GlobalProperty[]) { + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, + { /* end of list */ } + }, }; static QEMUMachine pc_machine_v0_14 = { @@ -419,6 +441,11 @@ static QEMUMachine pc_machine_v0_14 = { .property = "event_idx", .value = "off", }, + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, { /* end of list */ } }, }; @@ -466,6 +493,11 @@ static QEMUMachine pc_machine_v0_13 = { .property = "use_broken_id", .value = stringify(1), }, + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, { /* end of list */ } }, }; @@ -517,6 +549,11 @@ static QEMUMachine pc_machine_v0_12 = { .property = "use_broken_id", .value = stringify(1), }, + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, { /* end of list */ } } }; @@ -576,6 +613,11 @@ static QEMUMachine pc_machine_v0_11 = { .property = "use_broken_id", .value = stringify(1), }, + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, { /* end of list */ } } }; @@ -647,6 +689,11 @@ static QEMUMachine pc_machine_v0_10 = { .property = "use_broken_id", .value = stringify(1), }, + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, { /* end of list */ } }, }; @@ -656,6 +703,14 @@ static QEMUMachine isapc_machine = { .desc = "ISA-only PC", .init = pc_init_isa, .max_cpus = 1, + .compat_props = (GlobalProperty[]) { + { + .driver = "pc-sysfw", + .property = "rom_only", + .value = stringify(1), + }, + { /* end of list */ } + }, }; #ifdef CONFIG_XEN @@ -670,6 +725,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_machine_v1_1); qemu_register_machine(&pc_machine_v1_0); qemu_register_machine(&pc_machine_v0_15); qemu_register_machine(&pc_machine_v0_14); diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c new file mode 100644 index 0000000000..abf9004182 --- /dev/null +++ b/hw/pc_sysfw.c @@ -0,0 +1,254 @@ +/* + * QEMU PC System Firmware + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2011-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "hw.h" +#include "pc.h" +#include "hw/boards.h" +#include "loader.h" +#include "sysemu.h" +#include "flash.h" +#include "kvm.h" + +#define BIOS_FILENAME "bios.bin" + +typedef struct PcSysFwDevice { + SysBusDevice busdev; + uint8_t rom_only; +} PcSysFwDevice; + +static void pc_isa_bios_init(MemoryRegion *rom_memory, + MemoryRegion *flash_mem, + int ram_size) +{ + int isa_bios_size; + MemoryRegion *isa_bios; + uint64_t flash_size; + void *flash_ptr, *isa_bios_ptr; + + flash_size = memory_region_size(flash_mem); + + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = flash_size; + if (isa_bios_size > (128 * 1024)) { + isa_bios_size = 128 * 1024; + } + isa_bios = g_malloc(sizeof(*isa_bios)); + memory_region_init_ram(isa_bios, "isa-bios", isa_bios_size); + vmstate_register_ram_global(isa_bios); + memory_region_add_subregion_overlap(rom_memory, + 0x100000 - isa_bios_size, + isa_bios, + 1); + + /* copy ISA rom image from top of flash memory */ + flash_ptr = memory_region_get_ram_ptr(flash_mem); + isa_bios_ptr = memory_region_get_ram_ptr(isa_bios); + memcpy(isa_bios_ptr, + ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size), + isa_bios_size); + + memory_region_set_readonly(isa_bios, true); +} + +static void pc_fw_add_pflash_drv(void) +{ + QemuOpts *opts; + QEMUMachine *machine; + char *filename; + + if (bios_name == NULL) { + bios_name = BIOS_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + + opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); + if (opts == NULL) { + return; + } + + machine = find_default_machine(); + if (machine == NULL) { + return; + } + + drive_init(opts, machine->use_scsi); +} + +static void pc_system_flash_init(MemoryRegion *rom_memory, + DriveInfo *pflash_drv) +{ + BlockDriverState *bdrv; + int64_t size; + target_phys_addr_t phys_addr; + int sector_bits, sector_size; + pflash_t *system_flash; + MemoryRegion *flash_mem; + + bdrv = pflash_drv->bdrv; + size = bdrv_getlength(pflash_drv->bdrv); + sector_bits = 12; + sector_size = 1 << sector_bits; + + if ((size % sector_size) != 0) { + fprintf(stderr, + "qemu: PC system firmware (pflash) must be a multiple of 0x%x\n", + sector_size); + exit(1); + } + + phys_addr = 0x100000000ULL - size; + system_flash = pflash_cfi01_register(phys_addr, NULL, "system.flash", size, + bdrv, sector_size, size >> sector_bits, + 1, 0x0000, 0x0000, 0x0000, 0x0000, 0); + flash_mem = pflash_cfi01_get_memory(system_flash); + + pc_isa_bios_init(rom_memory, flash_mem, size); +} + +static void old_pc_system_rom_init(MemoryRegion *rom_memory) +{ + char *filename; + MemoryRegion *bios, *isa_bios; + int bios_size, isa_bios_size; + int ret; + + /* BIOS load */ + if (bios_name == NULL) { + bios_name = BIOS_FILENAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = get_image_size(filename); + } else { + bios_size = -1; + } + if (bios_size <= 0 || + (bios_size % 65536) != 0) { + goto bios_error; + } + bios = g_malloc(sizeof(*bios)); + memory_region_init_ram(bios, "pc.bios", bios_size); + vmstate_register_ram_global(bios); + memory_region_set_readonly(bios, true); + ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); + if (ret != 0) { + bios_error: + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); + exit(1); + } + if (filename) { + g_free(filename); + } + + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = bios_size; + if (isa_bios_size > (128 * 1024)) { + isa_bios_size = 128 * 1024; + } + isa_bios = g_malloc(sizeof(*isa_bios)); + memory_region_init_alias(isa_bios, "isa-bios", bios, + bios_size - isa_bios_size, isa_bios_size); + memory_region_add_subregion_overlap(rom_memory, + 0x100000 - isa_bios_size, + isa_bios, + 1); + memory_region_set_readonly(isa_bios, true); + + /* map all the bios at the top of memory */ + memory_region_add_subregion(rom_memory, + (uint32_t)(-bios_size), + bios); +} + +void pc_system_firmware_init(MemoryRegion *rom_memory) +{ + DriveInfo *pflash_drv; + PcSysFwDevice *sysfw_dev; + + sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw"); + + if (sysfw_dev->rom_only) { + old_pc_system_rom_init(rom_memory); + return; + } + + pflash_drv = drive_get(IF_PFLASH, 0, 0); + + /* Currently KVM cannot execute from device memory. + Use old rom based firmware initialization for KVM. */ + if (kvm_enabled()) { + if (pflash_drv != NULL) { + fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n"); + exit(1); + } else { + sysfw_dev->rom_only = 1; + old_pc_system_rom_init(rom_memory); + return; + } + } + + /* If a pflash drive is not found, then create one using + the bios filename. */ + if (pflash_drv == NULL) { + pc_fw_add_pflash_drv(); + pflash_drv = drive_get(IF_PFLASH, 0, 0); + } + + if (pflash_drv != NULL) { + pc_system_flash_init(rom_memory, pflash_drv); + } else { + fprintf(stderr, "qemu: PC system firmware (pflash) not available\n"); + exit(1); + } +} + +static Property pcsysfw_properties[] = { + DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pcsysfw_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + + dc->desc = "PC System Firmware"; + dc->props = pcsysfw_properties; +} + +static TypeInfo pcsysfw_info = { + .name = "pc-sysfw", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (PcSysFwDevice), + .class_init = pcsysfw_class_init, +}; + +static void pcsysfw_register (void) +{ + type_register_static (&pcsysfw_info); +} + +type_init (pcsysfw_register); + @@ -614,7 +614,7 @@ static void pci_init_w1cmask(PCIDevice *dev) PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); } -static void pci_init_wmask_bridge(PCIDevice *d) +static void pci_init_mask_bridge(PCIDevice *d) { /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and PCI_SEC_LETENCY_TIMER */ @@ -635,6 +635,14 @@ static void pci_init_wmask_bridge(PCIDevice *d) /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); + /* Supported memory and i/o types */ + d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_32; + d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_32; + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_TYPE_64); + pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_TYPE_64); + /* TODO: add this define to pci_regs.h in linux and then in qemu. */ #define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ #define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ @@ -657,6 +665,9 @@ static void pci_init_wmask_bridge(PCIDevice *d) * completeness. */ pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_DISCARD_STATUS); + d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK; + pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_TYPE_MASK); } static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) @@ -778,7 +789,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_init_wmask(pci_dev); pci_init_w1cmask(pci_dev); if (pc->is_bridge) { - pci_init_wmask_bridge(pci_dev); + pci_init_mask_bridge(pci_dev); } if (pci_init_multifunction(bus, pci_dev)) { pci_config_free(pci_dev); @@ -465,6 +465,67 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) return val & mask; } +/* Access a register specified by a mask */ +static inline void +pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) +{ + uint8_t val = pci_get_byte(config); + uint8_t rval = reg << (ffs(mask) - 1); + pci_set_byte(config, (~mask & val) | (mask & rval)); +} + +static inline uint8_t +pci_get_byte_by_mask(uint8_t *config, uint8_t mask) +{ + uint8_t val = pci_get_byte(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) +{ + uint16_t val = pci_get_word(config); + uint16_t rval = reg << (ffs(mask) - 1); + pci_set_word(config, (~mask & val) | (mask & rval)); +} + +static inline uint16_t +pci_get_word_by_mask(uint8_t *config, uint16_t mask) +{ + uint16_t val = pci_get_word(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) +{ + uint32_t val = pci_get_long(config); + uint32_t rval = reg << (ffs(mask) - 1); + pci_set_long(config, (~mask & val) | (mask & rval)); +} + +static inline uint32_t +pci_get_long_by_mask(uint8_t *config, uint32_t mask) +{ + uint32_t val = pci_get_long(config); + return (val & mask) >> (ffs(mask) - 1); +} + +static inline void +pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) +{ + uint64_t val = pci_get_quad(config); + uint64_t rval = reg << (ffs(mask) - 1); + pci_set_quad(config, (~mask & val) | (mask & rval)); +} + +static inline uint64_t +pci_get_quad_by_mask(uint8_t *config, uint64_t mask) +{ + uint64_t val = pci_get_quad(config); + return (val & mask) >> (ffs(mask) - 1); +} + PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index ee0c3baab1..b03f623cb1 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -283,8 +283,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, TARGET_FMT_plx "\n", __func__, offset, pfl->sector_len); - memset(p + offset, 0xff, pfl->sector_len); - pflash_update(pfl, offset, pfl->sector_len); + if (!pfl->ro) { + memset(p + offset, 0xff, pfl->sector_len); + pflash_update(pfl, offset, pfl->sector_len); + } else { + pfl->status |= 0x20; /* Block erase error */ + } pfl->status |= 0x80; /* Ready! */ break; case 0x50: /* Clear status bits */ @@ -323,8 +327,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, case 0x10: /* Single Byte Program */ case 0x40: /* Single Byte Program */ DPRINTF("%s: Single Byte Program\n", __func__); - pflash_data_write(pfl, offset, value, width, be); - pflash_update(pfl, offset, width); + if (!pfl->ro) { + pflash_data_write(pfl, offset, value, width, be); + pflash_update(pfl, offset, width); + } else { + pfl->status |= 0x10; /* Programming error */ + } pfl->status |= 0x80; /* Ready! */ pfl->wcycle = 0; break; @@ -372,7 +380,11 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, case 2: switch (pfl->cmd) { case 0xe8: /* Block write */ - pflash_data_write(pfl, offset, value, width, be); + if (!pfl->ro) { + pflash_data_write(pfl, offset, value, width, be); + } else { + pfl->status |= 0x10; /* Programming error */ + } pfl->status |= 0x80; @@ -382,8 +394,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: block write finished\n", __func__); pfl->wcycle++; - /* Flush the entire write buffer onto backing storage. */ - pflash_update(pfl, offset & mask, pfl->writeblock_size); + if (!pfl->ro) { + /* Flush the entire write buffer onto backing storage. */ + pflash_update(pfl, offset & mask, pfl->writeblock_size); + } else { + pfl->status |= 0x10; /* Programming error */ + } } pfl->counter--; @@ -607,13 +623,13 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, } bdrv_attach_dev_nofail(pfl->bs, pfl); } -#if 0 /* XXX: there should be a bit to set up read-only, - * the same way the hardware does (with WP pin). - */ - pfl->ro = 1; -#else - pfl->ro = 0; -#endif + + if (pfl->bs) { + pfl->ro = bdrv_is_read_only(pfl->bs); + } else { + pfl->ro = 0; + } + pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); pfl->base = base; pfl->sector_len = sector_len; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 2ca0fd4560..3e2002e4b3 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -330,35 +330,37 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n", __func__, offset, value, width); p = pfl->storage; - switch (width) { - case 1: - p[offset] &= value; - pflash_update(pfl, offset, 1); - break; - case 2: - if (be) { - p[offset] &= value >> 8; - p[offset + 1] &= value; - } else { + if (!pfl->ro) { + switch (width) { + case 1: p[offset] &= value; - p[offset + 1] &= value >> 8; + pflash_update(pfl, offset, 1); + break; + case 2: + if (be) { + p[offset] &= value >> 8; + p[offset + 1] &= value; + } else { + p[offset] &= value; + p[offset + 1] &= value >> 8; + } + pflash_update(pfl, offset, 2); + break; + case 4: + if (be) { + p[offset] &= value >> 24; + p[offset + 1] &= value >> 16; + p[offset + 2] &= value >> 8; + p[offset + 3] &= value; + } else { + p[offset] &= value; + p[offset + 1] &= value >> 8; + p[offset + 2] &= value >> 16; + p[offset + 3] &= value >> 24; + } + pflash_update(pfl, offset, 4); + break; } - pflash_update(pfl, offset, 2); - break; - case 4: - if (be) { - p[offset] &= value >> 24; - p[offset + 1] &= value >> 16; - p[offset + 2] &= value >> 8; - p[offset + 3] &= value; - } else { - p[offset] &= value; - p[offset + 1] &= value >> 8; - p[offset + 2] &= value >> 16; - p[offset + 3] &= value >> 24; - } - pflash_update(pfl, offset, 4); - break; } pfl->status = 0x00 | ~(value & 0x80); /* Let's pretend write is immediate */ @@ -404,9 +406,11 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, } /* Chip erase */ DPRINTF("%s: start chip erase\n", __func__); - memset(pfl->storage, 0xFF, pfl->chip_len); + if (!pfl->ro) { + memset(pfl->storage, 0xFF, pfl->chip_len); + pflash_update(pfl, 0, pfl->chip_len); + } pfl->status = 0x00; - pflash_update(pfl, 0, pfl->chip_len); /* Let's wait 5 seconds before chip erase is done */ qemu_mod_timer(pfl->timer, qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5)); @@ -417,8 +421,10 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, offset &= ~(pfl->sector_len - 1); DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__, offset); - memset(p + offset, 0xFF, pfl->sector_len); - pflash_update(pfl, offset, pfl->sector_len); + if (!pfl->ro) { + memset(p + offset, 0xFF, pfl->sector_len); + pflash_update(pfl, offset, pfl->sector_len); + } pfl->status = 0x00; /* Let's wait 1/2 second before sector erase is done */ qemu_mod_timer(pfl->timer, @@ -645,16 +651,17 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, } bdrv_attach_dev_nofail(pfl->bs, pfl); } + pflash_setup_mappings(pfl); pfl->rom_mode = 1; memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem); -#if 0 /* XXX: there should be a bit to set up read-only, - * the same way the hardware does (with WP pin). - */ - pfl->ro = 1; -#else - pfl->ro = 0; -#endif + + if (pfl->bs) { + pfl->ro = bdrv_is_read_only(pfl->bs); + } else { + pfl->ro = 0; + } + pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); pfl->sector_len = sector_len; pfl->width = width; diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 7b74dd5beb..0423af1c31 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -27,16 +27,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) } /* Bit */ -static int parse_bit(DeviceState *dev, Property *prop, const char *str) -{ - if (!strcasecmp(str, "on")) - bit_prop_set(dev, prop, true); - else if (!strcasecmp(str, "off")) - bit_prop_set(dev, prop, false); - else - return -EINVAL; - return 0; -} static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) { @@ -79,7 +69,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_bit = { .name = "boolean", .legacy_name = "on/off", - .parse = parse_bit, .print = print_bit, .get = get_bit, .set = set_bit, @@ -87,26 +76,6 @@ PropertyInfo qdev_prop_bit = { /* --- 8bit integer --- */ -static int parse_uint8(DeviceState *dev, Property *prop, const char *str) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu8, *ptr); -} - static void get_int8(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -149,8 +118,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .parse = parse_uint8, - .print = print_uint8, .get = get_int8, .set = set_int8, .min = 0, @@ -164,6 +131,10 @@ static int parse_hex8(DeviceState *dev, Property *prop, const char *str) uint8_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -191,26 +162,6 @@ PropertyInfo qdev_prop_hex8 = { /* --- 16bit integer --- */ -static int parse_uint16(DeviceState *dev, Property *prop, const char *str) -{ - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu16, *ptr); -} - static void get_int16(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -253,8 +204,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .parse = parse_uint16, - .print = print_uint16, .get = get_int16, .set = set_int16, .min = 0, @@ -263,26 +212,6 @@ PropertyInfo qdev_prop_uint16 = { /* --- 32bit integer --- */ -static int parse_uint32(DeviceState *dev, Property *prop, const char *str) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu32, *ptr); -} - static void get_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -325,37 +254,14 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint32 = { .name = "uint32", - .parse = parse_uint32, - .print = print_uint32, .get = get_int32, .set = set_int32, .min = 0, .max = 0xFFFFFFFFULL, }; -static int parse_int32(DeviceState *dev, Property *prop, const char *str) -{ - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - *ptr = strtol(str, &end, 10); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - int32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRId32, *ptr); -} - PropertyInfo qdev_prop_int32 = { .name = "int32", - .parse = parse_int32, - .print = print_int32, .get = get_int32, .set = set_int32, .min = -0x80000000LL, @@ -369,6 +275,10 @@ static int parse_hex32(DeviceState *dev, Property *prop, const char *str) uint32_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -396,26 +306,6 @@ PropertyInfo qdev_prop_hex32 = { /* --- 64bit integer --- */ -static int parse_uint64(DeviceState *dev, Property *prop, const char *str) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoull(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; -} - -static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu64, *ptr); -} - static void get_int64(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -443,8 +333,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .parse = parse_uint64, - .print = print_uint64, .get = get_int64, .set = set_int64, }; @@ -456,6 +344,10 @@ static int parse_hex64(DeviceState *dev, Property *prop, const char *str) uint64_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoull(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -737,19 +629,6 @@ PropertyInfo qdev_prop_netdev = { /* --- vlan --- */ -static int parse_vlan(DeviceState *dev, Property *prop, const char *str) -{ - VLANState **ptr = qdev_get_prop_ptr(dev, prop); - int id; - - if (sscanf(str, "%d", &id) != 1) - return -EINVAL; - *ptr = qemu_find_vlan(id, 1); - if (*ptr == NULL) - return -ENOENT; - return 0; -} - static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) { VLANState **ptr = qdev_get_prop_ptr(dev, prop); @@ -808,7 +687,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_vlan = { .name = "vlan", - .parse = parse_vlan, .print = print_vlan, .get = get_vlan, .set = set_vlan, @@ -943,25 +821,40 @@ PropertyInfo qdev_prop_losttickpolicy = { /* * bus-local address, i.e. "$slot" or "$slot.$fn" */ -static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; + Error *local_err = NULL; + char *str = (char *)""; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + return set_int32(obj, v, opaque, name, errp); + } if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { fn = 0; if (sscanf(str, "%x%n", &slot, &n) != 1) { - return -EINVAL; + goto invalid; } } - if (str[n] != '\0') - return -EINVAL; - if (fn > 7) - return -EINVAL; - if (slot > 31) - return -EINVAL; + if (str[n] != '\0' || fn > 7 || slot > 31) { + goto invalid; + } *ptr = slot << 3 | fn; - return 0; + return; + +invalid: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -978,10 +871,9 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t PropertyInfo qdev_prop_pci_devfn = { .name = "int32", .legacy_name = "pci-devfn", - .parse = parse_pci_devfn, .print = print_pci_devfn, .get = get_int32, - .set = set_int32, + .set = set_pci_devfn, /* FIXME: this should be -1...255, but the address is stored * into an uint32_t rather than int32_t. */ @@ -1054,9 +946,9 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) legacy_name = g_strdup_printf("legacy-%s", name); if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - object_property_set_str(OBJECT(dev), value, legacy_name, &err); + object_property_parse(OBJECT(dev), value, legacy_name, &err); } else { - object_property_set_str(OBJECT(dev), value, name, &err); + object_property_parse(OBJECT(dev), value, name, &err); } g_free(legacy_name); diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 133d09324c..708414376e 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -121,19 +121,17 @@ void qxl_render_update(PCIQXLDevice *qxl) dpy_resize(vga->ds); } - if (!qxl->guest_primary.commands) { - return; - } - qxl->guest_primary.commands = 0; - update.left = 0; update.right = qxl->guest_primary.surface.width; update.top = 0; update.bottom = qxl->guest_primary.surface.height; memset(dirty, 0, sizeof(dirty)); - qxl_spice_update_area(qxl, 0, &update, - dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); + if (runstate_is_running() && qxl->guest_primary.commands) { + qxl->guest_primary.commands = 0; + qxl_spice_update_area(qxl, 0, &update, + dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); + } if (redraw) { memset(dirty, 0, sizeof(dirty)); dirty[0] = update; @@ -625,7 +625,7 @@ static void interface_release_resource(QXLInstance *sin, if (ext.group_id == MEMSLOT_GROUP_HOST) { /* host group -> vga mode update request */ - qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); + qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); return; } @@ -748,7 +748,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) qxl->current_async = QXL_UNDEFINED_IO; qemu_mutex_unlock(&qxl->async_lock); - dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); + dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", + current_async, cookie); switch (current_async) { case QXL_IO_CREATE_PRIMARY_ASYNC: qxl_create_guest_primary_complete(qxl); @@ -1006,7 +1007,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) qxl_spice_destroy_surfaces(d, QXL_SYNC); } -/* called from spice server thread context only */ +/* can be also called from spice server thread context */ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) { uint64_t phys = le64_to_cpu(pqxl); @@ -1015,7 +1016,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) switch (group_id) { case MEMSLOT_GROUP_HOST: - return (void*)offset; + return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: PANIC_ON(slot >= NUM_MEMSLOTS); PANIC_ON(!qxl->guest_slots[slot].active); @@ -1465,6 +1466,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) } } +static void qxl_dirty_surfaces(PCIQXLDevice *qxl) +{ + intptr_t vram_start; + int i; + + if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { + return; + } + + /* dirty the primary surface */ + qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, + qxl->shadow_rom.surface0_area_size); + + vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); + + /* dirty the off-screen surfaces */ + for (i = 0; i < NUM_SURFACES; i++) { + QXLSurfaceCmd *cmd; + intptr_t surface_offset; + int surface_size; + + if (qxl->guest_surfaces.cmds[i] == 0) { + continue; + } + + cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], + MEMSLOT_GROUP_GUEST); + assert(cmd->type == QXL_SURFACE_CMD_CREATE); + surface_offset = (intptr_t)qxl_phys2virt(qxl, + cmd->u.surface_create.data, + MEMSLOT_GROUP_GUEST); + surface_offset -= vram_start; + surface_size = cmd->u.surface_create.height * + abs(cmd->u.surface_create.stride); + dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, + i, (int)surface_offset, surface_size); + qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); + } +} + static void qxl_vm_change_state_handler(void *opaque, int running, RunState state) { @@ -1478,14 +1519,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, * called */ qxl_update_irq(qxl); - } else if (qxl->mode == QXL_MODE_NATIVE) { - /* dirty all vram (which holds surfaces) and devram (primary surface) - * to make sure they are saved */ - /* FIXME #1: should go out during "live" stage */ - /* FIXME #2: we only need to save the areas which are actually used */ - qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size); - qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, - qxl->shadow_rom.surface0_area_size); + } else { + /* make sure surfaces are saved before migration */ + qxl_dirty_surfaces(qxl); } } @@ -1518,6 +1554,31 @@ static DisplayChangeListener display_listener = { .dpy_refresh = display_refresh, }; +static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) +{ + /* vga ram (bar 0) */ + if (qxl->ram_size_mb != -1) { + qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024; + } + if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + + /* vram (surfaces, bar 1) */ + if (qxl->vram_size_mb != -1) { + qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; + } + if (qxl->vram_size < 4096) { + qxl->vram_size = 4096; + } + if (qxl->revision == 1) { + qxl->vram_size = 4096; + } + + qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); +} + static int qxl_init_common(PCIQXLDevice *qxl) { uint8_t* config = qxl->pci.config; @@ -1556,13 +1617,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) init_qxl_rom(qxl); init_qxl_ram(qxl); - if (qxl->vram_size < 16 * 1024 * 1024) { - qxl->vram_size = 16 * 1024 * 1024; - } - if (qxl->revision == 1) { - qxl->vram_size = 4096; - } - qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); @@ -1605,15 +1659,11 @@ static int qxl_init_primary(PCIDevice *dev) { PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; - ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); PortioList *qxl_vga_port_list = g_new(PortioList, 1); qxl->id = 0; - - if (ram_size < 32 * 1024 * 1024) { - ram_size = 32 * 1024 * 1024; - } - vga_common_init(vga, ram_size); + qxl_init_ramsize(qxl, 32); + vga_common_init(vga, qxl->vga.vram_size); vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); @@ -1632,14 +1682,9 @@ static int qxl_init_secondary(PCIDevice *dev) { static int device_id = 1; PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); - ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); qxl->id = device_id++; - - if (ram_size < 16 * 1024 * 1024) { - ram_size = 16 * 1024 * 1024; - } - qxl->vga.vram_size = ram_size; + qxl_init_ramsize(qxl, 16); memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size); vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); @@ -1821,6 +1866,8 @@ static Property qxl_properties[] = { DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), + DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -89,6 +89,10 @@ typedef struct PCIQXLDevice { /* io bar */ MemoryRegion io_bar; + + /* user-friendly properties (in megabytes) */ + uint32_t ram_size_mb; + uint32_t vram_size_mb; } PCIQXLDevice; #define PANIC_ON(x) if ((x)) { \ diff --git a/include/qemu/object.h b/include/qemu/object.h index 5179c0cf5a..69e4b7b282 100644 --- a/include/qemu/object.h +++ b/include/qemu/object.h @@ -730,6 +730,30 @@ void object_property_set(Object *obj, struct Visitor *v, const char *name, struct Error **errp); /** + * object_property_parse: + * @obj: the object + * @string: the string that will be used to parse the property value. + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Parses a string and writes the result into a property of an object. + */ +void object_property_parse(Object *obj, const char *string, + const char *name, struct Error **errp); + +/** + * object_property_print: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns a string representation of the value of the property. The + * caller shall free the string. + */ +char *object_property_print(Object *obj, const char *name, + struct Error **errp); + +/** * object_property_get_type: * @obj: the object * @name: the name of the property @@ -813,6 +837,10 @@ Object *object_resolve_path_type(const char *path, const char *typename, * * There is no way for a child to determine what its parent is. It is not * a bidirectional relationship. This is by design. + * + * The value of a child property as a C string will be the child object's + * canonical path. It can be retrieved using object_property_get_str(). + * The child object itself can be retrieved using object_property_get_link(). */ void object_property_add_child(Object *obj, const char *name, Object *child, struct Error **errp); @@ -823,13 +823,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d CharDriverState *s; if (strcmp(protocol, "spice") == 0) { + int fd = monitor_get_fd(mon, fdname); + int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); + int tls = qdict_get_try_bool(qdict, "tls", 0); if (!using_spice) { /* correct one? spice isn't a device ,,, */ qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); return -1; } - qerror_report(QERR_ADD_CLIENT_FAILED); - return -1; + if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { + close(fd); + } + return 0; #ifdef CONFIG_VNC } else if (strcmp(protocol, "vnc") == 0) { int fd = monitor_get_fd(mon, fdname); diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index ddef3eda12..a4e088c9fc 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -12,6 +12,7 @@ */ #include "qapi/qapi-visit-core.h" +#include "qapi/qapi-visit-impl.h" void visit_start_handle(Visitor *v, void **obj, const char *kind, const char *name, Error **errp) @@ -116,3 +117,53 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp) v->type_number(v, obj, name, errp); } } + +void output_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, + Error **errp) +{ + int i = 0; + int value = *obj; + char *enum_str; + + assert(strings); + while (strings[i++] != NULL); + if (value < 0 || value >= i - 1) { + error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); + return; + } + + enum_str = (char *)strings[value]; + visit_type_str(v, &enum_str, name, errp); +} + +void input_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, + Error **errp) +{ + int64_t value = 0; + char *enum_str; + + assert(strings); + + visit_type_str(v, &enum_str, name, errp); + if (error_is_set(errp)) { + return; + } + + while (strings[value] != NULL) { + if (strcmp(strings[value], enum_str) == 0) { + break; + } + value++; + } + + if (strings[value] == NULL) { + error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); + g_free(enum_str); + return; + } + + g_free(enum_str); + *obj = value; +} diff --git a/qapi/qapi-visit-impl.h b/qapi/qapi-visit-impl.h new file mode 100644 index 0000000000..0f3a1898fe --- /dev/null +++ b/qapi/qapi-visit-impl.h @@ -0,0 +1,23 @@ +/* + * Core Definitions for QAPI Visitor implementations + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Author: Paolo Bonizni <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +#ifndef QAPI_VISITOR_IMPL_H +#define QAPI_VISITOR_IMPL_H + +#include "qapi/qapi-types-core.h" +#include "qapi/qapi-visit-core.h" + +void input_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, Error **errp); +void output_type_enum(Visitor *v, int *obj, const char *strings[], + const char *kind, const char *name, Error **errp); + +#endif diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index c78022bb87..e6b6152e08 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -12,6 +12,7 @@ */ #include "qmp-input-visitor.h" +#include "qapi/qapi-visit-impl.h" #include "qemu-queue.h" #include "qemu-common.h" #include "qemu-objects.h" @@ -217,37 +218,6 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name, *obj = qfloat_get_double(qobject_to_qfloat(qobj)); } -static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[], - const char *kind, const char *name, - Error **errp) -{ - int64_t value = 0; - char *enum_str; - - assert(strings); - - qmp_input_type_str(v, &enum_str, name, errp); - if (error_is_set(errp)) { - return; - } - - while (strings[value] != NULL) { - if (strcmp(strings[value], enum_str) == 0) { - break; - } - value++; - } - - if (strings[value] == NULL) { - error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); - g_free(enum_str); - return; - } - - g_free(enum_str); - *obj = value; -} - static void qmp_input_start_optional(Visitor *v, bool *present, const char *name, Error **errp) { @@ -262,10 +232,6 @@ static void qmp_input_start_optional(Visitor *v, bool *present, *present = true; } -static void qmp_input_end_optional(Visitor *v, Error **errp) -{ -} - Visitor *qmp_input_get_visitor(QmpInputVisitor *v) { return &v->visitor; @@ -288,13 +254,12 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.start_list = qmp_input_start_list; v->visitor.next_list = qmp_input_next_list; v->visitor.end_list = qmp_input_end_list; - v->visitor.type_enum = qmp_input_type_enum; + v->visitor.type_enum = input_type_enum; v->visitor.type_int = qmp_input_type_int; v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; v->visitor.start_optional = qmp_input_start_optional; - v->visitor.end_optional = qmp_input_end_optional; v->obj = obj; qobject_incref(v->obj); diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index f76d0159cd..e0697b0d0f 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -12,6 +12,7 @@ */ #include "qmp-output-visitor.h" +#include "qapi/qapi-visit-impl.h" #include "qemu-queue.h" #include "qemu-common.h" #include "qemu-objects.h" @@ -180,25 +181,6 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name, qmp_output_add(qov, name, qfloat_from_double(*obj)); } -static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[], - const char *kind, const char *name, - Error **errp) -{ - int i = 0; - int value = *obj; - char *enum_str; - - assert(strings); - while (strings[i++] != NULL); - if (value < 0 || value >= i - 1) { - error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null"); - return; - } - - enum_str = (char *)strings[value]; - qmp_output_type_str(v, &enum_str, name, errp); -} - QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) { QObject *obj = qmp_output_first(qov); @@ -239,7 +221,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void) v->visitor.start_list = qmp_output_start_list; v->visitor.next_list = qmp_output_next_list; v->visitor.end_list = qmp_output_end_list; - v->visitor.type_enum = qmp_output_type_enum; + v->visitor.type_enum = output_type_enum; v->visitor.type_int = qmp_output_type_int; v->visitor.type_bool = qmp_output_type_bool; v->visitor.type_str = qmp_output_type_str; diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c new file mode 100644 index 0000000000..497eb9a60a --- /dev/null +++ b/qapi/string-input-visitor.c @@ -0,0 +1,138 @@ +/* + * String parsing visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "string-input-visitor.h" +#include "qapi/qapi-visit-impl.h" +#include "qerror.h" + +struct StringInputVisitor +{ + Visitor visitor; + const char *string; +}; + +static void parse_type_int(Visitor *v, int64_t *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + char *endp = (char *) siv->string; + long long val; + + errno = 0; + if (siv->string) { + val = strtoll(siv->string, &endp, 0); + } + if (!siv->string || errno || endp == siv->string || *endp) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "integer"); + return; + } + + *obj = val; +} + +static void parse_type_bool(Visitor *v, bool *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + if (siv->string) { + if (!strcasecmp(siv->string, "on") || + !strcasecmp(siv->string, "yes") || + !strcasecmp(siv->string, "true")) { + *obj = true; + return; + } + if (!strcasecmp(siv->string, "off") || + !strcasecmp(siv->string, "no") || + !strcasecmp(siv->string, "false")) { + *obj = false; + return; + } + } + + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "boolean"); +} + +static void parse_type_str(Visitor *v, char **obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + if (siv->string) { + *obj = g_strdup(siv->string); + } else { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "string"); + } +} + +static void parse_type_number(Visitor *v, double *obj, const char *name, + Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + char *endp = (char *) siv->string; + double val; + + errno = 0; + if (siv->string) { + val = strtod(siv->string, &endp); + } + if (!siv->string || errno || endp == siv->string || *endp) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "number"); + return; + } + + *obj = val; +} + +static void parse_start_optional(Visitor *v, bool *present, + const char *name, Error **errp) +{ + StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); + + if (!siv->string) { + *present = false; + return; + } + + *present = true; +} + +Visitor *string_input_get_visitor(StringInputVisitor *v) +{ + return &v->visitor; +} + +void string_input_visitor_cleanup(StringInputVisitor *v) +{ + g_free(v); +} + +StringInputVisitor *string_input_visitor_new(const char *str) +{ + StringInputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type_enum = input_type_enum; + v->visitor.type_int = parse_type_int; + v->visitor.type_bool = parse_type_bool; + v->visitor.type_str = parse_type_str; + v->visitor.type_number = parse_type_number; + v->visitor.start_optional = parse_start_optional; + + v->string = str; + return v; +} diff --git a/qapi/string-input-visitor.h b/qapi/string-input-visitor.h new file mode 100644 index 0000000000..d269d42cef --- /dev/null +++ b/qapi/string-input-visitor.h @@ -0,0 +1,25 @@ +/* + * String parsing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef STRING_INPUT_VISITOR_H +#define STRING_INPUT_VISITOR_H + +#include "qapi-visit-core.h" + +typedef struct StringInputVisitor StringInputVisitor; + +StringInputVisitor *string_input_visitor_new(const char *str); +void string_input_visitor_cleanup(StringInputVisitor *v); + +Visitor *string_input_get_visitor(StringInputVisitor *v); + +#endif diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c new file mode 100644 index 0000000000..92b0305212 --- /dev/null +++ b/qapi/string-output-visitor.c @@ -0,0 +1,89 @@ +/* + * String printing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "string-output-visitor.h" +#include "qapi/qapi-visit-impl.h" +#include "qerror.h" + +struct StringOutputVisitor +{ + Visitor visitor; + char *string; +}; + +static void string_output_set(StringOutputVisitor *sov, char *string) +{ + g_free(sov->string); + sov->string = string; +} + +static void print_type_int(Visitor *v, int64_t *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup_printf("%lld", (long long) *obj)); +} + +static void print_type_bool(Visitor *v, bool *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup(*obj ? "true" : "false")); +} + +static void print_type_str(Visitor *v, char **obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup(*obj ? *obj : "")); +} + +static void print_type_number(Visitor *v, double *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + string_output_set(sov, g_strdup_printf("%g", *obj)); +} + +char *string_output_get_string(StringOutputVisitor *sov) +{ + char *string = sov->string; + sov->string = NULL; + return string; +} + +Visitor *string_output_get_visitor(StringOutputVisitor *sov) +{ + return &sov->visitor; +} + +void string_output_visitor_cleanup(StringOutputVisitor *sov) +{ + g_free(sov->string); + g_free(sov); +} + +StringOutputVisitor *string_output_visitor_new(void) +{ + StringOutputVisitor *v; + + v = g_malloc0(sizeof(*v)); + + v->visitor.type_enum = output_type_enum; + v->visitor.type_int = print_type_int; + v->visitor.type_bool = print_type_bool; + v->visitor.type_str = print_type_str; + v->visitor.type_number = print_type_number; + + return v; +} diff --git a/qapi/string-output-visitor.h b/qapi/string-output-visitor.h new file mode 100644 index 0000000000..8868454110 --- /dev/null +++ b/qapi/string-output-visitor.h @@ -0,0 +1,26 @@ +/* + * String printing Visitor + * + * Copyright Red Hat, Inc. 2012 + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef STRING_OUTPUT_VISITOR_H +#define STRING_OUTPUT_VISITOR_H + +#include "qapi-visit-core.h" + +typedef struct StringOutputVisitor StringOutputVisitor; + +StringOutputVisitor *string_output_visitor_new(void); +void string_output_visitor_cleanup(StringOutputVisitor *v); + +char *string_output_get_string(StringOutputVisitor *v); +Visitor *string_output_get_visitor(StringOutputVisitor *v); + +#endif diff --git a/qemu-char.c b/qemu-char.c index b1d80dd24e..bb9e3f50a8 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -218,15 +218,13 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_null(QemuOpts *opts) { CharDriverState *chr; chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = null_chr_write; - - *_chr= chr; - return 0; + return chr; } /* MUX driver for serial I/O splitting */ @@ -636,21 +634,19 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) { int fd_out; TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"), O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); if (fd_out < 0) { - return -errno; + return NULL; } - - *_chr = qemu_chr_open_fd(-1, fd_out); - return 0; + return qemu_chr_open_fd(-1, fd_out); } -static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) { int fd_in, fd_out; char filename_in[256], filename_out[256]; @@ -658,7 +654,7 @@ static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr) if (filename == NULL) { fprintf(stderr, "chardev: pipe: no filename given\n"); - return -EINVAL; + return NULL; } snprintf(filename_in, 256, "%s.in", filename); @@ -672,12 +668,10 @@ static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr) close(fd_out); TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY)); if (fd_in < 0) { - return -errno; + return NULL; } } - - *_chr = qemu_chr_open_fd(fd_in, fd_out); - return 0; + return qemu_chr_open_fd(fd_in, fd_out); } @@ -768,14 +762,13 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr) fd_chr_close(chr); } -static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) { CharDriverState *chr; if (stdio_nb_clients >= STDIO_MAX_CLIENTS) { - return -EBUSY; + return NULL; } - if (stdio_nb_clients == 0) { old_fd0_flags = fcntl(0, F_GETFL); tcgetattr (0, &oldtty); @@ -792,8 +785,7 @@ static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr) display_type != DT_NOGRAPHIC); qemu_chr_fe_set_echo(chr, false); - *_chr = chr; - return 0; + return chr; } #ifdef __sun__ @@ -980,7 +972,7 @@ static void pty_chr_close(struct CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) { CharDriverState *chr; PtyCharDriver *s; @@ -995,7 +987,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr) #endif if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) { - return -errno; + return NULL; } /* Set raw attributes on the pty. */ @@ -1021,8 +1013,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr) s->fd = master_fd; s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr); - *_chr = chr; - return 0; + return chr; } static void tty_serial_init(int fd, int speed, @@ -1223,7 +1214,7 @@ static void qemu_chr_close_tty(CharDriverState *chr) } } -static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; @@ -1231,20 +1222,18 @@ static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr) TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); if (fd < 0) { - return -errno; + return NULL; } tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; - - *_chr = chr; - return 0; + return chr; } #else /* ! __linux__ && ! __sun__ */ -static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) { - return -ENOTSUP; + return NULL; } #endif /* __linux__ || __sun__ */ @@ -1358,21 +1347,21 @@ static void pp_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; ParallelCharDriver *drv; int fd; - TFR(fd = open(filename, O_RDWR)); + TFR(fd = qemu_open(filename, O_RDWR)); if (fd < 0) { - return -errno; + return NULL; } if (ioctl(fd, PPCLAIM) < 0) { close(fd); - return -errno; + return NULL; } drv = g_malloc0(sizeof(ParallelCharDriver)); @@ -1387,8 +1376,7 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) qemu_chr_generic_open(chr); - *_chr = chr; - return 0; + return chr; } #endif /* __linux__ */ @@ -1430,7 +1418,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; @@ -1438,16 +1426,14 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) fd = qemu_open(filename, O_RDWR); if (fd < 0) { - return -errno; + return NULL; } chr = g_malloc0(sizeof(CharDriverState)); chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; - - *_chr = chr; - return 0; + return chr; } #endif @@ -1663,7 +1649,7 @@ static int win_chr_poll(void *opaque) return 0; } -static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_win(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; @@ -1678,12 +1664,10 @@ static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr) if (win_chr_init(chr, filename) < 0) { g_free(s); g_free(chr); - return -EIO; + return NULL; } qemu_chr_generic_open(chr); - - *_chr = chr; - return 0; + return chr; } static int win_chr_pipe_poll(void *opaque) @@ -1765,7 +1749,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) } -static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; @@ -1780,15 +1764,13 @@ static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr) if (win_chr_pipe_init(chr, filename) < 0) { g_free(s); g_free(chr); - return -EIO; + return NULL; } qemu_chr_generic_open(chr); - - *_chr = chr; - return 0; + return chr; } -static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr) +static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) { CharDriverState *chr; WinCharState *s; @@ -1799,16 +1781,15 @@ static int qemu_chr_open_win_file(HANDLE fd_out, CharDriverState **pchr) chr->opaque = s; chr->chr_write = win_chr_write; qemu_chr_generic_open(chr); - *pchr = chr; - return 0; + return chr; } -static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **chr) +static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts) { - return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr); + return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } -static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) { const char *file_out = qemu_opt_get(opts, "path"); HANDLE fd_out; @@ -1816,10 +1797,10 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr) fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_out == INVALID_HANDLE_VALUE) { - return -EIO; + return NULL; } - return qemu_chr_open_win_file(fd_out, _chr); + return qemu_chr_open_win_file(fd_out); } static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) @@ -1960,7 +1941,7 @@ static void win_stdio_close(CharDriverState *chr) stdio_nb_clients--; } -static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) { CharDriverState *chr; WinStdioCharState *stdio; @@ -1969,7 +1950,7 @@ static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) if (stdio_nb_clients >= STDIO_MAX_CLIENTS || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { - return -EIO; + return NULL; } chr = g_malloc0(sizeof(CharDriverState)); @@ -2028,9 +2009,7 @@ static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) chr->chr_set_echo = qemu_chr_set_echo_win_stdio; qemu_chr_fe_set_echo(chr, false); - *_chr = chr; - - return 0; + return chr; } #endif /* !_WIN32 */ @@ -2111,12 +2090,11 @@ static void udp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; int fd = -1; - int ret; chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(NetCharDriver)); @@ -2124,7 +2102,6 @@ static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr) fd = inet_dgram_opts(opts); if (fd < 0) { fprintf(stderr, "inet_dgram_opts failed\n"); - ret = -errno; goto return_err; } @@ -2135,9 +2112,7 @@ static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr) chr->chr_write = udp_chr_write; chr->chr_update_read_handler = udp_chr_update_read_handler; chr->chr_close = udp_chr_close; - - *_chr = chr; - return 0; + return chr; return_err: g_free(chr); @@ -2145,7 +2120,7 @@ return_err: if (fd >= 0) { closesocket(fd); } - return ret; + return NULL; } /***********************************************************/ @@ -2436,7 +2411,7 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) +static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; @@ -2446,7 +2421,6 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) int do_nodelay; int is_unix; int is_telnet; - int ret; is_listen = qemu_opt_get_bool(opts, "server", 0); is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); @@ -2473,7 +2447,6 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) } } if (fd < 0) { - ret = -errno; goto fail; } @@ -2528,16 +2501,14 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) tcp_chr_accept(chr); socket_set_nonblock(s->listen_fd); } - - *_chr = chr; - return 0; + return chr; fail: if (fd >= 0) closesocket(fd); g_free(s); g_free(chr); - return ret; + return NULL; } /***********************************************************/ @@ -2730,7 +2701,7 @@ fail: static const struct { const char *name; - int (*open)(QemuOpts *opts, CharDriverState **chr); + CharDriverState *(*open)(QemuOpts *opts); } backend_table[] = { { .name = "null", .open = qemu_chr_open_null }, { .name = "socket", .open = qemu_chr_open_socket }, @@ -2771,7 +2742,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, { CharDriverState *chr; int i; - int ret; if (qemu_opts_id(opts) == NULL) { fprintf(stderr, "chardev: no id specified\n"); @@ -2793,10 +2763,10 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, return NULL; } - ret = backend_table[i].open(opts, &chr); - if (ret < 0) { - fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n", - qemu_opt_get(opts, "backend"), strerror(-ret)); + chr = backend_table[i].open(opts); + if (!chr) { + fprintf(stderr, "chardev: opening backend \"%s\" failed\n", + qemu_opt_get(opts, "backend")); return NULL; } diff --git a/qemu-config.c b/qemu-config.c index c9763e0b93..7d9da787c7 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -566,6 +566,18 @@ static QemuOptsList qemu_machine_opts = { .name = "kvm_shadow_mem", .type = QEMU_OPT_SIZE, .help = "KVM shadow MMU size", + }, { + .name = "kernel", + .type = QEMU_OPT_STRING, + .help = "Linux kernel image file", + }, { + .name = "initrd", + .type = QEMU_OPT_STRING, + .help = "Linux initial ramdisk file", + }, { + .name = "append", + .type = QEMU_OPT_STRING, + .help = "Linux kernel command line", }, { /* End of list */ } }, diff --git a/qemu-sockets.c b/qemu-sockets.c index 61b2247077..6bcb8e3e0f 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -26,7 +26,6 @@ # define AI_ADDRCONFIG 0 #endif -static int sockets_debug = 0; static const int on=1, off=0; /* used temporarely until all users are converted to QemuOpts */ @@ -101,21 +100,6 @@ const char *inet_strfamily(int family) return "unknown"; } -static void inet_print_addrinfo(const char *tag, struct addrinfo *res) -{ - struct addrinfo *e; - char uaddr[INET6_ADDRSTRLEN+1]; - char uport[33]; - - for (e = res; e != NULL; e = e->ai_next) { - getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, - uaddr,INET6_ADDRSTRLEN,uport,32, - NI_NUMERICHOST | NI_NUMERICSERV); - fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", - tag, inet_strfamily(e->ai_family), uaddr, uport); - } -} - int inet_listen_opts(QemuOpts *opts, int port_offset) { struct addrinfo ai,*res,*e; @@ -123,7 +107,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset) char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; - int slisten,rc,to,try_next; + int slisten, rc, to, port_min, port_max, p; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; @@ -153,8 +137,6 @@ int inet_listen_opts(QemuOpts *opts, int port_offset) gai_strerror(rc)); return -1; } - if (sockets_debug) - inet_print_addrinfo(__FUNCTION__, res); /* create socket + bind */ for (e = res; e != NULL; e = e->ai_next) { @@ -177,23 +159,18 @@ int inet_listen_opts(QemuOpts *opts, int port_offset) } #endif - for (;;) { + port_min = inet_getport(e); + port_max = to ? to + port_offset : port_min; + for (p = port_min; p <= port_max; p++) { + inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { - if (sockets_debug) - fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, - inet_strfamily(e->ai_family), uaddr, inet_getport(e)); goto listen; } - try_next = to && (inet_getport(e) <= to + port_offset); - if (!try_next || sockets_debug) + if (p == port_max) { fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), uaddr, inet_getport(e), strerror(errno)); - if (try_next) { - inet_setport(e, inet_getport(e) + 1); - continue; } - break; } closesocket(slisten); } @@ -249,8 +226,6 @@ int inet_connect_opts(QemuOpts *opts) gai_strerror(rc)); return -1; } - if (sockets_debug) - inet_print_addrinfo(__FUNCTION__, res); for (e = res; e != NULL; e = e->ai_next) { if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, @@ -269,17 +244,13 @@ int inet_connect_opts(QemuOpts *opts) /* connect to peer */ if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { - if (sockets_debug || NULL == e->ai_next) + if (NULL == e->ai_next) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), e->ai_canonname, uaddr, uport, strerror(errno)); closesocket(sock); continue; } - if (sockets_debug) - fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, - inet_strfamily(e->ai_family), - e->ai_canonname, uaddr, uport); freeaddrinfo(res); return sock; } @@ -322,10 +293,6 @@ int inet_dgram_opts(QemuOpts *opts) gai_strerror(rc)); return -1; } - if (sockets_debug) { - fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port); - inet_print_addrinfo(__FUNCTION__, peer); - } /* lookup local addr */ memset(&ai,0, sizeof(ai)); @@ -346,10 +313,6 @@ int inet_dgram_opts(QemuOpts *opts) gai_strerror(rc)); return -1; } - if (sockets_debug) { - fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port); - inet_print_addrinfo(__FUNCTION__, local); - } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); @@ -541,8 +504,6 @@ int unix_listen_opts(QemuOpts *opts) goto err; } - if (sockets_debug) - fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); return sock; err: @@ -576,8 +537,6 @@ int unix_connect_opts(QemuOpts *opts) return -1; } - if (sockets_debug) - fprintf(stderr, "connect(unix:%s): OK\n", path); return sock; } diff --git a/qmp-commands.hx b/qmp-commands.hx index b5e2ab8574..dee95f1d67 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -910,8 +910,8 @@ EQMP { .name = "add_client", - .args_type = "protocol:s,fdname:s,skipauth:b?", - .params = "protocol fdname skipauth", + .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", + .params = "protocol fdname skipauth tls", .help = "add a graphics client", .user_print = monitor_user_noop, .mhandler.cmd_new = add_graphics_client, @@ -927,6 +927,8 @@ Arguments: - "protocol": protocol name (json-string) - "fdname": file descriptor name (json-string) +- "skipauth": whether to skip authentication (json-bool, optional) +- "tls": whether to perform TLS (json-bool, optional) Example: diff --git a/qom/object.c b/qom/object.c index 0cbd9bb004..aa037d299f 100644 --- a/qom/object.c +++ b/qom/object.c @@ -13,6 +13,8 @@ #include "qemu/object.h" #include "qemu-common.h" #include "qapi/qapi-visit-core.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" /* TODO: replace QObject with a simpler visitor to avoid a dependency * of the QOM core on QObject? */ @@ -262,7 +264,7 @@ void object_initialize_with_type(void *data, TypeImpl *type) Object *obj = data; g_assert(type != NULL); - g_assert(type->instance_size >= sizeof(ObjectClass)); + g_assert(type->instance_size >= sizeof(Object)); type_class_init(type); g_assert(type->abstract == false); @@ -782,6 +784,29 @@ int64_t object_property_get_int(Object *obj, const char *name, return retval; } +void object_property_parse(Object *obj, const char *string, + const char *name, Error **errp) +{ + StringInputVisitor *mi; + mi = string_input_visitor_new(string); + object_property_set(obj, string_input_get_visitor(mi), name, errp); + + string_input_visitor_cleanup(mi); +} + +char *object_property_print(Object *obj, const char *name, + Error **errp) +{ + StringOutputVisitor *mo; + char *string; + + mo = string_output_visitor_new(); + object_property_get(obj, string_output_get_visitor(mo), name, NULL); + string = string_output_get_string(mo); + string_output_visitor_cleanup(mo); + return string; +} + const char *object_property_get_type(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = object_property_find(obj, name); @@ -867,6 +892,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { Object **child = opaque; + Object *old_target; bool ambiguous = false; const char *type; char *path; @@ -876,10 +902,8 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, visit_type_str(v, &path, name, errp); - if (*child) { - object_unref(*child); - *child = NULL; - } + old_target = *child; + *child = NULL; if (strcmp(path, "") != 0) { Object *target; @@ -905,6 +929,10 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, } g_free(path); + + if (old_target != NULL) { + object_unref(old_target); + } } void object_property_add_link(Object *obj, const char *name, diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 7e8eaa9fd8..1e735ffd09 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -188,7 +188,7 @@ static void print_allowed_subtypes(void) fprintf(stderr, "\n"); } -int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) +CharDriverState *qemu_chr_open_spice(QemuOpts *opts) { CharDriverState *chr; SpiceCharDriver *s; @@ -200,7 +200,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) if (name == NULL) { fprintf(stderr, "spice-qemu-char: missing name parameter\n"); print_allowed_subtypes(); - return -EINVAL; + return NULL; } for(;*psubtype != NULL; ++psubtype) { if (strcmp(name, *psubtype) == 0) { @@ -211,7 +211,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) if (subtype == NULL) { fprintf(stderr, "spice-qemu-char: unsupported name\n"); print_allowed_subtypes(); - return -EINVAL; + return NULL; } chr = g_malloc0(sizeof(CharDriverState)); @@ -233,6 +233,5 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) } #endif - *_chr = chr; - return 0; + return chr; } diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf index 43ad282b5c..d0503804c2 100644 --- a/sysconfigs/target/target-x86_64.conf +++ b/sysconfigs/target/target-x86_64.conf @@ -7,9 +7,9 @@ family = "6" model = "2" stepping = "3" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" - feature_ecx = "sse3 ssse3" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "ssse3 sse3" + extfeature_edx = "i64 xd syscall" extfeature_ecx = "lahf_lm" xlevel = "0x8000000A" model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)" @@ -21,9 +21,9 @@ family = "6" model = "2" stepping = "3" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" - feature_ecx = "sse3 cx16 ssse3 sse4.1" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "sse4.1 cx16 ssse3 sse3" + extfeature_edx = "i64 xd syscall" extfeature_ecx = "lahf_lm" xlevel = "0x8000000A" model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)" @@ -35,24 +35,38 @@ family = "6" model = "2" stepping = "3" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" - feature_ecx = "sse3 cx16 ssse3 sse4.1 sse4.2 popcnt" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "popcnt sse4.2 sse4.1 cx16 ssse3 sse3" + extfeature_edx = "i64 syscall xd" extfeature_ecx = "lahf_lm" xlevel = "0x8000000A" model_id = "Intel Core i7 9xx (Nehalem Class Core i7)" [cpudef] + name = "Westmere" + level = "11" + vendor = "GenuineIntel" + family = "6" + model = "44" + stepping = "1" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "aes popcnt sse4.2 sse4.1 cx16 ssse3 sse3" + extfeature_edx = "i64 syscall xd" + extfeature_ecx = "lahf_lm" + xlevel = "0x8000000A" + model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)" + +[cpudef] name = "Opteron_G1" level = "5" vendor = "AuthenticAMD" family = "15" model = "6" stepping = "1" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" feature_ecx = "sse3" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx" -# extfeature_ecx = "" + extfeature_edx = "lm fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu" + extfeature_ecx = " " xlevel = "0x80000008" model_id = "AMD Opteron 240 (Gen 1 Class Opteron)" @@ -63,9 +77,9 @@ family = "15" model = "6" stepping = "1" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" - feature_ecx = "sse3 cx16" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "cx16 sse3" + extfeature_edx = "lm rdtscp fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu" extfeature_ecx = "svm lahf_lm" xlevel = "0x80000008" model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)" @@ -77,10 +91,10 @@ family = "15" model = "6" stepping = "1" - feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36" - feature_ecx = "sse3 cx16 monitor popcnt" - extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp" - extfeature_ecx = "svm sse4a abm misalignsse lahf_lm" + feature_edx = "sse2 sse fxsr mmx clflush pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de fpu" + feature_ecx = "popcnt cx16 monitor sse3" + extfeature_edx = "lm rdtscp fxsr mmx nx pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de fpu" + extfeature_ecx = "misalignsse sse4a abm svm lahf_lm" xlevel = "0x80000008" model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)" diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index b9bfeaff70..c2edb646fe 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -44,7 +44,7 @@ static const char *feature_name[] = { "ht" /* Intel htt */, "tm", "ia64", "pbe", }; static const char *ext_feature_name[] = { - "pni|sse3" /* Intel,AMD sse3 */, "pclmuldq", "dtes64", "monitor", + "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor", "ds_cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, "fma", "cx16", "xtpr", "pdcm", @@ -59,9 +59,9 @@ static const char *ext2_feature_name[] = { "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mtrr", "pge", "mca", "cmov", "pat", "pse36", NULL, NULL /* Linux mp */, - "nx" /* Intel xd */, NULL, "mmxext", "mmx", - "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", - NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow", + "nx|xd", NULL, "mmxext", "mmx", + "fxsr", "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp", + NULL, "lm|i64", "3dnowext", "3dnow", }; static const char *ext3_feature_name[] = { "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, @@ -597,6 +597,46 @@ static int check_features_against_host(x86_def_t *guest_def) return rv; } +static void x86_cpuid_version_set_family(CPUX86State *env, int family) +{ + env->cpuid_version &= ~0xff00f00; + if (family > 0x0f) { + env->cpuid_version |= 0xf00 | ((family - 0x0f) << 20); + } else { + env->cpuid_version |= family << 8; + } +} + +static void x86_cpuid_version_set_model(CPUX86State *env, int model) +{ + env->cpuid_version &= ~0xf00f0; + env->cpuid_version |= ((model & 0xf) << 4) | ((model >> 4) << 16); +} + +static void x86_cpuid_version_set_stepping(CPUX86State *env, int stepping) +{ + env->cpuid_version &= ~0xf; + env->cpuid_version |= stepping & 0xf; +} + +static void x86_cpuid_set_model_id(CPUX86State *env, const char *model_id) +{ + int c, len, i; + + if (model_id == NULL) { + model_id = ""; + } + len = strlen(model_id); + for (i = 0; i < 48; i++) { + if (i >= len) { + c = '\0'; + } else { + c = (uint8_t)model_id[i]; + } + env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); + } +} + static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) { unsigned int i; @@ -883,12 +923,9 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) } env->cpuid_vendor_override = def->vendor_override; env->cpuid_level = def->level; - if (def->family > 0x0f) - env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20); - else - env->cpuid_version = def->family << 8; - env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16); - env->cpuid_version |= def->stepping; + x86_cpuid_version_set_family(env, def->family); + x86_cpuid_version_set_model(env, def->model); + x86_cpuid_version_set_stepping(env, def->stepping); env->cpuid_features = def->features; env->cpuid_ext_features = def->ext_features; env->cpuid_ext2_features = def->ext2_features; @@ -910,20 +947,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) env->cpuid_ext3_features &= TCG_EXT3_FEATURES; env->cpuid_svm_features &= TCG_SVM_FEATURES; } - { - const char *model_id = def->model_id; - int c, len, i; - if (!model_id) - model_id = ""; - len = strlen(model_id); - for(i = 0; i < 48; i++) { - if (i >= len) - c = '\0'; - else - c = (uint8_t)model_id[i]; - env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); - } - } + x86_cpuid_set_model_id(env, def->model_id); return 0; } diff --git a/test-string-input-visitor.c b/test-string-input-visitor.c new file mode 100644 index 0000000000..5370e32041 --- /dev/null +++ b/test-string-input-visitor.c @@ -0,0 +1,195 @@ +/* + * String Input Visitor unit-tests. + * + * Copyright (C) 2012 Red Hat Inc. + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-input-visitor) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <stdarg.h> + +#include "qapi/string-input-visitor.h" +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" + +typedef struct TestInputVisitorData { + StringInputVisitor *siv; +} TestInputVisitorData; + +static void visitor_input_teardown(TestInputVisitorData *data, + const void *unused) +{ + if (data->siv) { + string_input_visitor_cleanup(data->siv); + data->siv = NULL; + } +} + +/* This is provided instead of a test setup function so that the JSON + string used by the tests are kept in the test functions (and not + int main()) */ +static +Visitor *visitor_input_test_init(TestInputVisitorData *data, + const char *string) +{ + Visitor *v; + + data->siv = string_input_visitor_new(string); + g_assert(data->siv != NULL); + + v = string_input_get_visitor(data->siv); + g_assert(v != NULL); + + return v; +} + +static void test_visitor_in_int(TestInputVisitorData *data, + const void *unused) +{ + int64_t res = 0, value = -42; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, "-42"); + + visit_type_int(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, value); +} + +static void test_visitor_in_bool(TestInputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + bool res = false; + Visitor *v; + + v = visitor_input_test_init(data, "true"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "yes"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "on"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, true); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "false"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "no"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); + visitor_input_teardown(data, unused); + + v = visitor_input_test_init(data, "off"); + + visit_type_bool(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(res, ==, false); +} + +static void test_visitor_in_number(TestInputVisitorData *data, + const void *unused) +{ + double res = 0, value = 3.14; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, "3.14"); + + visit_type_number(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpfloat(res, ==, value); +} + +static void test_visitor_in_string(TestInputVisitorData *data, + const void *unused) +{ + char *res = NULL, *value = (char *) "Q E M U"; + Error *errp = NULL; + Visitor *v; + + v = visitor_input_test_init(data, value); + + visit_type_str(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpstr(res, ==, value); + + g_free(res); +} + +static void test_visitor_in_enum(TestInputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + Visitor *v; + EnumOne i; + + for (i = 0; EnumOne_lookup[i]; i++) { + EnumOne res = -1; + + v = visitor_input_test_init(data, EnumOne_lookup[i]); + + visit_type_EnumOne(v, &res, NULL, &errp); + g_assert(!error_is_set(&errp)); + g_assert_cmpint(i, ==, res); + + visitor_input_teardown(data, NULL); + } + + data->siv = NULL; +} + +static void input_visitor_test_add(const char *testpath, + TestInputVisitorData *data, + void (*test_func)(TestInputVisitorData *data, const void *user_data)) +{ + g_test_add(testpath, TestInputVisitorData, data, NULL, test_func, + visitor_input_teardown); +} + +int main(int argc, char **argv) +{ + TestInputVisitorData in_visitor_data; + + g_test_init(&argc, &argv, NULL); + + input_visitor_test_add("/string-visitor/input/int", + &in_visitor_data, test_visitor_in_int); + input_visitor_test_add("/string-visitor/input/bool", + &in_visitor_data, test_visitor_in_bool); + input_visitor_test_add("/string-visitor/input/number", + &in_visitor_data, test_visitor_in_number); + input_visitor_test_add("/string-visitor/input/string", + &in_visitor_data, test_visitor_in_string); + input_visitor_test_add("/string-visitor/input/enum", + &in_visitor_data, test_visitor_in_enum); + + g_test_run(); + + return 0; +} diff --git a/test-string-output-visitor.c b/test-string-output-visitor.c new file mode 100644 index 0000000000..22909b84ef --- /dev/null +++ b/test-string-output-visitor.c @@ -0,0 +1,188 @@ +/* + * String Output Visitor unit-tests. + * + * Copyright (C) 2012 Red Hat Inc. + * + * Authors: + * Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-visitor) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> + +#include "qapi/string-output-visitor.h" +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" + +typedef struct TestOutputVisitorData { + StringOutputVisitor *sov; + Visitor *ov; +} TestOutputVisitorData; + +static void visitor_output_setup(TestOutputVisitorData *data, + const void *unused) +{ + data->sov = string_output_visitor_new(); + g_assert(data->sov != NULL); + + data->ov = string_output_get_visitor(data->sov); + g_assert(data->ov != NULL); +} + +static void visitor_output_teardown(TestOutputVisitorData *data, + const void *unused) +{ + string_output_visitor_cleanup(data->sov); + data->sov = NULL; + data->ov = NULL; +} + +static void test_visitor_out_int(TestOutputVisitorData *data, + const void *unused) +{ + int64_t value = -42; + Error *errp = NULL; + char *str; + + visit_type_int(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "-42"); + g_free(str); +} + +static void test_visitor_out_bool(TestOutputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + bool value = true; + char *str; + + visit_type_bool(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "true"); + g_free(str); +} + +static void test_visitor_out_number(TestOutputVisitorData *data, + const void *unused) +{ + double value = 3.14; + Error *errp = NULL; + char *str; + + visit_type_number(data->ov, &value, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "3.14"); + g_free(str); +} + +static void test_visitor_out_string(TestOutputVisitorData *data, + const void *unused) +{ + char *string = (char *) "Q E M U"; + Error *errp = NULL; + char *str; + + visit_type_str(data->ov, &string, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, string); + g_free(str); +} + +static void test_visitor_out_no_string(TestOutputVisitorData *data, + const void *unused) +{ + char *string = NULL; + Error *errp = NULL; + char *str; + + /* A null string should return "" */ + visit_type_str(data->ov, &string, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, ""); + g_free(str); +} + +static void test_visitor_out_enum(TestOutputVisitorData *data, + const void *unused) +{ + Error *errp = NULL; + char *str; + EnumOne i; + + for (i = 0; i < ENUM_ONE_MAX; i++) { + visit_type_EnumOne(data->ov, &i, "unused", &errp); + g_assert(!error_is_set(&errp)); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, EnumOne_lookup[i]); + g_free(str); + } +} + +static void test_visitor_out_enum_errors(TestOutputVisitorData *data, + const void *unused) +{ + EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; + Error *errp; + + for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { + errp = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); + g_assert(error_is_set(&errp) == true); + error_free(errp); + } +} + +static void output_visitor_test_add(const char *testpath, + TestOutputVisitorData *data, + void (*test_func)(TestOutputVisitorData *data, const void *user_data)) +{ + g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, + test_func, visitor_output_teardown); +} + +int main(int argc, char **argv) +{ + TestOutputVisitorData out_visitor_data; + + g_test_init(&argc, &argv, NULL); + + output_visitor_test_add("/string-visitor/output/int", + &out_visitor_data, test_visitor_out_int); + output_visitor_test_add("/string-visitor/output/bool", + &out_visitor_data, test_visitor_out_bool); + output_visitor_test_add("/string-visitor/output/number", + &out_visitor_data, test_visitor_out_number); + output_visitor_test_add("/string-visitor/output/string", + &out_visitor_data, test_visitor_out_string); + output_visitor_test_add("/string-visitor/output/no-string", + &out_visitor_data, test_visitor_out_no_string); + output_visitor_test_add("/string-visitor/output/enum", + &out_visitor_data, test_visitor_out_enum); + output_visitor_test_add("/string-visitor/output/enum-errors", + &out_visitor_data, test_visitor_out_enum_errors); + + g_test_run(); + + return 0; +} diff --git a/tests/Makefile b/tests/Makefile index 55e8eb0ad5..74b29dc076 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor -CHECKS += test-coroutine +CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS) @@ -12,7 +12,9 @@ check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y) check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y) test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y) -test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) +test-qmp-input-visitor.o test-qmp-output-visitor.o \ +test-string-input-visitor.o test-string-output-visitor.o \ + test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) $(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py @@ -25,6 +27,12 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") +test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) +test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o + +test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) +test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o + test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o diff --git a/trace-events b/trace-events index 9b26ce2304..e918ff61fd 100644 --- a/trace-events +++ b/trace-events @@ -141,6 +141,10 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x" ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x" ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x" +# hw/jazz-led.c +jazz_led_read(uint64_t addr, uint8_t val) "read addr=0x%"PRIx64": 0x%x" +jazz_led_write(uint64_t addr, uint8_t new) "write addr=0x%"PRIx64": 0x%x" + # hw/lance.c lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x" lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x" diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index c35b29c1f6..3299da87d6 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -33,6 +33,7 @@ void qemu_spice_init(void); void qemu_spice_input_init(void); void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); +int qemu_spice_display_add_client(int csock, int skipauth, int tls); int qemu_spice_add_interface(SpiceBaseInstance *sin); int qemu_spice_set_passwd(const char *passwd, bool fail_if_connected, bool disconnect_if_connected); @@ -44,7 +45,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); -int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr); +CharDriverState *qemu_chr_open_spice(QemuOpts *opts); #else /* CONFIG_SPICE */ #include "monitor.h" @@ -68,6 +69,12 @@ static inline int qemu_spice_migrate_info(const char *h, int p, int t, return -1; } +static inline int qemu_spice_display_add_client(int csock, int skipauth, + int tls) +{ + return -1; +} + #endif /* CONFIG_SPICE */ #endif /* QEMU_SPICE_H */ diff --git a/ui/spice-core.c b/ui/spice-core.c index b4629f895b..1308a3d886 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -220,10 +220,23 @@ static void channel_event(int event, SpiceChannelEventInfo *info) } client = qdict_new(); - add_addr_info(client, &info->paddr, info->plen); - server = qdict_new(); - add_addr_info(server, &info->laddr, info->llen); + +#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT + if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { + add_addr_info(client, (struct sockaddr *)&info->paddr_ext, + info->plen_ext); + add_addr_info(server, (struct sockaddr *)&info->laddr_ext, + info->llen_ext); + } else { + fprintf(stderr, "spice: %s, extended address is expected\n", + __func__); +#endif + add_addr_info(client, &info->paddr, info->plen); + add_addr_info(server, &info->laddr, info->llen); +#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT + } +#endif if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { qdict_put(server, "auth", qstring_from_str(auth)); @@ -376,16 +389,30 @@ static SpiceChannelList *qmp_query_spice_channels(void) QTAILQ_FOREACH(item, &channel_list, link) { SpiceChannelList *chan; char host[NI_MAXHOST], port[NI_MAXSERV]; + struct sockaddr *paddr; + socklen_t plen; chan = g_malloc0(sizeof(*chan)); chan->value = g_malloc0(sizeof(*chan->value)); - getnameinfo(&item->info->paddr, item->info->plen, +#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT + if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { + paddr = (struct sockaddr *)&item->info->paddr_ext; + plen = item->info->plen_ext; + } else { +#endif + paddr = &item->info->paddr; + plen = item->info->plen; +#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT + } +#endif + + getnameinfo(paddr, plen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); chan->value->host = g_strdup(host); chan->value->port = g_strdup(port); - chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); + chan->value->family = g_strdup(inet_strfamily(paddr->sa_family)); chan->value->connection_id = item->info->connection_id; chan->value->channel_type = item->info->type; @@ -747,6 +774,19 @@ int qemu_spice_set_pw_expire(time_t expires) return qemu_spice_set_ticket(false, false); } +int qemu_spice_display_add_client(int csock, int skipauth, int tls) +{ +#if SPICE_SERVER_VERSION >= 0x000a01 + if (tls) { + return spice_server_add_ssl_client(spice_server, csock, skipauth); + } else { + return spice_server_add_client(spice_server, csock, skipauth); + } +#else + return -1; +#endif +} + static void spice_register_config(void) { qemu_add_opts(&qemu_spice_opts); @@ -1187,7 +1187,7 @@ static QEMUMachine *find_machine(const char *name) return NULL; } -static QEMUMachine *find_default_machine(void) +QEMUMachine *find_default_machine(void) { QEMUMachine *m; @@ -1857,8 +1857,10 @@ struct device_config { DEV_PARALLEL, /* -parallel */ DEV_VIRTCON, /* -virtioconsole */ DEV_DEBUGCON, /* -debugcon */ + DEV_GDB, /* -gdb, -s */ } type; const char *cmdline; + Location loc; QTAILQ_ENTRY(device_config) next; }; QTAILQ_HEAD(, device_config) device_configs = QTAILQ_HEAD_INITIALIZER(device_configs); @@ -1870,6 +1872,7 @@ static void add_device_config(int type, const char *cmdline) conf = g_malloc0(sizeof(*conf)); conf->type = type; conf->cmdline = cmdline; + loc_save(&conf->loc); QTAILQ_INSERT_TAIL(&device_configs, conf, next); } @@ -1881,7 +1884,9 @@ static int foreach_device_config(int type, int (*func)(const char *cmdline)) QTAILQ_FOREACH(conf, &device_configs, next) { if (conf->type != type) continue; + loc_push_restore(&conf->loc); rc = func(conf->cmdline); + loc_pop(&conf->loc); if (0 != rc) return rc; } @@ -2178,7 +2183,6 @@ int qemu_init_main_loop(void) int main(int argc, char **argv, char **envp) { - const char *gdbstub_dev = NULL; int i; int snapshot, linux_boot; const char *icount_option = NULL; @@ -2238,11 +2242,8 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_MACHINE); machine = find_default_machine(); cpu_model = NULL; - initrd_filename = NULL; ram_size = 0; snapshot = 0; - kernel_filename = NULL; - kernel_cmdline = ""; cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; @@ -2318,9 +2319,6 @@ int main(int argc, char **argv, char **envp) cpu_model = optarg; } break; - case QEMU_OPTION_initrd: - initrd_filename = optarg; - break; case QEMU_OPTION_hda: { char buf[256]; @@ -2451,10 +2449,13 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_kernel: - kernel_filename = optarg; + qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg); + break; + case QEMU_OPTION_initrd: + qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg); break; case QEMU_OPTION_append: - kernel_cmdline = optarg; + qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg); break; case QEMU_OPTION_cdrom: drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); @@ -2606,10 +2607,10 @@ int main(int argc, char **argv, char **envp) log_file = optarg; break; case QEMU_OPTION_s: - gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT; + add_device_config(DEV_GDB, "tcp::" DEFAULT_GDBSTUB_PORT); break; case QEMU_OPTION_gdb: - gdbstub_dev = optarg; + add_device_config(DEV_GDB, optarg); break; case QEMU_OPTION_L: data_dir = optarg; @@ -3249,6 +3250,17 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "qemu_init_main_loop failed\n"); exit(1); } + + kernel_filename = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"), + 0), "kernel"); + initrd_filename = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"), + 0), "initrd"); + kernel_cmdline = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"), + 0), "append"); + if (!kernel_cmdline) { + kernel_cmdline = ""; + } + linux_boot = (kernel_filename != NULL); if (!linux_boot && *kernel_cmdline != '\0') { @@ -3488,9 +3500,7 @@ int main(int argc, char **argv, char **envp) } text_consoles_set_display(ds); - if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { - fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", - gdbstub_dev); + if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } |