diff options
95 files changed, 2636 insertions, 544 deletions
@@ -109,8 +109,8 @@ endif -include $(SUBDIR_DEVICES_MAK_DEP) %/config-devices.mak: default-configs/%.mak - $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, " GEN $@") - @if test -f $@; then \ + $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@.tmp $<, " GEN $@.tmp") + $(call quiet-command, if test -f $@; then \ if cmp -s $@.old $@; then \ mv $@.tmp $@; \ cp -p $@ $@.old; \ @@ -126,7 +126,7 @@ endif else \ mv $@.tmp $@; \ cp -p $@ $@.old; \ - fi + fi, " GEN $@"); defconfig: rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK) @@ -197,9 +197,9 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) -$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo +$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o") -$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h +$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo") Makefile: $(version-obj-y) $(version-lobj-y) @@ -36,7 +36,7 @@ static QEMUBalloonEvent *balloon_event_fn; static QEMUBalloonStatus *balloon_stat_fn; static void *balloon_opaque; -static bool have_ballon(Error **errp) +static bool have_balloon(Error **errp) { if (kvm_enabled() && !kvm_has_sync_mmu()) { error_set(errp, ERROR_CLASS_KVM_MISSING_CAP, @@ -81,7 +81,7 @@ BalloonInfo *qmp_query_balloon(Error **errp) { BalloonInfo *info; - if (!have_ballon(errp)) { + if (!have_balloon(errp)) { return NULL; } @@ -92,7 +92,7 @@ BalloonInfo *qmp_query_balloon(Error **errp) void qmp_balloon(int64_t target, Error **errp) { - if (!have_ballon(errp)) { + if (!have_balloon(errp)) { return; } @@ -1364,7 +1364,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0, &error_abort); - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size, &error_abort); ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err); qemu_opts_del(opts); if (ret < 0) { @@ -5649,18 +5649,22 @@ void bdrv_img_create(const char *filename, const char *fmt, /* Create parameter list with default values */ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort); /* Parse -o options */ if (options) { - if (qemu_opts_do_parse(opts, options, NULL) != 0) { + qemu_opts_do_parse(opts, options, NULL, &local_err); + if (local_err) { + error_report_err(local_err); + local_err = NULL; error_setg(errp, "Invalid options for file format '%s'", fmt); goto out; } } if (base_filename) { - if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename)) { + qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &local_err); + if (local_err) { error_setg(errp, "Backing file not supported for file format '%s'", fmt); goto out; @@ -5668,7 +5672,8 @@ void bdrv_img_create(const char *filename, const char *fmt, } if (base_fmt) { - if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) { + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &local_err); + if (local_err) { error_setg(errp, "Backing file format not supported for file " "format '%s'", fmt); goto out; @@ -5731,7 +5736,7 @@ void bdrv_img_create(const char *filename, const char *fmt, goto out; } - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort); bdrv_unref(bs); } else { diff --git a/block/iscsi.c b/block/iscsi.c index 12ddbfb095..1fa855acdd 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -65,6 +65,7 @@ typedef struct IscsiLun { unsigned long *allocationmap; int cluster_sectors; bool use_16_for_rw; + bool write_protected; } IscsiLun; typedef struct IscsiTask { @@ -1268,10 +1269,6 @@ out: /* * We support iscsi url's on the form * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun> - * - * Note: flags are currently not used by iscsi_open. If this function - * is changed such that flags are used, please examine iscsi_reopen_prepare() - * to see if needs to be changed as well. */ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) @@ -1385,9 +1382,10 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, scsi_free_scsi_task(task); task = NULL; + iscsilun->write_protected = iscsi_is_write_protected(iscsilun); /* Check the write protect flag of the LUN if we want to write */ if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && - iscsi_is_write_protected(iscsilun)) { + iscsilun->write_protected) { error_setg(errp, "Cannot open a write protected LUN as read-write"); ret = -EACCES; goto out; @@ -1541,13 +1539,17 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) sector_limits_lun2qemu(iscsilun->bl.opt_xfer_len, iscsilun); } -/* Since iscsi_open() ignores bdrv_flags, there is nothing to do here in - * prepare. Note that this will not re-establish a connection with an iSCSI - * target - it is effectively a NOP. */ +/* Note that this will not re-establish a connection with an iSCSI target - it + * is effectively a NOP. */ static int iscsi_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { - /* NOP */ + IscsiLun *iscsilun = state->bs->opaque; + + if (state->flags & BDRV_O_RDWR && iscsilun->write_protected) { + error_setg(errp, "Cannot open a write protected LUN as read-write"); + return -EACCES; + } return 0; } diff --git a/block/nbd.c b/block/nbd.c index 2f3b9adf72..697c0219b4 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -215,7 +215,8 @@ static void nbd_config(BDRVNBDState *s, QDict *options, char **export, } if (!qemu_opt_get(s->socket_opts, "port")) { - qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT); + qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT, + &error_abort); } *export = g_strdup(qdict_get_try_str(options, "export")); diff --git a/block/qcow2.c b/block/qcow2.c index 2ed8d95b1f..50e0a947df 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1858,8 +1858,9 @@ static int qcow2_create2(const char *filename, int64_t total_size, meta_size += nreftablee * sizeof(uint64_t); qemu_opt_set_number(opts, BLOCK_OPT_SIZE, - aligned_total_size + meta_size); - qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_lookup[prealloc]); + aligned_total_size + meta_size, &error_abort); + qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_lookup[prealloc], + &error_abort); } ret = bdrv_create_file(filename, opts, &local_err); diff --git a/block/vvfat.c b/block/vvfat.c index a1a44f0ef5..9be632f404 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2924,8 +2924,9 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) } opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort); - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512); - qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:"); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512, + &error_abort); + qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort); ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp); qemu_opts_del(opts); diff --git a/blockdev.c b/blockdev.c index ae73539551..b9c1c0cc1a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -180,21 +180,19 @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, const char *optstr) { QemuOpts *opts; - char buf[32]; opts = drive_def(optstr); if (!opts) { return NULL; } if (type != IF_DEFAULT) { - qemu_opt_set(opts, "if", if_name[type]); + qemu_opt_set(opts, "if", if_name[type], &error_abort); } if (index >= 0) { - snprintf(buf, sizeof(buf), "%d", index); - qemu_opt_set(opts, "index", buf); + qemu_opt_set_number(opts, "index", index, &error_abort); } if (file) - qemu_opt_set(opts, "file", file); + qemu_opt_set(opts, "file", file, &error_abort); return opts; } @@ -584,7 +582,7 @@ static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to, /* rename all items in opts */ while ((value = qemu_opt_get(opts, from))) { - qemu_opt_set(opts, to, value); + qemu_opt_set(opts, to, value, &error_abort); qemu_opt_unset(opts, from); } } @@ -737,15 +735,15 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) /* Specific options take precedence */ if (!qemu_opt_get(all_opts, "cache.writeback")) { qemu_opt_set_bool(all_opts, "cache.writeback", - !!(flags & BDRV_O_CACHE_WB)); + !!(flags & BDRV_O_CACHE_WB), &error_abort); } if (!qemu_opt_get(all_opts, "cache.direct")) { qemu_opt_set_bool(all_opts, "cache.direct", - !!(flags & BDRV_O_NOCACHE)); + !!(flags & BDRV_O_NOCACHE), &error_abort); } if (!qemu_opt_get(all_opts, "cache.no-flush")) { qemu_opt_set_bool(all_opts, "cache.no-flush", - !!(flags & BDRV_O_NO_FLUSH)); + !!(flags & BDRV_O_NO_FLUSH), &error_abort); } qemu_opt_unset(all_opts, "cache"); } @@ -935,13 +933,14 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); if (arch_type == QEMU_ARCH_S390X) { - qemu_opt_set(devopts, "driver", "virtio-blk-s390"); + qemu_opt_set(devopts, "driver", "virtio-blk-s390", &error_abort); } else { - qemu_opt_set(devopts, "driver", "virtio-blk-pci"); + qemu_opt_set(devopts, "driver", "virtio-blk-pci", &error_abort); } - qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id")); + qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"), + &error_abort); if (devaddr) { - qemu_opt_set(devopts, "addr", devaddr); + qemu_opt_set(devopts, "addr", devaddr, &error_abort); } } diff --git a/bootdevice.c b/bootdevice.c index c3a010c094..673bfef60c 100644 --- a/bootdevice.c +++ b/bootdevice.c @@ -105,7 +105,9 @@ void restore_boot_order(void *opaque) return; } - qemu_boot_set(normal_boot_order, NULL); + if (boot_set_handler) { + qemu_boot_set(normal_boot_order, &error_abort); + } qemu_unregister_reset(restore_boot_order, normal_boot_order); g_free(normal_boot_order); @@ -221,10 +223,15 @@ char *get_boot_devices_list(size_t *size, bool ignore_suffixes) } if (!ignore_suffixes) { - d = qdev_get_own_fw_dev_path_from_handler(i->dev->parent_bus, i->dev); - if (d) { - assert(!i->suffix); - suffix = d; + if (i->dev) { + d = qdev_get_own_fw_dev_path_from_handler(i->dev->parent_bus, + i->dev); + if (d) { + assert(!i->suffix); + suffix = d; + } else { + suffix = g_strdup(i->suffix); + } } else { suffix = g_strdup(i->suffix); } @@ -778,7 +778,7 @@ static void qemu_tcg_init_cpu_signals(void) static QemuMutex qemu_global_mutex; static QemuCond qemu_io_proceeded_cond; -static bool iothread_requesting_mutex; +static unsigned iothread_requesting_mutex; static QemuThread io_thread; @@ -1025,6 +1025,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } } + /* process any pending work */ + exit_request = 1; + while (1) { tcg_exec_all(); @@ -1115,15 +1118,16 @@ bool qemu_in_vcpu_thread(void) void qemu_mutex_lock_iothread(void) { - if (!tcg_enabled()) { + atomic_inc(&iothread_requesting_mutex); + if (!tcg_enabled() || !first_cpu) { qemu_mutex_lock(&qemu_global_mutex); + atomic_dec(&iothread_requesting_mutex); } else { - iothread_requesting_mutex = true; if (qemu_mutex_trylock(&qemu_global_mutex)) { qemu_cpu_kick_thread(first_cpu); qemu_mutex_lock(&qemu_global_mutex); } - iothread_requesting_mutex = false; + atomic_dec(&iothread_requesting_mutex); qemu_cond_broadcast(&qemu_io_proceeded_cond); } } diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index b00c2e150e..149ae1b595 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -34,6 +34,7 @@ CONFIG_PFLASH_CFI02=y CONFIG_MICRODRIVE=y CONFIG_USB_MUSB=y CONFIG_USB_EHCI_SYSBUS=y +CONFIG_PLATFORM_BUS=y CONFIG_ARM11MPCORE=y CONFIG_A9MPCORE=y @@ -91,3 +92,7 @@ CONFIG_INTEGRATOR_DEBUG=y CONFIG_ALLWINNER_A10_PIT=y CONFIG_ALLWINNER_A10_PIC=y CONFIG_ALLWINNER_A10=y + +CONFIG_XIO3130=y +CONFIG_IOH3420=y +CONFIG_I82801B11=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index f5634bf7a3..6a74e00399 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -42,3 +42,6 @@ CONFIG_IOAPIC=y CONFIG_ICC_BUS=y CONFIG_PVPANIC=y CONFIG_MEM_HOTPLUG=y +CONFIG_XIO3130=y +CONFIG_IOH3420=y +CONFIG_I82801B11=y diff --git a/default-configs/pci.mak b/default-configs/pci.mak index bea6b01553..58a2c0ace1 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -35,3 +35,4 @@ CONFIG_SDHCI=y CONFIG_EDU=y CONFIG_VGA=y CONFIG_VGA_PCI=y +CONFIG_IVSHMEM=$(CONFIG_KVM) diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index aebfab92eb..4b60e699ff 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -43,6 +43,7 @@ CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=y CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) +CONFIG_PLATFORM_BUS=y CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y # For PReP diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index f195a8721a..de71e41b00 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -44,6 +44,7 @@ CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=y CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) +CONFIG_PLATFORM_BUS=y CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y # For pSeries diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 41990f7af0..46b87ddb43 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -42,3 +42,6 @@ CONFIG_IOAPIC=y CONFIG_ICC_BUS=y CONFIG_PVPANIC=y CONFIG_MEM_HOTPLUG=y +CONFIG_XIO3130=y +CONFIG_IOH3420=y +CONFIG_I82801B11=y diff --git a/docs/memory-hotplug.txt b/docs/memory-hotplug.txt new file mode 100644 index 0000000000..f70571df0c --- /dev/null +++ b/docs/memory-hotplug.txt @@ -0,0 +1,76 @@ +QEMU memory hotplug +=================== + +This document explains how to use the memory hotplug feature in QEMU, +which is present since v2.1.0. + +Please, note that memory hotunplug is not supported yet. This means +that you're able to add memory, but you're not able to remove it. +Also, proper guest support is required for memory hotplug to work. + +Basic RAM hotplug +----------------- + +In order to be able to hotplug memory, QEMU has to be told how many +hotpluggable memory slots to create and what is the maximum amount of +memory the guest can grow. This is done at startup time by means of +the -m command-line option, which has the following format: + + -m [size=]megs[,slots=n,maxmem=size] + +Where, + + - "megs" is the startup RAM. It is the RAM the guest will boot with + - "slots" is the number of hotpluggable memory slots + - "maxmem" is the maximum RAM size the guest can have + +For example, the following command-line: + + qemu [...] 1G,slots=3,maxmem=4G + +Creates a guest with 1GB of memory and three hotpluggable memory slots. +The hotpluggable memory slots are empty when the guest is booted, so all +memory the guest will see after boot is 1GB. The maximum memory the +guest can reach is 4GB. This means that three additional gigabytes can be +hotplugged by using any combination of the available memory slots. + +Two monitor commands are used to hotplug memory: + + - "object_add": creates a memory backend object + - "device_add": creates a front-end pc-dimm device and inserts it + into the first empty slot + +For example, the following commands add another 1GB to the guest +discussed earlier: + + (qemu) object_add memory-backend-ram,id=mem1,size=1G + (qemu) device_add pc-dimm,id=dimm1,memdev=mem1 + +Using the file backend +---------------------- + +Besides basic RAM hotplug, QEMU also supports using files as a memory +backend. This is useful for using hugetlbfs in Linux, which provides +access to bigger page sizes. + +For example, assuming that the host has 1GB hugepages available in +the /mnt/hugepages-1GB directory, a 1GB hugepage could be hotplugged +into the guest from the previous section with the following commands: + + (qemu) object_add memory-backend-file,id=mem1,size=1G,mem-path=/mnt/hugepages-1GB + (qemu) device_add pc-dimm,id=dimm1,memdev=mem1 + +It's also possible to start a guest with memory cold-plugged into the +hotpluggable memory slots. This might seem counterintuitive at first, +but this allows for a lot of flexibility when using the file backend. + +In the following command-line example, a 8GB guest is created where 6GB +comes from regular RAM, 1GB is a 1GB hugepage page and 256MB is from +2MB pages. Also, the guest has additional memory slots to hotplug more +2GB if needed: + + qemu [...] -m 6GB,slots=4,maxmem=10G \ + -object memory-backend-file,id=mem1,size=1G,mem-path=/mnt/hugepages-1G \ + -device pc-dimm,id=dimm1,memdev=mem1 \ + -object memory-backend-file,id=mem2,size=256M,mem-path=/mnt/hugepages-2MB \ + -device pc-dimm,id=dimm2,memdev=mem2 @@ -29,6 +29,10 @@ #include "block/qapi.h" #include "qemu-io.h" +#ifdef CONFIG_SPICE +#include <spice/enums.h> +#endif + static void hmp_handle_error(Monitor *mon, Error **errp) { assert(errp); @@ -412,7 +416,7 @@ void hmp_info_block(Monitor *mon, const QDict *qdict) /* Print BlockBackend information */ if (!nodes) { - block_list = qmp_query_block(false); + block_list = qmp_query_block(NULL); } else { block_list = NULL; } @@ -545,6 +549,25 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict) { SpiceChannelList *chan; SpiceInfo *info; + const char *channel_name; + const char * const channel_names[] = { + [SPICE_CHANNEL_MAIN] = "main", + [SPICE_CHANNEL_DISPLAY] = "display", + [SPICE_CHANNEL_INPUTS] = "inputs", + [SPICE_CHANNEL_CURSOR] = "cursor", + [SPICE_CHANNEL_PLAYBACK] = "playback", + [SPICE_CHANNEL_RECORD] = "record", + [SPICE_CHANNEL_TUNNEL] = "tunnel", + [SPICE_CHANNEL_SMARTCARD] = "smartcard", + [SPICE_CHANNEL_USBREDIR] = "usbredir", + [SPICE_CHANNEL_PORT] = "port", +#if 0 + /* minimum spice-protocol is 0.12.3, webdav was added in 0.12.7, + * no easy way to #ifdef (SPICE_CHANNEL_* is a enum). Disable + * as quick fix for build failures with older versions. */ + [SPICE_CHANNEL_WEBDAV] = "webdav", +#endif + }; info = qmp_query_spice(NULL); @@ -581,6 +604,15 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict) chan->value->connection_id); monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n", chan->value->channel_type, chan->value->channel_id); + + channel_name = "unknown"; + if (chan->value->channel_type > 0 && + chan->value->channel_type < ARRAY_SIZE(channel_names) && + channel_names[chan->value->channel_type]) { + channel_name = channel_names[chan->value->channel_type]; + } + + monitor_printf(mon, " channel name: %s\n", channel_name); } } diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 84a55e41a2..e82d61d28c 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -83,11 +83,7 @@ static void clipper_init(MachineState *machine) pci_vga_init(pci_bus); /* Serial code setup. */ - for (i = 0; i < MAX_SERIAL_PORTS; ++i) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } + serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); /* Network setup. e1000 is good enough, failing Tulip support. */ for (i = 0; i < nb_nics; i++) { diff --git a/hw/char/parallel.c b/hw/char/parallel.c index c2b553f0d1..4079554bb9 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -641,3 +641,28 @@ static void parallel_register_types(void) } type_init(parallel_register_types) + +static void parallel_init(ISABus *bus, int index, CharDriverState *chr) +{ + DeviceState *dev; + ISADevice *isadev; + + isadev = isa_create(bus, "isa-parallel"); + dev = DEVICE(isadev); + qdev_prop_set_uint32(dev, "index", index); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); +} + +void parallel_hds_isa_init(ISABus *bus, int n) +{ + int i; + + assert(n <= MAX_PARALLEL_PORTS); + + for (i = 0; i < n; i++) { + if (parallel_hds[i]) { + parallel_init(bus, i, parallel_hds[i]); + } + } +} diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index c9fcb2761f..f3db024d06 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -119,20 +119,27 @@ static void serial_register_types(void) type_init(serial_register_types) -bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr) +static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr) { DeviceState *dev; ISADevice *isadev; - isadev = isa_try_create(bus, TYPE_ISA_SERIAL); - if (!isadev) { - return false; - } + isadev = isa_create(bus, TYPE_ISA_SERIAL); dev = DEVICE(isadev); qdev_prop_set_uint32(dev, "index", index); qdev_prop_set_chr(dev, "chardev", chr); - if (qdev_init(dev) < 0) { - return false; + qdev_init_nofail(dev); +} + +void serial_hds_isa_init(ISABus *bus, int n) +{ + int i; + + assert(n <= MAX_SERIAL_PORTS); + + for (i = 0; i < n; ++i) { + if (serial_hds[i]) { + serial_isa_init(bus, i, serial_hds[i]); + } } - return true; } diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 9dce1bc53c..abb3560bea 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -14,4 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o -common-obj-$(CONFIG_SOFTMMU) += platform-bus.o +common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 5f63c5bbde..6be58669f7 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -373,10 +373,15 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, way is somewhat unclean, and best avoided. */ void qdev_init_nofail(DeviceState *dev) { - const char *typename = object_get_typename(OBJECT(dev)); + Error *err = NULL; - if (qdev_init(dev) < 0) { - error_report("Initialization of device %s failed", typename); + assert(!dev->realized); + + object_property_set_bool(OBJECT(dev), true, "realized", &err); + if (err) { + error_report("Initialization of device %s failed: %s", + object_get_typename(OBJECT(dev)), + error_get_pretty(err)); exit(1); } } @@ -995,7 +1000,12 @@ void qdev_alias_all_properties(DeviceState *target, Object *source) static int qdev_add_hotpluggable_device(Object *obj, void *opaque) { GSList **list = opaque; - DeviceState *dev = DEVICE(obj); + DeviceState *dev = (DeviceState *)object_dynamic_cast(OBJECT(obj), + TYPE_DEVICE); + + if (dev == NULL) { + return 0; + } if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) { *list = g_slist_append(*list, dev); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 208346d274..b6d65b9487 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -120,9 +120,12 @@ static QXLMode qxl_modes[] = { QXL_MODE_EX(2560, 2048), QXL_MODE_EX(2800, 2100), QXL_MODE_EX(3200, 2400), + /* these modes need more than 32 MB video memory */ QXL_MODE_EX(3840, 2160), /* 4k mainstream */ QXL_MODE_EX(4096, 2160), /* 4k */ + /* these modes need more than 64 MB video memory */ QXL_MODE_EX(7680, 4320), /* 8k mainstream */ + /* these modes need more than 128 MB video memory */ QXL_MODE_EX(8192, 4320), /* 8k */ }; @@ -297,19 +300,6 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qxl->ssd.cursor = cursor_builtin_hidden(); } - -static inline uint32_t msb_mask(uint32_t val) -{ - uint32_t mask; - - do { - mask = ~(val - 1) & val; - val &= ~mask; - } while (mask < val); - - return mask; -} - static ram_addr_t qxl_rom_size(void) { uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) + @@ -367,6 +357,8 @@ static void init_qxl_rom(PCIQXLDevice *d) num_pages -= surface0_area_size; num_pages = num_pages / QXL_PAGE_SIZE; + assert(ram_header_size + surface0_area_size <= d->vga.vram_size); + rom->draw_area_offset = cpu_to_le32(0); rom->surface0_area_size = cpu_to_le32(surface0_area_size); rom->pages_offset = cpu_to_le32(surface0_area_size); @@ -1155,7 +1147,6 @@ static void qxl_soft_reset(PCIQXLDevice *d) qxl_enter_vga_mode(d); } else { d->mode = QXL_MODE_UNDEFINED; - update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE); } } @@ -1880,6 +1871,12 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl) if (qxl->vgamem_size_mb < 8) { qxl->vgamem_size_mb = 8; } + /* XXX: we round vgamem_size_mb up to a nearest power of two and it must be + * less than vga_common_init()'s maximum on qxl->vga.vram_size (512 now). + */ + if (qxl->vgamem_size_mb > 256) { + qxl->vgamem_size_mb = 256; + } qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024; /* vga ram (bar 0, total) */ @@ -1910,10 +1907,10 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl) qxl->vram32_size = 4096; qxl->vram_size = 4096; } - qxl->vgamem_size = msb_mask(qxl->vgamem_size * 2 - 1); - qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); - qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1); - qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + qxl->vgamem_size = pow2ceil(qxl->vgamem_size); + qxl->vga.vram_size = pow2ceil(qxl->vga.vram_size); + qxl->vram32_size = pow2ceil(qxl->vram32_size); + qxl->vram_size = pow2ceil(qxl->vram_size); } static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) @@ -1945,7 +1942,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) break; case 4: /* qxl-4 */ pci_device_rev = QXL_REVISION_STABLE_V12; - io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); + io_size = pow2ceil(QXL_IO_RANGE_SIZE); break; default: error_setg(errp, "Invalid revision %d for qxl device (max %d)", diff --git a/hw/display/vga.c b/hw/display/vga.c index c8c49abc6e..c0f7b343bb 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -2094,6 +2094,17 @@ static const GraphicHwOps vga_ops = { .text_update = vga_update_text, }; +static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax) +{ + if (val < vmin) { + return vmin; + } + if (val > vmax) { + return vmax; + } + return val; +} + void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) { int i, j, v, b; @@ -2121,13 +2132,10 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) expand4to8[i] = v; } - /* valid range: 1 MB -> 256 MB */ - s->vram_size = 1024 * 1024; - while (s->vram_size < (s->vram_size_mb << 20) && - s->vram_size < (256 << 20)) { - s->vram_size <<= 1; - } - s->vram_size_mb = s->vram_size >> 20; + s->vram_size_mb = uint_clamp(s->vram_size_mb, 1, 512); + s->vram_size_mb = pow2ceil(s->vram_size_mb); + s->vram_size = s->vram_size_mb << 20; + if (!s->vbe_size) { s->vbe_size = s->vram_size; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ae3ef0af4f..79eaad5fec 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -41,6 +41,7 @@ #include "hw/pci/msi.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" +#include "sysemu/numa.h" #include "sysemu/kvm.h" #include "kvm_i386.h" #include "hw/xen/xen.h" @@ -1137,15 +1138,11 @@ void pc_acpi_init(const char *default_dsdt) if (filename == NULL) { fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); } else { - char *arg; - QemuOpts *opts; + QemuOpts *opts = qemu_opts_create(qemu_find_opts("acpi"), NULL, 0, + &error_abort); Error *err = NULL; - arg = g_strdup_printf("file=%s", filename); - - /* creates a deep copy of "arg" */ - opts = qemu_opts_parse(qemu_find_opts("acpi"), arg, 0); - g_assert(opts != NULL); + qemu_opt_set(opts, "file", filename, &error_abort); acpi_table_add_builtin(opts, &err); if (err) { @@ -1153,7 +1150,6 @@ void pc_acpi_init(const char *default_dsdt) error_get_pretty(err)); error_free(err); } - g_free(arg); g_free(filename); } } @@ -1425,17 +1421,8 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, pcspk_init(isa_bus, pit); } - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(isa_bus, i, parallel_hds[i]); - } - } + serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); + parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); i8042 = isa_create_simple(isa_bus, "i8042"); diff --git a/hw/ide/isa.c b/hw/ide/isa.c index b084162ddc..c0c4e1b098 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -88,9 +88,7 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, qdev_prop_set_uint32(dev, "iobase", iobase); qdev_prop_set_uint32(dev, "iobase2", iobase2); qdev_prop_set_uint32(dev, "irq", isairq); - if (qdev_init(dev) < 0) { - return NULL; - } + qdev_init_nofail(dev); s = ISA_IDE(dev); if (hd0) { diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 18cdc54bf9..de81b9ceab 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -22,6 +22,7 @@ #include "qemu/config-file.h" #include "qapi/visitor.h" #include "qemu/range.h" +#include "sysemu/numa.h" typedef struct pc_dimms_capacity { uint64_t size; @@ -99,6 +100,32 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque) return 0; } +ram_addr_t get_current_ram_size(void) +{ + MemoryDeviceInfoList *info_list = NULL; + MemoryDeviceInfoList **prev = &info_list; + MemoryDeviceInfoList *info; + ram_addr_t size = ram_size; + + qmp_pc_dimm_device_list(qdev_get_machine(), &prev); + for (info = info_list; info; info = info->next) { + MemoryDeviceInfo *value = info->value; + + if (value) { + switch (value->kind) { + case MEMORY_DEVICE_INFO_KIND_DIMM: + size += value->dimm->size; + break; + default: + break; + } + } + } + qapi_free_MemoryDeviceInfoList(info_list); + + return size; +} + static int pc_dimm_slot2bitmap(Object *obj, void *opaque) { unsigned long *bitmap = opaque; diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 6a9ebfa911..ea73585a92 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -277,7 +277,6 @@ static void mips_fulong2e_init(MachineState *machine) PCIBus *pci_bus; ISABus *isa_bus; I2CBus *smbus; - int i; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; MIPSCPU *cpu; CPUMIPSState *env; @@ -384,15 +383,8 @@ static void mips_fulong2e_init(MachineState *machine) rtc_init(isa_bus, 2000, NULL); - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - - if (parallel_hds[0]) { - parallel_init(isa_bus, 0, parallel_hds[0]); - } + serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); + parallel_hds_isa_init(isa_bus, 1); /* Sound card */ audio_init(pci_bus); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 5845158a74..533b2e60fe 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1172,10 +1172,9 @@ void mips_malta_init(MachineState *machine) isa_create_simple(isa_bus, "i8042"); rtc_init(isa_bus, 2000, NULL); - serial_isa_init(isa_bus, 0, serial_hds[0]); - serial_isa_init(isa_bus, 1, serial_hds[1]); - if (parallel_hds[0]) - parallel_init(isa_bus, 0, parallel_hds[0]); + serial_hds_isa_init(isa_bus, 2); + parallel_hds_isa_init(isa_bus, 1); + for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 3e90e273dc..52564be692 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -284,11 +284,7 @@ void mips_r4k_init(MachineState *machine) pit = pit_init(isa_bus, 0x40, 0, NULL); - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } + serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); isa_vga_init(isa_bus); diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 029a56f279..6c6e29681a 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -19,9 +19,7 @@ common-obj-$(CONFIG_PUV3) += puv3_pm.o common-obj-$(CONFIG_MACIO) += macio/ -ifeq ($(CONFIG_PCI), y) -obj-$(CONFIG_KVM) += ivshmem.o -endif +obj-$(CONFIG_IVSHMEM) += ivshmem.o obj-$(CONFIG_REALVIEW) += arm_sysctl.o obj-$(CONFIG_NSERIES) += cbus.o diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index 2fbbc6ccc0..c57365fdec 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -443,10 +443,7 @@ DeviceState *etsec_create(hwaddr base, dev = qdev_create(NULL, "eTSEC"); qdev_set_nic_properties(dev, nd); - - if (qdev_init(dev)) { - return NULL; - } + qdev_init_nofail(dev); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq); diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs index 968b3694ab..96c596eb31 100644 --- a/hw/pci-bridge/Makefile.objs +++ b/hw/pci-bridge/Makefile.objs @@ -1,5 +1,6 @@ common-obj-y += pci_bridge_dev.o -common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o -common-obj-y += i82801b11.o +common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o +common-obj-$(CONFIG_IOH3420) += ioh3420.o +common-obj-$(CONFIG_I82801B11) += i82801b11.o # NewWorld PowerMac common-obj-$(CONFIG_DEC_PCI) += dec.o diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a82a0f99b3..23cde20019 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -25,6 +25,7 @@ * */ #include "sysemu/sysemu.h" +#include "sysemu/numa.h" #include "hw/hw.h" #include "hw/fw-path-provider.h" #include "elf.h" diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index db39ae0e23..dca9576828 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -221,11 +221,16 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, const char *serial, Error **errp) { const char *driver; + char *name; DeviceState *dev; Error *err = NULL; driver = blk_is_sg(blk) ? "scsi-generic" : "scsi-disk"; dev = qdev_create(&bus->qbus, driver); + name = g_strdup_printf("legacy[%d]", unit); + object_property_add_child(OBJECT(bus), name, OBJECT(dev), NULL); + g_free(name); + qdev_prop_set_uint32(dev, "scsi-id", unit); if (bootindex >= 0) { object_property_set_int(OBJECT(dev), bootindex, "bootindex", diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 418d73b1b4..3f40ff090f 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -211,8 +211,6 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) s->dataplane_starting = true; - assert(!s->blocker); - error_setg(&s->blocker, "block device is in use by data plane"); /* Set up guest notifier (irq) */ rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true); if (rc != 0) { @@ -279,8 +277,6 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) if (!s->dataplane_started || s->dataplane_stopping) { return; } - error_free(s->blocker); - s->blocker = NULL; s->dataplane_stopping = true; assert(s->ctx == iothread_get_aio_context(vs->conf.iothread)); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index c5d910995f..cfb52e8fd9 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -255,10 +255,8 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) int target; int ret = 0; - if (s->dataplane_started && blk_get_aio_context(d->conf.blk) != s->ctx) { - aio_context_acquire(s->ctx); - blk_set_aio_context(d->conf.blk, s->ctx); - aio_context_release(s->ctx); + if (s->dataplane_started) { + assert(blk_get_aio_context(d->conf.blk) == s->ctx); } /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf.response = VIRTIO_SCSI_S_OK; @@ -541,10 +539,8 @@ bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); return false; } - if (s->dataplane_started && blk_get_aio_context(d->conf.blk) != s->ctx) { - aio_context_acquire(s->ctx); - blk_set_aio_context(d->conf.blk, s->ctx); - aio_context_release(s->ctx); + if (s->dataplane_started) { + assert(blk_get_aio_context(d->conf.blk) == s->ctx); } req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), @@ -768,6 +764,9 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } blk_op_block_all(sd->conf.blk, s->blocker); + aio_context_acquire(s->ctx); + blk_set_aio_context(sd->conf.blk, s->ctx); + aio_context_release(s->ctx); } if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { @@ -905,6 +904,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) virtio_scsi_save, virtio_scsi_load, s); s->migration_state_notifier.notify = virtio_scsi_migration_state_changed; add_migration_state_change_notifier(&s->migration_state_notifier); + + error_setg(&s->blocker, "block device is in use by data plane"); } static void virtio_scsi_instance_init(Object *obj) @@ -930,6 +931,8 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) { VirtIOSCSI *s = VIRTIO_SCSI(dev); + error_free(s->blocker); + unregister_savevm(dev, "virtio-scsi", s); remove_migration_state_change_notifier(&s->migration_state_notifier); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 4620cc613a..b310588ff7 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -850,17 +850,9 @@ static void sun4uv_init(MemoryRegion *address_space_mem, NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); i++; } - for(; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_isa_init(isa_bus, i, serial_hds[i]); - } - } - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(isa_bus, i, parallel_hds[i]); - } - } + serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); + parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); for(i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL); diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index b27b1f441e..18669917f5 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1394,8 +1394,8 @@ static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) if (!opts) { return NULL; } - qemu_opt_set(opts, "type", "nic"); - qemu_opt_set(opts, "model", "usb"); + qemu_opt_set(opts, "type", "nic", &error_abort); + qemu_opt_set(opts, "model", "usb", &error_abort); idx = net_client_init(opts, 0, &local_err); if (local_err) { diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index af2e1b915d..65d9aa6147 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -683,7 +683,7 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) if (strstart(filename, "format=", &p2)) { int len = MIN(p1 - p2, sizeof(fmt)); pstrcpy(fmt, len, p2); - qemu_opt_set(opts, "format", fmt); + qemu_opt_set(opts, "format", fmt, &error_abort); } else if (*filename != ':') { error_report("unrecognized USB mass-storage option %s", filename); return NULL; @@ -694,8 +694,8 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) error_report("block device specification needed"); return NULL; } - qemu_opt_set(opts, "file", filename); - qemu_opt_set(opts, "if", "none"); + qemu_opt_set(opts, "file", filename, &error_abort); + qemu_opt_set(opts, "if", "none", &error_abort); /* create host drive */ dinfo = drive_new(opts, 0); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 09eaa1fe88..ba15ae0019 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1767,9 +1767,18 @@ static void xhci_xfer_report(XHCITransfer *xfer) break; } - if (!reported && ((trb->control & TRB_TR_IOC) || - (shortpkt && (trb->control & TRB_TR_ISP)) || - (xfer->status != CC_SUCCESS && left == 0))) { + /* + * XHCI 1.1, 4.11.3.1 Transfer Event TRB -- "each Transfer TRB + * encountered with its IOC flag set to '1' shall generate a Transfer + * Event." + * + * Otherwise, longer transfers can have multiple data TRBs (for scatter + * gather). Short transfers and errors should be reported once per + * transfer only. + */ + if ((trb->control & TRB_TR_IOC) || + (!reported && ((shortpkt && (trb->control & TRB_TR_ISP)) || + (xfer->status != CC_SUCCESS && left == 0)))) { event.slotid = xfer->slotid; event.epid = xfer->epid; event.length = (trb->status & 0x1ffff) - chunk; diff --git a/hw/vfio/common.c b/hw/vfio/common.c index c5d15510dd..9db7d8da17 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -475,12 +475,12 @@ static void vfio_listener_region_del(MemoryListener *listener, } } -const MemoryListener vfio_memory_listener = { +static const MemoryListener vfio_memory_listener = { .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, }; -void vfio_listener_release(VFIOContainer *container) +static void vfio_listener_release(VFIOContainer *container) { memory_listener_unregister(&container->iommu_data.type1.listener); } @@ -493,7 +493,7 @@ int vfio_mmap_region(Object *obj, VFIORegion *region, int ret = 0; VFIODevice *vbasedev = region->vbasedev; - if (VFIO_ALLOW_MMAP && size && region->flags & + if (vbasedev->allow_mmap && size && region->flags & VFIO_REGION_INFO_FLAG_MMAP) { int prot = 0; @@ -932,8 +932,8 @@ static int vfio_container_do_ioctl(AddressSpace *as, int32_t groupid, if (group->container) { ret = ioctl(container->fd, req, param); if (ret < 0) { - error_report("vfio: failed to ioctl container: ret=%d, %s", - ret, strerror(errno)); + error_report("vfio: failed to ioctl %d to container: ret=%d, %s", + _IOC_NR(req) - VFIO_BASE, ret, strerror(errno)); } } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 84e9d995aa..6b80539c1f 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -153,13 +153,17 @@ typedef struct VFIOPCIDevice { VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ PCIHostDeviceAddress host; EventNotifier err_notifier; + EventNotifier req_notifier; uint32_t features; #define VFIO_FEATURE_ENABLE_VGA_BIT 0 #define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT) +#define VFIO_FEATURE_ENABLE_REQ_BIT 1 +#define VFIO_FEATURE_ENABLE_REQ (1 << VFIO_FEATURE_ENABLE_REQ_BIT) int32_t bootindex; uint8_t pm_cap; bool has_vga; bool pci_aer; + bool req_enabled; bool has_flr; bool has_pm_reset; bool rom_read_failed; @@ -3088,6 +3092,7 @@ static int vfio_populate_device(VFIOPCIDevice *vdev) vdev->has_vga = true; } + irq_info.index = VFIO_PCI_ERR_IRQ_INDEX; ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); @@ -3223,6 +3228,97 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev) event_notifier_cleanup(&vdev->err_notifier); } +static void vfio_req_notifier_handler(void *opaque) +{ + VFIOPCIDevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->req_notifier)) { + return; + } + + qdev_unplug(&vdev->pdev.qdev, NULL); +} + +static void vfio_register_req_notifier(VFIOPCIDevice *vdev) +{ + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info), + .index = VFIO_PCI_REQ_IRQ_INDEX }; + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + if (!(vdev->features & VFIO_FEATURE_ENABLE_REQ)) { + return; + } + + if (ioctl(vdev->vbasedev.fd, + VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0 || irq_info.count < 1) { + return; + } + + if (event_notifier_init(&vdev->req_notifier, 0)) { + error_report("vfio: Unable to init event notifier for device request"); + return; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_REQ_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&vdev->req_notifier); + qemu_set_fd_handler(*pfd, vfio_req_notifier_handler, NULL, vdev); + + if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_report("vfio: Failed to set up device request notification"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->req_notifier); + } else { + vdev->req_enabled = true; + } + + g_free(irq_set); +} + +static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) +{ + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + if (!vdev->req_enabled) { + return; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_REQ_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + *pfd = -1; + + if (ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + error_report("vfio: Failed to de-assign device request fd: %m"); + } + g_free(irq_set); + qemu_set_fd_handler(event_notifier_get_fd(&vdev->req_notifier), + NULL, NULL, vdev); + event_notifier_cleanup(&vdev->req_notifier); + + vdev->req_enabled = false; +} + static int vfio_initfn(PCIDevice *pdev) { VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); @@ -3370,6 +3466,7 @@ static int vfio_initfn(PCIDevice *pdev) } vfio_register_err_notifier(vdev); + vfio_register_req_notifier(vdev); return 0; @@ -3397,6 +3494,7 @@ static void vfio_exitfn(PCIDevice *pdev) { VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); vfio_disable_interrupts(vdev); @@ -3455,7 +3553,10 @@ static Property vfio_pci_dev_properties[] = { intx.mmap_timeout, 1100), DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features, VFIO_FEATURE_ENABLE_VGA_BIT, false), + DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features, + VFIO_FEATURE_ENABLE_REQ_BIT, true), DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1), + DEFINE_PROP_BOOL("x-mmap", VFIOPCIDevice, vbasedev.allow_mmap, true), /* * TODO - support passed fds... is this necessary? * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name), diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 21e449af8f..95b0643448 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -25,6 +25,7 @@ #include "exec/address-spaces.h" #include "qapi/visitor.h" #include "qapi-event.h" +#include "trace.h" #if defined(__linux__) #include <sys/mman.h> @@ -222,6 +223,8 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) if (!int128_nz(section.size) || !memory_region_is_ram(section.mr)) continue; + trace_virtio_balloon_handle_output(memory_region_name(section.mr), + pa); /* Using memory_region_get_ram_ptr is bending the rules a bit, but should be OK because we only want a single page. */ addr = section.offset_within_region; @@ -285,6 +288,7 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) config.num_pages = cpu_to_le32(dev->num_pages); config.actual = cpu_to_le32(dev->actual); + trace_virtio_balloon_get_config(config.num_pages, config.actual); memcpy(config_data, &config, sizeof(struct virtio_balloon_config)); } @@ -294,13 +298,16 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, VirtIOBalloon *dev = VIRTIO_BALLOON(vdev); struct virtio_balloon_config config; uint32_t oldactual = dev->actual; + ram_addr_t vm_ram_size = get_current_ram_size(); + memcpy(&config, config_data, sizeof(struct virtio_balloon_config)); dev->actual = le32_to_cpu(config.actual); if (dev->actual != oldactual) { - qapi_event_send_balloon_change(ram_size - + qapi_event_send_balloon_change(vm_ram_size - ((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT), &error_abort); } + trace_virtio_balloon_set_config(dev->actual, oldactual); } static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) @@ -312,22 +319,24 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) static void virtio_balloon_stat(void *opaque, BalloonInfo *info) { VirtIOBalloon *dev = opaque; - info->actual = ram_size - ((uint64_t) dev->actual << - VIRTIO_BALLOON_PFN_SHIFT); + info->actual = get_current_ram_size() - ((uint64_t) dev->actual << + VIRTIO_BALLOON_PFN_SHIFT); } static void virtio_balloon_to_target(void *opaque, ram_addr_t target) { VirtIOBalloon *dev = VIRTIO_BALLOON(opaque); VirtIODevice *vdev = VIRTIO_DEVICE(dev); + ram_addr_t vm_ram_size = get_current_ram_size(); - if (target > ram_size) { - target = ram_size; + if (target > vm_ram_size) { + target = vm_ram_size; } if (target) { - dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; + dev->num_pages = (vm_ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; virtio_notify_config(vdev); } + trace_virtio_balloon_to_target(target, dev->num_pages); } static void virtio_balloon_save(QEMUFile *f, void *opaque) diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index c307f9b57e..54440c91c5 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -68,7 +68,7 @@ int select_watchdog(const char *p) /* add the device */ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); - qemu_opt_set(opts, "driver", p); + qemu_opt_set(opts, "driver", p, &error_abort); return 0; } } diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index e5a6bba783..d441c024c2 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -162,6 +162,23 @@ static void lx60_reset(void *opaque) cpu_reset(CPU(cpu)); } +static uint64_t lx60_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + return 0; +} + +static void lx60_io_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ +} + +static const MemoryRegionOps lx60_io_ops = { + .read = lx60_io_read, + .write = lx60_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static void lx_init(const LxBoardDesc *board, MachineState *machine) { #ifdef TARGET_WORDS_BIGENDIAN @@ -211,7 +228,8 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine) memory_region_add_subregion(system_memory, 0, ram); system_io = g_malloc(sizeof(*system_io)); - memory_region_init(system_io, NULL, "lx60.io", 224 * 1024 * 1024); + memory_region_init_io(system_io, NULL, &lx60_io_ops, NULL, "lx60.io", + 224 * 1024 * 1024); memory_region_add_subregion(system_memory, 0xf0000000, system_io); lx60_fpga_init(system_io, 0x0d020000); if (nd_table[0].used) { @@ -390,7 +408,7 @@ static void xtensa_ml605_init(MachineState *machine) { static const LxBoardDesc ml605_board = { .flash_base = 0xf8000000, - .flash_size = 0x02000000, + .flash_size = 0x01000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; diff --git a/include/block/block.h b/include/block/block.h index 471d11dbbe..649c269ecd 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -547,8 +547,7 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs); * Changes the #AioContext used for fd handlers, timers, and BHs by this * BlockDriverState and all its children. * - * This function must be called from the old #AioContext or with a lock held so - * the old #AioContext is not executing. + * This function must be called with iothread lock held. */ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context); diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 427b8515a3..fcc316271e 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -52,6 +52,7 @@ typedef uintptr_t ram_addr_t; #endif extern ram_addr_t ram_size; +ram_addr_t get_current_ram_size(void); /* memory API */ diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index f431764bf5..15beb6b45c 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -92,6 +92,6 @@ SerialState *serial_mm_init(MemoryRegion *address_space, /* serial-isa.c */ #define TYPE_ISA_SERIAL "isa-serial" -bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr); +void serial_hds_isa_init(ISABus *bus, int n); #endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 3b999668e2..1b35168e96 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -108,23 +108,8 @@ struct PcGuestInfo { }; /* parallel.c */ -static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr) -{ - DeviceState *dev; - ISADevice *isadev; - isadev = isa_try_create(bus, "isa-parallel"); - if (!isadev) { - return false; - } - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "index", index); - qdev_prop_set_chr(dev, "chardev", chr); - if (qdev_init(dev) < 0) { - return false; - } - return true; -} +void parallel_hds_isa_init(ISABus *bus, int n); bool parallel_mm_init(MemoryRegion *address_space, hwaddr base, int it_shift, qemu_irq irq, diff --git a/include/hw/sparc/grlib.h b/include/hw/sparc/grlib.h index 470ce72250..9a0db7b47b 100644 --- a/include/hw/sparc/grlib.h +++ b/include/hw/sparc/grlib.h @@ -55,9 +55,7 @@ DeviceState *grlib_irqmp_create(hwaddr base, qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in); qdev_prop_set_ptr(dev, "set_pil_in_opaque", env); - if (qdev_init(dev)) { - return NULL; - } + qdev_init_nofail(dev); env->irq_manager = dev; @@ -87,9 +85,7 @@ DeviceState *grlib_gptimer_create(hwaddr base, qdev_prop_set_uint32(dev, "frequency", freq); qdev_prop_set_uint32(dev, "irq-line", base_irq); - if (qdev_init(dev)) { - return NULL; - } + qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); @@ -112,9 +108,7 @@ DeviceState *grlib_apbuart_create(hwaddr base, dev = qdev_create(NULL, "grlib,apbuart"); qdev_prop_set_chr(dev, "chrdev", serial); - if (qdev_init(dev)) { - return NULL; - } + qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 5f3679b7b2..0d1fb805bb 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -36,7 +36,6 @@ #endif /* Extra debugging, trap acceleration paths for more logging */ -#define VFIO_ALLOW_MMAP 1 #define VFIO_ALLOW_KVM_INTX 1 #define VFIO_ALLOW_KVM_MSI 1 #define VFIO_ALLOW_KVM_MSIX 1 @@ -102,6 +101,7 @@ typedef struct VFIODevice { int type; bool reset_works; bool needs_reset; + bool allow_mmap; VFIODeviceOps *ops; unsigned int num_irqs; unsigned int num_regions; @@ -131,7 +131,6 @@ void vfio_region_write(void *opaque, hwaddr addr, uint64_t data, unsigned size); uint64_t vfio_region_read(void *opaque, hwaddr addr, unsigned size); -void vfio_listener_release(VFIOContainer *container); int vfio_mmap_region(Object *vdev, VFIORegion *region, MemoryRegion *mem, MemoryRegion *submem, void **map, size_t size, off_t offset, @@ -143,7 +142,6 @@ int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vbasedev); extern const MemoryRegionOps vfio_region_ops; -extern const MemoryListener vfio_memory_listener; extern QLIST_HEAD(vfio_group_head, VFIOGroup) vfio_group_list; extern QLIST_HEAD(vfio_as_head, VFIOAddressSpace) vfio_address_spaces; diff --git a/include/qemu-common.h b/include/qemu-common.h index 644b46dcdd..1b5cffb403 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -418,6 +418,9 @@ static inline bool is_power_of_2(uint64_t value) /* round down to the nearest power of 2*/ int64_t pow2floor(int64_t value); +/* round up to the nearest power of 2 (0 if overflow) */ +uint64_t pow2ceil(uint64_t value); + #include "qemu/module.h" /* diff --git a/include/qemu/option.h b/include/qemu/option.h index 58c0157ed5..f88b545dfc 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -94,11 +94,12 @@ uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name, uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, uint64_t defval); int qemu_opt_unset(QemuOpts *opts, const char *name); -int qemu_opt_set(QemuOpts *opts, const char *name, const char *value); -void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, - Error **errp); -int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val); -int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val); +void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, + Error **errp); +void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, + Error **errp); +void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, + Error **errp); typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque); int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, int abort_on_failure); @@ -108,13 +109,14 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists, Error **errp); void qemu_opts_reset(QemuOptsList *list); void qemu_opts_loc_restore(QemuOpts *opts); -int qemu_opts_set(QemuOptsList *list, const char *id, - const char *name, const char *value); +void qemu_opts_set(QemuOptsList *list, const char *id, + const char *name, const char *value, Error **errp); const char *qemu_opts_id(QemuOpts *opts); void qemu_opts_set_id(QemuOpts *opts, char *id); void qemu_opts_del(QemuOpts *opts); void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp); -int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname); +void qemu_opts_do_parse(QemuOpts *opts, const char *params, + const char *firstname, Error **errp); QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev); void qemu_opts_set_defaults(QemuOptsList *list, const char *params, int permit_abbrev); diff --git a/include/qom/object.h b/include/qom/object.h index 89c3092967..87575735fe 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -273,7 +273,7 @@ typedef struct InterfaceInfo InterfaceInfo; * .name = TYPE_DERIVED, * .parent = TYPE_MY, * .class_size = sizeof(DerivedClass), - * .class_init = my_class_init, + * .class_init = derived_class_init, * }; * </programlisting> * </example> diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h new file mode 100644 index 0000000000..5633b856a8 --- /dev/null +++ b/include/sysemu/numa.h @@ -0,0 +1,24 @@ +#ifndef SYSEMU_NUMA_H +#define SYSEMU_NUMA_H + +#include <stdint.h> +#include "qemu/bitmap.h" +#include "qemu/option.h" +#include "sysemu/sysemu.h" +#include "sysemu/hostmem.h" + +extern int nb_numa_nodes; /* Number of NUMA nodes */ + +typedef struct node_info { + uint64_t node_mem; + DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS); + struct HostMemoryBackend *node_memdev; + bool present; +} NodeInfo; +extern NodeInfo numa_info[MAX_NODES]; +void parse_numa_opts(void); +void numa_post_machine_init(void); +void query_numa_node_mem(uint64_t node_mem[]); +extern QemuOptsList qemu_numa_opts; + +#endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index e7135e1ccc..6e8509735a 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -144,24 +144,6 @@ extern int mem_prealloc; */ #define MAX_CPUMASK_BITS 255 -extern int nb_numa_nodes; /* Number of NUMA nodes */ -extern int max_numa_nodeid; /* Highest specified NUMA node ID, plus one. - * For all nodes, nodeid < max_numa_nodeid - */ - -typedef struct node_info { - uint64_t node_mem; - DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS); - struct HostMemoryBackend *node_memdev; - bool present; -} NodeInfo; -extern NodeInfo numa_info[MAX_NODES]; -void set_numa_nodes(void); -void set_numa_modes(void); -void query_numa_node_mem(uint64_t node_mem[]); -extern QemuOptsList qemu_numa_opts; -int numa_init_func(QemuOpts *opts, void *opaque); - #define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom { const char *name; diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 0f21aa6266..95ba870302 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -333,6 +333,7 @@ enum { VFIO_PCI_MSI_IRQ_INDEX, VFIO_PCI_MSIX_IRQ_INDEX, VFIO_PCI_ERR_IRQ_INDEX, + VFIO_PCI_REQ_IRQ_INDEX, VFIO_PCI_NUM_IRQS }; diff --git a/migration/rdma.c b/migration/rdma.c index 6bee30c6c1..17d00351b1 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -510,7 +510,7 @@ static inline uint8_t *ram_chunk_end(const RDMALocalBlock *rdma_ram_block, return result; } -static int __qemu_rdma_add_block(RDMAContext *rdma, void *host_addr, +static int rdma_add_block(RDMAContext *rdma, void *host_addr, ram_addr_t block_offset, uint64_t length) { RDMALocalBlocks *local = &rdma->local_ram_blocks; @@ -551,13 +551,12 @@ static int __qemu_rdma_add_block(RDMAContext *rdma, void *host_addr, g_hash_table_insert(rdma->blockmap, (void *) block_offset, block); - trace___qemu_rdma_add_block(local->nb_blocks, - (uint64_t) block->local_host_addr, block->offset, - block->length, - (uint64_t) (block->local_host_addr + block->length), - BITS_TO_LONGS(block->nb_chunks) * - sizeof(unsigned long) * 8, - block->nb_chunks); + trace_rdma_add_block(local->nb_blocks, (uint64_t) block->local_host_addr, + block->offset, block->length, + (uint64_t) (block->local_host_addr + block->length), + BITS_TO_LONGS(block->nb_chunks) * + sizeof(unsigned long) * 8, + block->nb_chunks); local->nb_blocks++; @@ -572,7 +571,7 @@ static int __qemu_rdma_add_block(RDMAContext *rdma, void *host_addr, static void qemu_rdma_init_one_block(void *host_addr, ram_addr_t block_offset, ram_addr_t length, void *opaque) { - __qemu_rdma_add_block(opaque, host_addr, block_offset, length); + rdma_add_block(opaque, host_addr, block_offset, length); } /* @@ -595,7 +594,7 @@ static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) return 0; } -static int __qemu_rdma_delete_block(RDMAContext *rdma, ram_addr_t block_offset) +static int rdma_delete_block(RDMAContext *rdma, ram_addr_t block_offset) { RDMALocalBlocks *local = &rdma->local_ram_blocks; RDMALocalBlock *block = g_hash_table_lookup(rdma->blockmap, @@ -657,7 +656,7 @@ static int __qemu_rdma_delete_block(RDMAContext *rdma, ram_addr_t block_offset) local->block = NULL; } - trace___qemu_rdma_delete_block(local->nb_blocks, + trace_rdma_delete_block(local->nb_blocks, (uint64_t)block->local_host_addr, block->offset, block->length, (uint64_t)(block->local_host_addr + block->length), @@ -2187,8 +2186,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) if (rdma->local_ram_blocks.block) { while (rdma->local_ram_blocks.nb_blocks) { - __qemu_rdma_delete_block(rdma, - rdma->local_ram_blocks.block->offset); + rdma_delete_block(rdma, rdma->local_ram_blocks.block->offset); } } @@ -35,6 +35,7 @@ #include "sysemu/char.h" #include "ui/qemu-spice.h" #include "sysemu/sysemu.h" +#include "sysemu/numa.h" #include "monitor/monitor.h" #include "qemu/readline.h" #include "ui/console.h" @@ -1094,12 +1095,13 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, const char *subject = qdict_get_try_str(qdict, "cert-subject"); int port = qdict_get_try_int(qdict, "port", -1); int tls_port = qdict_get_try_int(qdict, "tls-port", -1); - Error *err; + Error *err = NULL; int ret; if (strcmp(protocol, "spice") == 0) { if (!qemu_using_spice(&err)) { qerror_report_err(err); + error_free(err); return -1; } @@ -970,7 +970,7 @@ void hmp_host_net_add(Monitor *mon, const QDict *qdict) return; } - qemu_opt_set(opts, "type", device); + qemu_opt_set(opts, "type", device, &error_abort); net_client_init(opts, 0, &local_err); if (local_err) { @@ -1296,9 +1296,9 @@ int net_init_clients(void) if (default_net) { /* if no clients, we use a default config */ - qemu_opts_set(net, NULL, "type", "nic"); + qemu_opts_set(net, NULL, "type", "nic", &error_abort); #ifdef CONFIG_SLIRP - qemu_opts_set(net, NULL, "type", "user"); + qemu_opts_set(net, NULL, "type", "user", &error_abort); #endif } @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysemu/sysemu.h" +#include "sysemu/numa.h" #include "exec/cpu-common.h" #include "qemu/bitmap.h" #include "qom/cpu.h" @@ -36,6 +36,8 @@ #include "sysemu/hostmem.h" #include "qmp-commands.h" #include "hw/mem/pc-dimm.h" +#include "qemu/option.h" +#include "qemu/config-file.h" QemuOptsList qemu_numa_opts = { .name = "numa", @@ -45,6 +47,11 @@ QemuOptsList qemu_numa_opts = { }; static int have_memdevs = -1; +static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one. + * For all nodes, nodeid < max_numa_nodeid + */ +int nb_numa_nodes; +NodeInfo numa_info[MAX_NODES]; static void numa_node_parse(NumaNodeOptions *node, QemuOpts *opts, Error **errp) { @@ -116,7 +123,7 @@ static void numa_node_parse(NumaNodeOptions *node, QemuOpts *opts, Error **errp) max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1); } -int numa_init_func(QemuOpts *opts, void *opaque) +static int parse_numa(QemuOpts *opts, void *opaque) { NumaOptions *object = NULL; Error *err = NULL; @@ -158,10 +165,15 @@ error: return -1; } -void set_numa_nodes(void) +void parse_numa_opts(void) { int i; + if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, + NULL, 1) != 0) { + exit(1); + } + assert(max_numa_nodeid <= MAX_NODES); /* No support for sparse NUMA node IDs yet: */ @@ -233,7 +245,7 @@ void set_numa_nodes(void) } } -void set_numa_modes(void) +void numa_post_machine_init(void) { CPUState *cpu; int i; diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin Binary files differindex fab9da2b3f..1c3f4021fc 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex 8c718e1b92..3724535de9 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin Binary files differindex 0c4d25346b..09dd0fa19c 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin Binary files differindex 4e08e1362d..92f22bf48c 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin Binary files differindex e5e5b14e4d..73c3468e20 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin Binary files differindex cf2576d344..86f9f7e823 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin Binary files differindex bad187dc2e..de3226e7aa 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin diff --git a/qdev-monitor.c b/qdev-monitor.c index 0c25b823f2..5d30ac534c 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -772,8 +772,8 @@ int qemu_global_option(const char *str) } opts = qemu_opts_create(&qemu_global_opts, NULL, 0, &error_abort); - qemu_opt_set(opts, "driver", driver); - qemu_opt_set(opts, "property", property); - qemu_opt_set(opts, "value", str+offset+1); + qemu_opt_set(opts, "driver", driver, &error_abort); + qemu_opt_set(opts, "property", property, &error_abort); + qemu_opt_set(opts, "value", str + offset + 1, &error_abort); return 0; } diff --git a/qemu-char.c b/qemu-char.c index 8159462fc0..a405d76c31 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3312,14 +3312,14 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (strstart(filename, "mon:", &p)) { filename = p; - qemu_opt_set(opts, "mux", "on"); + qemu_opt_set(opts, "mux", "on", &error_abort); if (strcmp(filename, "stdio") == 0) { /* Monitor is muxed to stdio: do not exit on Ctrl+C by default * but pass it to the guest. Handle this only for compat syntax, * for -chardev syntax we have special option for this. * This is what -nographic did, redirecting+muxing serial+monitor * to stdio causing Ctrl+C to be passed to guest. */ - qemu_opt_set(opts, "signal", "off"); + qemu_opt_set(opts, "signal", "off", &error_abort); } } @@ -3329,20 +3329,20 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) strcmp(filename, "braille") == 0 || strcmp(filename, "testdev") == 0 || strcmp(filename, "stdio") == 0) { - qemu_opt_set(opts, "backend", filename); + qemu_opt_set(opts, "backend", filename, &error_abort); return opts; } if (strstart(filename, "vc", &p)) { - qemu_opt_set(opts, "backend", "vc"); + qemu_opt_set(opts, "backend", "vc", &error_abort); if (*p == ':') { if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) { /* pixels */ - qemu_opt_set(opts, "width", width); - qemu_opt_set(opts, "height", height); + qemu_opt_set(opts, "width", width, &error_abort); + qemu_opt_set(opts, "height", height, &error_abort); } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) { /* chars */ - qemu_opt_set(opts, "cols", width); - qemu_opt_set(opts, "rows", height); + qemu_opt_set(opts, "cols", width, &error_abort); + qemu_opt_set(opts, "rows", height, &error_abort); } else { goto fail; } @@ -3350,22 +3350,22 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) return opts; } if (strcmp(filename, "con:") == 0) { - qemu_opt_set(opts, "backend", "console"); + qemu_opt_set(opts, "backend", "console", &error_abort); return opts; } if (strstart(filename, "COM", NULL)) { - qemu_opt_set(opts, "backend", "serial"); - qemu_opt_set(opts, "path", filename); + qemu_opt_set(opts, "backend", "serial", &error_abort); + qemu_opt_set(opts, "path", filename, &error_abort); return opts; } if (strstart(filename, "file:", &p)) { - qemu_opt_set(opts, "backend", "file"); - qemu_opt_set(opts, "path", p); + qemu_opt_set(opts, "backend", "file", &error_abort); + qemu_opt_set(opts, "path", p, &error_abort); return opts; } if (strstart(filename, "pipe:", &p)) { - qemu_opt_set(opts, "backend", "pipe"); - qemu_opt_set(opts, "path", p); + qemu_opt_set(opts, "backend", "pipe", &error_abort); + qemu_opt_set(opts, "path", p, &error_abort); return opts; } if (strstart(filename, "tcp:", &p) || @@ -3375,27 +3375,30 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) goto fail; } - qemu_opt_set(opts, "backend", "socket"); - qemu_opt_set(opts, "host", host); - qemu_opt_set(opts, "port", port); + qemu_opt_set(opts, "backend", "socket", &error_abort); + qemu_opt_set(opts, "host", host, &error_abort); + qemu_opt_set(opts, "port", port, &error_abort); if (p[pos] == ',') { - if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0) + qemu_opts_do_parse(opts, p+pos+1, NULL, &local_err); + if (local_err) { + error_report_err(local_err); goto fail; + } } if (strstart(filename, "telnet:", &p)) - qemu_opt_set(opts, "telnet", "on"); + qemu_opt_set(opts, "telnet", "on", &error_abort); return opts; } if (strstart(filename, "udp:", &p)) { - qemu_opt_set(opts, "backend", "udp"); + qemu_opt_set(opts, "backend", "udp", &error_abort); if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) { goto fail; } } - qemu_opt_set(opts, "host", host); - qemu_opt_set(opts, "port", port); + qemu_opt_set(opts, "host", host, &error_abort); + qemu_opt_set(opts, "port", port, &error_abort); if (p[pos] == '@') { p += pos + 1; if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { @@ -3404,26 +3407,29 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) goto fail; } } - qemu_opt_set(opts, "localaddr", host); - qemu_opt_set(opts, "localport", port); + qemu_opt_set(opts, "localaddr", host, &error_abort); + qemu_opt_set(opts, "localport", port, &error_abort); } return opts; } if (strstart(filename, "unix:", &p)) { - qemu_opt_set(opts, "backend", "socket"); - if (qemu_opts_do_parse(opts, p, "path") != 0) + qemu_opt_set(opts, "backend", "socket", &error_abort); + qemu_opts_do_parse(opts, p, "path", &local_err); + if (local_err) { + error_report_err(local_err); goto fail; + } return opts; } if (strstart(filename, "/dev/parport", NULL) || strstart(filename, "/dev/ppi", NULL)) { - qemu_opt_set(opts, "backend", "parport"); - qemu_opt_set(opts, "path", filename); + qemu_opt_set(opts, "backend", "parport", &error_abort); + qemu_opt_set(opts, "path", filename, &error_abort); return opts; } if (strstart(filename, "/dev/", NULL)) { - qemu_opt_set(opts, "backend", "tty"); - qemu_opt_set(opts, "path", filename); + qemu_opt_set(opts, "backend", "tty", &error_abort); + qemu_opt_set(opts, "path", filename, &error_abort); return opts; } diff --git a/qemu-img.c b/qemu-img.c index fcdfb6719e..7ac7f56c5d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -332,17 +332,23 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, const char *base_filename, const char *base_fmt) { + Error *err = NULL; + if (base_filename) { - if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename)) { + qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename, &err); + if (err) { error_report("Backing file not supported for file format '%s'", fmt); + error_free(err); return -1; } } if (base_fmt) { - if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) { + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, &err); + if (err) { error_report("Backing file format not supported for file " "format '%s'", fmt); + error_free(err); return -1; } } @@ -1544,13 +1550,18 @@ static int img_convert(int argc, char **argv) create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); - if (options && qemu_opts_do_parse(opts, options, NULL)) { - error_report("Invalid options for file format '%s'", out_fmt); - ret = -1; - goto out; + if (options) { + qemu_opts_do_parse(opts, options, NULL, &local_err); + if (local_err) { + error_report("Invalid options for file format '%s'", out_fmt); + error_free(local_err); + ret = -1; + goto out; + } } - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512, + &error_abort); ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL); if (ret < 0) { goto out; @@ -2749,6 +2760,7 @@ out: static int img_resize(int argc, char **argv) { + Error *err = NULL; int c, ret, relative; const char *filename, *fmt, *size; int64_t n, total_size; @@ -2820,8 +2832,9 @@ static int img_resize(int argc, char **argv) /* Parse size */ param = qemu_opts_create(&resize_options, NULL, 0, &error_abort); - if (qemu_opt_set(param, BLOCK_OPT_SIZE, size)) { - /* Error message already printed when size parsing fails */ + qemu_opt_set(param, BLOCK_OPT_SIZE, size, &err); + if (err) { + error_report_err(err); ret = -1; qemu_opts_del(param); goto out; @@ -2878,6 +2891,7 @@ static void amend_status_cb(BlockDriverState *bs, static int img_amend(int argc, char **argv) { + Error *err = NULL; int c, ret = 0; char *options = NULL; QemuOptsList *create_opts = NULL; @@ -2983,10 +2997,14 @@ static int img_amend(int argc, char **argv) create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); - if (options && qemu_opts_do_parse(opts, options, NULL)) { - error_report("Invalid options for file format '%s'", fmt); - ret = -1; - goto out; + if (options) { + qemu_opts_do_parse(opts, options, NULL, &err); + if (err) { + error_report("Invalid options for file format '%s'", fmt); + error_free(err); + ret = -1; + goto out; + } } /* In case the driver does not call amend_status_cb() */ diff --git a/qemu-options.hx b/qemu-options.hx index 85ca3ad55b..b0345aebca 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -237,12 +237,24 @@ DEF("m", HAS_ARG, QEMU_OPTION_m, "NOTE: Some architectures might enforce a specific granularity\n", QEMU_ARCH_ALL) STEXI -@item -m [size=]@var{megs} +@item -m [size=]@var{megs}[,slots=n,maxmem=size] @findex -m -Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally, -a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or -gigabytes respectively. Optional pair @var{slots}, @var{maxmem} could be used -to set amount of hotluggable memory slots and possible maximum amount of memory. +Sets guest startup RAM size to @var{megs} megabytes. Default is 128 MiB. +Optionally, a suffix of ``M'' or ``G'' can be used to signify a value in +megabytes or gigabytes respectively. Optional pair @var{slots}, @var{maxmem} +could be used to set amount of hotpluggable memory slots and maximum amount of +memory. Note that @var{maxmem} must be aligned to the page size. + +For example, the following command-line sets the guest startup RAM size to +1GB, creates 3 slots to hotplug additional memory and sets the maximum +memory the guest can reach to 4GB: + +@example +qemu-system-x86_64 -m 1G,slots=3,maxmem=4G +@end example + +If @var{slots} and @var{maxmem} are not specified, memory hotplug won't +be enabled and the guest startup RAM will never increase. ETEXI DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath, @@ -520,16 +520,13 @@ static void qtest_event(void *opaque, int event) } } -static void configure_qtest_icount(const char *options) +static int qtest_init_accel(MachineState *ms) { - QemuOpts *opts = qemu_opts_parse(qemu_find_opts("icount"), options, 1); + QemuOpts *opts = qemu_opts_create(qemu_find_opts("icount"), NULL, 0, + &error_abort); + qemu_opt_set(opts, "shift", "0", &error_abort); configure_icount(opts, &error_abort); qemu_opts_del(opts); -} - -static int qtest_init_accel(MachineState *ms) -{ - configure_qtest_icount("0"); return 0; } diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k index e653c75f5d..c719ba6892 100644 --- a/roms/config.seabios-128k +++ b/roms/config.seabios-128k @@ -5,3 +5,4 @@ CONFIG_ROM_SIZE=128 CONFIG_XEN=n CONFIG_USB_XHCI=n CONFIG_USB_UAS=n +CONFIG_SDCARD=n diff --git a/roms/seabios b/roms/seabios -Subproject 8936dbb2cd5403c9a8279c849f7f4b0ccc0796a +Subproject 4c59f5d83044df4d57b90958b0fdfcecb913fdd diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh index 7242707819..7958086132 100644 --- a/scripts/make_device_config.sh +++ b/scripts/make_device_config.sh @@ -2,7 +2,7 @@ # Construct a target device config file from a default, pulling in any # files from include directives. -dest=$1.tmp +dest=$1 dep=`dirname $1`-`basename $1`.d src=$2 src_dir=`dirname $src` diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 1eb272dd26..db872180c6 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -123,16 +123,19 @@ const char *%(name)s_lookup[] = { name=name) i = 0 for value in values: + index = generate_enum_full_value(name, value) ret += mcgen(''' - "%(value)s", + [%(index)s] = "%(value)s", ''', - value=value) + index = index, value = value) + max_index = generate_enum_full_value(name, 'MAX') ret += mcgen(''' - NULL, + [%(max_index)s] = NULL, }; -''') +''', + max_index=max_index) return ret def generate_enum(name, values): diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py index 46eebb128b..c77d5b7ab0 100644 --- a/scripts/tracetool/format/d.py +++ b/scripts/tracetool/format/d.py @@ -16,6 +16,19 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out +# Reserved keywords from +# https://wikis.oracle.com/display/DTrace/Types,+Operators+and+Expressions +RESERVED_WORDS = ( + 'auto', 'goto', 'sizeof', 'break', 'if', 'static', 'case', 'import', + 'string', 'char', 'inline', 'stringof', 'const', 'int', 'struct', + 'continue', 'long', 'switch', 'counter', 'offsetof', 'this', + 'default', 'probe', 'translator', 'do', 'provider', 'typedef', + 'double', 'register', 'union', 'else', 'restrict', 'unsigned', + 'enum', 'return', 'void', 'extern', 'self', 'volatile', 'float', + 'short', 'while', 'for', 'signed', 'xlate', +) + + def generate(events, backend): events = [e for e in events if "disable" not in e.properties] @@ -25,18 +38,17 @@ def generate(events, backend): 'provider qemu {') for e in events: - args = str(e.args) - - # DTrace provider syntax expects foo() for empty - # params, not foo(void) - if args == 'void': - args = '' + args = [] + for type_, name in e.args: + if name in RESERVED_WORDS: + name += '_' + args.append(type_ + ' ' + name) # Define prototype for probe arguments out('', 'probe %(name)s(%(args)s);', name=e.name, - args=args) + args=','.join(args)) out('', '};') diff --git a/stubs/qmp_pc_dimm_device_list.c b/stubs/qmp_pc_dimm_device_list.c index 5cb220c66c..b584bd8b24 100644 --- a/stubs/qmp_pc_dimm_device_list.c +++ b/stubs/qmp_pc_dimm_device_list.c @@ -5,3 +5,8 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque) { return 0; } + +ram_addr_t get_current_ram_size(void) +{ + return ram_size; +} diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 7405feee88..4c823460e1 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -17,9 +17,12 @@ /* Arithmetic */ DEF_HELPER_3(add_ssov, i32, env, i32, i32) +DEF_HELPER_3(add64_ssov, i64, env, i64, i64) DEF_HELPER_3(add_suov, i32, env, i32, i32) DEF_HELPER_3(add_h_ssov, i32, env, i32, i32) DEF_HELPER_3(add_h_suov, i32, env, i32, i32) +DEF_HELPER_4(addr_h_ssov, i32, env, i64, i32, i32) +DEF_HELPER_4(addsur_h_ssov, i32, env, i64, i32, i32) DEF_HELPER_3(sub_ssov, i32, env, i32, i32) DEF_HELPER_3(sub_suov, i32, env, i32, i32) DEF_HELPER_3(sub_h_ssov, i32, env, i32, i32) @@ -31,6 +34,9 @@ DEF_HELPER_3(absdif_ssov, i32, env, i32, i32) DEF_HELPER_4(madd32_ssov, i32, env, i32, i32, i32) DEF_HELPER_4(madd32_suov, i32, env, i32, i32, i32) DEF_HELPER_4(madd64_ssov, i64, env, i32, i64, i32) +DEF_HELPER_5(madd64_q_ssov, i64, env, i64, i32, i32, i32) +DEF_HELPER_3(madd32_q_add_ssov, i32, env, i64, i64) +DEF_HELPER_5(maddr_q_ssov, i32, env, i32, i32, i32, i32) DEF_HELPER_4(madd64_suov, i64, env, i32, i64, i32) DEF_HELPER_4(msub32_ssov, i32, env, i32, i32, i32) DEF_HELPER_4(msub32_suov, i32, env, i32, i32, i32) @@ -44,6 +50,9 @@ DEF_HELPER_2(abs_b, i32, env, i32) DEF_HELPER_2(abs_h, i32, env, i32) DEF_HELPER_3(absdif_b, i32, env, i32, i32) DEF_HELPER_3(absdif_h, i32, env, i32, i32) +DEF_HELPER_4(addr_h, i32, env, i64, i32, i32) +DEF_HELPER_4(addsur_h, i32, env, i64, i32, i32) +DEF_HELPER_5(maddr_q, i32, env, i32, i32, i32, i32) DEF_HELPER_3(add_b, i32, env, i32, i32) DEF_HELPER_3(add_h, i32, env, i32, i32) DEF_HELPER_3(sub_b, i32, env, i32, i32) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index ed26b302b0..40d32af5d3 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -184,6 +184,31 @@ target_ulong helper_add_ssov(CPUTriCoreState *env, target_ulong r1, return ssov32(env, result); } +uint64_t helper_add64_ssov(CPUTriCoreState *env, uint64_t r1, uint64_t r2) +{ + uint64_t result; + int64_t ovf; + + result = r1 + r2; + ovf = (result ^ r1) & ~(r1 ^ r2); + env->PSW_USB_AV = (result ^ result * 2u) >> 32; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if (ovf < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* ext_ret > MAX_INT */ + if ((int64_t)r1 >= 0) { + result = INT64_MAX; + /* ext_ret < MIN_INT */ + } else { + result = INT64_MIN; + } + } else { + env->PSW_USB_V = 0; + } + return result; +} + target_ulong helper_add_h_ssov(CPUTriCoreState *env, target_ulong r1, target_ulong r2) { @@ -194,6 +219,99 @@ target_ulong helper_add_h_ssov(CPUTriCoreState *env, target_ulong r1, return ssov16(env, ret_hw0, ret_hw1); } +uint32_t helper_addr_h_ssov(CPUTriCoreState *env, uint64_t r1, uint32_t r2_l, + uint32_t r2_h) +{ + int64_t mul_res0 = sextract64(r1, 0, 32); + int64_t mul_res1 = sextract64(r1, 32, 32); + int64_t r2_low = sextract64(r2_l, 0, 32); + int64_t r2_high = sextract64(r2_h, 0, 32); + int64_t result0, result1; + uint32_t ovf0, ovf1; + uint32_t avf0, avf1; + + ovf0 = ovf1 = 0; + + result0 = r2_low + mul_res0 + 0x8000; + result1 = r2_high + mul_res1 + 0x8000; + + avf0 = result0 * 2u; + avf0 = result0 ^ avf0; + avf1 = result1 * 2u; + avf1 = result1 ^ avf1; + + if (result0 > INT32_MAX) { + ovf0 = (1 << 31); + result0 = INT32_MAX; + } else if (result0 < INT32_MIN) { + ovf0 = (1 << 31); + result0 = INT32_MIN; + } + + if (result1 > INT32_MAX) { + ovf1 = (1 << 31); + result1 = INT32_MAX; + } else if (result1 < INT32_MIN) { + ovf1 = (1 << 31); + result1 = INT32_MIN; + } + + env->PSW_USB_V = ovf0 | ovf1; + env->PSW_USB_SV |= env->PSW_USB_V; + + env->PSW_USB_AV = avf0 | avf1; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return (result1 & 0xffff0000ULL) | ((result0 >> 16) & 0xffffULL); +} + +uint32_t helper_addsur_h_ssov(CPUTriCoreState *env, uint64_t r1, uint32_t r2_l, + uint32_t r2_h) +{ + int64_t mul_res0 = sextract64(r1, 0, 32); + int64_t mul_res1 = sextract64(r1, 32, 32); + int64_t r2_low = sextract64(r2_l, 0, 32); + int64_t r2_high = sextract64(r2_h, 0, 32); + int64_t result0, result1; + uint32_t ovf0, ovf1; + uint32_t avf0, avf1; + + ovf0 = ovf1 = 0; + + result0 = r2_low - mul_res0 + 0x8000; + result1 = r2_high + mul_res1 + 0x8000; + + avf0 = result0 * 2u; + avf0 = result0 ^ avf0; + avf1 = result1 * 2u; + avf1 = result1 ^ avf1; + + if (result0 > INT32_MAX) { + ovf0 = (1 << 31); + result0 = INT32_MAX; + } else if (result0 < INT32_MIN) { + ovf0 = (1 << 31); + result0 = INT32_MIN; + } + + if (result1 > INT32_MAX) { + ovf1 = (1 << 31); + result1 = INT32_MAX; + } else if (result1 < INT32_MIN) { + ovf1 = (1 << 31); + result1 = INT32_MIN; + } + + env->PSW_USB_V = ovf0 | ovf1; + env->PSW_USB_SV |= env->PSW_USB_V; + + env->PSW_USB_AV = avf0 | avf1; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return (result1 & 0xffff0000ULL) | ((result0 >> 16) & 0xffffULL); +} + + target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1, target_ulong r2) { @@ -403,6 +521,131 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, return ret; } +uint32_t +helper_madd32_q_add_ssov(CPUTriCoreState *env, uint64_t r1, uint64_t r2) +{ + int64_t result; + + result = (r1 + r2); + + env->PSW_USB_AV = (result ^ result * 2u); + env->PSW_USB_SAV |= env->PSW_USB_AV; + + /* we do the saturation by hand, since we produce an overflow on the host + if the mul before was (0x80000000 * 0x80000000) << 1). If this is the + case, we flip the saturated value. */ + if (r2 == 0x8000000000000000LL) { + if (result > 0x7fffffffLL) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + result = INT32_MIN; + } else if (result < -0x80000000LL) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + result = INT32_MAX; + } else { + env->PSW_USB_V = 0; + } + } else { + if (result > 0x7fffffffLL) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + result = INT32_MAX; + } else if (result < -0x80000000LL) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + result = INT32_MIN; + } else { + env->PSW_USB_V = 0; + } + } + return (uint32_t)result; +} + +uint64_t helper_madd64_q_ssov(CPUTriCoreState *env, uint64_t r1, uint32_t r2, + uint32_t r3, uint32_t n) +{ + int64_t t1 = (int64_t)r1; + int64_t t2 = sextract64(r2, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t result, mul; + int64_t ovf; + + mul = (t2 * t3) << n; + result = mul + t1; + + env->PSW_USB_AV = (result ^ result * 2u) >> 32; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + ovf = (result ^ mul) & ~(mul ^ t1); + /* we do the saturation by hand, since we produce an overflow on the host + if the mul was (0x80000000 * 0x80000000) << 1). If this is the + case, we flip the saturated value. */ + if ((r2 == 0x80000000) && (r3 == 0x80000000) && (n == 1)) { + if (ovf >= 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* ext_ret > MAX_INT */ + if (mul < 0) { + result = INT64_MAX; + /* ext_ret < MIN_INT */ + } else { + result = INT64_MIN; + } + } else { + env->PSW_USB_V = 0; + } + } else { + if (ovf < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + /* ext_ret > MAX_INT */ + if (mul >= 0) { + result = INT64_MAX; + /* ext_ret < MIN_INT */ + } else { + result = INT64_MIN; + } + } else { + env->PSW_USB_V = 0; + } + } + return (uint64_t)result; +} + +uint32_t helper_maddr_q_ssov(CPUTriCoreState *env, uint32_t r1, uint32_t r2, + uint32_t r3, uint32_t n) +{ + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t mul, ret; + + if ((t2 == -0x8000ll) && (t3 == -0x8000ll) && (n == 1)) { + mul = 0x7fffffff; + } else { + mul = (t2 * t3) << n; + } + + ret = t1 + mul + 0x8000; + + env->PSW_USB_AV = ret ^ ret * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + if (ret > 0x7fffffffll) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV |= env->PSW_USB_V; + ret = INT32_MAX; + } else if (ret < -0x80000000ll) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV |= env->PSW_USB_V; + ret = INT32_MIN; + } else { + env->PSW_USB_V = 0; + } + return ret & 0xffff0000ll; +} + uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, uint64_t r2, target_ulong r3) { @@ -443,13 +686,28 @@ target_ulong helper_msub32_ssov(CPUTriCoreState *env, target_ulong r1, target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1, target_ulong r2, target_ulong r3) { - int64_t t1 = extract64(r1, 0, 32); - int64_t t2 = extract64(r2, 0, 32); - int64_t t3 = extract64(r3, 0, 32); - int64_t result; + uint64_t t1 = extract64(r1, 0, 32); + uint64_t t2 = extract64(r2, 0, 32); + uint64_t t3 = extract64(r3, 0, 32); + uint64_t result; + uint64_t mul; - result = t2 - (t1 * t3); - return suov32_neg(env, result); + mul = (t1 * t3); + result = t2 - mul; + + env->PSW_USB_AV = result ^ result * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + /* we calculate ovf by hand here, because the multiplication can overflow on + the host, which would give false results if we compare to less than + zero */ + if (mul > t2) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + result = 0; + } else { + env->PSW_USB_V = 0; + } + return result; } uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, @@ -604,6 +862,110 @@ uint32_t helper_absdif_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2) return ret; } +uint32_t helper_addr_h(CPUTriCoreState *env, uint64_t r1, uint32_t r2_l, + uint32_t r2_h) +{ + int64_t mul_res0 = sextract64(r1, 0, 32); + int64_t mul_res1 = sextract64(r1, 32, 32); + int64_t r2_low = sextract64(r2_l, 0, 32); + int64_t r2_high = sextract64(r2_h, 0, 32); + int64_t result0, result1; + uint32_t ovf0, ovf1; + uint32_t avf0, avf1; + + ovf0 = ovf1 = 0; + + result0 = r2_low + mul_res0 + 0x8000; + result1 = r2_high + mul_res1 + 0x8000; + + if ((result0 > INT32_MAX) || (result0 < INT32_MIN)) { + ovf0 = (1 << 31); + } + + if ((result1 > INT32_MAX) || (result1 < INT32_MIN)) { + ovf1 = (1 << 31); + } + + env->PSW_USB_V = ovf0 | ovf1; + env->PSW_USB_SV |= env->PSW_USB_V; + + avf0 = result0 * 2u; + avf0 = result0 ^ avf0; + avf1 = result1 * 2u; + avf1 = result1 ^ avf1; + + env->PSW_USB_AV = avf0 | avf1; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return (result1 & 0xffff0000ULL) | ((result0 >> 16) & 0xffffULL); +} + +uint32_t helper_addsur_h(CPUTriCoreState *env, uint64_t r1, uint32_t r2_l, + uint32_t r2_h) +{ + int64_t mul_res0 = sextract64(r1, 0, 32); + int64_t mul_res1 = sextract64(r1, 32, 32); + int64_t r2_low = sextract64(r2_l, 0, 32); + int64_t r2_high = sextract64(r2_h, 0, 32); + int64_t result0, result1; + uint32_t ovf0, ovf1; + uint32_t avf0, avf1; + + ovf0 = ovf1 = 0; + + result0 = r2_low - mul_res0 + 0x8000; + result1 = r2_high + mul_res1 + 0x8000; + + if ((result0 > INT32_MAX) || (result0 < INT32_MIN)) { + ovf0 = (1 << 31); + } + + if ((result1 > INT32_MAX) || (result1 < INT32_MIN)) { + ovf1 = (1 << 31); + } + + env->PSW_USB_V = ovf0 | ovf1; + env->PSW_USB_SV |= env->PSW_USB_V; + + avf0 = result0 * 2u; + avf0 = result0 ^ avf0; + avf1 = result1 * 2u; + avf1 = result1 ^ avf1; + + env->PSW_USB_AV = avf0 | avf1; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return (result1 & 0xffff0000ULL) | ((result0 >> 16) & 0xffffULL); +} + +uint32_t helper_maddr_q(CPUTriCoreState *env, uint32_t r1, uint32_t r2, + uint32_t r3, uint32_t n) +{ + int64_t t1 = sextract64(r1, 0, 32); + int64_t t2 = sextract64(r2, 0, 32); + int64_t t3 = sextract64(r3, 0, 32); + int64_t mul, ret; + + if ((t2 == -0x8000ll) && (t3 == -0x8000ll) && (n == 1)) { + mul = 0x7fffffff; + } else { + mul = (t2 * t3) << n; + } + + ret = t1 + mul + 0x8000; + + if ((ret > 0x7fffffffll) || (ret < -0x80000000ll)) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV |= env->PSW_USB_V; + } else { + env->PSW_USB_V = 0; + } + env->PSW_USB_AV = ret ^ ret * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + + return ret & 0xffff0000ll; +} + uint32_t helper_add_b(CPUTriCoreState *env, target_ulong r1, target_ulong r2) { int32_t b, i; diff --git a/target-tricore/translate.c b/target-tricore/translate.c index 996435dbd0..f720cd7fc5 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -80,6 +80,13 @@ enum { BS_EXCP = 3, }; +enum { + MODE_LL = 0, + MODE_LU = 1, + MODE_UL = 2, + MODE_UU = 3, +}; + void tricore_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags) { @@ -395,6 +402,88 @@ static inline void gen_add_d(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(t0); } +static inline void +gen_add64_d(TCGv_i64 ret, TCGv_i64 r1, TCGv_i64 r2) +{ + TCGv temp = tcg_temp_new(); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 result = tcg_temp_new_i64(); + + tcg_gen_add_i64(result, r1, r2); + /* calc v bit */ + tcg_gen_xor_i64(t1, result, r1); + tcg_gen_xor_i64(t0, r1, r2); + tcg_gen_andc_i64(t1, t1, t0); + tcg_gen_trunc_shr_i64_i32(cpu_PSW_V, t1, 32); + /* calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* calc AV/SAV bits */ + tcg_gen_trunc_shr_i64_i32(temp, result, 32); + tcg_gen_add_tl(cpu_PSW_AV, temp, temp); + tcg_gen_xor_tl(cpu_PSW_AV, temp, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back result */ + tcg_gen_mov_i64(ret, result); + + tcg_temp_free(temp); + tcg_temp_free_i64(result); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static inline void +gen_addsub64_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, void(*op1)(TCGv, TCGv, TCGv), + void(*op2)(TCGv, TCGv, TCGv)) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv temp3 = tcg_temp_new(); + TCGv temp4 = tcg_temp_new(); + + (*op1)(temp, r1_low, r2); + /* calc V0 bit */ + tcg_gen_xor_tl(temp2, temp, r1_low); + tcg_gen_xor_tl(temp3, r1_low, r2); + if (op1 == tcg_gen_add_tl) { + tcg_gen_andc_tl(temp2, temp2, temp3); + } else { + tcg_gen_and_tl(temp2, temp2, temp3); + } + + (*op2)(temp3, r1_high, r3); + /* calc V1 bit */ + tcg_gen_xor_tl(cpu_PSW_V, temp3, r1_high); + tcg_gen_xor_tl(temp4, r1_high, r3); + if (op2 == tcg_gen_add_tl) { + tcg_gen_andc_tl(cpu_PSW_V, cpu_PSW_V, temp4); + } else { + tcg_gen_and_tl(cpu_PSW_V, cpu_PSW_V, temp4); + } + /* combine V0/V1 bits */ + tcg_gen_or_tl(cpu_PSW_V, cpu_PSW_V, temp2); + /* calc sv bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* write result */ + tcg_gen_mov_tl(ret_low, temp); + tcg_gen_mov_tl(ret_high, temp3); + /* calc AV bit */ + tcg_gen_add_tl(temp, ret_low, ret_low); + tcg_gen_xor_tl(temp, temp, ret_low); + tcg_gen_add_tl(cpu_PSW_AV, ret_high, ret_high); + tcg_gen_xor_tl(cpu_PSW_AV, cpu_PSW_AV, ret_high); + tcg_gen_or_tl(cpu_PSW_AV, cpu_PSW_AV, temp); + /* calc SAV bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(temp3); + tcg_temp_free(temp4); +} + /* ret = r2 + (r1 * r3); */ static inline void gen_madd32_d(TCGv ret, TCGv r1, TCGv r2, TCGv r3) { @@ -523,6 +612,694 @@ gen_maddui64_d(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, tcg_temp_free(temp); } +static inline void +gen_madd_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_extr_i64_i32(temp, temp2, temp64); + gen_addsub64_h(ret_low, ret_high, r1_low, r1_high, temp, temp2, + tcg_gen_add_tl, tcg_gen_add_tl); + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddsu_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_extr_i64_i32(temp, temp2, temp64); + gen_addsub64_h(ret_low, ret_high, r1_low, r1_high, temp, temp2, + tcg_gen_sub_tl, tcg_gen_add_tl); + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddsum_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + TCGv_i64 temp64_2 = tcg_temp_new_i64(); + TCGv_i64 temp64_3 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_concat_i32_i64(temp64_3, r1_low, r1_high); + tcg_gen_sari_i64(temp64_2, temp64, 32); /* high */ + tcg_gen_ext32s_i64(temp64, temp64); /* low */ + tcg_gen_sub_i64(temp64, temp64_2, temp64); + tcg_gen_shli_i64(temp64, temp64, 16); + + gen_add64_d(temp64_2, temp64_3, temp64); + /* write back result */ + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64_2); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); + tcg_temp_free_i64(temp64_2); + tcg_temp_free_i64(temp64_3); +} + +static inline void gen_adds(TCGv ret, TCGv r1, TCGv r2); + +static inline void +gen_madds_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv temp3 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_extr_i64_i32(temp, temp2, temp64); + gen_adds(ret_low, r1_low, temp); + tcg_gen_mov_tl(temp, cpu_PSW_V); + tcg_gen_mov_tl(temp3, cpu_PSW_AV); + gen_adds(ret_high, r1_high, temp2); + /* combine v bits */ + tcg_gen_or_tl(cpu_PSW_V, cpu_PSW_V, temp); + /* combine av bits */ + tcg_gen_or_tl(cpu_PSW_AV, cpu_PSW_AV, temp3); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(temp3); + tcg_temp_free_i64(temp64); + +} + +static inline void gen_subs(TCGv ret, TCGv r1, TCGv r2); + +static inline void +gen_maddsus_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv temp3 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_extr_i64_i32(temp, temp2, temp64); + gen_subs(ret_low, r1_low, temp); + tcg_gen_mov_tl(temp, cpu_PSW_V); + tcg_gen_mov_tl(temp3, cpu_PSW_AV); + gen_adds(ret_high, r1_high, temp2); + /* combine v bits */ + tcg_gen_or_tl(cpu_PSW_V, cpu_PSW_V, temp); + /* combine av bits */ + tcg_gen_or_tl(cpu_PSW_AV, cpu_PSW_AV, temp3); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(temp3); + tcg_temp_free_i64(temp64); + +} + +static inline void +gen_maddsums_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + TCGv_i64 temp64_2 = tcg_temp_new_i64(); + + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_sari_i64(temp64_2, temp64, 32); /* high */ + tcg_gen_ext32s_i64(temp64, temp64); /* low */ + tcg_gen_sub_i64(temp64, temp64_2, temp64); + tcg_gen_shli_i64(temp64, temp64, 16); + tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); + + gen_helper_add64_ssov(temp64, cpu_env, temp64_2, temp64); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); + tcg_temp_free_i64(temp64_2); +} + + +static inline void +gen_maddm_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + TCGv_i64 temp64_2 = tcg_temp_new_i64(); + TCGv_i64 temp64_3 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mulm_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mulm_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mulm_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mulm_h, temp64, r2, r3, temp); + break; + } + tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); + gen_add64_d(temp64_3, temp64_2, temp64); + /* write back result */ + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64_3); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); + tcg_temp_free_i64(temp64_2); + tcg_temp_free_i64(temp64_3); +} + +static inline void +gen_maddms_h(TCGv ret_low, TCGv ret_high, TCGv r1_low, TCGv r1_high, TCGv r2, + TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + TCGv_i64 temp64_2 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mulm_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mulm_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mulm_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mulm_h, temp64, r2, r3, temp); + break; + } + tcg_gen_concat_i32_i64(temp64_2, r1_low, r1_high); + gen_helper_add64_ssov(temp64, cpu_env, temp64_2, temp64); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); + tcg_temp_free_i64(temp64_2); +} + +static inline void +gen_maddr64_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, uint32_t n, + uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + gen_helper_addr_h(ret, cpu_env, temp64, r1_low, r1_high); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddr32_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + + tcg_gen_andi_tl(temp2, r1, 0xffff0000); + tcg_gen_shli_tl(temp, r1, 16); + gen_maddr64_h(ret, temp, temp2, r2, r3, n, mode); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_maddsur32_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_andi_tl(temp2, r1, 0xffff0000); + tcg_gen_shli_tl(temp, r1, 16); + gen_helper_addsur_h(ret, cpu_env, temp64, temp, temp2); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free_i64(temp64); +} + + +static inline void +gen_maddr64s_h(TCGv ret, TCGv r1_low, TCGv r1_high, TCGv r2, TCGv r3, + uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + gen_helper_addr_h_ssov(ret, cpu_env, temp64, r1_low, r1_high); + + tcg_temp_free(temp); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddr32s_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + + tcg_gen_andi_tl(temp2, r1, 0xffff0000); + tcg_gen_shli_tl(temp, r1, 16); + gen_maddr64s_h(ret, temp, temp2, r2, r3, n, mode); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_maddsur32s_h(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n, uint32_t mode) +{ + TCGv temp = tcg_const_i32(n); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 temp64 = tcg_temp_new_i64(); + switch (mode) { + case MODE_LL: + GEN_HELPER_LL(mul_h, temp64, r2, r3, temp); + break; + case MODE_LU: + GEN_HELPER_LU(mul_h, temp64, r2, r3, temp); + break; + case MODE_UL: + GEN_HELPER_UL(mul_h, temp64, r2, r3, temp); + break; + case MODE_UU: + GEN_HELPER_UU(mul_h, temp64, r2, r3, temp); + break; + } + tcg_gen_andi_tl(temp2, r1, 0xffff0000); + tcg_gen_shli_tl(temp, r1, 16); + gen_helper_addsur_h_ssov(ret, cpu_env, temp64, temp, temp2); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free_i64(temp64); +} + +static inline void +gen_maddr_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) +{ + TCGv temp = tcg_const_i32(n); + gen_helper_maddr_q(ret, cpu_env, r1, r2, r3, temp); + tcg_temp_free(temp); +} + +static inline void +gen_maddrs_q(TCGv ret, TCGv r1, TCGv r2, TCGv r3, uint32_t n) +{ + TCGv temp = tcg_const_i32(n); + gen_helper_maddr_q_ssov(ret, cpu_env, r1, r2, r3, temp); + tcg_temp_free(temp); +} + +static inline void +gen_madd32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n, + uint32_t up_shift, CPUTriCoreState *env) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv temp3 = tcg_temp_new(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(t2, arg2); + tcg_gen_ext_i32_i64(t3, arg3); + + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_shli_i64(t2, t2, n); + + tcg_gen_ext_i32_i64(t1, arg1); + tcg_gen_sari_i64(t2, t2, up_shift); + + tcg_gen_add_i64(t3, t1, t2); + tcg_gen_trunc_i64_i32(temp3, t3); + /* calc v bit */ + tcg_gen_setcondi_i64(TCG_COND_GT, t1, t3, 0x7fffffffLL); + tcg_gen_setcondi_i64(TCG_COND_LT, t2, t3, -0x80000000LL); + tcg_gen_or_i64(t1, t1, t2); + tcg_gen_trunc_i64_i32(cpu_PSW_V, t1); + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* We produce an overflow on the host if the mul before was + (0x80000000 * 0x80000000) << 1). If this is the + case, we negate the ovf. */ + if (n == 1) { + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, arg2, 0x80000000); + tcg_gen_setcond_tl(TCG_COND_EQ, temp2, arg2, arg3); + tcg_gen_and_tl(temp, temp, temp2); + tcg_gen_shli_tl(temp, temp, 31); + /* negate v bit, if special condition */ + tcg_gen_xor_tl(cpu_PSW_V, cpu_PSW_V, temp); + } + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, temp3, temp3); + tcg_gen_xor_tl(cpu_PSW_AV, temp3, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* write back result */ + tcg_gen_mov_tl(ret, temp3); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(temp3); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void +gen_m16add32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(temp, arg2, arg3); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(temp, arg2, arg3); + tcg_gen_shli_tl(temp, temp, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, temp, 0x80000000); + tcg_gen_sub_tl(temp, temp, temp2); + } + gen_add_d(ret, arg1, temp); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_m16adds32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(temp, arg2, arg3); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(temp, arg2, arg3); + tcg_gen_shli_tl(temp, temp, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, temp, 0x80000000); + tcg_gen_sub_tl(temp, temp, temp2); + } + gen_adds(ret, arg1, temp); + + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_m16add64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, + TCGv arg3, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + if (n == 0) { + tcg_gen_mul_tl(temp, arg2, arg3); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(temp, arg2, arg3); + tcg_gen_shli_tl(temp, temp, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, temp, 0x80000000); + tcg_gen_sub_tl(temp, temp, temp2); + } + tcg_gen_ext_i32_i64(t2, temp); + tcg_gen_shli_i64(t2, t2, 16); + tcg_gen_concat_i32_i64(t1, arg1_low, arg1_high); + gen_add64_d(t3, t1, t2); + /* write back result */ + tcg_gen_extr_i64_i32(rl, rh, t3); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static inline void +gen_m16adds64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, + TCGv arg3, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + + if (n == 0) { + tcg_gen_mul_tl(temp, arg2, arg3); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(temp, arg2, arg3); + tcg_gen_shli_tl(temp, temp, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp2, temp, 0x80000000); + tcg_gen_sub_tl(temp, temp, temp2); + } + tcg_gen_ext_i32_i64(t2, temp); + tcg_gen_shli_i64(t2, t2, 16); + tcg_gen_concat_i32_i64(t1, arg1_low, arg1_high); + + gen_helper_add64_ssov(t1, cpu_env, t1, t2); + tcg_gen_extr_i64_i32(rl, rh, t1); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); +} + +static inline void +gen_madd64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, + TCGv arg3, uint32_t n, CPUTriCoreState *env) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_temp_new_i64(); + TCGv temp, temp2; + + tcg_gen_concat_i32_i64(t1, arg1_low, arg1_high); + tcg_gen_ext_i32_i64(t2, arg2); + tcg_gen_ext_i32_i64(t3, arg3); + + tcg_gen_mul_i64(t2, t2, t3); + if (n != 0) { + tcg_gen_shli_i64(t2, t2, 1); + } + tcg_gen_add_i64(t4, t1, t2); + /* calc v bit */ + tcg_gen_xor_i64(t3, t4, t1); + tcg_gen_xor_i64(t2, t1, t2); + tcg_gen_andc_i64(t3, t3, t2); + tcg_gen_trunc_shr_i64_i32(cpu_PSW_V, t3, 32); + /* We produce an overflow on the host if the mul before was + (0x80000000 * 0x80000000) << 1). If this is the + case, we negate the ovf. */ + if (n == 1) { + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, arg2, 0x80000000); + tcg_gen_setcond_tl(TCG_COND_EQ, temp2, arg2, arg3); + tcg_gen_and_tl(temp, temp, temp2); + tcg_gen_shli_tl(temp, temp, 31); + /* negate v bit, if special condition */ + tcg_gen_xor_tl(cpu_PSW_V, cpu_PSW_V, temp); + + tcg_temp_free(temp); + tcg_temp_free(temp2); + } + /* write back result */ + tcg_gen_extr_i64_i32(rl, rh, t4); + /* Calc SV bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + /* Calc AV/SAV bits */ + tcg_gen_add_tl(cpu_PSW_AV, rh, rh); + tcg_gen_xor_tl(cpu_PSW_AV, rh, cpu_PSW_AV); + /* calc SAV */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); + tcg_temp_free_i64(t4); +} + +static inline void +gen_madds32_q(TCGv ret, TCGv arg1, TCGv arg2, TCGv arg3, uint32_t n, + uint32_t up_shift) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(t1, arg1); + tcg_gen_ext_i32_i64(t2, arg2); + tcg_gen_ext_i32_i64(t3, arg3); + + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_sari_i64(t2, t2, up_shift - n); + + gen_helper_madd32_q_add_ssov(ret, cpu_env, t1, t2); + + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); +} + +static inline void +gen_madds64_q(TCGv rl, TCGv rh, TCGv arg1_low, TCGv arg1_high, TCGv arg2, + TCGv arg3, uint32_t n) +{ + TCGv_i64 r1 = tcg_temp_new_i64(); + TCGv temp = tcg_const_i32(n); + + tcg_gen_concat_i32_i64(r1, arg1_low, arg1_high); + gen_helper_madd64_q_ssov(r1, cpu_env, r1, arg2, arg3, temp); + tcg_gen_extr_i64_i32(rl, rh, r1); + + tcg_temp_free_i64(r1); + tcg_temp_free(temp); +} /* ret = r2 - (r1 * r3); */ static inline void gen_msub32_d(TCGv ret, TCGv r1, TCGv r2, TCGv r3) { @@ -1152,15 +1929,33 @@ static void gen_mulr_q(TCGv ret, TCGv arg1, TCGv arg2, uint32_t n) } static inline void +gen_madds_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_madd64_ssov(temp64, cpu_env, r1, temp64, r3); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free_i64(temp64); +} + +static inline void gen_maddsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) { TCGv temp = tcg_const_i32(con); + gen_madds_64(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + +static inline void +gen_maddsu_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_madd64_ssov(temp64, cpu_env, r1, temp64, temp); + gen_helper_madd64_suov(temp64, cpu_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); - tcg_temp_free(temp); tcg_temp_free_i64(temp64); } @@ -1169,12 +1964,8 @@ gen_maddsui_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) { TCGv temp = tcg_const_i32(con); - TCGv_i64 temp64 = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_madd64_suov(temp64, cpu_env, r1, temp64, temp); - tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + gen_maddsu_64(ret_low, ret_high, r1, r2_low, r2_high, temp); tcg_temp_free(temp); - tcg_temp_free_i64(temp64); } static inline void gen_msubsi_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) @@ -1192,15 +1983,33 @@ static inline void gen_msubsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) } static inline void +gen_msubs_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ + TCGv_i64 temp64 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); + gen_helper_msub64_ssov(temp64, cpu_env, r1, temp64, r3); + tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + tcg_temp_free_i64(temp64); +} + +static inline void gen_msubsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) { TCGv temp = tcg_const_i32(con); + gen_msubs_64(ret_low, ret_high, r1, r2_low, r2_high, temp); + tcg_temp_free(temp); +} + +static inline void +gen_msubsu_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, + TCGv r3) +{ TCGv_i64 temp64 = tcg_temp_new_i64(); tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_msub64_ssov(temp64, cpu_env, r1, temp64, temp); + gen_helper_msub64_suov(temp64, cpu_env, r1, temp64, r3); tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); - tcg_temp_free(temp); tcg_temp_free_i64(temp64); } @@ -1209,12 +2018,8 @@ gen_msubsui_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) { TCGv temp = tcg_const_i32(con); - TCGv_i64 temp64 = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(temp64, r2_low, r2_high); - gen_helper_msub64_suov(temp64, cpu_env, r1, temp64, temp); - tcg_gen_extr_i64_i32(ret_low, ret_high, temp64); + gen_msubsu_64(ret_low, ret_high, r1, r2_low, r2_high, temp); tcg_temp_free(temp); - tcg_temp_free_i64(temp64); } static void gen_saturate(TCGv ret, TCGv arg, int32_t up, int32_t low) @@ -4183,10 +4988,10 @@ static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx, switch (op1) { case OPC1_32_RLC_ADDI: - gen_addi_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const16); + gen_addi_d(cpu_gpr_d[r2], cpu_gpr_d[r1], const16); break; case OPC1_32_RLC_ADDIH: - gen_addi_CC(cpu_gpr_d[r2], cpu_gpr_d[r1], const16 << 16); + gen_addi_d(cpu_gpr_d[r2], cpu_gpr_d[r1], const16 << 16); break; case OPC1_32_RLC_ADDIH_A: tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r1], const16 << 16); @@ -5186,6 +5991,485 @@ static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx) } } +/* RRR2 format */ +static void decode_rrr2_madd(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t r1, r2, r3, r4; + + op2 = MASK_OP_RRR2_OP2(ctx->opcode); + r1 = MASK_OP_RRR2_S1(ctx->opcode); + r2 = MASK_OP_RRR2_S2(ctx->opcode); + r3 = MASK_OP_RRR2_S3(ctx->opcode); + r4 = MASK_OP_RRR2_D(ctx->opcode); + switch (op2) { + case OPC2_32_RRR2_MADD_32: + gen_madd32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], + cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADD_64: + gen_madd64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADDS_32: + gen_helper_madd32_ssov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADDS_64: + gen_madds_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADD_U_64: + gen_maddu64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADDS_U_32: + gen_helper_madd32_suov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MADDS_U_64: + gen_maddsu_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + } +} + +static void decode_rrr2_msub(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t r1, r2, r3, r4; + + op2 = MASK_OP_RRR2_OP2(ctx->opcode); + r1 = MASK_OP_RRR2_S1(ctx->opcode); + r2 = MASK_OP_RRR2_S2(ctx->opcode); + r3 = MASK_OP_RRR2_S3(ctx->opcode); + r4 = MASK_OP_RRR2_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR2_MSUB_32: + gen_msub32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], + cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUB_64: + gen_msub64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUBS_32: + gen_helper_msub32_ssov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUBS_64: + gen_msubs_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUB_U_64: + gen_msubu64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUBS_U_32: + gen_helper_msub32_suov(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r2]); + break; + case OPC2_32_RRR2_MSUBS_U_64: + gen_msubsu_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], + cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); + break; + } +} + +/* RRR1 format */ +static void decode_rrr1_madd(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t r1, r2, r3, r4, n; + + op2 = MASK_OP_RRR1_OP2(ctx->opcode); + r1 = MASK_OP_RRR1_S1(ctx->opcode); + r2 = MASK_OP_RRR1_S2(ctx->opcode); + r3 = MASK_OP_RRR1_S3(ctx->opcode); + r4 = MASK_OP_RRR1_D(ctx->opcode); + n = MASK_OP_RRR1_N(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR1_MADD_H_LL: + gen_madd_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADD_H_LU: + gen_madd_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADD_H_UL: + gen_madd_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADD_H_UU: + gen_madd_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDS_H_LL: + gen_madds_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDS_H_LU: + gen_madds_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDS_H_UL: + gen_madds_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDS_H_UU: + gen_madds_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDM_H_LL: + gen_maddm_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDM_H_LU: + gen_maddm_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDM_H_UL: + gen_maddm_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDM_H_UU: + gen_maddm_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDMS_H_LL: + gen_maddms_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDMS_H_LU: + gen_maddms_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDMS_H_UL: + gen_maddms_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDMS_H_UU: + gen_maddms_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDR_H_LL: + gen_maddr32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDR_H_LU: + gen_maddr32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDR_H_UL: + gen_maddr32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDR_H_UU: + gen_maddr32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDRS_H_LL: + gen_maddr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDRS_H_LU: + gen_maddr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDRS_H_UL: + gen_maddr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDRS_H_UU: + gen_maddr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UU); + break; + } +} + +static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t r1, r2, r3, r4, n; + TCGv temp, temp2; + + op2 = MASK_OP_RRR1_OP2(ctx->opcode); + r1 = MASK_OP_RRR1_S1(ctx->opcode); + r2 = MASK_OP_RRR1_S2(ctx->opcode); + r3 = MASK_OP_RRR1_S3(ctx->opcode); + r4 = MASK_OP_RRR1_D(ctx->opcode); + n = MASK_OP_RRR1_N(ctx->opcode); + + temp = tcg_const_i32(n); + temp2 = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RRR1_MADD_Q_32: + gen_madd32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, 32, env); + break; + case OPC2_32_RRR1_MADD_Q_64: + gen_madd64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, env); + break; + case OPC2_32_RRR1_MADD_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_madd32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + temp, n, 16, env); + break; + case OPC2_32_RRR1_MADD_Q_64_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_madd64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, + n, env); + break; + case OPC2_32_RRR1_MADD_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_madd32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + temp, n, 16, env); + break; + case OPC2_32_RRR1_MADD_Q_64_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_madd64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, + n, env); + break; + case OPC2_32_RRR1_MADD_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_m16add32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADD_Q_64_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_m16add64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], temp, temp2, n); + break; + case OPC2_32_RRR1_MADD_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_m16add32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADD_Q_64_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_m16add64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDS_Q_32: + gen_madds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, 32); + break; + case OPC2_32_RRR1_MADDS_Q_64: + gen_madds64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n); + break; + case OPC2_32_RRR1_MADDS_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_madds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + temp, n, 16); + break; + case OPC2_32_RRR1_MADDS_Q_64_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_madds64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, + n); + break; + case OPC2_32_RRR1_MADDS_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_madds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + temp, n, 16); + break; + case OPC2_32_RRR1_MADDS_Q_64_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_madds64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, + n); + break; + case OPC2_32_RRR1_MADDS_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_m16adds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDS_Q_64_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_m16adds64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDS_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_m16adds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDS_Q_64_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_m16adds64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDR_H_64_UL: + gen_maddr64_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r3+1], + cpu_gpr_d[r1], cpu_gpr_d[r2], n, 2); + break; + case OPC2_32_RRR1_MADDRS_H_64_UL: + gen_maddr64s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r3+1], + cpu_gpr_d[r1], cpu_gpr_d[r2], n, 2); + break; + case OPC2_32_RRR1_MADDR_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_maddr_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDR_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_maddr_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDRS_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_maddrs_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RRR1_MADDRS_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_maddrs_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); + break; + } + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +static void decode_rrr1_maddsu_h(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + uint32_t r1, r2, r3, r4, n; + + op2 = MASK_OP_RRR1_OP2(ctx->opcode); + r1 = MASK_OP_RRR1_S1(ctx->opcode); + r2 = MASK_OP_RRR1_S2(ctx->opcode); + r3 = MASK_OP_RRR1_S3(ctx->opcode); + r4 = MASK_OP_RRR1_D(ctx->opcode); + n = MASK_OP_RRR1_N(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR1_MADDSU_H_32_LL: + gen_maddsu_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSU_H_32_LU: + gen_maddsu_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSU_H_32_UL: + gen_maddsu_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSU_H_32_UU: + gen_maddsu_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDSUS_H_32_LL: + gen_maddsus_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSUS_H_32_LU: + gen_maddsus_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSUS_H_32_UL: + gen_maddsus_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSUS_H_32_UU: + gen_maddsus_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UU); + break; + case OPC2_32_RRR1_MADDSUM_H_64_LL: + gen_maddsum_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSUM_H_64_LU: + gen_maddsum_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSUM_H_64_UL: + gen_maddsum_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSUM_H_64_UU: + gen_maddsum_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UU); + break; + case OPC2_32_RRR1_MADDSUMS_H_64_LL: + gen_maddsums_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSUMS_H_64_LU: + gen_maddsums_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSUMS_H_64_UL: + gen_maddsums_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSUMS_H_64_UU: + gen_maddsums_h(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, MODE_UU); + break; + case OPC2_32_RRR1_MADDSUR_H_16_LL: + gen_maddsur32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSUR_H_16_LU: + gen_maddsur32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSUR_H_16_UL: + gen_maddsur32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSUR_H_16_UU: + gen_maddsur32_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UU); + break; + case OPC2_32_RRR1_MADDSURS_H_16_LL: + gen_maddsur32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LL); + break; + case OPC2_32_RRR1_MADDSURS_H_16_LU: + gen_maddsur32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_LU); + break; + case OPC2_32_RRR1_MADDSURS_H_16_UL: + gen_maddsur32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UL); + break; + case OPC2_32_RRR1_MADDSURS_H_16_UU: + gen_maddsur32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], + cpu_gpr_d[r2], n, MODE_UU); + break; + } +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { int op1; @@ -5475,6 +6759,23 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) break; case OPCM_32_RRR_DIVIDE: decode_rrr_divide(env, ctx); +/* RRR2 Format */ + case OPCM_32_RRR2_MADD: + decode_rrr2_madd(env, ctx); + break; + case OPCM_32_RRR2_MSUB: + decode_rrr2_msub(env, ctx); + break; +/* RRR1 format */ + case OPCM_32_RRR1_MADD: + decode_rrr1_madd(env, ctx); + break; + case OPCM_32_RRR1_MADDQ_H: + decode_rrr1_maddq_h(env, ctx); + break; + case OPCM_32_RRR1_MADDSU_H: + decode_rrr1_maddsu_h(env, ctx); + break; } } diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h index baf537f160..41c9ef60ad 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target-tricore/tricore-opcodes.h @@ -1245,10 +1245,10 @@ enum { OPC2_32_RRR1_MADDS_Q_64_LL = 0x3d, OPC2_32_RRR1_MADDS_Q_32_UU = 0x24, OPC2_32_RRR1_MADDS_Q_64_UU = 0x3c, - OPC2_32_RRR1_MADDR_H_16_UL = 0x1e, - OPC2_32_RRR1_MADDRS_H_16_UL = 0x3e, - OPC2_32_RRR1_MADDR_Q_32_L = 0x07, - OPC2_32_RRR1_MADDR_Q_32_U = 0x06, + OPC2_32_RRR1_MADDR_H_64_UL = 0x1e, + OPC2_32_RRR1_MADDRS_H_64_UL = 0x3e, + OPC2_32_RRR1_MADDR_Q_32_LL = 0x07, + OPC2_32_RRR1_MADDR_Q_32_UU = 0x06, OPC2_32_RRR1_MADDRS_Q_32_LL = 0x27, OPC2_32_RRR1_MADDRS_Q_32_UU = 0x26, }; @@ -1371,7 +1371,7 @@ enum { OPC2_32_RRR2_MADD_64 = 0x6a, OPC2_32_RRR2_MADDS_32 = 0x8a, OPC2_32_RRR2_MADDS_64 = 0xea, - OPC2_32_RRR2_MADD_U_32 = 0x68, + OPC2_32_RRR2_MADD_U_64 = 0x68, OPC2_32_RRR2_MADDS_U_32 = 0x88, OPC2_32_RRR2_MADDS_U_64 = 0xe8, }; diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h index 9de5c6eb9f..2258224d09 100644 --- a/target-xtensa/cpu-qom.h +++ b/target-xtensa/cpu-qom.h @@ -85,6 +85,9 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env) void xtensa_cpu_do_interrupt(CPUState *cpu); bool xtensa_cpu_exec_interrupt(CPUState *cpu, int interrupt_request); +void xtensa_cpu_do_unassigned_access(CPUState *cpu, hwaddr addr, + bool is_write, bool is_exec, int opaque, + unsigned size); void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 6a5414f815..2b75678995 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -151,6 +151,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) #ifndef CONFIG_USER_ONLY cc->do_unaligned_access = xtensa_cpu_do_unaligned_access; cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug; + cc->do_unassigned_access = xtensa_cpu_do_unassigned_access; #endif cc->debug_excp_handler = xtensa_breakpoint_handler; dc->vmsd = &vmstate_xtensa_cpu; diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 49e86343ed..be657e615d 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -71,6 +71,20 @@ void tlb_fill(CPUState *cs, } } +void xtensa_cpu_do_unassigned_access(CPUState *cs, hwaddr addr, + bool is_write, bool is_exec, int opaque, + unsigned size) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + CPUXtensaState *env = &cpu->env; + + HELPER(exception_cause_vaddr)(env, env->pc, + is_exec ? + INSTR_PIF_ADDR_ERROR_CAUSE : + LOAD_STORE_PIF_ADDR_ERROR_CAUSE, + is_exec ? addr : cs->mem_io_vaddr); +} + static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) { uint32_t paddr; diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index ca08ac523d..da564923d0 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -148,13 +148,13 @@ static void test_qemu_opt_get(void) opt = qemu_opt_get(opts, "str2"); g_assert(opt == NULL); - qemu_opt_set(opts, "str2", "value"); + qemu_opt_set(opts, "str2", "value", &error_abort); /* now we have set str2, should know about it */ opt = qemu_opt_get(opts, "str2"); g_assert_cmpstr(opt, ==, "value"); - qemu_opt_set(opts, "str2", "value2"); + qemu_opt_set(opts, "str2", "value2", &error_abort); /* having reset the value, the returned should be the reset one */ opt = qemu_opt_get(opts, "str2"); @@ -169,10 +169,10 @@ static void test_qemu_opt_get(void) static void test_qemu_opt_get_bool(void) { + Error *err = NULL; QemuOptsList *list; QemuOpts *opts; bool opt; - int ret; list = qemu_find_opts("opts_list_02"); g_assert(list != NULL); @@ -192,16 +192,16 @@ static void test_qemu_opt_get_bool(void) opt = qemu_opt_get_bool(opts, "bool1", false); g_assert(opt == false); - ret = qemu_opt_set_bool(opts, "bool1", true); - g_assert(ret == 0); + qemu_opt_set_bool(opts, "bool1", true, &err); + g_assert(!err); /* now we have set bool1, should know about it */ opt = qemu_opt_get_bool(opts, "bool1", false); g_assert(opt == true); /* having reset the value, opt should be the reset one not defval */ - ret = qemu_opt_set_bool(opts, "bool1", false); - g_assert(ret == 0); + qemu_opt_set_bool(opts, "bool1", false, &err); + g_assert(!err); opt = qemu_opt_get_bool(opts, "bool1", true); g_assert(opt == false); @@ -215,10 +215,10 @@ static void test_qemu_opt_get_bool(void) static void test_qemu_opt_get_number(void) { + Error *err = NULL; QemuOptsList *list; QemuOpts *opts; uint64_t opt; - int ret; list = qemu_find_opts("opts_list_01"); g_assert(list != NULL); @@ -238,16 +238,16 @@ static void test_qemu_opt_get_number(void) opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 5); - ret = qemu_opt_set_number(opts, "number1", 10); - g_assert(ret == 0); + qemu_opt_set_number(opts, "number1", 10, &err); + g_assert(!err); /* now we have set number1, should know about it */ opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 10); /* having reset it, the returned should be the reset one not defval */ - ret = qemu_opt_set_number(opts, "number1", 15); - g_assert(ret == 0); + qemu_opt_set_number(opts, "number1", 15, &err); + g_assert(!err); opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 15); @@ -331,7 +331,7 @@ static void test_qemu_opt_unset(void) g_assert_cmpstr(value, ==, "value"); /* reset it to value2 */ - qemu_opt_set(opts, "key", "value2"); + qemu_opt_set(opts, "key", "value2", &error_abort); value = qemu_opt_get(opts, "key"); g_assert_cmpstr(value, ==, "value2"); @@ -349,10 +349,10 @@ static void test_qemu_opt_unset(void) static void test_qemu_opts_reset(void) { + Error *err = NULL; QemuOptsList *list; QemuOpts *opts; uint64_t opt; - int ret; list = qemu_find_opts("opts_list_01"); g_assert(list != NULL); @@ -372,8 +372,8 @@ static void test_qemu_opts_reset(void) opt = qemu_opt_get_number(opts, "number1", 5); g_assert(opt == 5); - ret = qemu_opt_set_number(opts, "number1", 10); - g_assert(ret == 0); + qemu_opt_set_number(opts, "number1", 10, &err); + g_assert(!err); /* now we have set number1, should know about it */ opt = qemu_opt_get_number(opts, "number1", 5); @@ -388,9 +388,9 @@ static void test_qemu_opts_reset(void) static void test_qemu_opts_set(void) { + Error *err = NULL; QemuOptsList *list; QemuOpts *opts; - int ret; const char *opt; list = qemu_find_opts("opts_list_01"); @@ -403,8 +403,8 @@ static void test_qemu_opts_set(void) g_assert(opts == NULL); /* implicitly create opts and set str3 value */ - ret = qemu_opts_set(list, NULL, "str3", "value"); - g_assert(ret == 0); + qemu_opts_set(list, NULL, "str3", "value", &err); + g_assert(!err); g_assert(!QTAILQ_EMPTY(&list->head)); /* get the just created opts */ diff --git a/trace-events b/trace-events index f87b077805..4ac588c275 100644 --- a/trace-events +++ b/trace-events @@ -143,6 +143,10 @@ cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u" # balloon.c # Since requests are raised via monitor, not many tracepoints are needed. balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu" +virtio_balloon_handle_output(const char *name, uint64_t gpa) "setion name: %s gpa: %"PRIx64"" +virtio_balloon_get_config(uint32_t num_pages, uint32_t acutal) "num_pages: %d acutal: %d" +virtio_balloon_set_config(uint32_t acutal, uint32_t oldacutal) "acutal: %d oldacutal: %d" +virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: %"PRIx64" num_pages: %d" # hw/intc/apic_common.c cpu_set_apic_base(uint64_t val) "%016"PRIx64 @@ -1378,8 +1382,6 @@ migrate_pending(uint64_t size, uint64_t max) "pending size %" PRIu64 " max %" PR migrate_transferred(uint64_t tranferred, uint64_t time_spent, double bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %g max_size %" PRId64 # migration/rdma.c -__qemu_rdma_add_block(int block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Added Block: %d, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" -__qemu_rdma_delete_block(int block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Deleted Block: %d, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" qemu_dma_accept_incoming_migration(void) "" qemu_dma_accept_incoming_migration_accepted(void) "" qemu_rdma_accept_pin_state(bool pin) "%d" @@ -1433,6 +1435,8 @@ qemu_rdma_write_one_recvregres(int mykey, int theirkey, uint64_t chunk) "Receive qemu_rdma_write_one_sendreg(uint64_t chunk, int len, int index, int64_t offset) "Sending registration request chunk %" PRIu64 " for %d bytes, index: %d, offset: %" PRId64 qemu_rdma_write_one_top(uint64_t chunks, uint64_t size) "Writing %" PRIu64 " chunks, (%" PRIu64 " MB)" qemu_rdma_write_one_zero(uint64_t chunk, int len, int index, int64_t offset) "Entire chunk is zero, sending compress: %" PRIu64 " for %d bytes, index: %d, offset: %" PRId64 +rdma_add_block(int block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Added Block: %d, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" +rdma_delete_block(int block, uint64_t addr, uint64_t offset, uint64_t len, uint64_t end, uint64_t bits, int chunks) "Deleted Block: %d, addr: %" PRIu64 ", offset: %" PRIu64 " length: %" PRIu64 " end: %" PRIu64 " bits %" PRIu64 " chunks %d" rdma_start_incoming_migration(void) "" rdma_start_incoming_migration_after_dest_init(void) "" rdma_start_incoming_migration_after_rdma_listen(void) "" diff --git a/util/cutils.c b/util/cutils.c index dbe7412bd8..c2250d1ba5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -483,6 +483,20 @@ int64_t pow2floor(int64_t value) return value; } +/* round up to the nearest power of 2 (0 if overflow) */ +uint64_t pow2ceil(uint64_t value) +{ + uint8_t nlz = clz64(value); + + if (is_power_of_2(value)) { + return value; + } + if (!nlz) { + return 0; + } + return 1ULL << (64 - nlz); +} + /* * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128) * Input is limited to 14-bit numbers diff --git a/util/qemu-config.c b/util/qemu-config.c index b13efe2788..f3463df678 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -219,6 +219,7 @@ void qemu_add_opts(QemuOptsList *list) int qemu_set_option(const char *str) { + Error *local_err = NULL; char group[64], id[64], arg[64]; QemuOptsList *list; QemuOpts *opts; @@ -242,7 +243,9 @@ int qemu_set_option(const char *str) return -1; } - if (qemu_opt_set(opts, arg, str+offset+1) == -1) { + qemu_opt_set(opts, arg, str + offset + 1, &local_err); + if (local_err) { + error_report_err(local_err); return -1; } return 0; @@ -335,7 +338,9 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) error_report("no group defined"); goto out; } - if (qemu_opt_set(opts, arg, value) != 0) { + qemu_opt_set(opts, arg, value, &local_err); + if (local_err) { + error_report_err(local_err); goto out; } continue; diff --git a/util/qemu-option.c b/util/qemu-option.c index d3ab65d24f..fda4e5fcbf 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -548,27 +548,14 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value, } } -int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) -{ - Error *local_err = NULL; - - opt_set(opts, name, value, false, &local_err); - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; - } - - return 0; -} - -void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, - Error **errp) +void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, + Error **errp) { opt_set(opts, name, value, false, errp); } -int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) +void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, + Error **errp) { QemuOpt *opt; const QemuOptDesc *desc = opts->list->desc; @@ -576,9 +563,9 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) opt = g_malloc0(sizeof(*opt)); opt->desc = find_desc_by_name(desc, name); if (!opt->desc && !opts_accepts_any(opts)) { - qerror_report(QERR_INVALID_PARAMETER, name); + error_set(errp, QERR_INVALID_PARAMETER, name); g_free(opt); - return -1; + return; } opt->name = g_strdup(name); @@ -586,11 +573,10 @@ int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) opt->value.boolean = !!val; opt->str = g_strdup(val ? "on" : "off"); QTAILQ_INSERT_TAIL(&opts->head, opt, next); - - return 0; } -int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) +void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, + Error **errp) { QemuOpt *opt; const QemuOptDesc *desc = opts->list->desc; @@ -598,9 +584,9 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) opt = g_malloc0(sizeof(*opt)); opt->desc = find_desc_by_name(desc, name); if (!opt->desc && !opts_accepts_any(opts)) { - qerror_report(QERR_INVALID_PARAMETER, name); + error_set(errp, QERR_INVALID_PARAMETER, name); g_free(opt); - return -1; + return; } opt->name = g_strdup(name); @@ -608,8 +594,6 @@ int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) opt->value.uint = val; opt->str = g_strdup_printf("%" PRId64, val); QTAILQ_INSERT_TAIL(&opts->head, opt, next); - - return 0; } int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, @@ -692,19 +676,18 @@ void qemu_opts_loc_restore(QemuOpts *opts) loc_restore(&opts->loc); } -int qemu_opts_set(QemuOptsList *list, const char *id, - const char *name, const char *value) +void qemu_opts_set(QemuOptsList *list, const char *id, + const char *name, const char *value, Error **errp) { QemuOpts *opts; Error *local_err = NULL; opts = qemu_opts_create(list, id, 1, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_propagate(errp, local_err); + return; } - return qemu_opt_set(opts, name, value); + qemu_opt_set(opts, name, value, errp); } const char *qemu_opts_id(QemuOpts *opts) @@ -767,8 +750,8 @@ void qemu_opts_print(QemuOpts *opts, const char *sep) } } -static int opts_do_parse(QemuOpts *opts, const char *params, - const char *firstname, bool prepend) +static void opts_do_parse(QemuOpts *opts, const char *params, + const char *firstname, bool prepend, Error **errp) { char option[128], value[1024]; const char *p,*pe,*pc; @@ -806,25 +789,30 @@ static int opts_do_parse(QemuOpts *opts, const char *params, /* store and parse */ opt_set(opts, option, value, prepend, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_propagate(errp, local_err); + return; } } if (*p != ',') { break; } } - return 0; } -int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) +/** + * Store options parsed from @params into @opts. + * If @firstname is non-null, the first key=value in @params may omit + * key=, and is treated as if key was @firstname. + * On error, store an error object through @errp if non-null. + */ +void qemu_opts_do_parse(QemuOpts *opts, const char *params, + const char *firstname, Error **errp) { - return opts_do_parse(opts, params, firstname, false); + opts_do_parse(opts, params, firstname, false, errp); } static QemuOpts *opts_parse(QemuOptsList *list, const char *params, - int permit_abbrev, bool defaults) + int permit_abbrev, bool defaults, Error **errp) { const char *firstname; char value[1024], *id = NULL; @@ -853,14 +841,13 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, assert(!defaults || list->merge_lists); opts = qemu_opts_create(list, id, !defaults, &local_err); if (opts == NULL) { - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - } + error_propagate(errp, local_err); return NULL; } - if (opts_do_parse(opts, params, firstname, defaults) != 0) { + opts_do_parse(opts, params, firstname, defaults, &local_err); + if (local_err) { + error_propagate(errp, local_err); qemu_opts_del(opts); return NULL; } @@ -868,10 +855,25 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return opts; } +/** + * Create a QemuOpts in @list and with options parsed from @params. + * If @permit_abbrev, the first key=value in @params may omit key=, + * and is treated as if key was @list->implied_opt_name. + * Report errors with qerror_report_err(). + * Return the new QemuOpts on success, null pointer on error. + */ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev) { - return opts_parse(list, params, permit_abbrev, false); + Error *err = NULL; + QemuOpts *opts; + + opts = opts_parse(list, params, permit_abbrev, false, &err); + if (!opts) { + qerror_report_err(err); + error_free(err); + } + return opts; } void qemu_opts_set_defaults(QemuOptsList *list, const char *params, @@ -879,7 +881,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, { QemuOpts *opts; - opts = opts_parse(list, params, permit_abbrev, true); + opts = opts_parse(list, params, permit_abbrev, true, NULL); assert(opts); } @@ -924,7 +926,7 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) return; } - qemu_opt_set_err(state->opts, key, value, state->errp); + qemu_opt_set(state->opts, key, value, state->errp); } /* diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 61fc3c1364..87c9bc6c68 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -199,11 +199,13 @@ listen: freeaddrinfo(res); return -1; } - snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); - qemu_opt_set(opts, "host", uaddr); - qemu_opt_set(opts, "port", uport); - qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); - qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); + qemu_opt_set(opts, "host", uaddr, &error_abort); + qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset, + &error_abort); + qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6, + &error_abort); + qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6, + &error_abort); freeaddrinfo(res); return slisten; } @@ -580,16 +582,14 @@ static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr) bool ipv6 = addr->ipv6 || !addr->has_ipv6; if (!ipv4 || !ipv6) { - qemu_opt_set_bool(opts, "ipv4", ipv4); - qemu_opt_set_bool(opts, "ipv6", ipv6); + qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort); + qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort); } if (addr->has_to) { - char to[20]; - snprintf(to, sizeof(to), "%d", addr->to); - qemu_opt_set(opts, "to", to); + qemu_opt_set_number(opts, "to", addr->to, &error_abort); } - qemu_opt_set(opts, "host", addr->host); - qemu_opt_set(opts, "port", addr->port); + qemu_opt_set(opts, "host", addr->host, &error_abort); + qemu_opt_set(opts, "port", addr->port, &error_abort); } int inet_listen(const char *str, char *ostr, int olen, @@ -726,7 +726,7 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) goto err; } close(fd); - qemu_opt_set(opts, "path", un.sun_path); + qemu_opt_set(opts, "path", un.sun_path, &error_abort); } unlink(un.sun_path); @@ -838,11 +838,11 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp) if (len) { path = g_malloc(len+1); snprintf(path, len+1, "%.*s", len, str); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); g_free(path); } } else { - qemu_opt_set(opts, "path", str); + qemu_opt_set(opts, "path", str, &error_abort); } sock = unix_listen_opts(opts, errp); @@ -859,7 +859,7 @@ int unix_connect(const char *path, Error **errp) int sock; opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); sock = unix_connect_opts(opts, errp, NULL, NULL); qemu_opts_del(opts); return sock; @@ -876,7 +876,7 @@ int unix_nonblocking_connect(const char *path, g_assert(callback != NULL); opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path); + qemu_opt_set(opts, "path", path, &error_abort); sock = unix_connect_opts(opts, errp, callback, opaque); qemu_opts_del(opts); return sock; @@ -933,7 +933,7 @@ int socket_connect(SocketAddress *addr, Error **errp, break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->q_unix->path); + qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort); fd = unix_connect_opts(opts, errp, callback, opaque); break; @@ -965,7 +965,7 @@ int socket_listen(SocketAddress *addr, Error **errp) break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->q_unix->path); + qemu_opt_set(opts, "path", addr->q_unix->path, &error_abort); fd = unix_listen_opts(opts, errp); break; @@ -990,8 +990,8 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) case SOCKET_ADDRESS_KIND_INET: inet_addr_to_opts(opts, remote->inet); if (local) { - qemu_opt_set(opts, "localaddr", local->inet->host); - qemu_opt_set(opts, "localport", local->inet->port); + qemu_opt_set(opts, "localaddr", local->inet->host, &error_abort); + qemu_opt_set(opts, "localport", local->inet->port, &error_abort); } fd = inet_dgram_opts(opts, errp); break; @@ -78,6 +78,7 @@ int main(int argc, char **argv) #include "monitor/monitor.h" #include "ui/console.h" #include "sysemu/sysemu.h" +#include "sysemu/numa.h" #include "exec/gdbstub.h" #include "qemu/timer.h" #include "sysemu/char.h" @@ -183,10 +184,6 @@ uint8_t qemu_extra_params_fw[2]; int icount_align_option; -int nb_numa_nodes; -int max_numa_nodeid; -NodeInfo numa_info[MAX_NODES]; - /* The bytes in qemu_uuid[] are in the order specified by RFC4122, _not_ in the * little-endian "wire format" described in the SMBIOS 2.6 specification. */ @@ -710,13 +707,17 @@ void vm_start(void) /***********************************************************/ /* real time host monotonic timer */ +static time_t qemu_time(void) +{ + return qemu_clock_get_ms(QEMU_CLOCK_HOST) / 1000; +} + /***********************************************************/ /* host time/date access */ void qemu_get_timedate(struct tm *tm, int offset) { - time_t ti; + time_t ti = qemu_time(); - time(&ti); ti += offset; if (rtc_date_offset == -1) { if (rtc_utc) @@ -744,7 +745,7 @@ int qemu_timedate_diff(struct tm *tm) else seconds = mktimegm(tm) + rtc_date_offset; - return seconds - time(NULL); + return seconds - qemu_time(); } static void configure_rtc_date_offset(const char *startdate, int legacy) @@ -782,7 +783,7 @@ static void configure_rtc_date_offset(const char *startdate, int legacy) "'2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } - rtc_date_offset = time(NULL) - rtc_start_date; + rtc_date_offset = qemu_time() - rtc_start_date; } } @@ -1096,7 +1097,7 @@ static int drive_init_func(QemuOpts *opts, void *opaque) static int drive_enable_snapshot(QemuOpts *opts, void *opaque) { if (qemu_opt_get(opts, "snapshot") == NULL) { - qemu_opt_set(opts, "snapshot", "on"); + qemu_opt_set(opts, "snapshot", "on", &error_abort); } return 0; } @@ -2074,7 +2075,7 @@ static int balloon_parse(const char *arg) opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); } - qemu_opt_set(opts, "driver", "virtio-balloon"); + qemu_opt_set(opts, "driver", "virtio-balloon", &error_abort); return 0; } @@ -2220,11 +2221,11 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty) error_report_err(local_err); exit(1); } - qemu_opt_set(opts, "mode", mode); - qemu_opt_set(opts, "chardev", label); - qemu_opt_set_bool(opts, "pretty", pretty); + qemu_opt_set(opts, "mode", mode, &error_abort); + qemu_opt_set(opts, "chardev", label, &error_abort); + qemu_opt_set_bool(opts, "pretty", pretty, &error_abort); if (def) - qemu_opt_set(opts, "default", "on"); + qemu_opt_set(opts, "default", "on", &error_abort); monitor_device_index++; } @@ -2336,13 +2337,13 @@ static int virtcon_parse(const char *devname) bus_opts = qemu_opts_create(device, NULL, 0, &error_abort); if (arch_type == QEMU_ARCH_S390X) { - qemu_opt_set(bus_opts, "driver", "virtio-serial-s390"); + qemu_opt_set(bus_opts, "driver", "virtio-serial-s390", &error_abort); } else { - qemu_opt_set(bus_opts, "driver", "virtio-serial-pci"); + qemu_opt_set(bus_opts, "driver", "virtio-serial-pci", &error_abort); } dev_opts = qemu_opts_create(device, NULL, 0, &error_abort); - qemu_opt_set(dev_opts, "driver", "virtconsole"); + qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort); snprintf(label, sizeof(label), "virtcon%d", index); virtcon_hds[index] = qemu_chr_new(label, devname, NULL); @@ -2351,7 +2352,7 @@ static int virtcon_parse(const char *devname) " to character backend '%s'\n", devname); return -1; } - qemu_opt_set(dev_opts, "chardev", label); + qemu_opt_set(dev_opts, "chardev", label, &error_abort); index++; return 0; @@ -2375,7 +2376,7 @@ static int sclp_parse(const char *devname) assert(arch_type == QEMU_ARCH_S390X); dev_opts = qemu_opts_create(device, NULL, 0, NULL); - qemu_opt_set(dev_opts, "driver", "sclpconsole"); + qemu_opt_set(dev_opts, "driver", "sclpconsole", &error_abort); snprintf(label, sizeof(label), "sclpcon%d", index); sclp_hds[index] = qemu_chr_new(label, devname, NULL); @@ -2384,7 +2385,7 @@ static int sclp_parse(const char *devname) " to character backend '%s'\n", devname); return -1; } - qemu_opt_set(dev_opts, "chardev", label); + qemu_opt_set(dev_opts, "chardev", label, &error_abort); index++; return 0; @@ -2402,8 +2403,8 @@ static int debugcon_parse(const char *devname) fprintf(stderr, "qemu: already have a debugcon device\n"); exit(1); } - qemu_opt_set(opts, "driver", "isa-debugcon"); - qemu_opt_set(opts, "chardev", "debugcon"); + qemu_opt_set(opts, "driver", "isa-debugcon", &error_abort); + qemu_opt_set(opts, "chardev", "debugcon", &error_abort); return 0; } @@ -2684,7 +2685,7 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size) } /* store value for the future use */ - qemu_opt_set_number(opts, "size", ram_size); + qemu_opt_set_number(opts, "size", ram_size, &error_abort); *maxram_size = ram_size; maxmem_str = qemu_opt_get(opts, "maxmem"); @@ -2730,7 +2731,8 @@ int main(int argc, char **argv, char **envp) int snapshot, linux_boot; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; - const char *boot_order; + const char *boot_order = NULL; + const char *boot_once = NULL; DisplayState *ds; int cyls, heads, secs, translation; QemuOpts *hda_opts = NULL, *opts, *machine_opts, *icount_opts = NULL; @@ -2764,6 +2766,9 @@ int main(int argc, char **argv, char **envp) FILE *vmstate_dump_file = NULL; Error *main_loop_err = NULL; + qemu_init_cpu_loop(); + qemu_mutex_lock_iothread(); + atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); qemu_init_exec_dir(argv[0]); @@ -2814,14 +2819,6 @@ int main(int argc, char **argv, char **envp) cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; - for (i = 0; i < MAX_NODES; i++) { - numa_info[i].node_mem = 0; - numa_info[i].present = false; - bitmap_zero(numa_info[i].node_cpu, MAX_CPUMASK_BITS); - } - - nb_numa_nodes = 0; - max_numa_nodeid = 0; nb_nics = 0; bdrv_init_with_whitelist(); @@ -2969,21 +2966,24 @@ int main(int argc, char **argv, char **envp) exit(1); } if (hda_opts != NULL) { - char num[16]; - snprintf(num, sizeof(num), "%d", cyls); - qemu_opt_set(hda_opts, "cyls", num); - snprintf(num, sizeof(num), "%d", heads); - qemu_opt_set(hda_opts, "heads", num); - snprintf(num, sizeof(num), "%d", secs); - qemu_opt_set(hda_opts, "secs", num); + qemu_opt_set_number(hda_opts, "cyls", cyls, + &error_abort); + qemu_opt_set_number(hda_opts, "heads", heads, + &error_abort); + qemu_opt_set_number(hda_opts, "secs", secs, + &error_abort); if (translation == BIOS_ATA_TRANSLATION_LARGE) { - qemu_opt_set(hda_opts, "trans", "large"); + qemu_opt_set(hda_opts, "trans", "large", + &error_abort); } else if (translation == BIOS_ATA_TRANSLATION_RECHS) { - qemu_opt_set(hda_opts, "trans", "rechs"); + qemu_opt_set(hda_opts, "trans", "rechs", + &error_abort); } else if (translation == BIOS_ATA_TRANSLATION_LBA) { - qemu_opt_set(hda_opts, "trans", "lba"); + qemu_opt_set(hda_opts, "trans", "lba", + &error_abort); } else if (translation == BIOS_ATA_TRANSLATION_NONE) { - qemu_opt_set(hda_opts, "trans", "none"); + qemu_opt_set(hda_opts, "trans", "none", + &error_abort); } } } @@ -3021,16 +3021,20 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_kernel: - qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg); + qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg, + &error_abort); break; case QEMU_OPTION_initrd: - qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg); + qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg, + &error_abort); break; case QEMU_OPTION_append: - qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg); + qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg, + &error_abort); break; case QEMU_OPTION_dtb: - qemu_opts_set(qemu_find_opts("machine"), 0, "dtb", optarg); + qemu_opts_set(qemu_find_opts("machine"), 0, "dtb", optarg, + &error_abort); break; case QEMU_OPTION_cdrom: drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); @@ -3134,7 +3138,8 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_bios: - qemu_opts_set(qemu_find_opts("machine"), 0, "firmware", optarg); + qemu_opts_set(qemu_find_opts("machine"), 0, "firmware", optarg, + &error_abort); break; case QEMU_OPTION_singlestep: singlestep = 1; @@ -3264,35 +3269,39 @@ int main(int argc, char **argv, char **envp) writeout = qemu_opt_get(opts, "writeout"); if (writeout) { #ifdef CONFIG_SYNC_FILE_RANGE - qemu_opt_set(fsdev, "writeout", writeout); + qemu_opt_set(fsdev, "writeout", writeout, &error_abort); #else fprintf(stderr, "writeout=immediate not supported on " "this platform\n"); exit(1); #endif } - qemu_opt_set(fsdev, "fsdriver", qemu_opt_get(opts, "fsdriver")); - qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path")); + qemu_opt_set(fsdev, "fsdriver", + qemu_opt_get(opts, "fsdriver"), &error_abort); + qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"), + &error_abort); qemu_opt_set(fsdev, "security_model", - qemu_opt_get(opts, "security_model")); + qemu_opt_get(opts, "security_model"), + &error_abort); socket = qemu_opt_get(opts, "socket"); if (socket) { - qemu_opt_set(fsdev, "socket", socket); + qemu_opt_set(fsdev, "socket", socket, &error_abort); } sock_fd = qemu_opt_get(opts, "sock_fd"); if (sock_fd) { - qemu_opt_set(fsdev, "sock_fd", sock_fd); + qemu_opt_set(fsdev, "sock_fd", sock_fd, &error_abort); } qemu_opt_set_bool(fsdev, "readonly", - qemu_opt_get_bool(opts, "readonly", 0)); + qemu_opt_get_bool(opts, "readonly", 0), + &error_abort); device = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); - qemu_opt_set(device, "driver", "virtio-9p-pci"); + qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort); qemu_opt_set(device, "fsdev", - qemu_opt_get(opts, "mount_tag")); + qemu_opt_get(opts, "mount_tag"), &error_abort); qemu_opt_set(device, "mount_tag", - qemu_opt_get(opts, "mount_tag")); + qemu_opt_get(opts, "mount_tag"), &error_abort); break; } case QEMU_OPTION_virtfs_synth: { @@ -3305,13 +3314,13 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "duplicate option: %s\n", "virtfs_synth"); exit(1); } - qemu_opt_set(fsdev, "fsdriver", "synth"); + qemu_opt_set(fsdev, "fsdriver", "synth", &error_abort); device = qemu_opts_create(qemu_find_opts("device"), NULL, 0, &error_abort); - qemu_opt_set(device, "driver", "virtio-9p-pci"); - qemu_opt_set(device, "fsdev", "v_synth"); - qemu_opt_set(device, "mount_tag", "v_synth"); + qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort); + qemu_opt_set(device, "fsdev", "v_synth", &error_abort); + qemu_opt_set(device, "mount_tag", "v_synth", &error_abort); break; } case QEMU_OPTION_serial: @@ -4038,39 +4047,36 @@ int main(int argc, char **argv, char **envp) kernel_cmdline = qemu_opt_get(machine_opts, "append"); bios_name = qemu_opt_get(machine_opts, "firmware"); - boot_order = machine_class->default_boot_order; opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); if (opts) { - char *normal_boot_order; - const char *order, *once; Error *local_err = NULL; - order = qemu_opt_get(opts, "order"); - if (order) { - validate_bootdevices(order, &local_err); + boot_order = qemu_opt_get(opts, "order"); + if (boot_order) { + validate_bootdevices(boot_order, &local_err); if (local_err) { error_report_err(local_err); exit(1); } - boot_order = order; } - once = qemu_opt_get(opts, "once"); - if (once) { - validate_bootdevices(once, &local_err); + boot_once = qemu_opt_get(opts, "once"); + if (boot_once) { + validate_bootdevices(boot_once, &local_err); if (local_err) { error_report_err(local_err); exit(1); } - normal_boot_order = g_strdup(boot_order); - boot_order = once; - qemu_register_reset(restore_boot_order, normal_boot_order); } boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu); boot_strict = qemu_opt_get_bool(opts, "strict", false); } + if (!boot_order) { + boot_order = machine_class->default_boot_order; + } + if (!kernel_cmdline) { kernel_cmdline = ""; current_machine->kernel_cmdline = (char *)kernel_cmdline; @@ -4095,9 +4101,6 @@ int main(int argc, char **argv, char **envp) os_set_line_buffering(); - qemu_init_cpu_loop(); - qemu_mutex_lock_iothread(); - #ifdef CONFIG_SPICE /* spice needs the timers to be initialized by this point */ qemu_spice_init(); @@ -4161,12 +4164,7 @@ int main(int argc, char **argv, char **envp) default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); - if (qemu_opts_foreach(qemu_find_opts("numa"), numa_init_func, - NULL, 1) != 0) { - exit(1); - } - - set_numa_nodes(); + parse_numa_opts(); if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) { exit(1); @@ -4225,7 +4223,7 @@ int main(int argc, char **argv, char **envp) cpu_synchronize_all_post_init(); - set_numa_modes(); + numa_post_machine_init(); /* init USB devices */ if (usb_enabled()) { @@ -4242,6 +4240,16 @@ int main(int argc, char **argv, char **envp) net_check_clients(); + if (boot_once) { + Error *local_err = NULL; + qemu_boot_set(boot_once, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + exit(1); + } + qemu_register_reset(restore_boot_order, g_strdup(boot_order)); + } + ds = init_displaystate(); /* init local displays */ |