diff options
368 files changed, 5320 insertions, 3145 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 02710f857c..606d9c08b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -84,6 +84,13 @@ F: include/exec/exec-all.h F: include/exec/helper*.h F: include/exec/tb-hash.h +FPU emulation +M: Aurelien Jarno <aurelien@aurel32.net> +M: Peter Maydell <peter.maydell@linaro.org> +S: Odd Fixes +F: fpu/ +F: include/fpu/ + Alpha M: Richard Henderson <rth@twiddle.net> S: Maintained @@ -1276,6 +1283,15 @@ S: Maintained F: include/qemu/sockets.h F: util/qemu-sockets.c +Throttling infrastructure +M: Alberto Garcia <berto@igalia.com> +S: Supported +F: block/throttle-groups.c +F: include/block/throttle-groups.h +F: include/qemu/throttle.h +F: util/throttle.c +L: qemu-block@nongnu.org + Usermode Emulation ------------------ Overall @@ -391,7 +391,7 @@ bepo cz ifdef INSTALL_BLOBS BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \ -acpi-dsdt.aml q35-acpi-dsdt.aml \ +acpi-dsdt.aml \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ diff --git a/audio/audio.h b/audio/audio.h index e7ea39777e..b41a97053d 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -24,7 +24,6 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H -#include "config-host.h" #include "qemu/queue.h" typedef void (*audio_callback_fn) (void *opaque, int avail); @@ -1191,10 +1191,6 @@ static int bdrv_fill_options(QDict **options, const char *filename, } } - if (runstate_check(RUN_STATE_INMIGRATE)) { - *flags |= BDRV_O_INACTIVE; - } - return 0; } diff --git a/block/qapi.c b/block/qapi.c index 67891b7d19..db2d3fb915 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -92,6 +92,26 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp) info->has_iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; info->iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max; + info->has_bps_max_length = info->has_bps_max; + info->bps_max_length = + cfg.buckets[THROTTLE_BPS_TOTAL].burst_length; + info->has_bps_rd_max_length = info->has_bps_rd_max; + info->bps_rd_max_length = + cfg.buckets[THROTTLE_BPS_READ].burst_length; + info->has_bps_wr_max_length = info->has_bps_wr_max; + info->bps_wr_max_length = + cfg.buckets[THROTTLE_BPS_WRITE].burst_length; + + info->has_iops_max_length = info->has_iops_max; + info->iops_max_length = + cfg.buckets[THROTTLE_OPS_TOTAL].burst_length; + info->has_iops_rd_max_length = info->has_iops_rd_max; + info->iops_rd_max_length = + cfg.buckets[THROTTLE_OPS_READ].burst_length; + info->has_iops_wr_max_length = info->has_iops_wr_max; + info->iops_wr_max_length = + cfg.buckets[THROTTLE_OPS_WRITE].burst_length; + info->has_iops_size = cfg.op_size; info->iops_size = cfg.op_size; diff --git a/block/quorum.c b/block/quorum.c index a5ae4b812b..11cc60b713 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -286,7 +286,8 @@ static void quorum_aio_cb(void *opaque, int ret) if (acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO) { /* We try to read next child in FIFO order if we fail to read */ - if (ret < 0 && ++acb->child_iter < s->num_children) { + if (ret < 0 && (acb->child_iter + 1) < s->num_children) { + acb->child_iter++; read_fifo_child(acb); return; } diff --git a/blockdev.c b/blockdev.c index 1f7347821c..d4bc435940 100644 --- a/blockdev.c +++ b/blockdev.c @@ -343,29 +343,6 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals, return true; } -static bool check_throttle_config(ThrottleConfig *cfg, Error **errp) -{ - if (throttle_conflicting(cfg)) { - error_setg(errp, "bps/iops/max total values and read/write values" - " cannot be used at the same time"); - return false; - } - - if (!throttle_is_valid(cfg)) { - error_setg(errp, "bps/iops/max values must be within [0, %lld]", - THROTTLE_VALUE_MAX); - return false; - } - - if (throttle_max_is_missing_limit(cfg)) { - error_setg(errp, "bps_max/iops_max require corresponding" - " bps/iops values"); - return false; - } - - return true; -} - typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType; /* All parameters but @opts are optional and may be set to NULL. */ @@ -410,7 +387,7 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, } if (throttle_cfg) { - memset(throttle_cfg, 0, sizeof(*throttle_cfg)); + throttle_config_init(throttle_cfg); throttle_cfg->buckets[THROTTLE_BPS_TOTAL].avg = qemu_opt_get_number(opts, "throttling.bps-total", 0); throttle_cfg->buckets[THROTTLE_BPS_READ].avg = @@ -437,10 +414,23 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, throttle_cfg->buckets[THROTTLE_OPS_WRITE].max = qemu_opt_get_number(opts, "throttling.iops-write-max", 0); + throttle_cfg->buckets[THROTTLE_BPS_TOTAL].burst_length = + qemu_opt_get_number(opts, "throttling.bps-total-max-length", 1); + throttle_cfg->buckets[THROTTLE_BPS_READ].burst_length = + qemu_opt_get_number(opts, "throttling.bps-read-max-length", 1); + throttle_cfg->buckets[THROTTLE_BPS_WRITE].burst_length = + qemu_opt_get_number(opts, "throttling.bps-write-max-length", 1); + throttle_cfg->buckets[THROTTLE_OPS_TOTAL].burst_length = + qemu_opt_get_number(opts, "throttling.iops-total-max-length", 1); + throttle_cfg->buckets[THROTTLE_OPS_READ].burst_length = + qemu_opt_get_number(opts, "throttling.iops-read-max-length", 1); + throttle_cfg->buckets[THROTTLE_OPS_WRITE].burst_length = + qemu_opt_get_number(opts, "throttling.iops-write-max-length", 1); + throttle_cfg->op_size = qemu_opt_get_number(opts, "throttling.iops-size", 0); - if (!check_throttle_config(throttle_cfg, errp)) { + if (!throttle_is_valid(throttle_cfg, errp)) { return; } } @@ -610,6 +600,10 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on")); } + if (runstate_check(RUN_STATE_INMIGRATE)) { + bdrv_flags |= BDRV_O_INACTIVE; + } + blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags, errp); if (!blk) { @@ -688,6 +682,10 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) goto fail; } + if (runstate_check(RUN_STATE_INMIGRATE)) { + bdrv_flags |= BDRV_O_INACTIVE; + } + bs = NULL; ret = bdrv_open(&bs, NULL, NULL, bs_opts, bdrv_flags, errp); if (ret < 0) { @@ -2515,6 +2513,8 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, } bdrv_flags = blk_get_open_flags_from_root_state(blk); + bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | + BDRV_O_PROTOCOL); if (!has_read_only) { read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN; @@ -2600,6 +2600,18 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, int64_t iops_rd_max, bool has_iops_wr_max, int64_t iops_wr_max, + bool has_bps_max_length, + int64_t bps_max_length, + bool has_bps_rd_max_length, + int64_t bps_rd_max_length, + bool has_bps_wr_max_length, + int64_t bps_wr_max_length, + bool has_iops_max_length, + int64_t iops_max_length, + bool has_iops_rd_max_length, + int64_t iops_rd_max_length, + bool has_iops_wr_max_length, + int64_t iops_wr_max_length, bool has_iops_size, int64_t iops_size, bool has_group, @@ -2626,7 +2638,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, goto out; } - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps; cfg.buckets[THROTTLE_BPS_READ].avg = bps_rd; cfg.buckets[THROTTLE_BPS_WRITE].avg = bps_wr; @@ -2654,11 +2666,30 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, cfg.buckets[THROTTLE_OPS_WRITE].max = iops_wr_max; } + if (has_bps_max_length) { + cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = bps_max_length; + } + if (has_bps_rd_max_length) { + cfg.buckets[THROTTLE_BPS_READ].burst_length = bps_rd_max_length; + } + if (has_bps_wr_max_length) { + cfg.buckets[THROTTLE_BPS_WRITE].burst_length = bps_wr_max_length; + } + if (has_iops_max_length) { + cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = iops_max_length; + } + if (has_iops_rd_max_length) { + cfg.buckets[THROTTLE_OPS_READ].burst_length = iops_rd_max_length; + } + if (has_iops_wr_max_length) { + cfg.buckets[THROTTLE_OPS_WRITE].burst_length = iops_wr_max_length; + } + if (has_iops_size) { cfg.op_size = iops_size; } - if (!check_throttle_config(&cfg, errp)) { + if (!throttle_is_valid(&cfg, errp)) { goto out; } @@ -4087,6 +4118,30 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_NUMBER, .help = "total bytes write burst", },{ + .name = "throttling.iops-total-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the iops-total-max burst period, in seconds", + },{ + .name = "throttling.iops-read-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the iops-read-max burst period, in seconds", + },{ + .name = "throttling.iops-write-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the iops-write-max burst period, in seconds", + },{ + .name = "throttling.bps-total-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the bps-total-max burst period, in seconds", + },{ + .name = "throttling.bps-read-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the bps-read-max burst period, in seconds", + },{ + .name = "throttling.bps-write-max-length", + .type = QEMU_OPT_NUMBER, + .help = "length of the bps-write-max burst period, in seconds", + },{ .name = "throttling.iops-size", .type = QEMU_OPT_NUMBER, .help = "when limiting by iops max size of an I/O in bytes", diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 735cb4042a..1b5f9983d1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -17,15 +17,12 @@ #ifndef QEMU_H #define QEMU_H -#include <signal.h> -#include <string.h> #include "cpu.h" #include "exec/cpu_ldst.h" #undef DEBUG_REMAP #ifdef DEBUG_REMAP -#include <stdlib.h> #endif /* DEBUG_REMAP */ #include "exec/user/abitypes.h" @@ -279,6 +279,7 @@ smartcard="" libusb="" usb_redir="" opengl="" +opengl_dmabuf="no" zlib="yes" lzo="" snappy="" @@ -3274,7 +3275,7 @@ libs_softmmu="$libs_softmmu $fdt_libs" # opengl probe (for sdl2, gtk, milkymist-tmu2) if test "$opengl" != "no" ; then - opengl_pkgs="epoxy" + opengl_pkgs="epoxy libdrm gbm" if $pkg_config $opengl_pkgs x11; then opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags" opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs" @@ -3292,6 +3293,18 @@ if test "$opengl" != "no" ; then fi fi +if test "$opengl" = "yes"; then + cat > $TMPC << EOF +#include <epoxy/egl.h> +#ifndef EGL_MESA_image_dma_buf_export +# error mesa/epoxy lacks support for dmabufs (mesa 10.6+) +#endif +int main(void) { return 0; } +EOF + if compile_prog "" "" ; then + opengl_dmabuf=yes + fi +fi ########################################## # archipelago probe @@ -4752,6 +4765,7 @@ echo "smartcard support $smartcard" echo "libusb $libusb" echo "usb net redir $usb_redir" echo "OpenGL support $opengl" +echo "OpenGL dmabufs $opengl_dmabuf" echo "libiscsi support $libiscsi" echo "libnfs support $libnfs" echo "build guest agent $guest_agent" @@ -5050,6 +5064,7 @@ if test "$gtk" = "yes" ; then echo "CONFIG_GTK=y" >> $config_host_mak echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak + echo "GTK_LIBS=$gtk_libs" >> $config_host_mak if test "$gtk_gl" = "yes" ; then echo "CONFIG_GTK_GL=y" >> $config_host_mak fi @@ -5158,6 +5173,9 @@ if test "$opengl" = "yes" ; then echo "CONFIG_OPENGL=y" >> $config_host_mak echo "OPENGL_CFLAGS=$opengl_cflags" >> $config_host_mak echo "OPENGL_LIBS=$opengl_libs" >> $config_host_mak + if test "$opengl_dmabuf" = "yes" ; then + echo "CONFIG_OPENGL_DMABUF=y" >> $config_host_mak + fi fi if test "$lzo" = "yes" ; then diff --git a/contrib/ivshmem-client/ivshmem-client.h b/contrib/ivshmem-client/ivshmem-client.h index 3a4f809682..54cde17d93 100644 --- a/contrib/ivshmem-client/ivshmem-client.h +++ b/contrib/ivshmem-client/ivshmem-client.h @@ -19,7 +19,6 @@ * purposes. */ -#include <limits.h> #include <sys/select.h> #include "qemu/queue.h" diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h index c9359a0a8a..e9de8a369d 100644 --- a/contrib/ivshmem-server/ivshmem-server.h +++ b/contrib/ivshmem-server/ivshmem-server.h @@ -26,10 +26,7 @@ * associated to the ivshmem shared memory. */ -#include <limits.h> #include <sys/select.h> -#include <stdint.h> -#include <stdbool.h> #include "qemu/event_notifier.h" #include "qemu/queue.h" @@ -1568,28 +1568,22 @@ CpuInfoList *qmp_query_cpus(Error **errp) info->value->thread_id = cpu->thread_id; #if defined(TARGET_I386) info->value->arch = CPU_INFO_ARCH_X86; - info->value->u.x86 = g_new0(CpuInfoX86, 1); - info->value->u.x86->pc = env->eip + env->segs[R_CS].base; + info->value->u.x86.pc = env->eip + env->segs[R_CS].base; #elif defined(TARGET_PPC) info->value->arch = CPU_INFO_ARCH_PPC; - info->value->u.ppc = g_new0(CpuInfoPPC, 1); - info->value->u.ppc->nip = env->nip; + info->value->u.ppc.nip = env->nip; #elif defined(TARGET_SPARC) info->value->arch = CPU_INFO_ARCH_SPARC; - info->value->u.q_sparc = g_new0(CpuInfoSPARC, 1); - info->value->u.q_sparc->pc = env->pc; - info->value->u.q_sparc->npc = env->npc; + info->value->u.q_sparc.pc = env->pc; + info->value->u.q_sparc.npc = env->npc; #elif defined(TARGET_MIPS) info->value->arch = CPU_INFO_ARCH_MIPS; - info->value->u.q_mips = g_new0(CpuInfoMIPS, 1); - info->value->u.q_mips->PC = env->active_tc.PC; + info->value->u.q_mips.PC = env->active_tc.PC; #elif defined(TARGET_TRICORE) info->value->arch = CPU_INFO_ARCH_TRICORE; - info->value->u.tricore = g_new0(CpuInfoTricore, 1); - info->value->u.tricore->PC = env->PC; + info->value->u.tricore.PC = env->PC; #else info->value->arch = CPU_INFO_ARCH_OTHER; - info->value->u.other = g_new0(CpuInfoOther, 1); #endif /* XXX: waiting for the qapi to support GSList */ diff --git a/device_tree.c b/device_tree.c index b1ad836073..6204af88c8 100644 --- a/device_tree.c +++ b/device_tree.c @@ -13,6 +13,10 @@ #include "qemu/osdep.h" +#ifdef CONFIG_LINUX +#include <dirent.h> +#endif + #include "qemu-common.h" #include "qemu/error-report.h" #include "sysemu/device_tree.h" @@ -112,6 +116,102 @@ fail: return NULL; } +#ifdef CONFIG_LINUX + +#define SYSFS_DT_BASEDIR "/proc/device-tree" + +/** + * read_fstree: this function is inspired from dtc read_fstree + * @fdt: preallocated fdt blob buffer, to be populated + * @dirname: directory to scan under SYSFS_DT_BASEDIR + * the search is recursive and the tree is searched down to the + * leaves (property files). + * + * the function asserts in case of error + */ +static void read_fstree(void *fdt, const char *dirname) +{ + DIR *d; + struct dirent *de; + struct stat st; + const char *root_dir = SYSFS_DT_BASEDIR; + const char *parent_node; + + if (strstr(dirname, root_dir) != dirname) { + error_setg(&error_fatal, "%s: %s must be searched within %s", + __func__, dirname, root_dir); + } + parent_node = &dirname[strlen(SYSFS_DT_BASEDIR)]; + + d = opendir(dirname); + if (!d) { + error_setg(&error_fatal, "%s cannot open %s", __func__, dirname); + } + + while ((de = readdir(d)) != NULL) { + char *tmpnam; + + if (!g_strcmp0(de->d_name, ".") + || !g_strcmp0(de->d_name, "..")) { + continue; + } + + tmpnam = g_strdup_printf("%s/%s", dirname, de->d_name); + + if (lstat(tmpnam, &st) < 0) { + error_setg(&error_fatal, "%s cannot lstat %s", __func__, tmpnam); + } + + if (S_ISREG(st.st_mode)) { + gchar *val; + gsize len; + + if (!g_file_get_contents(tmpnam, &val, &len, NULL)) { + error_setg(&error_fatal, "%s not able to extract info from %s", + __func__, tmpnam); + } + + if (strlen(parent_node) > 0) { + qemu_fdt_setprop(fdt, parent_node, + de->d_name, val, len); + } else { + qemu_fdt_setprop(fdt, "/", de->d_name, val, len); + } + g_free(val); + } else if (S_ISDIR(st.st_mode)) { + char *node_name; + + node_name = g_strdup_printf("%s/%s", + parent_node, de->d_name); + qemu_fdt_add_subnode(fdt, node_name); + g_free(node_name); + read_fstree(fdt, tmpnam); + } + + g_free(tmpnam); + } + + closedir(d); +} + +/* load_device_tree_from_sysfs: extract the dt blob from host sysfs */ +void *load_device_tree_from_sysfs(void) +{ + void *host_fdt; + int host_fdt_size; + + host_fdt = create_device_tree(&host_fdt_size); + read_fstree(host_fdt, SYSFS_DT_BASEDIR); + if (fdt_check_header(host_fdt)) { + error_setg(&error_fatal, + "%s host device tree extracted into memory is invalid", + __func__); + } + return host_fdt; +} + +#endif /* CONFIG_LINUX */ + static int findnode_nofail(void *fdt, const char *node_path) { int offset; @@ -126,6 +226,60 @@ static int findnode_nofail(void *fdt, const char *node_path) return offset; } +char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, + Error **errp) +{ + int offset, len, ret; + const char *iter_name; + unsigned int path_len = 16, n = 0; + GSList *path_list = NULL, *iter; + char **path_array; + + offset = fdt_node_offset_by_compatible(fdt, -1, compat); + + while (offset >= 0) { + iter_name = fdt_get_name(fdt, offset, &len); + if (!iter_name) { + offset = len; + break; + } + if (!strcmp(iter_name, name)) { + char *path; + + path = g_malloc(path_len); + while ((ret = fdt_get_path(fdt, offset, path, path_len)) + == -FDT_ERR_NOSPACE) { + path_len += 16; + path = g_realloc(path, path_len); + } + path_list = g_slist_prepend(path_list, path); + n++; + } + offset = fdt_node_offset_by_compatible(fdt, offset, compat); + } + + if (offset < 0 && offset != -FDT_ERR_NOTFOUND) { + error_setg(errp, "%s: abort parsing dt for %s/%s: %s", + __func__, name, compat, fdt_strerror(offset)); + for (iter = path_list; iter; iter = iter->next) { + g_free(iter->data); + } + g_slist_free(path_list); + return NULL; + } + + path_array = g_new(char *, n + 1); + path_array[n--] = NULL; + + for (iter = path_list; iter; iter = iter->next) { + path_array[n--] = iter->data; + } + + g_slist_free(path_list); + + return path_array; +} + int qemu_fdt_setprop(void *fdt, const char *node_path, const char *property, const void *val, int size) { @@ -179,31 +333,39 @@ int qemu_fdt_setprop_string(void *fdt, const char *node_path, } const void *qemu_fdt_getprop(void *fdt, const char *node_path, - const char *property, int *lenp) + const char *property, int *lenp, Error **errp) { int len; const void *r; + if (!lenp) { lenp = &len; } r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp); if (!r) { - error_report("%s: Couldn't get %s/%s: %s", __func__, - node_path, property, fdt_strerror(*lenp)); - exit(1); + error_setg(errp, "%s: Couldn't get %s/%s: %s", __func__, + node_path, property, fdt_strerror(*lenp)); } return r; } uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path, - const char *property) + const char *property, int *lenp, Error **errp) { int len; - const uint32_t *p = qemu_fdt_getprop(fdt, node_path, property, &len); - if (len != 4) { - error_report("%s: %s/%s not 4 bytes long (not a cell?)", - __func__, node_path, property); - exit(1); + const uint32_t *p; + + if (!lenp) { + lenp = &len; + } + p = qemu_fdt_getprop(fdt, node_path, property, lenp, errp); + if (!p) { + return 0; + } else if (*lenp != 4) { + error_setg(errp, "%s: %s/%s not 4 bytes long (not a cell?)", + __func__, node_path, property); + *lenp = -EINVAL; + return 0; } return be32_to_cpu(*p); } diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc index d4d46d5ff3..9280950ce3 100644 --- a/disas/arm-a64.cc +++ b/disas/arm-a64.cc @@ -17,12 +17,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "vixl/a64/disasm-a64.h" - extern "C" { +#include "qemu/osdep.h" #include "disas/bfd.h" } +#include "vixl/a64/disasm-a64.h" + using namespace vixl; static Decoder *vixl_decoder = NULL; diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 128f074a2d..999f3b98f0 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -187,11 +187,11 @@ prevent incomplete include files. Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME } -A struct is a dictionary containing a single 'data' key whose -value is a dictionary. This corresponds to a struct in C or an Object -in JSON. Each value of the 'data' dictionary must be the name of a -type, or a one-element array containing a type name. An example of a -struct is: +A struct is a dictionary containing a single 'data' key whose value is +a dictionary; the dictionary may be empty. This corresponds to a +struct in C or an Object in JSON. Each value of the 'data' dictionary +must be the name of a type, or a one-element array containing a type +name. An example of a struct is: { 'struct': 'MyType', 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } @@ -288,9 +288,10 @@ or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME, Union types are used to let the user choose between several different variants for an object. There are two flavors: simple (no -discriminator or base), flat (both discriminator and base). A union +discriminator or base), and flat (both discriminator and base). A union type is defined using a data dictionary as explained in the following -paragraphs. +paragraphs. The data dictionary for either type of union must not +be empty. A simple union type defines a mapping from automatic discriminator values to data types like in this example: diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt index f236d8c6d9..80cdfd0e91 100644 --- a/docs/specs/qcow2.txt +++ b/docs/specs/qcow2.txt @@ -103,7 +103,18 @@ in the description of a field. write to an image with unknown auto-clear features if it clears the respective bits from this field first. - Bits 0-63: Reserved (set to 0) + Bit 0: Bitmaps extension bit + This bit indicates consistency for the bitmaps + extension data. + + It is an error if this bit is set without the + bitmaps extension present. + + If the bitmaps extension is present but this + bit is unset, the bitmaps extension data must be + considered inconsistent. + + Bits 1-63: Reserved (set to 0) 96 - 99: refcount_order Describes the width of a reference count block entry (width @@ -123,6 +134,7 @@ be stored. Each extension has a structure like the following: 0x00000000 - End of the header extension area 0xE2792ACA - Backing file format name 0x6803f857 - Feature name table + 0x23852875 - Bitmaps extension other - Unknown header extension, can be safely ignored @@ -166,6 +178,36 @@ the header extension data. Each entry look like this: terminated if it has full length) +== Bitmaps extension == + +The bitmaps extension is an optional header extension. It provides the ability +to store bitmaps related to a virtual disk. For now, there is only one bitmap +type: the dirty tracking bitmap, which tracks virtual disk changes from some +point in time. + +The data of the extension should be considered consistent only if the +corresponding auto-clear feature bit is set, see autoclear_features above. + +The fields of the bitmaps extension are: + + Byte 0 - 3: nb_bitmaps + The number of bitmaps contained in the image. Must be + greater than or equal to 1. + + Note: Qemu currently only supports up to 65535 bitmaps per + image. + + 4 - 7: Reserved, must be zero. + + 8 - 15: bitmap_directory_size + Size of the bitmap directory in bytes. It is the cumulative + size of all (nb_bitmaps) bitmap headers. + + 16 - 23: bitmap_directory_offset + Offset into the image file at which the bitmap directory + starts. Must be aligned to a cluster boundary. + + == Host cluster management == qcow2 manages the allocation of host clusters by maintaining a reference count @@ -360,3 +402,180 @@ Snapshot table entry: variable: Padding to round up the snapshot table entry size to the next multiple of 8. + + +== Bitmaps == + +As mentioned above, the bitmaps extension provides the ability to store bitmaps +related to a virtual disk. This section describes how these bitmaps are stored. + +All stored bitmaps are related to the virtual disk stored in the same image, so +each bitmap size is equal to the virtual disk size. + +Each bit of the bitmap is responsible for strictly defined range of the virtual +disk. For bit number bit_nr the corresponding range (in bytes) will be: + + [bit_nr * bitmap_granularity .. (bit_nr + 1) * bitmap_granularity - 1] + +Granularity is a property of the concrete bitmap, see below. + + +=== Bitmap directory === + +Each bitmap saved in the image is described in a bitmap directory entry. The +bitmap directory is a contiguous area in the image file, whose starting offset +and length are given by the header extension fields bitmap_directory_offset and +bitmap_directory_size. The entries of the bitmap directory have variable +length, depending on the lengths of the bitmap name and extra data. These +entries are also called bitmap headers. + +Structure of a bitmap directory entry: + + Byte 0 - 7: bitmap_table_offset + Offset into the image file at which the bitmap table + (described below) for the bitmap starts. Must be aligned to + a cluster boundary. + + 8 - 11: bitmap_table_size + Number of entries in the bitmap table of the bitmap. + + 12 - 15: flags + Bit + 0: in_use + The bitmap was not saved correctly and may be + inconsistent. + + 1: auto + The bitmap must reflect all changes of the virtual + disk by any application that would write to this qcow2 + file (including writes, snapshot switching, etc.). The + type of this bitmap must be 'dirty tracking bitmap'. + + 2: extra_data_compatible + This flags is meaningful when the extra data is + unknown to the software (currently any extra data is + unknown to Qemu). + If it is set, the bitmap may be used as expected, extra + data must be left as is. + If it is not set, the bitmap must not be used, but + both it and its extra data be left as is. + + Bits 3 - 31 are reserved and must be 0. + + 16: type + This field describes the sort of the bitmap. + Values: + 1: Dirty tracking bitmap + + Values 0, 2 - 255 are reserved. + + 17: granularity_bits + Granularity bits. Valid values: 0 - 63. + + Note: Qemu currently doesn't support granularity_bits + greater than 31. + + Granularity is calculated as + granularity = 1 << granularity_bits + + A bitmap's granularity is how many bytes of the image + accounts for one bit of the bitmap. + + 18 - 19: name_size + Size of the bitmap name. Must be non-zero. + + Note: Qemu currently doesn't support values greater than + 1023. + + 20 - 23: extra_data_size + Size of type-specific extra data. + + For now, as no extra data is defined, extra_data_size is + reserved and should be zero. If it is non-zero the + behavior is defined by extra_data_compatible flag. + + variable: extra_data + Extra data for the bitmap, occupying extra_data_size bytes. + Extra data must never contain references to clusters or in + some other way allocate additional clusters. + + variable: name + The name of the bitmap (not null terminated), occupying + name_size bytes. Must be unique among all bitmap names + within the bitmaps extension. + + variable: Padding to round up the bitmap directory entry size to the + next multiple of 8. All bytes of the padding must be zero. + + +=== Bitmap table === + +Each bitmap is stored using a one-level structure (as opposed to two-level +structures like for refcounts and guest clusters mapping) for the mapping of +bitmap data to host clusters. This structure is called the bitmap table. + +Each bitmap table has a variable size (stored in the bitmap directory entry) +and may use multiple clusters, however, it must be contiguous in the image +file. + +Structure of a bitmap table entry: + + Bit 0: Reserved and must be zero if bits 9 - 55 are non-zero. + If bits 9 - 55 are zero: + 0: Cluster should be read as all zeros. + 1: Cluster should be read as all ones. + + 1 - 8: Reserved and must be zero. + + 9 - 55: Bits 9 - 55 of the host cluster offset. Must be aligned to + a cluster boundary. If the offset is 0, the cluster is + unallocated; in that case, bit 0 determines how this + cluster should be treated during reads. + + 56 - 63: Reserved and must be zero. + + +=== Bitmap data === + +As noted above, bitmap data is stored in separate clusters, described by the +bitmap table. Given an offset (in bytes) into the bitmap data, the offset into +the image file can be obtained as follows: + + image_offset(bitmap_data_offset) = + bitmap_table[bitmap_data_offset / cluster_size] + + (bitmap_data_offset % cluster_size) + +This offset is not defined if bits 9 - 55 of bitmap table entry are zero (see +above). + +Given an offset byte_nr into the virtual disk and the bitmap's granularity, the +bit offset into the image file to the corresponding bit of the bitmap can be +calculated like this: + + bit_offset(byte_nr) = + image_offset(byte_nr / granularity / 8) * 8 + + (byte_nr / granularity) % 8 + +If the size of the bitmap data is not a multiple of the cluster size then the +last cluster of the bitmap data contains some unused tail bits. These bits must +be zero. + + +=== Dirty tracking bitmaps === + +Bitmaps with 'type' field equal to one are dirty tracking bitmaps. + +When the virtual disk is in use dirty tracking bitmap may be 'enabled' or +'disabled'. While the bitmap is 'enabled', all writes to the virtual disk +should be reflected in the bitmap. A set bit in the bitmap means that the +corresponding range of the virtual disk (see above) was written to while the +bitmap was 'enabled'. An unset bit means that this range was not written to. + +The software doesn't have to sync the bitmap in the image file with its +representation in RAM after each write. Flag 'in_use' should be set while the +bitmap is not synced. + +In the image file the 'enabled' state is reflected by the 'auto' flag. If this +flag is set, the software must consider the bitmap as 'enabled' and start +tracking virtual disk changes to this bitmap from the first write to the +virtual disk. If this flag is not set then the bitmap is disabled. diff --git a/docs/throttle.txt b/docs/throttle.txt new file mode 100644 index 0000000000..28204e46ca --- /dev/null +++ b/docs/throttle.txt @@ -0,0 +1,252 @@ +The QEMU throttling infrastructure +================================== +Copyright (C) 2016 Igalia, S.L. +Author: Alberto Garcia <berto@igalia.com> + +This work is licensed under the terms of the GNU GPL, version 2 or +later. See the COPYING file in the top-level directory. + +Introduction +------------ +QEMU includes a throttling module that can be used to set limits to +I/O operations. The code itself is generic and independent of the I/O +units, but it is currenly used to limit the number of bytes per second +and operations per second (IOPS) when performing disk I/O. + +This document explains how to use the throttling code in QEMU, and how +it works internally. The implementation is in throttle.c. + + +Using throttling to limit disk I/O +---------------------------------- +Two aspects of the disk I/O can be limited: the number of bytes per +second and the number of operations per second (IOPS). For each one of +them the user can set a global limit or separate limits for read and +write operations. This gives us a total of six different parameters. + +I/O limits can be set using the throttling.* parameters of -drive, or +using the QMP 'block_set_io_throttle' command. These are the names of +the parameters for both cases: + +|-----------------------+-----------------------| +| -drive | block_set_io_throttle | +|-----------------------+-----------------------| +| throttling.iops-total | iops | +| throttling.iops-read | iops_rd | +| throttling.iops-write | iops_wr | +| throttling.bps-total | bps | +| throttling.bps-read | bps_rd | +| throttling.bps-write | bps_wr | +|-----------------------+-----------------------| + +It is possible to set limits for both IOPS and bps and the same time, +and for each case we can decide whether to have separate read and +write limits or not, but note that if iops-total is set then neither +iops-read nor iops-write can be set. The same applies to bps-total and +bps-read/write. + +The default value of these parameters is 0, and it means 'unlimited'. + +In its most basic usage, the user can add a drive to QEMU with a limit +of 100 IOPS with the following -drive line: + + -drive file=hd0.qcow2,throttling.iops-total=100 + +We can do the same using QMP. In this case all these parameters are +mandatory, so we must set to 0 the ones that we don't want to limit: + + { "execute": "block_set_io_throttle", + "arguments": { + "device": "virtio0", + "iops": 100, + "iops_rd": 0, + "iops_wr": 0, + "bps": 0, + "bps_rd": 0, + "bps_wr": 0 + } + } + + +I/O bursts +---------- +In addition to the basic limits we have just seen, QEMU allows the +user to do bursts of I/O for a configurable amount of time. A burst is +an amount of I/O that can exceed the basic limit. Bursts are useful to +allow better performance when there are peaks of activity (the OS +boots, a service needs to be restarted) while keeping the average +limits lower the rest of the time. + +Two parameters control bursts: their length and the maximum amount of +I/O they allow. These two can be configured separately for each one of +the six basic parameters described in the previous section, but in +this section we'll use 'iops-total' as an example. + +The I/O limit during bursts is set using 'iops-total-max', and the +maximum length (in seconds) is set with 'iops-total-max-length'. So if +we want to configure a drive with a basic limit of 100 IOPS and allow +bursts of 2000 IOPS for 60 seconds, we would do it like this (the line +is split for clarity): + + -drive file=hd0.qcow2, + throttling.iops-total=100, + throttling.iops-total-max=2000, + throttling.iops-total-max-length=60 + +Or, with QMP: + + { "execute": "block_set_io_throttle", + "arguments": { + "device": "virtio0", + "iops": 100, + "iops_rd": 0, + "iops_wr": 0, + "bps": 0, + "bps_rd": 0, + "bps_wr": 0, + "iops_max": 2000, + "iops_max_length": 60, + } + } + +With this, the user can perform I/O on hd0.qcow2 at a rate of 2000 +IOPS for 1 minute before it's throttled down to 100 IOPS. + +The user will be able to do bursts again if there's a sufficiently +long period of time with unused I/O (see below for details). + +The default value for 'iops-total-max' is 0 and it means that bursts +are not allowed. 'iops-total-max-length' can only be set if +'iops-total-max' is set as well, and its default value is 1 second. + +Here's the complete list of parameters for configuring bursts: + +|----------------------------------+-----------------------| +| -drive | block_set_io_throttle | +|----------------------------------+-----------------------| +| throttling.iops-total-max | iops_max | +| throttling.iops-total-max-length | iops_max_length | +| throttling.iops-read-max | iops_rd_max | +| throttling.iops-read-max-length | iops_rd_max_length | +| throttling.iops-write-max | iops_wr_max | +| throttling.iops-write-max-length | iops_wr_max_length | +| throttling.bps-total-max | bps_max | +| throttling.bps-total-max-length | bps_max_length | +| throttling.bps-read-max | bps_rd_max | +| throttling.bps-read-max-length | bps_rd_max_length | +| throttling.bps-write-max | bps_wr_max | +| throttling.bps-write-max-length | bps_wr_max_length | +|----------------------------------+-----------------------| + + +Controlling the size of I/O operations +-------------------------------------- +When applying IOPS limits all I/O operations are treated equally +regardless of their size. This means that the user can take advantage +of this in order to circumvent the limits and submit one huge I/O +request instead of several smaller ones. + +QEMU provides a setting called throttling.iops-size to prevent this +from happening. This setting specifies the size (in bytes) of an I/O +request for accounting purposes. Larger requests will be counted +proportionally to this size. + +For example, if iops-size is set to 4096 then an 8KB request will be +counted as two, and a 6KB request will be counted as one and a +half. This only applies to requests larger than iops-size: smaller +requests will be always counted as one, no matter their size. + +The default value of iops-size is 0 and it means that the size of the +requests is never taken into account when applying IOPS limits. + + +Applying I/O limits to groups of disks +-------------------------------------- +In all the examples so far we have seen how to apply limits to the I/O +performed on individual drives, but QEMU allows grouping drives so +they all share the same limits. + +The way it works is that each drive with I/O limits is assigned to a +group named using the throttling.group parameter. If this parameter is +not specified, then the device name (i.e. 'virtio0', 'ide0-hd0') will +be used as the group name. + +Limits set using the throttling.* parameters discussed earlier in this +document apply to the combined I/O of all members of a group. + +Consider this example: + + -drive file=hd1.qcow2,throttling.iops-total=6000,throttling.group=foo + -drive file=hd2.qcow2,throttling.iops-total=6000,throttling.group=foo + -drive file=hd3.qcow2,throttling.iops-total=3000,throttling.group=bar + -drive file=hd4.qcow2,throttling.iops-total=6000,throttling.group=foo + -drive file=hd5.qcow2,throttling.iops-total=3000,throttling.group=bar + -drive file=hd6.qcow2,throttling.iops-total=5000 + +Here hd1, hd2 and hd4 are all members of a group named 'foo' with a +combined IOPS limit of 6000, and hd3 and hd5 are members of 'bar'. hd6 +is left alone (technically it is part of a 1-member group). + +Limits are applied in a round-robin fashion so if there are concurrent +I/O requests on several drives of the same group they will be +distributed evenly. + +When I/O limits are applied to an existing drive using the QMP command +'block_set_io_throttle', the following things need to be taken into +account: + + - I/O limits are shared within the same group, so new values will + affect all members and overwrite the previous settings. In other + words: if different limits are applied to members of the same + group, the last one wins. + + - If 'group' is unset it is assumed to be the current group of that + drive. If the drive is not in a group yet, it will be added to a + group named after the device name. + + - If 'group' is set then the drive will be moved to that group if + it was member of a different one. In this case the limits + specified in the parameters will be applied to the new group + only. + + - I/O limits can be disabled by setting all of them to 0. In this + case the device will be removed from its group and the rest of + its members will not be affected. The 'group' parameter is + ignored. + + +The Leaky Bucket algorithm +-------------------------- +I/O limits in QEMU are implemented using the leaky bucket algorithm +(specifically the "Leaky bucket as a meter" variant). + +This algorithm uses the analogy of a bucket that leaks water +constantly. The water that gets into the bucket represents the I/O +that has been performed, and no more I/O is allowed once the bucket is +full. + +To see the way this corresponds to the throttling parameters in QEMU, +consider the following values: + + iops-total=100 + iops-total-max=2000 + iops-total-max-length=60 + + - Water leaks from the bucket at a rate of 100 IOPS. + - Water can be added to the bucket at a rate of 2000 IOPS. + - The size of the bucket is 2000 x 60 = 120000 + - If 'iops-total-max-length' is unset then the bucket size is 100. + +The bucket is initially empty, therefore water can be added until it's +full at a rate of 2000 IOPS (the burst rate). Once the bucket is full +we can only add as much water as it leaks, therefore the I/O rate is +reduced to 100 IOPS. If we add less water than it leaks then the +bucket will start to empty, allowing for bursts again. + +Note that since water is leaking from the bucket even during bursts, +it will take a bit more than 60 seconds at 2000 IOPS to fill it +up. After those 60 seconds the bucket will have leaked 60 x 100 = +6000, allowing for 3 more seconds of I/O at 2000 IOPS. + +Also, due to the way the algorithm works, longer burst can be done at +a lower I/O rate, e.g. 1000 IOPS during 120 seconds. diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index e95b4450fa..9cc6158cb4 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -99,7 +99,7 @@ this code that are retained. | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ -static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr) +static inline void shift32RightJamming(uint32_t a, int count, uint32_t *zPtr) { uint32_t z; @@ -125,7 +125,7 @@ static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ -static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr) +static inline void shift64RightJamming(uint64_t a, int count, uint64_t *zPtr) { uint64_t z; @@ -161,7 +161,7 @@ static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t static inline void shift64ExtraRightJamming( - uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr) + uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) { uint64_t z0, z1; int8_t negCount = ( - count ) & 63; @@ -198,7 +198,7 @@ static inline void static inline void shift128Right( - uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr) + uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) { uint64_t z0, z1; int8_t negCount = ( - count ) & 63; @@ -233,7 +233,7 @@ static inline void static inline void shift128RightJamming( - uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr) + uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) { uint64_t z0, z1; int8_t negCount = ( - count ) & 63; @@ -287,7 +287,7 @@ static inline void uint64_t a0, uint64_t a1, uint64_t a2, - int_fast16_t count, + int count, uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr @@ -342,7 +342,7 @@ static inline void static inline void shortShift128Left( - uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr) + uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) { *z1Ptr = a1<<count; @@ -364,7 +364,7 @@ static inline void uint64_t a0, uint64_t a1, uint64_t a2, - int_fast16_t count, + int count, uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr @@ -635,7 +635,7 @@ static uint64_t estimateDiv128To64( uint64_t a0, uint64_t a1, uint64_t b ) | value. *----------------------------------------------------------------------------*/ -static uint32_t estimateSqrt32(int_fast16_t aExp, uint32_t a) +static uint32_t estimateSqrt32(int aExp, uint32_t a) { static const uint16_t sqrtOddAdjustments[] = { 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, diff --git a/fpu/softfloat.c b/fpu/softfloat.c index cfa9787d8d..166c48e434 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -118,7 +118,7 @@ static inline uint32_t extractFloat16Frac(float16 a) | Returns the exponent bits of the half-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline int_fast16_t extractFloat16Exp(float16 a) +static inline int extractFloat16Exp(float16 a) { return (float16_val(a) >> 10) & 0x1f; } @@ -314,7 +314,7 @@ static inline uint32_t extractFloat32Frac( float32 a ) | Returns the exponent bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline int_fast16_t extractFloat32Exp(float32 a) +static inline int extractFloat32Exp(float32 a) { return ( float32_val(a)>>23 ) & 0xFF; @@ -355,7 +355,7 @@ float32 float32_squash_input_denormal(float32 a, float_status *status) *----------------------------------------------------------------------------*/ static void - normalizeFloat32Subnormal(uint32_t aSig, int_fast16_t *zExpPtr, uint32_t *zSigPtr) + normalizeFloat32Subnormal(uint32_t aSig, int *zExpPtr, uint32_t *zSigPtr) { int8_t shiftCount; @@ -376,7 +376,7 @@ static void | significand. *----------------------------------------------------------------------------*/ -static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig) +static inline float32 packFloat32(flag zSign, int zExp, uint32_t zSig) { return make_float32( @@ -406,7 +406,7 @@ static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float32 roundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig, +static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, float_status *status) { int8_t roundingMode; @@ -481,7 +481,7 @@ static float32 roundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig, *----------------------------------------------------------------------------*/ static float32 - normalizeRoundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig, + normalizeRoundAndPackFloat32(flag zSign, int zExp, uint32_t zSig, float_status *status) { int8_t shiftCount; @@ -507,7 +507,7 @@ static inline uint64_t extractFloat64Frac( float64 a ) | Returns the exponent bits of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -static inline int_fast16_t extractFloat64Exp(float64 a) +static inline int extractFloat64Exp(float64 a) { return ( float64_val(a)>>52 ) & 0x7FF; @@ -548,7 +548,7 @@ float64 float64_squash_input_denormal(float64 a, float_status *status) *----------------------------------------------------------------------------*/ static void - normalizeFloat64Subnormal(uint64_t aSig, int_fast16_t *zExpPtr, uint64_t *zSigPtr) + normalizeFloat64Subnormal(uint64_t aSig, int *zExpPtr, uint64_t *zSigPtr) { int8_t shiftCount; @@ -569,7 +569,7 @@ static void | significand. *----------------------------------------------------------------------------*/ -static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig) +static inline float64 packFloat64(flag zSign, int zExp, uint64_t zSig) { return make_float64( @@ -599,12 +599,12 @@ static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float64 roundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig, +static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, float_status *status) { int8_t roundingMode; flag roundNearestEven; - int_fast16_t roundIncrement, roundBits; + int roundIncrement, roundBits; flag isTiny; roundingMode = status->float_rounding_mode; @@ -673,7 +673,7 @@ static float64 roundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig, *----------------------------------------------------------------------------*/ static float64 - normalizeRoundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig, + normalizeRoundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, float_status *status) { int8_t shiftCount; @@ -1543,7 +1543,8 @@ float128 uint64_to_float128(uint64_t a, float_status *status) int32_t float32_to_int32(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; uint64_t aSig64; @@ -1574,7 +1575,8 @@ int32_t float32_to_int32(float32 a, float_status *status) int32_t float32_to_int32_round_to_zero(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; int32_t z; a = float32_squash_input_denormal(a, status); @@ -1616,10 +1618,11 @@ int32_t float32_to_int32_round_to_zero(float32 a, float_status *status) | returned. *----------------------------------------------------------------------------*/ -int_fast16_t float32_to_int16_round_to_zero(float32 a, float_status *status) +int16_t float32_to_int16_round_to_zero(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; int32_t z; @@ -1668,7 +1671,8 @@ int_fast16_t float32_to_int16_round_to_zero(float32 a, float_status *status) int64_t float32_to_int64(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; uint64_t aSig64, aSigExtra; a = float32_squash_input_denormal(a, status); @@ -1707,7 +1711,8 @@ int64_t float32_to_int64(float32 a, float_status *status) uint64_t float32_to_uint64(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; uint64_t aSig64, aSigExtra; a = float32_squash_input_denormal(a, status); @@ -1771,7 +1776,8 @@ uint64_t float32_to_uint64_round_to_zero(float32 a, float_status *status) int64_t float32_to_int64_round_to_zero(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint32_t aSig; uint64_t aSig64; int64_t z; @@ -1817,7 +1823,7 @@ int64_t float32_to_int64_round_to_zero(float32 a, float_status *status) float64 float32_to_float64(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; a = float32_squash_input_denormal(a, status); @@ -1849,7 +1855,7 @@ float64 float32_to_float64(float32 a, float_status *status) floatx80 float32_to_floatx80(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; a = float32_squash_input_denormal(a, status); @@ -1881,7 +1887,7 @@ floatx80 float32_to_floatx80(float32 a, float_status *status) float128 float32_to_float128(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; a = float32_squash_input_denormal(a, status); @@ -1913,7 +1919,7 @@ float128 float32_to_float128(float32 a, float_status *status) float32 float32_round_to_int(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t lastBitMask, roundBitsMask; uint32_t z; a = float32_squash_input_denormal(a, status); @@ -1995,9 +2001,9 @@ float32 float32_round_to_int(float32 a, float_status *status) static float32 addFloat32Sigs(float32 a, float32 b, flag zSign, float_status *status) { - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint32_t aSig, bSig, zSig; - int_fast16_t expDiff; + int expDiff; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2081,9 +2087,9 @@ static float32 addFloat32Sigs(float32 a, float32 b, flag zSign, static float32 subFloat32Sigs(float32 a, float32 b, flag zSign, float_status *status) { - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint32_t aSig, bSig, zSig; - int_fast16_t expDiff; + int expDiff; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2207,7 +2213,7 @@ float32 float32_sub(float32 a, float32 b, float_status *status) float32 float32_mul(float32 a, float32 b, float_status *status) { flag aSign, bSign, zSign; - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint32_t aSig, bSig; uint64_t zSig64; uint32_t zSig; @@ -2272,7 +2278,7 @@ float32 float32_mul(float32 a, float32 b, float_status *status) float32 float32_div(float32 a, float32 b, float_status *status) { flag aSign, bSign, zSign; - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint32_t aSig, bSig, zSig; a = float32_squash_input_denormal(a, status); b = float32_squash_input_denormal(b, status); @@ -2342,7 +2348,7 @@ float32 float32_div(float32 a, float32 b, float_status *status) float32 float32_rem(float32 a, float32 b, float_status *status) { flag aSign, zSign; - int_fast16_t aExp, bExp, expDiff; + int aExp, bExp, expDiff; uint32_t aSig, bSig; uint32_t q; uint64_t aSig64, bSig64, q64; @@ -2450,7 +2456,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags, float_status *status) { flag aSign, bSign, cSign, zSign; - int_fast16_t aExp, bExp, cExp, pExp, zExp, expDiff; + int aExp, bExp, cExp, pExp, zExp, expDiff; uint32_t aSig, bSig, cSig; flag pInf, pZero, pSign; uint64_t pSig64, cSig64, zSig64; @@ -2670,7 +2676,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags, float32 float32_sqrt(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp, zExp; + int aExp, zExp; uint32_t aSig, zSig; uint64_t rem, term; a = float32_squash_input_denormal(a, status); @@ -2758,7 +2764,7 @@ static const float64 float32_exp2_coefficients[15] = float32 float32_exp2(float32 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; float64 r, x, xn; int i; @@ -2808,7 +2814,7 @@ float32 float32_exp2(float32 a, float_status *status) float32 float32_log2(float32 a, float_status *status) { flag aSign, zSign; - int_fast16_t aExp; + int aExp; uint32_t aSig, zSig, i; a = float32_squash_input_denormal(a, status); @@ -3075,7 +3081,8 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status) int32_t float64_to_int32(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig; a = float64_squash_input_denormal(a, status); @@ -3103,7 +3110,8 @@ int32_t float64_to_int32(float64 a, float_status *status) int32_t float64_to_int32_round_to_zero(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig, savedASig; int32_t z; a = float64_squash_input_denormal(a, status); @@ -3149,10 +3157,11 @@ int32_t float64_to_int32_round_to_zero(float64 a, float_status *status) | returned. *----------------------------------------------------------------------------*/ -int_fast16_t float64_to_int16_round_to_zero(float64 a, float_status *status) +int16_t float64_to_int16_round_to_zero(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig, savedASig; int32_t z; @@ -3203,7 +3212,8 @@ int_fast16_t float64_to_int16_round_to_zero(float64 a, float_status *status) int64_t float64_to_int64(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig, aSigExtra; a = float64_squash_input_denormal(a, status); @@ -3246,7 +3256,8 @@ int64_t float64_to_int64(float64 a, float_status *status) int64_t float64_to_int64_round_to_zero(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig; int64_t z; a = float64_squash_input_denormal(a, status); @@ -3298,7 +3309,7 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *status) float32 float64_to_float32(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t aSig; uint32_t zSig; a = float64_squash_input_denormal(a, status); @@ -3333,7 +3344,7 @@ float32 float64_to_float32(float64 a, float_status *status) | than the desired result exponent whenever `zSig' is a complete, normalized | significand. *----------------------------------------------------------------------------*/ -static float16 packFloat16(flag zSign, int_fast16_t zExp, uint16_t zSig) +static float16 packFloat16(flag zSign, int zExp, uint16_t zSig) { return make_float16( (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig); @@ -3367,7 +3378,7 @@ static float16 packFloat16(flag zSign, int_fast16_t zExp, uint16_t zSig) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float16 roundAndPackFloat16(flag zSign, int_fast16_t zExp, +static float16 roundAndPackFloat16(flag zSign, int zExp, uint32_t zSig, flag ieee, float_status *status) { @@ -3454,7 +3465,7 @@ static float16 roundAndPackFloat16(flag zSign, int_fast16_t zExp, return packFloat16(zSign, zExp, zSig >> 13); } -static void normalizeFloat16Subnormal(uint32_t aSig, int_fast16_t *zExpPtr, +static void normalizeFloat16Subnormal(uint32_t aSig, int *zExpPtr, uint32_t *zSigPtr) { int8_t shiftCount = countLeadingZeros32(aSig) - 21; @@ -3468,7 +3479,7 @@ static void normalizeFloat16Subnormal(uint32_t aSig, int_fast16_t *zExpPtr, float32 float16_to_float32(float16 a, flag ieee, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; aSign = extractFloat16Sign(a); @@ -3495,7 +3506,7 @@ float32 float16_to_float32(float16 a, flag ieee, float_status *status) float16 float32_to_float16(float32 a, flag ieee, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; a = float32_squash_input_denormal(a, status); @@ -3539,7 +3550,7 @@ float16 float32_to_float16(float32 a, flag ieee, float_status *status) float64 float16_to_float64(float16 a, flag ieee, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint32_t aSig; aSign = extractFloat16Sign(a); @@ -3567,7 +3578,7 @@ float64 float16_to_float64(float16 a, flag ieee, float_status *status) float16 float64_to_float16(float64 a, flag ieee, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t aSig; uint32_t zSig; @@ -3621,7 +3632,7 @@ float16 float64_to_float16(float64 a, flag ieee, float_status *status) floatx80 float64_to_floatx80(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t aSig; a = float64_squash_input_denormal(a, status); @@ -3654,7 +3665,7 @@ floatx80 float64_to_floatx80(float64 a, float_status *status) float128 float64_to_float128(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t aSig, zSig0, zSig1; a = float64_squash_input_denormal(a, status); @@ -3687,7 +3698,7 @@ float128 float64_to_float128(float64 a, float_status *status) float64 float64_round_to_int(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t lastBitMask, roundBitsMask; uint64_t z; a = float64_squash_input_denormal(a, status); @@ -3781,9 +3792,9 @@ float64 float64_trunc_to_int(float64 a, float_status *status) static float64 addFloat64Sigs(float64 a, float64 b, flag zSign, float_status *status) { - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint64_t aSig, bSig, zSig; - int_fast16_t expDiff; + int expDiff; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3867,9 +3878,9 @@ static float64 addFloat64Sigs(float64 a, float64 b, flag zSign, static float64 subFloat64Sigs(float64 a, float64 b, flag zSign, float_status *status) { - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint64_t aSig, bSig, zSig; - int_fast16_t expDiff; + int expDiff; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3993,7 +4004,7 @@ float64 float64_sub(float64 a, float64 b, float_status *status) float64 float64_mul(float64 a, float64 b, float_status *status) { flag aSign, bSign, zSign; - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint64_t aSig, bSig, zSig0, zSig1; a = float64_squash_input_denormal(a, status); @@ -4056,7 +4067,7 @@ float64 float64_mul(float64 a, float64 b, float_status *status) float64 float64_div(float64 a, float64 b, float_status *status) { flag aSign, bSign, zSign; - int_fast16_t aExp, bExp, zExp; + int aExp, bExp, zExp; uint64_t aSig, bSig, zSig; uint64_t rem0, rem1; uint64_t term0, term1; @@ -4134,7 +4145,7 @@ float64 float64_div(float64 a, float64 b, float_status *status) float64 float64_rem(float64 a, float64 b, float_status *status) { flag aSign, zSign; - int_fast16_t aExp, bExp, expDiff; + int aExp, bExp, expDiff; uint64_t aSig, bSig; uint64_t q, alternateASig; int64_t sigMean; @@ -4228,7 +4239,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags, float_status *status) { flag aSign, bSign, cSign, zSign; - int_fast16_t aExp, bExp, cExp, pExp, zExp, expDiff; + int aExp, bExp, cExp, pExp, zExp, expDiff; uint64_t aSig, bSig, cSig; flag pInf, pZero, pSign; uint64_t pSig0, pSig1, cSig0, cSig1, zSig0, zSig1; @@ -4469,7 +4480,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags, float64 float64_sqrt(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, zExp; + int aExp, zExp; uint64_t aSig, zSig, doubleZSig; uint64_t rem0, rem1, term0, term1; a = float64_squash_input_denormal(a, status); @@ -4522,7 +4533,7 @@ float64 float64_sqrt(float64 a, float_status *status) float64 float64_log2(float64 a, float_status *status) { flag aSign, zSign; - int_fast16_t aExp; + int aExp; uint64_t aSig, aSig0, aSig1, zSig, i; a = float64_squash_input_denormal(a, status); @@ -5005,7 +5016,7 @@ float64 floatx80_to_float64(floatx80 a, float_status *status) float128 floatx80_to_float128(floatx80 a, float_status *status) { flag aSign; - int_fast16_t aExp; + int aExp; uint64_t aSig, zSig0, zSig1; aSig = extractFloatx80Frac( a ); @@ -7117,10 +7128,10 @@ uint32_t float32_to_uint32_round_to_zero(float32 a, float_status *status) return res; } -int_fast16_t float32_to_int16(float32 a, float_status *status) +int16_t float32_to_int16(float32 a, float_status *status) { int32_t v; - int_fast16_t res; + int16_t res; int old_exc_flags = get_float_exception_flags(status); v = float32_to_int32(a, status); @@ -7137,10 +7148,10 @@ int_fast16_t float32_to_int16(float32 a, float_status *status) return res; } -uint_fast16_t float32_to_uint16(float32 a, float_status *status) +uint16_t float32_to_uint16(float32 a, float_status *status) { int32_t v; - uint_fast16_t res; + uint16_t res; int old_exc_flags = get_float_exception_flags(status); v = float32_to_int32(a, status); @@ -7157,10 +7168,10 @@ uint_fast16_t float32_to_uint16(float32 a, float_status *status) return res; } -uint_fast16_t float32_to_uint16_round_to_zero(float32 a, float_status *status) +uint16_t float32_to_uint16_round_to_zero(float32 a, float_status *status) { int64_t v; - uint_fast16_t res; + uint16_t res; int old_exc_flags = get_float_exception_flags(status); v = float32_to_int64_round_to_zero(a, status); @@ -7210,10 +7221,10 @@ uint32_t float64_to_uint32_round_to_zero(float64 a, float_status *status) return res; } -int_fast16_t float64_to_int16(float64 a, float_status *status) +int16_t float64_to_int16(float64 a, float_status *status) { int64_t v; - int_fast16_t res; + int16_t res; int old_exc_flags = get_float_exception_flags(status); v = float64_to_int32(a, status); @@ -7230,10 +7241,10 @@ int_fast16_t float64_to_int16(float64 a, float_status *status) return res; } -uint_fast16_t float64_to_uint16(float64 a, float_status *status) +uint16_t float64_to_uint16(float64 a, float_status *status) { int64_t v; - uint_fast16_t res; + uint16_t res; int old_exc_flags = get_float_exception_flags(status); v = float64_to_int32(a, status); @@ -7250,10 +7261,10 @@ uint_fast16_t float64_to_uint16(float64 a, float_status *status) return res; } -uint_fast16_t float64_to_uint16_round_to_zero(float64 a, float_status *status) +uint16_t float64_to_uint16_round_to_zero(float64 a, float_status *status) { int64_t v; - uint_fast16_t res; + uint16_t res; int old_exc_flags = get_float_exception_flags(status); v = float64_to_int64_round_to_zero(a, status); @@ -7284,7 +7295,8 @@ uint_fast16_t float64_to_uint16_round_to_zero(float64 a, float_status *status) uint64_t float64_to_uint64(float64 a, float_status *status) { flag aSign; - int_fast16_t aExp, shiftCount; + int aExp; + int shiftCount; uint64_t aSig, aSigExtra; a = float64_squash_input_denormal(a, status); diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 956fda0919..b8c26024a9 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -12,11 +12,8 @@ */ #ifndef _FILEOP_H #define _FILEOP_H -#include <sys/types.h> #include <dirent.h> -#include <sys/time.h> #include <utime.h> -#include <sys/stat.h> #include <sys/uio.h> #include <sys/vfs.h> @@ -314,22 +314,22 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) switch (cpu->value->arch) { case CPU_INFO_ARCH_X86: - monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86->pc); + monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86.pc); break; case CPU_INFO_ARCH_PPC: - monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc->nip); + monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc.nip); break; case CPU_INFO_ARCH_SPARC: monitor_printf(mon, " pc=0x%016" PRIx64, - cpu->value->u.q_sparc->pc); + cpu->value->u.q_sparc.pc); monitor_printf(mon, " npc=0x%016" PRIx64, - cpu->value->u.q_sparc->npc); + cpu->value->u.q_sparc.npc); break; case CPU_INFO_ARCH_MIPS: - monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips->PC); + monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips.PC); break; case CPU_INFO_ARCH_TRICORE: - monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore->PC); + monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore.PC); break; default: break; @@ -1414,6 +1414,18 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) 0, false, 0, + false, /* no burst length via HMP */ + 0, + false, + 0, + false, + 0, + false, + 0, + false, + 0, + false, + 0, false, /* No default I/O size */ 0, false, diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index eaf5a0c293..82962512a1 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -13,9 +13,6 @@ #ifndef HW_9PFS_SYNTH_H #define HW_9PFS_SYNTH_H 1 -#include <unistd.h> -#include <sys/types.h> -#include <limits.h> typedef struct V9fsSynthNode V9fsSynthNode; typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset, diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index edcd51be15..1a19418a8c 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -1,9 +1,7 @@ #ifndef _QEMU_9P_H #define _QEMU_9P_H -#include <sys/types.h> #include <dirent.h> -#include <sys/time.h> #include <utime.h> #include <sys/resource.h> #include <glib.h> diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 603068b5ea..667553514e 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1451,7 +1451,7 @@ build_header(GArray *linker, GArray *table_data, h->checksum = 0; /* Checksum to be filled in by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE, - table_data->data, h, len, &h->checksum); + table_data, h, len, &h->checksum); } void *acpi_data_push(GArray *table_data, unsigned size) diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c index e04d60ad3f..ace9abbd3e 100644 --- a/hw/acpi/bios-linker-loader.c +++ b/hw/acpi/bios-linker-loader.c @@ -25,6 +25,13 @@ #include "qemu/bswap.h" +/* + * Linker/loader is a paravirtualized interface that passes commands to guest. + * The commands can be used to request guest to + * - allocate memory chunks and initialize them from QEMU FW CFG files + * - link allocated chunks by storing pointer to one chunk into another + * - calculate ACPI checksum of part of the chunk and store into same chunk + */ #define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH struct BiosLinkerLoaderEntry { @@ -88,6 +95,12 @@ enum { BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2, }; +/* + * bios_linker_loader_init: allocate a new linker file blob array. + * + * After initialization, linker commands can be added, and will + * be stored in the array. + */ GArray *bios_linker_loader_init(void) { return g_array_new(false, true /* clear */, 1); @@ -99,6 +112,16 @@ void *bios_linker_loader_cleanup(GArray *linker) return g_array_free(linker, false); } +/* + * bios_linker_loader_alloc: ask guest to load file into guest memory. + * + * @linker: linker file blob array + * @file: file to be loaded + * @alloc_align: required minimal alignment in bytes. Must be a power of 2. + * @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table) + * + * Note: this command must precede any other linker command using this file. + */ void bios_linker_loader_alloc(GArray *linker, const char *file, uint32_t alloc_align, @@ -106,6 +129,8 @@ void bios_linker_loader_alloc(GArray *linker, { BiosLinkerLoaderEntry entry; + assert(!(alloc_align & (alloc_align - 1))); + memset(&entry, 0, sizeof entry); strncpy(entry.alloc.file, file, sizeof entry.alloc.file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE); @@ -118,23 +143,77 @@ void bios_linker_loader_alloc(GArray *linker, g_array_prepend_vals(linker, &entry, sizeof entry); } +/* + * bios_linker_loader_add_checksum: ask guest to add checksum of file data + * into (same) file at the specified pointer. + * + * Checksum calculation simply sums -X for each byte X in the range + * using 8-bit math (i.e. ACPI checksum). + * + * @linker: linker file blob array + * @file: file that includes the checksum to be calculated + * and the data to be checksummed + * @table: @file blob contents + * @start, @size: range of data to checksum + * @checksum: location of the checksum to be patched within file blob + * + * Notes: + * - checksum byte initial value must have been pushed into @table + * and reside at address @checksum. + * - @size bytes must have been pushed into @table and reside at address + * @start. + * - Guest calculates checksum of specified range of data, result is added to + * initial value at @checksum into copy of @file in Guest memory. + * - Range might include the checksum itself. + * - To avoid confusion, caller must always put 0x0 at @checksum. + * - @file must be loaded into Guest memory using bios_linker_loader_alloc + */ void bios_linker_loader_add_checksum(GArray *linker, const char *file, - void *table, + GArray *table, void *start, unsigned size, uint8_t *checksum) { BiosLinkerLoaderEntry entry; + ptrdiff_t checksum_offset = (gchar *)checksum - table->data; + ptrdiff_t start_offset = (gchar *)start - table->data; + + assert(checksum_offset >= 0); + assert(start_offset >= 0); + assert(checksum_offset + 1 <= table->len); + assert(start_offset + size <= table->len); + assert(*checksum == 0x0); memset(&entry, 0, sizeof entry); strncpy(entry.cksum.file, file, sizeof entry.cksum.file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM); - entry.cksum.offset = cpu_to_le32(checksum - (uint8_t *)table); - entry.cksum.start = cpu_to_le32((uint8_t *)start - (uint8_t *)table); + entry.cksum.offset = cpu_to_le32(checksum_offset); + entry.cksum.start = cpu_to_le32(start_offset); entry.cksum.length = cpu_to_le32(size); g_array_append_vals(linker, &entry, sizeof entry); } +/* + * bios_linker_loader_add_pointer: ask guest to add address of source file + * into destination file at the specified pointer. + * + * @linker: linker file blob array + * @dest_file: destination file that must be changed + * @src_file: source file who's address must be taken + * @table: @dest_file blob contents array + * @pointer: location of the pointer to be patched within destination file blob + * @pointer_size: size of pointer to be patched, in bytes + * + * Notes: + * - @pointer_size bytes must have been pushed into @table + * and reside at address @pointer. + * - Guest address is added to initial value at @pointer + * into copy of @dest_file in Guest memory. + * e.g. to get start of src_file in guest memory, put 0x0 there + * to get address of a field at offset 0x10 in src_file, put 0x10 there + * - Both @dest_file and @src_file must be + * loaded into Guest memory using bios_linker_loader_alloc + */ void bios_linker_loader_add_pointer(GArray *linker, const char *dest_file, const char *src_file, @@ -142,7 +221,10 @@ void bios_linker_loader_add_pointer(GArray *linker, uint8_t pointer_size) { BiosLinkerLoaderEntry entry; - size_t offset = (gchar *)pointer - table->data; + ptrdiff_t offset = (gchar *)pointer - table->data; + + assert(offset >= 0); + assert(offset + pointer_size <= table->len); memset(&entry, 0, sizeof entry); strncpy(entry.pointer.dest_file, dest_file, @@ -150,7 +232,6 @@ void bios_linker_loader_add_pointer(GArray *linker, strncpy(entry.pointer.src_file, src_file, sizeof entry.pointer.src_file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER); - assert(table->len >= offset + pointer_size); entry.pointer.offset = cpu_to_le32(offset); entry.pointer.size = pointer_size; assert(pointer_size == 1 || pointer_size == 2 || diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 4f9ce05d04..72202545e0 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -240,7 +240,7 @@ static void pm_powerdown_req(Notifier *n, void *opaque) } void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, - bool smm_enabled, bool enable_tco, + bool smm_enabled, qemu_irq sci_irq) { memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); @@ -264,10 +264,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, pm->smm_enabled = smm_enabled; - pm->enable_tco = enable_tco; - if (pm->enable_tco) { - acpi_pm_tco_init(&pm->tco_regs, &pm->io); - } + pm->enable_tco = true; + acpi_pm_tco_init(&pm->tco_regs, &pm->io); pm->irq = sci_irq; qemu_register_reset(pm_reset, pm); diff --git a/hw/arm/boot.c b/hw/arm/boot.c index cce8c7cd1c..0a56d34cfe 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -437,8 +437,10 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, return 0; } - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", + NULL, &error_fatal); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", + NULL, &error_fatal); if (acells == 0 || scells == 0) { fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); goto fail; diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c index 68a3de5cf8..04afeae226 100644 --- a/hw/arm/sysbus-fdt.c +++ b/hw/arm/sysbus-fdt.c @@ -22,6 +22,11 @@ */ #include "qemu/osdep.h" +#include <libfdt.h> +#include "qemu-common.h" +#ifdef CONFIG_LINUX +#include <linux/vfio.h> +#endif #include "hw/arm/sysbus-fdt.h" #include "qemu/error-report.h" #include "sysemu/device_tree.h" @@ -29,6 +34,7 @@ #include "sysemu/sysemu.h" #include "hw/vfio/vfio-platform.h" #include "hw/vfio/vfio-calxeda-xgmac.h" +#include "hw/vfio/vfio-amd-xgbe.h" #include "hw/arm/fdt.h" /* @@ -57,6 +63,146 @@ typedef struct NodeCreationPair { int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque); } NodeCreationPair; +/* helpers */ + +typedef struct HostProperty { + const char *name; + bool optional; +} HostProperty; + +#ifdef CONFIG_LINUX + +/** + * copy_properties_from_host + * + * copies properties listed in an array from host device tree to + * guest device tree. If a non optional property is not found, the + * function asserts. An optional property is ignored if not found + * in the host device tree. + * @props: array of HostProperty to copy + * @nb_props: number of properties in the array + * @host_dt: host device tree blob + * @guest_dt: guest device tree blob + * @node_path: host dt node path where the property is supposed to be + found + * @nodename: guest node name the properties should be added to + */ +static void copy_properties_from_host(HostProperty *props, int nb_props, + void *host_fdt, void *guest_fdt, + char *node_path, char *nodename) +{ + int i, prop_len; + const void *r; + Error *err = NULL; + + for (i = 0; i < nb_props; i++) { + r = qemu_fdt_getprop(host_fdt, node_path, + props[i].name, + &prop_len, + props[i].optional ? &err : &error_fatal); + if (r) { + qemu_fdt_setprop(guest_fdt, nodename, + props[i].name, r, prop_len); + } else { + if (prop_len != -FDT_ERR_NOTFOUND) { + /* optional property not returned although property exists */ + error_report_err(err); + } else { + error_free(err); + } + } + } +} + +/* clock properties whose values are copied/pasted from host */ +static HostProperty clock_copied_properties[] = { + {"compatible", false}, + {"#clock-cells", false}, + {"clock-frequency", true}, + {"clock-output-names", true}, +}; + +/** + * fdt_build_clock_node + * + * Build a guest clock node, used as a dependency from a passthrough'ed + * device. Most information are retrieved from the host clock node. + * Also check the host clock is a fixed one. + * + * @host_fdt: host device tree blob from which info are retrieved + * @guest_fdt: guest device tree blob where the clock node is added + * @host_phandle: phandle of the clock in host device tree + * @guest_phandle: phandle to assign to the guest node + */ +static void fdt_build_clock_node(void *host_fdt, void *guest_fdt, + uint32_t host_phandle, + uint32_t guest_phandle) +{ + char *node_path = NULL; + char *nodename; + const void *r; + int ret, node_offset, prop_len, path_len = 16; + + node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle); + if (node_offset <= 0) { + error_setg(&error_fatal, + "not able to locate clock handle %d in host device tree", + host_phandle); + } + node_path = g_malloc(path_len); + while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len)) + == -FDT_ERR_NOSPACE) { + path_len += 16; + node_path = g_realloc(node_path, path_len); + } + if (ret < 0) { + error_setg(&error_fatal, + "not able to retrieve node path for clock handle %d", + host_phandle); + } + + r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len, + &error_fatal); + if (strcmp(r, "fixed-clock")) { + error_setg(&error_fatal, + "clock handle %d is not a fixed clock", host_phandle); + } + + nodename = strrchr(node_path, '/'); + qemu_fdt_add_subnode(guest_fdt, nodename); + + copy_properties_from_host(clock_copied_properties, + ARRAY_SIZE(clock_copied_properties), + host_fdt, guest_fdt, + node_path, nodename); + + qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle); + + g_free(node_path); +} + +/** + * sysfs_to_dt_name: convert the name found in sysfs into the node name + * for instance e0900000.xgmac is converted into xgmac@e0900000 + * @sysfs_name: directory name in sysfs + * + * returns the device tree name upon success or NULL in case the sysfs name + * does not match the expected format + */ +static char *sysfs_to_dt_name(const char *sysfs_name) +{ + gchar **substrings = g_strsplit(sysfs_name, ".", 2); + char *dt_name = NULL; + + if (!substrings || !substrings[0] || !substrings[1]) { + goto out; + } + dt_name = g_strdup_printf("%s@%s", substrings[1], substrings[0]); +out: + g_strfreev(substrings); + return dt_name; +} + /* Device Specific Code */ /** @@ -71,7 +217,7 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) PlatformBusDevice *pbus = data->pbus; void *fdt = data->fdt; const char *parent_node = data->pbus_node_name; - int compat_str_len, i, ret = -1; + int compat_str_len, i; char *nodename; uint32_t *irq_attr, *reg_attr; uint64_t mmio_base, irq_number; @@ -96,12 +242,8 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) reg_attr[2 * i + 1] = cpu_to_be32( memory_region_size(&vdev->regions[i]->mem)); } - ret = qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, - vbasedev->num_regions * 2 * sizeof(uint32_t)); - if (ret) { - error_report("could not set reg property of node %s", nodename); - goto fail_reg; - } + qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, + vbasedev->num_regions * 2 * sizeof(uint32_t)); irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); for (i = 0; i < vbasedev->num_irqs; i++) { @@ -111,22 +253,173 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque) irq_attr[3 * i + 1] = cpu_to_be32(irq_number); irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); } - ret = qemu_fdt_setprop(fdt, nodename, "interrupts", + qemu_fdt_setprop(fdt, nodename, "interrupts", irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); - if (ret) { - error_report("could not set interrupts property of node %s", - nodename); + g_free(irq_attr); + g_free(reg_attr); + g_free(nodename); + return 0; +} + +/* AMD xgbe properties whose values are copied/pasted from host */ +static HostProperty amd_xgbe_copied_properties[] = { + {"compatible", false}, + {"dma-coherent", true}, + {"amd,per-channel-interrupt", true}, + {"phy-mode", false}, + {"mac-address", true}, + {"amd,speed-set", false}, + {"amd,serdes-blwc", true}, + {"amd,serdes-cdr-rate", true}, + {"amd,serdes-pq-skew", true}, + {"amd,serdes-tx-amp", true}, + {"amd,serdes-dfe-tap-config", true}, + {"amd,serdes-dfe-tap-enable", true}, + {"clock-names", false}, +}; + +/** + * add_amd_xgbe_fdt_node + * + * Generates the combined xgbe/phy node following kernel >=4.2 + * binding documentation: + * Documentation/devicetree/bindings/net/amd-xgbe.txt: + * Also 2 clock nodes are created (dma and ptp) + * + * Asserts in case of error + */ +static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) +{ + PlatformBusFDTData *data = opaque; + PlatformBusDevice *pbus = data->pbus; + VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); + VFIODevice *vbasedev = &vdev->vbasedev; + VFIOINTp *intp; + const char *parent_node = data->pbus_node_name; + char **node_path, *nodename, *dt_name; + void *guest_fdt = data->fdt, *host_fdt; + const void *r; + int i, prop_len; + uint32_t *irq_attr, *reg_attr, *host_clock_phandles; + uint64_t mmio_base, irq_number; + uint32_t guest_clock_phandles[2]; + + host_fdt = load_device_tree_from_sysfs(); + + dt_name = sysfs_to_dt_name(vbasedev->name); + if (!dt_name) { + error_setg(&error_fatal, "%s incorrect sysfs device name %s", + __func__, vbasedev->name); + } + node_path = qemu_fdt_node_path(host_fdt, dt_name, vdev->compat, + &error_fatal); + if (!node_path || !node_path[0]) { + error_setg(&error_fatal, "%s unable to retrieve node path for %s/%s", + __func__, dt_name, vdev->compat); } + + if (node_path[1]) { + error_setg(&error_fatal, "%s more than one node matching %s/%s!", + __func__, dt_name, vdev->compat); + } + + g_free(dt_name); + + if (vbasedev->num_regions != 5) { + error_setg(&error_fatal, "%s Does the host dt node combine XGBE/PHY?", + __func__); + } + + /* generate nodes for DMA_CLK and PTP_CLK */ + r = qemu_fdt_getprop(host_fdt, node_path[0], "clocks", + &prop_len, &error_fatal); + if (prop_len != 8) { + error_setg(&error_fatal, "%s clocks property should contain 2 handles", + __func__); + } + host_clock_phandles = (uint32_t *)r; + guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt); + guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt); + + /** + * clock handles fetched from host dt are in be32 layout whereas + * rest of the code uses cpu layout. Also guest clock handles are + * in cpu layout. + */ + fdt_build_clock_node(host_fdt, guest_fdt, + be32_to_cpu(host_clock_phandles[0]), + guest_clock_phandles[0]); + + fdt_build_clock_node(host_fdt, guest_fdt, + be32_to_cpu(host_clock_phandles[1]), + guest_clock_phandles[1]); + + /* combined XGBE/PHY node */ + mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); + nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node, + vbasedev->name, mmio_base); + qemu_fdt_add_subnode(guest_fdt, nodename); + + copy_properties_from_host(amd_xgbe_copied_properties, + ARRAY_SIZE(amd_xgbe_copied_properties), + host_fdt, guest_fdt, + node_path[0], nodename); + + qemu_fdt_setprop_cells(guest_fdt, nodename, "clocks", + guest_clock_phandles[0], + guest_clock_phandles[1]); + + reg_attr = g_new(uint32_t, vbasedev->num_regions * 2); + for (i = 0; i < vbasedev->num_regions; i++) { + mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i); + reg_attr[2 * i] = cpu_to_be32(mmio_base); + reg_attr[2 * i + 1] = cpu_to_be32( + memory_region_size(&vdev->regions[i]->mem)); + } + qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr, + vbasedev->num_regions * 2 * sizeof(uint32_t)); + + irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3); + for (i = 0; i < vbasedev->num_irqs; i++) { + irq_number = platform_bus_get_irqn(pbus, sbdev , i) + + data->irq_start; + irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI); + irq_attr[3 * i + 1] = cpu_to_be32(irq_number); + /* + * General device interrupt and PCS auto-negotiation interrupts are + * level-sensitive while the 4 per-channel interrupts are edge + * sensitive + */ + QLIST_FOREACH(intp, &vdev->intp_list, next) { + if (intp->pin == i) { + break; + } + } + if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) { + irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI); + } else { + irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + } + } + qemu_fdt_setprop(guest_fdt, nodename, "interrupts", + irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t)); + + g_free(host_fdt); + g_strfreev(node_path); g_free(irq_attr); -fail_reg: g_free(reg_attr); g_free(nodename); - return ret; + return 0; } +#endif /* CONFIG_LINUX */ + /* list of supported dynamic sysbus devices */ static const NodeCreationPair add_fdt_node_functions[] = { +#ifdef CONFIG_LINUX {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node}, + {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node}, +#endif {"", NULL}, /* last element */ }; diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 3154aeaa95..726c4e0c55 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -478,8 +478,10 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) uint32_t acells, scells, intc; const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; - acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells", + NULL, &error_fatal); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells", + NULL, &error_fatal); intc = find_int_controller(fdt); if (!intc) { /* Not fatal, we just won't provide virtio. This will diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 8cf9a2167f..b8b3ece8ca 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -359,7 +359,8 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - rsdp, rsdp, sizeof *rsdp, &rsdp->checksum); + rsdp_table, rsdp, sizeof *rsdp, + &rsdp->checksum); return rsdp_table; } diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h index 331bb6fec0..b7f0751268 100644 --- a/hw/audio/gusemu.h +++ b/hw/audio/gusemu.h @@ -34,7 +34,6 @@ typedef signed char GUSchar; typedef signed short GUSsample; #else - #include <stdint.h> typedef int8_t GUSchar; typedef uint8_t GUSbyte; typedef uint16_t GUSword; diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 0d9978109c..36f3d2b813 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -18,8 +18,6 @@ #include "qemu/thread.h" #include "qemu/error-report.h" #include "hw/virtio/virtio-access.h" -#include "hw/virtio/dataplane/vring.h" -#include "hw/virtio/dataplane/vring-accessors.h" #include "sysemu/block-backend.h" #include "hw/virtio/virtio-blk.h" #include "virtio-blk.h" @@ -28,7 +26,6 @@ #include "qom/object_interfaces.h" struct VirtIOBlockDataPlane { - bool started; bool starting; bool stopping; bool disabled; @@ -36,7 +33,7 @@ struct VirtIOBlockDataPlane { VirtIOBlkConf *conf; VirtIODevice *vdev; - Vring vring; /* virtqueue vring */ + VirtQueue *vq; /* virtqueue vring */ EventNotifier *guest_notifier; /* irq */ QEMUBH *bh; /* bh for guest notification */ @@ -49,93 +46,26 @@ struct VirtIOBlockDataPlane { */ IOThread *iothread; AioContext *ctx; - EventNotifier host_notifier; /* doorbell */ /* Operation blocker on BDS */ Error *blocker; - void (*saved_complete_request)(struct VirtIOBlockReq *req, - unsigned char status); }; /* Raise an interrupt to signal guest, if necessary */ -static void notify_guest(VirtIOBlockDataPlane *s) +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s) { - if (!vring_should_notify(s->vdev, &s->vring)) { - return; - } - - event_notifier_set(s->guest_notifier); + qemu_bh_schedule(s->bh); } static void notify_guest_bh(void *opaque) { VirtIOBlockDataPlane *s = opaque; - notify_guest(s); -} - -static void complete_request_vring(VirtIOBlockReq *req, unsigned char status) -{ - VirtIOBlockDataPlane *s = req->dev->dataplane; - stb_p(&req->in->status, status); - - vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len); - - /* Suppress notification to guest by BH and its scheduled - * flag because requests are completed as a batch after io - * plug & unplug is introduced, and the BH can still be - * executed in dataplane aio context even after it is - * stopped, so needn't worry about notification loss with BH. - */ - qemu_bh_schedule(s->bh); -} - -static void handle_notify(EventNotifier *e) -{ - VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, - host_notifier); - VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); - - event_notifier_test_and_clear(&s->host_notifier); - blk_io_plug(s->conf->conf.blk); - for (;;) { - MultiReqBuffer mrb = {}; - - /* Disable guest->host notifies to avoid unnecessary vmexits */ - vring_disable_notification(s->vdev, &s->vring); - - for (;;) { - VirtIOBlockReq *req = vring_pop(s->vdev, &s->vring, - sizeof(VirtIOBlockReq)); - - if (req == NULL) { - break; /* no more requests */ - } - - virtio_blk_init_request(vblk, req); - trace_virtio_blk_data_plane_process_request(s, req->elem.out_num, - req->elem.in_num, - req->elem.index); - - virtio_blk_handle_request(req, &mrb); - } - - if (mrb.num_reqs) { - virtio_blk_submit_multireq(s->conf->conf.blk, &mrb); - } - - if (likely(!vring_more_avail(s->vdev, &s->vring))) { /* vring emptied */ - /* Re-enable guest->host notifies and stop processing the vring. - * But if the guest has snuck in more descriptors, keep processing. - */ - if (vring_enable_notification(s->vdev, &s->vring)) { - break; - } - } else { /* fatal error */ - break; - } + if (!virtio_should_notify(s->vdev, s->vq)) { + return; } - blk_io_unplug(s->conf->conf.blk); + + event_notifier_set(s->guest_notifier); } static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s) @@ -260,23 +190,14 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); - VirtQueue *vq; int r; - if (s->started || s->disabled) { - return; - } - - if (s->starting) { + if (vblk->dataplane_started || s->starting) { return; } s->starting = true; - - vq = virtio_get_queue(s->vdev, 0); - if (!vring_setup(&s->vring, s->vdev, 0)) { - goto fail_vring; - } + s->vq = virtio_get_queue(s->vdev, 0); /* Set up guest notifier (irq) */ r = k->set_guest_notifiers(qbus->parent, 1, true); @@ -285,7 +206,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) "ensure -enable-kvm is set\n", r); goto fail_guest_notifiers; } - s->guest_notifier = virtio_queue_get_guest_notifier(vq); + s->guest_notifier = virtio_queue_get_guest_notifier(s->vq); /* Set up virtqueue notify */ r = k->set_host_notifier(qbus->parent, 0, true); @@ -293,34 +214,28 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); goto fail_host_notifier; } - s->host_notifier = *virtio_queue_get_host_notifier(vq); - - s->saved_complete_request = vblk->complete_request; - vblk->complete_request = complete_request_vring; s->starting = false; - s->started = true; + vblk->dataplane_started = true; trace_virtio_blk_data_plane_start(s); blk_set_aio_context(s->conf->conf.blk, s->ctx); /* Kick right away to begin processing requests already in vring */ - event_notifier_set(virtio_queue_get_host_notifier(vq)); + event_notifier_set(virtio_queue_get_host_notifier(s->vq)); /* Get this show started by hooking up our callbacks */ aio_context_acquire(s->ctx); - aio_set_event_notifier(s->ctx, &s->host_notifier, true, - handle_notify); + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, true, true); aio_context_release(s->ctx); return; fail_host_notifier: k->set_guest_notifiers(qbus->parent, 1, false); fail_guest_notifiers: - vring_teardown(&s->vring, s->vdev, 0); s->disabled = true; - fail_vring: s->starting = false; + vblk->dataplane_started = true; } /* Context: QEMU global mutex held */ @@ -330,39 +245,34 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); + if (!vblk->dataplane_started || s->stopping) { + return; + } /* Better luck next time. */ if (s->disabled) { s->disabled = false; - return; - } - if (!s->started || s->stopping) { + vblk->dataplane_started = false; return; } s->stopping = true; - vblk->complete_request = s->saved_complete_request; trace_virtio_blk_data_plane_stop(s); aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ - aio_set_event_notifier(s->ctx, &s->host_notifier, true, NULL); + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, false, false); /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); aio_context_release(s->ctx); - /* Sync vring state back to virtqueue so that non-dataplane request - * processing can continue when we disable the host notifier below. - */ - vring_teardown(&s->vring, s->vdev, 0); - k->set_host_notifier(qbus->parent, 0, false); /* Clean up guest notifier (irq) */ k->set_guest_notifiers(qbus->parent, 1, false); - s->started = false; + vblk->dataplane_started = false; s->stopping = false; } diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h index c88d40e72c..0714c11a2b 100644 --- a/hw/block/dataplane/virtio-blk.h +++ b/hw/block/dataplane/virtio-blk.h @@ -26,5 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s); #endif /* HW_DATAPLANE_VIRTIO_BLK_H */ diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index c427698fcb..cb710f16fa 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -21,7 +21,6 @@ #include "sysemu/blockdev.h" #include "hw/virtio/virtio-blk.h" #include "dataplane/virtio-blk.h" -#include "migration/migration.h" #include "block/scsi.h" #ifdef __linux__ # include <scsi/sg.h> @@ -45,8 +44,7 @@ void virtio_blk_free_request(VirtIOBlockReq *req) } } -static void virtio_blk_complete_request(VirtIOBlockReq *req, - unsigned char status) +static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); @@ -55,12 +53,11 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req, stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->in_len); - virtio_notify(vdev, s->vq); -} - -static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) -{ - req->dev->complete_request(req, status); + if (s->dataplane) { + virtio_blk_data_plane_notify(s->dataplane); + } else { + virtio_notify(vdev, s->vq); + } } static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, @@ -589,7 +586,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start * dataplane here instead of waiting for .set_status(). */ - if (s->dataplane) { + if (s->dataplane && !s->dataplane_started) { virtio_blk_data_plane_start(s->dataplane); return; } @@ -852,36 +849,6 @@ static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -/* Disable dataplane thread during live migration since it does not - * update the dirty memory bitmap yet. - */ -static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) -{ - VirtIOBlock *s = container_of(notifier, VirtIOBlock, - migration_state_notifier); - MigrationState *mig = data; - Error *err = NULL; - - if (migration_in_setup(mig)) { - if (!s->dataplane) { - return; - } - virtio_blk_data_plane_destroy(s->dataplane); - s->dataplane = NULL; - } else if (migration_has_finished(mig) || - migration_has_failed(mig)) { - if (s->dataplane) { - return; - } - blk_drain_all(); /* complete in-flight non-dataplane requests */ - virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->conf, - &s->dataplane, &err); - if (err != NULL) { - error_report_err(err); - } - } -} - static void virtio_blk_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -916,15 +883,12 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1; s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); - s->complete_request = virtio_blk_complete_request; virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); virtio_cleanup(vdev); return; } - s->migration_state_notifier.notify = virtio_blk_migration_state_changed; - add_migration_state_change_notifier(&s->migration_state_notifier); s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, @@ -940,7 +904,6 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); - remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; qemu_del_vm_change_state_handler(s->change); diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 40ba6a4207..bdb43a5a34 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -25,7 +25,6 @@ #define HW_VGA_INT_H 1 #include <hw/hw.h> -#include "qapi/error.h" #include "exec/memory.h" #define ST01_V_RETRACE 0x08 diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c index 9cbb16580e..d5650eb885 100644 --- a/hw/dma/etraxfs_dma.c +++ b/hw/dma/etraxfs_dma.c @@ -440,13 +440,16 @@ static int channel_out_run(struct fs_dma_ctrl *ctrl, int c) D(printf("channel %d pushes %x %u bytes eop=%u\n", c, saved_data_buf, len, out_eop)); - if (ctrl->channels[c].client->client.push) - ctrl->channels[c].client->client.push( - ctrl->channels[c].client->client.opaque, - buf, len, out_eop); - else + if (ctrl->channels[c].client->client.push) { + if (len > 0) { + ctrl->channels[c].client->client.push( + ctrl->channels[c].client->client.opaque, + buf, len, out_eop); + } + } else { printf("WARNING: DMA ch%d dataloss," " no attached client.\n", c); + } saved_data_buf += len; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4554eb88bc..52c9470a54 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2532,7 +2532,8 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - rsdp, rsdp, sizeof *rsdp, &rsdp->checksum); + rsdp_table, rsdp, sizeof *rsdp, + &rsdp->checksum); return rsdp_table; } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 208a224226..46522c90da 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -81,11 +81,9 @@ static void pc_q35_init(MachineState *machine) * If it doesn't, we need to split it in chunks below and above 4G. * In any case, try to make sure that guest addresses aligned at * 1G boundaries get mapped to host addresses aligned at 1G boundaries. - * For old machine types, use whatever split we used historically to avoid - * breaking migration. */ if (machine->ram_size >= 0xb0000000) { - lowmem = pcmc->gigabyte_align ? 0x80000000 : 0xb0000000; + lowmem = 0x80000000; } else { lowmem = 0xb0000000; } @@ -116,10 +114,6 @@ static void pc_q35_init(MachineState *machine) } pc_cpus_init(pcms); - if (!pcmc->has_acpi_build) { - /* only machine types 1.7 & older need this */ - pc_acpi_init("q35-acpi-dsdt.aml"); - } kvmclock_create(); @@ -225,7 +219,7 @@ static void pc_q35_init(MachineState *machine) (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); /* connect pm stuff to lpc */ - ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), !mc->no_tco); + ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms)); /* ahci and SATA device, for q35 1 ahci controller is built-in */ ahci = pci_create_simple_multifunction(host_bus, @@ -259,62 +253,6 @@ static void pc_q35_init(MachineState *machine) } } -/* Looking for a pc_compat_2_4() function? It doesn't exist. - * pc_compat_*() functions that run on machine-init time and - * change global QEMU state are deprecated. Please don't create - * one, and implement any pc-*-2.4 (and newer) compat code in - * HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options(). - */ - -static void pc_compat_2_3(MachineState *machine) -{ - PCMachineState *pcms = PC_MACHINE(machine); - savevm_skip_section_footers(); - if (kvm_enabled()) { - pcms->smm = ON_OFF_AUTO_OFF; - } - global_state_set_optional(); - savevm_skip_configuration(); -} - -static void pc_compat_2_2(MachineState *machine) -{ - pc_compat_2_3(machine); - machine->suppress_vmdesc = true; -} - -static void pc_compat_2_1(MachineState *machine) -{ - pc_compat_2_2(machine); - x86_cpu_change_kvm_default("svm", NULL); -} - -static void pc_compat_2_0(MachineState *machine) -{ - pc_compat_2_1(machine); -} - -static void pc_compat_1_7(MachineState *machine) -{ - pc_compat_2_0(machine); - x86_cpu_change_kvm_default("x2apic", NULL); -} - -static void pc_compat_1_6(MachineState *machine) -{ - pc_compat_1_7(machine); -} - -static void pc_compat_1_5(MachineState *machine) -{ - pc_compat_1_6(machine); -} - -static void pc_compat_1_4(MachineState *machine) -{ - pc_compat_1_5(machine); -} - #define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \ static void pc_init_##suffix(MachineState *machine) \ { \ @@ -336,7 +274,6 @@ static void pc_q35_machine_options(MachineClass *m) m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; m->no_floppy = 1; - m->no_tco = 0; } static void pc_q35_2_6_machine_options(MachineClass *m) @@ -371,112 +308,3 @@ static void pc_q35_2_4_machine_options(MachineClass *m) DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL, pc_q35_2_4_machine_options); - - -static void pc_q35_2_3_machine_options(MachineClass *m) -{ - pc_q35_2_4_machine_options(m); - m->hw_version = "2.3.0"; - m->no_floppy = 0; - m->no_tco = 1; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_3); -} - -DEFINE_Q35_MACHINE(v2_3, "pc-q35-2.3", pc_compat_2_3, - pc_q35_2_3_machine_options); - - -static void pc_q35_2_2_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_2_3_machine_options(m); - m->hw_version = "2.2.0"; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_2); - pcmc->rsdp_in_ram = false; -} - -DEFINE_Q35_MACHINE(v2_2, "pc-q35-2.2", pc_compat_2_2, - pc_q35_2_2_machine_options); - - -static void pc_q35_2_1_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_2_2_machine_options(m); - m->hw_version = "2.1.0"; - m->default_display = NULL; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_1); - pcmc->smbios_uuid_encoded = false; - pcmc->enforce_aligned_dimm = false; -} - -DEFINE_Q35_MACHINE(v2_1, "pc-q35-2.1", pc_compat_2_1, - pc_q35_2_1_machine_options); - - -static void pc_q35_2_0_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_2_1_machine_options(m); - m->hw_version = "2.0.0"; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_0); - pcmc->has_reserved_memory = false; - pcmc->smbios_legacy_mode = true; - pcmc->acpi_data_size = 0x10000; -} - -DEFINE_Q35_MACHINE(v2_0, "pc-q35-2.0", pc_compat_2_0, - pc_q35_2_0_machine_options); - - -static void pc_q35_1_7_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_2_0_machine_options(m); - m->hw_version = "1.7.0"; - m->default_machine_opts = NULL; - m->option_rom_has_mr = true; - SET_MACHINE_COMPAT(m, PC_COMPAT_1_7); - pcmc->smbios_defaults = false; - pcmc->gigabyte_align = false; -} - -DEFINE_Q35_MACHINE(v1_7, "pc-q35-1.7", pc_compat_1_7, - pc_q35_1_7_machine_options); - - -static void pc_q35_1_6_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_machine_options(m); - m->hw_version = "1.6.0"; - m->rom_file_has_mr = false; - SET_MACHINE_COMPAT(m, PC_COMPAT_1_6); - pcmc->has_acpi_build = false; -} - -DEFINE_Q35_MACHINE(v1_6, "pc-q35-1.6", pc_compat_1_6, - pc_q35_1_6_machine_options); - - -static void pc_q35_1_5_machine_options(MachineClass *m) -{ - pc_q35_1_6_machine_options(m); - m->hw_version = "1.5.0"; - SET_MACHINE_COMPAT(m, PC_COMPAT_1_5); -} - -DEFINE_Q35_MACHINE(v1_5, "pc-q35-1.5", pc_compat_1_5, - pc_q35_1_5_machine_options); - - -static void pc_q35_1_4_machine_options(MachineClass *m) -{ - pc_q35_1_5_machine_options(m); - m->hw_version = "1.4.0"; - m->hot_add_cpu = NULL; - SET_MACHINE_COMPAT(m, PC_COMPAT_1_4); -} - -DEFINE_Q35_MACHINE(v1_4, "pc-q35-1.4", pc_compat_1_4, - pc_q35_1_4_machine_options); diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 6cf2eb607d..4e896b29f1 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -369,13 +369,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level) } } -void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled, bool enable_tco) +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); qemu_irq sci_irq; sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0); - ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, enable_tco, sci_irq); + ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq); ich9_lpc_reset(&lpc->d.qdev); } diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 1aa12c64d0..650f0f89f4 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -192,32 +192,6 @@ 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->type) { - case MEMORY_DEVICE_INFO_KIND_DIMM: - size += value->u.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/net/fsl_etsec/registers.h b/hw/net/fsl_etsec/registers.h index 7ad7686470..6fb96842b8 100644 --- a/hw/net/fsl_etsec/registers.h +++ b/hw/net/fsl_etsec/registers.h @@ -24,7 +24,6 @@ #ifndef _ETSEC_REGISTERS_H_ #define _ETSEC_REGISTERS_H_ -#include <stdint.h> enum eTSEC_Register_Access_Type { ACC_RW = 1, /* Read/Write */ diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 3940a04b65..6e1032fc18 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -36,7 +36,6 @@ #include "standard-headers/linux/virtio_ring.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" struct vhost_net { struct vhost_dev dev; @@ -197,27 +196,6 @@ static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index) net->dev.vq_index = vq_index; } -static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer, - bool set) -{ - int r = 0; - - if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) || - (virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) { - r = qemu_set_vnet_le(peer, set); - if (r) { - error_report("backend does not support LE vnet headers"); - } - } else if (virtio_legacy_is_cross_endian(dev)) { - r = qemu_set_vnet_be(peer, set); - if (r) { - error_report("backend does not support BE vnet headers"); - } - } - - return r; -} - static int vhost_net_start_one(struct vhost_net *net, VirtIODevice *dev) { @@ -298,25 +276,32 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); VirtioBusState *vbus = VIRTIO_BUS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); - int r, e, i, j; + int r, e, i; if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); return -ENOSYS; } - for (j = 0; j < total_queues; j++) { - r = vhost_net_set_vnet_endian(dev, ncs[j].peer, true); - if (r < 0) { - goto err_endian; + for (i = 0; i < total_queues; i++) { + struct vhost_net *net; + + net = get_vhost_net(ncs[i].peer); + vhost_net_set_vq_index(net, i * 2); + + /* Suppress the masking guest notifiers on vhost user + * because vhost user doesn't interrupt masking/unmasking + * properly. + */ + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { + dev->use_guest_notifier_mask = false; } - vhost_net_set_vq_index(get_vhost_net(ncs[j].peer), j * 2); - } + } r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true); if (r < 0) { error_report("Error binding guest notifier: %d", -r); - goto err_endian; + goto err; } for (i = 0; i < total_queues; i++) { @@ -338,10 +323,7 @@ err_start: fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); fflush(stderr); } -err_endian: - while (--j >= 0) { - vhost_net_set_vnet_endian(dev, ncs[j].peer, false); - } +err: return r; } @@ -363,8 +345,6 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, fflush(stderr); } assert(r >= 0); - - assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0); } void vhost_net_cleanup(struct vhost_net *net) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index de696e8dd0..5798f87d8e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -129,6 +129,13 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (!n->vhost_started) { int r, i; + if (n->needs_vnet_hdr_swap) { + error_report("backend does not support %s vnet headers; " + "falling back on userspace virtio", + virtio_is_big_endian(vdev) ? "BE" : "LE"); + return; + } + /* Any packets outstanding? Purge them to avoid touching rings * when vhost is running. */ @@ -153,6 +160,59 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) } } +static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev, + NetClientState *peer, + bool enable) +{ + if (virtio_is_big_endian(vdev)) { + return qemu_set_vnet_be(peer, enable); + } else { + return qemu_set_vnet_le(peer, enable); + } +} + +static bool virtio_net_set_vnet_endian(VirtIODevice *vdev, NetClientState *ncs, + int queues, bool enable) +{ + int i; + + for (i = 0; i < queues; i++) { + if (virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, enable) < 0 && + enable) { + while (--i >= 0) { + virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, false); + } + + return true; + } + } + + return false; +} + +static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(n); + int queues = n->multiqueue ? n->max_queues : 1; + + if (virtio_net_started(n, status)) { + /* Before using the device, we tell the network backend about the + * endianness to use when parsing vnet headers. If the backend + * can't do it, we fallback onto fixing the headers in the core + * virtio-net code. + */ + n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs, + queues, true); + } else if (virtio_net_started(n, vdev->status)) { + /* After using the device, we need to reset the network backend to + * the default (guest native endianness), otherwise the guest may + * lose network connectivity if it is rebooted into a different + * endianness. + */ + virtio_net_set_vnet_endian(vdev, n->nic->ncs, queues, false); + } +} + static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); @@ -160,6 +220,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) int i; uint8_t queue_status; + virtio_net_vnet_endian_status(n, status); virtio_net_vhost_status(n, status); for (i = 0; i < n->max_queues; i++) { @@ -963,7 +1024,10 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, void *wbuf = (void *)buf; work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, size - n->host_hdr_len); - virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); + + if (n->needs_vnet_hdr_swap) { + virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); + } iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); } else { struct virtio_net_hdr hdr = { @@ -1184,7 +1248,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) error_report("virtio-net header incorrect"); exit(1); } - if (virtio_needs_swap(vdev)) { + if (n->needs_vnet_hdr_swap) { virtio_net_hdr_swap(vdev, (void *) &mhdr); sg2[0].iov_base = &mhdr; sg2[0].iov_len = n->guest_hdr_len; diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index 40ff0d0632..840c96198a 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -52,9 +52,9 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num) return irq_num; } -static int dec_pci_bridge_initfn(PCIDevice *pci_dev) +static void dec_pci_bridge_realize(PCIDevice *pci_dev, Error **errp) { - return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS); + pci_bridge_initfn(pci_dev, TYPE_PCI_BUS); } static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) @@ -62,7 +62,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = dec_pci_bridge_initfn; + k->realize = dec_pci_bridge_realize; k->exit = pci_bridge_exitfn; k->vendor_id = PCI_VENDOR_ID_DEC; k->device_id = PCI_DEVICE_ID_DEC_21154; diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index b143f8cb79..5c40708ba8 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -62,10 +62,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d) { int rc; - rc = pci_bridge_initfn(d, TYPE_PCI_BUS); - if (rc < 0) { - return rc; - } + pci_bridge_initfn(d, TYPE_PCI_BUS); rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET, I82801ba_SSVID_SVID, I82801ba_SSVID_SSID); diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index 8ac4240bb1..0937fa34be 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -98,11 +98,7 @@ static int ioh3420_initfn(PCIDevice *d) PCIESlot *s = PCIE_SLOT(d); int rc; - rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); - if (rc < 0) { - return rc; - } - + pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET, @@ -130,7 +126,7 @@ static int ioh3420_initfn(PCIDevice *d) goto err_pcie_cap; } pcie_cap_root_init(d); - rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); + rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF); if (rc < 0) { goto err; } diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index c9a7e2b2a3..100bb5ebf6 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -53,10 +53,8 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); int err; - err = pci_bridge_initfn(dev, TYPE_PCI_BUS); - if (err) { - goto bridge_error; - } + pci_bridge_initfn(dev, TYPE_PCI_BUS); + if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) { dev->config[PCI_INTERRUPT_PIN] = 0x1; memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", @@ -95,7 +93,7 @@ slotid_error: } shpc_error: pci_bridge_exitfn(dev); -bridge_error: + return err; } diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 9eb3d8895f..cf1ee63aba 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -61,11 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d) PCIESlot *s = PCIE_SLOT(d); int rc; - rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); - if (rc < 0) { - return rc; - } - + pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, @@ -93,7 +89,7 @@ static int xio3130_downstream_initfn(PCIDevice *d) goto err_pcie_cap; } pcie_cap_arifwd_init(d); - rc = pcie_aer_init(d, XIO3130_AER_OFFSET); + rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF); if (rc < 0) { goto err; } diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 7d255a6d52..164ef58c46 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -57,11 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d) PCIEPort *p = PCIE_PORT(d); int rc; - rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); - if (rc < 0) { - return rc; - } - + pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, @@ -82,7 +78,7 @@ static int xio3130_upstream_initfn(PCIDevice *d) } pcie_cap_flr_init(d); pcie_cap_deverr_init(d); - rc = pcie_aer_init(d, XIO3130_AER_OFFSET); + rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF); if (rc < 0) { goto err; } diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 75dee50bc3..aaef7bb3a1 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -635,12 +635,7 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level) static int apb_pci_bridge_initfn(PCIDevice *dev) { - int rc; - - rc = pci_bridge_initfn(dev, TYPE_PCI_BUS); - if (rc < 0) { - return rc; - } + pci_bridge_initfn(dev, TYPE_PCI_BUS); /* * command register: diff --git a/hw/pci/msix.c b/hw/pci/msix.c index eb4ef113d1..537fdba747 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -80,10 +80,10 @@ static void msix_clr_pending(PCIDevice *dev, int vector) static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask) { unsigned offset = vector * PCI_MSIX_ENTRY_SIZE; - uint32_t *data = (uint32_t *)&dev->msix_table[offset + PCI_MSIX_ENTRY_DATA]; + uint8_t *data = &dev->msix_table[offset + PCI_MSIX_ENTRY_DATA]; /* MSIs on Xen can be remapped into pirqs. In those cases, masking * and unmasking go through the PV evtchn path. */ - if (xen_is_pirq_msi(*data)) { + if (xen_enabled() && xen_is_pirq_msi(pci_get_long(data))) { return false; } return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] & diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b282120b12..e67664deb3 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -278,9 +278,9 @@ static void pcibus_reset(BusState *qbus) } } -static void pci_host_bus_register(PCIBus *bus, DeviceState *parent) +static void pci_host_bus_register(DeviceState *host) { - PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent); + PCIHostState *host_bridge = PCI_HOST_BRIDGE(host); QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next); } @@ -331,7 +331,6 @@ const char *pci_root_bus_path(PCIDevice *dev) } static void pci_bus_init(PCIBus *bus, DeviceState *parent, - const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, uint8_t devfn_min) @@ -344,7 +343,7 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, /* host bridge */ QLIST_INIT(&bus->child); - pci_host_bus_register(bus, parent); + pci_host_bus_register(parent); } bool pci_bus_is_express(PCIBus *bus) @@ -364,8 +363,7 @@ void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, uint8_t devfn_min, const char *typename) { qbus_create_inplace(bus, bus_size, typename, parent, name); - pci_bus_init(bus, parent, name, address_space_mem, - address_space_io, devfn_min); + pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min); } PCIBus *pci_bus_new(DeviceState *parent, const char *name, @@ -376,8 +374,7 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, PCIBus *bus; bus = PCI_BUS(qbus_create(typename, parent, name)); - pci_bus_init(bus, parent, name, address_space_mem, - address_space_io, devfn_min); + pci_bus_init(bus, parent, address_space_mem, address_space_io, devfn_min); return bus; } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 7eab9d57c5..3cf30bd334 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -333,7 +333,7 @@ void pci_bridge_reset(DeviceState *qdev) } /* default qdev initialization function for PCI-to-PCI bridge */ -int pci_bridge_initfn(PCIDevice *dev, const char *typename) +void pci_bridge_initfn(PCIDevice *dev, const char *typename) { PCIBus *parent = dev->bus; PCIBridge *br = PCI_BRIDGE(dev); @@ -379,7 +379,6 @@ int pci_bridge_initfn(PCIDevice *dev, const char *typename) br->windows = pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); - return 0; } /* default qdev clean up function for PCI-to-PCI bridge */ diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 435a6cfd57..4aca0c5912 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -608,7 +608,7 @@ void pcie_add_capability(PCIDevice *dev, assert(offset >= PCI_CONFIG_SPACE_SIZE); assert(offset < offset + size); - assert(offset + size < PCIE_CONFIG_SPACE_SIZE); + assert(offset + size <= PCIE_CONFIG_SPACE_SIZE); assert(size >= 8); assert(pci_is_express(dev)); diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index a9d9d06208..e2d4e68ba3 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -95,12 +95,12 @@ static void aer_log_clear_all_err(PCIEAERLog *aer_log) aer_log->log_num = 0; } -int pcie_aer_init(PCIDevice *dev, uint16_t offset) +int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size) { PCIExpressDevice *exp; pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, - offset, PCI_ERR_SIZEOF); + offset, size); exp = &dev->exp; exp->aer_cap = offset; @@ -371,7 +371,7 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) * * Walk up the bus tree from the device, propagate the error message. */ -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) +void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) { uint8_t type; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e214a34257..c119f55824 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1528,7 +1528,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) section_hdr = qemu_get_be32(f); if (section_hdr) { - Error *local_err; + Error *local_err = NULL; /* First section gives the htab size */ spapr_reallocate_hpt(spapr, section_hdr, &local_err); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 6e9b6be58c..1733482de6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -386,6 +386,65 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_SUCCESS; } +static target_ulong h_page_init(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + hwaddr dst = args[1]; + hwaddr src = args[2]; + hwaddr len = TARGET_PAGE_SIZE; + uint8_t *pdst, *psrc; + target_long ret = H_SUCCESS; + + if (flags & ~(H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE + | H_COPY_PAGE | H_ZERO_PAGE)) { + qemu_log_mask(LOG_UNIMP, "h_page_init: Bad flags (" TARGET_FMT_lx "\n", + flags); + return H_PARAMETER; + } + + /* Map-in destination */ + if (!is_ram_address(spapr, dst) || (dst & ~TARGET_PAGE_MASK) != 0) { + return H_PARAMETER; + } + pdst = cpu_physical_memory_map(dst, &len, 1); + if (!pdst || len != TARGET_PAGE_SIZE) { + return H_PARAMETER; + } + + if (flags & H_COPY_PAGE) { + /* Map-in source, copy to destination, and unmap source again */ + if (!is_ram_address(spapr, src) || (src & ~TARGET_PAGE_MASK) != 0) { + ret = H_PARAMETER; + goto unmap_out; + } + psrc = cpu_physical_memory_map(src, &len, 0); + if (!psrc || len != TARGET_PAGE_SIZE) { + ret = H_PARAMETER; + goto unmap_out; + } + memcpy(pdst, psrc, len); + cpu_physical_memory_unmap(psrc, len, 0, len); + } else if (flags & H_ZERO_PAGE) { + memset(pdst, 0, len); /* Just clear the destination page */ + } + + if (kvm_enabled() && (flags & H_ICACHE_SYNCHRONIZE) != 0) { + kvmppc_dcbst_range(cpu, pdst, len); + } + if (flags & (H_ICACHE_SYNCHRONIZE | H_ICACHE_INVALIDATE)) { + if (kvm_enabled()) { + kvmppc_icbi_range(cpu, pdst, len); + } else { + tb_flush(CPU(cpu)); + } + } + +unmap_out: + cpu_physical_memory_unmap(pdst, TARGET_PAGE_SIZE, 1, len); + return ret; +} + #define FLAGS_REGISTER_VPA 0x0000200000000000ULL #define FLAGS_REGISTER_DTL 0x0000400000000000ULL #define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL @@ -1045,6 +1104,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0); spapr_register_hypercall(H_SET_DABR, h_set_dabr); spapr_register_hypercall(H_SET_XDABR, h_set_xdabr); + spapr_register_hypercall(H_PAGE_INIT, h_page_init); spapr_register_hypercall(H_SET_MODE, h_set_mode); /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 8340326a50..367e47643f 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -39,14 +39,10 @@ void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread) } } -static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, - VirtQueue *vq, - EventNotifierHandler *handler, - int n) +static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - VirtIOSCSIVring *r; int rc; /* Set up virtqueue notify */ @@ -55,105 +51,17 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n", rc); s->dataplane_fenced = true; - return NULL; + return rc; } - r = g_new(VirtIOSCSIVring, 1); - r->host_notifier = *virtio_queue_get_host_notifier(vq); - r->guest_notifier = *virtio_queue_get_guest_notifier(vq); - aio_set_event_notifier(s->ctx, &r->host_notifier, true, handler); - - r->parent = s; - - if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) { - fprintf(stderr, "virtio-scsi: VRing setup failed\n"); - goto fail_vring; - } - return r; - -fail_vring: - aio_set_event_notifier(s->ctx, &r->host_notifier, true, NULL); - k->set_host_notifier(qbus->parent, n, false); - g_free(r); - return NULL; -} - -VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, - VirtIOSCSIVring *vring) -{ - VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; - VirtIOSCSIReq *req; - - req = vring_pop((VirtIODevice *)s, &vring->vring, - sizeof(VirtIOSCSIReq) + vs->cdb_size); - if (!req) { - return NULL; - } - virtio_scsi_init_req(s, NULL, req); - req->vring = vring; - return req; -} - -void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); - - vring_push(vdev, &req->vring->vring, &req->elem, - req->qsgl.size + req->resp_iov.size); - - if (vring_should_notify(vdev, &req->vring->vring)) { - event_notifier_set(&req->vring->guest_notifier); - } + virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, true, true); + return 0; } -static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) +void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req) { - VirtIOSCSIVring *vring = container_of(notifier, - VirtIOSCSIVring, host_notifier); - VirtIOSCSI *s = VIRTIO_SCSI(vring->parent); - VirtIOSCSIReq *req; - - event_notifier_test_and_clear(notifier); - while ((req = virtio_scsi_pop_req_vring(s, vring))) { - virtio_scsi_handle_ctrl_req(s, req); - } -} - -static void virtio_scsi_iothread_handle_event(EventNotifier *notifier) -{ - VirtIOSCSIVring *vring = container_of(notifier, - VirtIOSCSIVring, host_notifier); - VirtIOSCSI *s = vring->parent; - VirtIODevice *vdev = VIRTIO_DEVICE(s); - - event_notifier_test_and_clear(notifier); - - if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { - return; - } - - if (s->events_dropped) { - virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); - } -} - -static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) -{ - VirtIOSCSIVring *vring = container_of(notifier, - VirtIOSCSIVring, host_notifier); - VirtIOSCSI *s = (VirtIOSCSI *)vring->parent; - VirtIOSCSIReq *req, *next; - QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - - event_notifier_test_and_clear(notifier); - while ((req = virtio_scsi_pop_req_vring(s, vring))) { - if (virtio_scsi_handle_cmd_req_prepare(s, req)) { - QTAILQ_INSERT_TAIL(&reqs, req, next); - } - } - - QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { - virtio_scsi_handle_cmd_req_submit(s, req); + if (virtio_should_notify(vdev, req->vq)) { + event_notifier_set(virtio_queue_get_guest_notifier(req->vq)); } } @@ -163,46 +71,10 @@ static void virtio_scsi_clear_aio(VirtIOSCSI *s) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); int i; - if (s->ctrl_vring) { - aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, - true, NULL); - } - if (s->event_vring) { - aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, - true, NULL); - } - if (s->cmd_vrings) { - for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) { - aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier, - true, NULL); - } - } -} - -static void virtio_scsi_vring_teardown(VirtIOSCSI *s) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(s); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); - int i; - - if (s->ctrl_vring) { - vring_teardown(&s->ctrl_vring->vring, vdev, 0); - g_free(s->ctrl_vring); - s->ctrl_vring = NULL; - } - if (s->event_vring) { - vring_teardown(&s->event_vring->vring, vdev, 1); - g_free(s->event_vring); - s->event_vring = NULL; - } - if (s->cmd_vrings) { - for (i = 0; i < vs->conf.num_queues && s->cmd_vrings[i]; i++) { - vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); - g_free(s->cmd_vrings[i]); - s->cmd_vrings[i] = NULL; - } - free(s->cmd_vrings); - s->cmd_vrings = NULL; + virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, false, false); + virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, false, false); + for (i = 0; i < vs->conf.num_queues; i++) { + virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, false, false); } } @@ -229,30 +101,21 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) if (rc != 0) { fprintf(stderr, "virtio-scsi: Failed to set guest notifiers (%d), " "ensure -enable-kvm is set\n", rc); - s->dataplane_fenced = true; goto fail_guest_notifiers; } aio_context_acquire(s->ctx); - s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq, - virtio_scsi_iothread_handle_ctrl, - 0); - if (!s->ctrl_vring) { + rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0); + if (rc) { goto fail_vrings; } - s->event_vring = virtio_scsi_vring_init(s, vs->event_vq, - virtio_scsi_iothread_handle_event, - 1); - if (!s->event_vring) { + rc = virtio_scsi_vring_init(s, vs->event_vq, 1); + if (rc) { goto fail_vrings; } - s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues); for (i = 0; i < vs->conf.num_queues; i++) { - s->cmd_vrings[i] = - virtio_scsi_vring_init(s, vs->cmd_vqs[i], - virtio_scsi_iothread_handle_cmd, - i + 2); - if (!s->cmd_vrings[i]) { + rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2); + if (rc) { goto fail_vrings; } } @@ -265,13 +128,14 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) fail_vrings: virtio_scsi_clear_aio(s); aio_context_release(s->ctx); - virtio_scsi_vring_teardown(s); for (i = 0; i < vs->conf.num_queues + 2; i++) { k->set_host_notifier(qbus->parent, i, false); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); fail_guest_notifiers: + s->dataplane_fenced = true; s->dataplane_starting = false; + s->dataplane_started = true; } /* Context: QEMU global mutex held */ @@ -282,12 +146,14 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); int i; + if (!s->dataplane_started || s->dataplane_stopping) { + return; + } + /* Better luck next time. */ if (s->dataplane_fenced) { s->dataplane_fenced = false; - return; - } - if (!s->dataplane_started || s->dataplane_stopping) { + s->dataplane_started = false; return; } s->dataplane_stopping = true; @@ -295,24 +161,12 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) aio_context_acquire(s->ctx); - aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, - true, NULL); - aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, - true, NULL); - for (i = 0; i < vs->conf.num_queues; i++) { - aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier, - true, NULL); - } + virtio_scsi_clear_aio(s); blk_drain_all(); /* ensure there are no in-flight requests */ aio_context_release(s->ctx); - /* Sync vring state back to virtqueue so that non-dataplane request - * processing can continue when we disable the host notifier below. - */ - virtio_scsi_vring_teardown(s); - for (i = 0; i < vs->conf.num_queues + 2; i++) { k->set_host_notifier(qbus->parent, i, false); } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 5b29baccf3..0c30d2e692 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -23,7 +23,6 @@ #include <block/scsi.h> #include <hw/virtio/virtio-bus.h> #include "hw/virtio/virtio-access.h" -#include "migration/migration.h" static inline int virtio_scsi_get_lun(uint8_t *lun) { @@ -43,7 +42,8 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) { - const size_t zero_skip = offsetof(VirtIOSCSIReq, vring); + const size_t zero_skip = + offsetof(VirtIOSCSIReq, resp_iov) + sizeof(req->resp_iov); req->vq = vq; req->dev = s; @@ -66,11 +66,10 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) VirtIODevice *vdev = VIRTIO_DEVICE(s); qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size); - if (req->vring) { - assert(req->vq == NULL); - virtio_scsi_vring_push_notify(req); + virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); + if (s->dataplane_started) { + virtio_scsi_dataplane_notify(vdev, req); } else { - virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); virtio_notify(vdev, vq); } @@ -417,7 +416,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx && !s->dataplane_disabled) { + if (s->ctx && !s->dataplane_started) { virtio_scsi_dataplane_start(s); return; } @@ -567,7 +566,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSIReq *req, *next; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - if (s->ctx && !s->dataplane_disabled) { + if (s->ctx && !s->dataplane_started) { virtio_scsi_dataplane_start(s); return; } @@ -687,11 +686,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, aio_context_acquire(s->ctx); } - if (s->dataplane_started) { - req = virtio_scsi_pop_req_vring(s, s->event_vring); - } else { - req = virtio_scsi_pop_req(s, vs->event_vq); - } + req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { s->events_dropped = true; goto out; @@ -733,7 +728,7 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx && !s->dataplane_disabled) { + if (s->ctx && !s->dataplane_started) { virtio_scsi_dataplane_start(s); return; } @@ -901,31 +896,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, } } -/* Disable dataplane thread during live migration since it does not - * update the dirty memory bitmap yet. - */ -static void virtio_scsi_migration_state_changed(Notifier *notifier, void *data) -{ - VirtIOSCSI *s = container_of(notifier, VirtIOSCSI, - migration_state_notifier); - MigrationState *mig = data; - - if (migration_in_setup(mig)) { - if (!s->dataplane_started) { - return; - } - virtio_scsi_dataplane_stop(s); - s->dataplane_disabled = true; - } else if (migration_has_finished(mig) || - migration_has_failed(mig)) { - if (s->dataplane_started) { - return; - } - blk_drain_all(); /* complete in-flight non-dataplane requests */ - s->dataplane_disabled = false; - } -} - static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -956,8 +926,6 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, 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"); @@ -991,8 +959,6 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) error_free(s->blocker); unregister_savevm(dev, "virtio-scsi", s); - remove_migration_state_change_notifier(&s->migration_state_notifier); - virtio_scsi_common_unrealize(dev, errp); } diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 133bd0d455..5cfea6e0da 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -25,7 +25,6 @@ obj-$(CONFIG_OMAP) += omap_gptimer.o obj-$(CONFIG_OMAP) += omap_synctimer.o obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o obj-$(CONFIG_SH4) += sh_timer.o -obj-$(CONFIG_TUSB6010) += tusb6010.o obj-$(CONFIG_DIGIC) += digic-timer.o obj-$(CONFIG_MC146818RTC) += mc146818rtc.o diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 8f00fbd8f6..2717027d34 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -10,6 +10,8 @@ common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o +obj-$(CONFIG_TUSB6010) += tusb6010.o + # emulated usb devices common-obj-$(CONFIG_USB) += dev-hub.o common-obj-$(CONFIG_USB) += dev-hid.o diff --git a/hw/usb/core.c b/hw/usb/core.c index bea5e1ee8b..45fa00c517 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -129,9 +129,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p) } usb_packet_copy(p, s->setup_buf, p->iov.size); + s->setup_index = 0; p->actual_length = 0; s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; - s->setup_index = 0; + if (s->setup_len > sizeof(s->data_buf)) { + fprintf(stderr, + "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", + s->setup_len, sizeof(s->data_buf)); + p->status = USB_RET_STALL; + return; + } request = (s->setup_buf[0] << 8) | s->setup_buf[1]; value = (s->setup_buf[3] << 8) | s->setup_buf[2]; @@ -152,13 +159,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p) } s->setup_state = SETUP_STATE_DATA; } else { - if (s->setup_len > sizeof(s->data_buf)) { - fprintf(stderr, - "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", - s->setup_len, sizeof(s->data_buf)); - p->status = USB_RET_STALL; - return; - } if (s->setup_len == 0) s->setup_state = SETUP_STATE_ACK; else @@ -177,7 +177,7 @@ static void do_token_in(USBDevice *s, USBPacket *p) request = (s->setup_buf[0] << 8) | s->setup_buf[1]; value = (s->setup_buf[3] << 8) | s->setup_buf[2]; index = (s->setup_buf[5] << 8) | s->setup_buf[4]; - + switch(s->setup_state) { case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 8e8db03a0c..4d81c68e0e 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -1,7 +1,6 @@ #ifndef QEMU_HW_USB_DESC_H #define QEMU_HW_USB_DESC_H -#include <inttypes.h> #include <wchar.h> /* binary representation */ diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 985a6298bf..c6abd38c2a 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -654,7 +654,8 @@ typedef struct USBNetState { static int is_rndis(USBNetState *s) { - return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE; + return s->dev.config ? + s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0; } static int ndis_query(USBNetState *s, uint32_t oid, @@ -915,8 +916,9 @@ static int rndis_query_response(USBNetState *s, bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; buflen = le32_to_cpu(buf->InformationBufferLength); - if (bufoffs + buflen > length) + if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { return USB_RET_STALL; + } infobuflen = ndis_query(s, le32_to_cpu(buf->OID), bufoffs + (uint8_t *) buf, buflen, infobuf, @@ -961,8 +963,9 @@ static int rndis_set_response(USBNetState *s, bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; buflen = le32_to_cpu(buf->InformationBufferLength); - if (bufoffs + buflen > length) + if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { return USB_RET_STALL; + } ret = ndis_set(s, le32_to_cpu(buf->OID), bufoffs + (uint8_t *) buf, buflen); @@ -1212,8 +1215,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); - if (offs + size <= len) + if (offs < len && size < len && offs + size <= len) { qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size); + } } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index bed55dda78..17ed4617ef 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1347,16 +1347,6 @@ static void ohci_frame_boundary(void *opaque) */ static int ohci_bus_start(OHCIState *ohci) { - ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - ohci_frame_boundary, - ohci); - - if (ohci->eof_timer == NULL) { - trace_usb_ohci_bus_eof_timer_failed(ohci->name); - ohci_die(ohci); - return 0; - } - trace_usb_ohci_start(ohci->name); /* Delay the first SOF event by one frame time as @@ -1373,11 +1363,7 @@ static int ohci_bus_start(OHCIState *ohci) static void ohci_bus_stop(OHCIState *ohci) { trace_usb_ohci_stop(ohci->name); - if (ohci->eof_timer) { - timer_del(ohci->eof_timer); - timer_free(ohci->eof_timer); - } - ohci->eof_timer = NULL; + timer_del(ohci->eof_timer); } /* Sets a flag in a port status register but only set it if the port is @@ -1907,6 +1893,9 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_packet_init(&ohci->usb_packet); ohci->async_td = 0; + + ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + ohci_frame_boundary, ohci); } #define TYPE_PCI_OHCI "pci-ohci" @@ -1976,6 +1965,9 @@ static void usb_ohci_exit(PCIDevice *dev) if (!ohci->masterbus) { usb_bus_release(&s->bus); } + + timer_del(s->eof_timer); + timer_free(s->eof_timer); } static void usb_ohci_reset_pci(DeviceState *d) @@ -2041,23 +2033,13 @@ static bool ohci_eof_timer_needed(void *opaque) { OHCIState *ohci = opaque; - return ohci->eof_timer != NULL; -} - -static int ohci_eof_timer_pre_load(void *opaque) -{ - OHCIState *ohci = opaque; - - ohci_bus_start(ohci); - - return 0; + return timer_pending(ohci->eof_timer); } static const VMStateDescription vmstate_ohci_eof_timer = { .name = "ohci-core/eof-timer", .version_id = 1, .minimum_version_id = 1, - .pre_load = ohci_eof_timer_pre_load, .needed = ohci_eof_timer_needed, .fields = (VMStateField[]) { VMSTATE_TIMER_PTR(eof_timer, OHCIState), diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 5ccfb8395a..c370240be2 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -773,8 +773,22 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, bool spd; bool queuing = (q != NULL); uint8_t pid = td->token & 0xff; - UHCIAsync *async = uhci_async_find_td(s, td_addr); + UHCIAsync *async; + + switch (pid) { + case USB_TOKEN_OUT: + case USB_TOKEN_SETUP: + case USB_TOKEN_IN: + break; + default: + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; + s->cmd &= ~UHCI_CMD_RS; + uhci_update_irq(s); + return TD_RESULT_STOP_FRAME; + } + async = uhci_async_find_td(s, td_addr); if (async) { if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) { assert(q == NULL || q == async->queue); @@ -880,11 +894,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, break; default: - /* invalid pid : frame interrupted */ - uhci_async_free(async); - s->status |= UHCI_STS_HCPERR; - uhci_update_irq(s); - return TD_RESULT_STOP_FRAME; + abort(); /* Never to execute */ } if (async->packet.status == USB_RET_ASYNC) { diff --git a/hw/timer/tusb6010.c b/hw/usb/tusb6010.c index 9f6af90806..9f6af90806 100644 --- a/hw/timer/tusb6010.c +++ b/hw/usb/tusb6010.c diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index d3248633c1..ceddbb8f99 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -3,4 +3,5 @@ obj-$(CONFIG_SOFTMMU) += common.o obj-$(CONFIG_PCI) += pci.o pci-quirks.o obj-$(CONFIG_SOFTMMU) += platform.o obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o +obj-$(CONFIG_SOFTMMU) += amd-xgbe.o endif diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c new file mode 100644 index 0000000000..2c60310cf9 --- /dev/null +++ b/hw/vfio/amd-xgbe.c @@ -0,0 +1,56 @@ +/* + * AMD XGBE VFIO device + * + * Copyright Linaro Limited, 2015 + * + * Authors: + * Eric Auger <eric.auger@linaro.org> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/vfio/vfio-amd-xgbe.h" + +static void amd_xgbe_realize(DeviceState *dev, Error **errp) +{ + VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev); + VFIOAmdXgbeDeviceClass *k = VFIO_AMD_XGBE_DEVICE_GET_CLASS(dev); + + vdev->compat = g_strdup("amd,xgbe-seattle-v1a"); + + k->parent_realize(dev, errp); +} + +static const VMStateDescription vfio_platform_amd_xgbe_vmstate = { + .name = TYPE_VFIO_AMD_XGBE, + .unmigratable = 1, +}; + +static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VFIOAmdXgbeDeviceClass *vcxc = + VFIO_AMD_XGBE_DEVICE_CLASS(klass); + vcxc->parent_realize = dc->realize; + dc->realize = amd_xgbe_realize; + dc->desc = "VFIO AMD XGBE"; + dc->vmsd = &vfio_platform_amd_xgbe_vmstate; +} + +static const TypeInfo vfio_amd_xgbe_dev_info = { + .name = TYPE_VFIO_AMD_XGBE, + .parent = TYPE_VFIO_PLATFORM, + .instance_size = sizeof(VFIOAmdXgbeDevice), + .class_init = vfio_amd_xgbe_class_init, + .class_size = sizeof(VFIOAmdXgbeDeviceClass), +}; + +static void register_amd_xgbe_dev_type(void) +{ + type_register_static(&vfio_amd_xgbe_dev_info); +} + +type_init(register_amd_xgbe_dev_type) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 49f3d2d239..20b505f4ec 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1207,7 +1207,7 @@ static int vfio_msix_early_setup(VFIOPCIDevice *vdev) } if (pread(fd, &ctrl, sizeof(ctrl), - vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { + vdev->config_offset + pos + PCI_MSIX_FLAGS) != sizeof(ctrl)) { return -errno; } @@ -1505,10 +1505,11 @@ static void vfio_unmap_bars(VFIOPCIDevice *vdev) */ static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos) { - uint8_t tmp, next = 0xff; + uint8_t tmp; + uint16_t next = PCI_CONFIG_SPACE_SIZE; for (tmp = pdev->config[PCI_CAPABILITY_LIST]; tmp; - tmp = pdev->config[tmp + 1]) { + tmp = pdev->config[tmp + PCI_CAP_LIST_NEXT]) { if (tmp > pos && tmp < next) { next = tmp; } @@ -1697,7 +1698,7 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) int ret; cap_id = pdev->config[pos]; - next = pdev->config[pos + 1]; + next = pdev->config[pos + PCI_CAP_LIST_NEXT]; /* * If it becomes important to configure capabilities to their actual @@ -1711,7 +1712,7 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) * pci_add_capability always inserts the new capability at the head * of the chain. Therefore to end up with a chain that matches the * physical device, we insert from the end by making this recursive. - * This is also why we pre-caclulate size above as cached config space + * This is also why we pre-calculate size above as cached config space * will be changed as we unwind the stack. */ if (next) { @@ -1727,7 +1728,7 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) } /* Use emulated next pointer to allow dropping caps */ - pci_set_byte(vdev->emulated_config_bits + pos + 1, 0xff); + pci_set_byte(vdev->emulated_config_bits + pos + PCI_CAP_LIST_NEXT, 0xff); switch (cap_id) { case PCI_CAP_ID_MSI: diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 19b224a44d..3e2b175da8 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -2,7 +2,6 @@ common-obj-y += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-y += virtio-bus.o common-obj-y += virtio-mmio.o -obj-$(CONFIG_VIRTIO) += dataplane/ obj-y += virtio.o virtio-balloon.o obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o diff --git a/hw/virtio/dataplane/Makefile.objs b/hw/virtio/dataplane/Makefile.objs deleted file mode 100644 index 753a9cab44..0000000000 --- a/hw/virtio/dataplane/Makefile.objs +++ /dev/null @@ -1 +0,0 @@ -obj-y += vring.o diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c deleted file mode 100644 index 4308d9f055..0000000000 --- a/hw/virtio/dataplane/vring.c +++ /dev/null @@ -1,549 +0,0 @@ -/* Copyright 2012 Red Hat, Inc. - * Copyright IBM, Corp. 2012 - * - * Based on Linux 2.6.39 vhost code: - * Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2006 Rusty Russell IBM Corporation - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * Stefan Hajnoczi <stefanha@redhat.com> - * - * Inspiration, some code, and most witty comments come from - * Documentation/virtual/lguest/lguest.c, by Rusty Russell - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#include "qemu/osdep.h" -#include "trace.h" -#include "hw/hw.h" -#include "exec/memory.h" -#include "exec/address-spaces.h" -#include "hw/virtio/virtio-access.h" -#include "hw/virtio/dataplane/vring.h" -#include "hw/virtio/dataplane/vring-accessors.h" -#include "qemu/error-report.h" - -/* vring_map can be coupled with vring_unmap or (if you still have the - * value returned in *mr) memory_region_unref. - * Returns NULL on failure. - * Callers that can handle a partial mapping must supply mapped_len pointer to - * get the actual length mapped. - * Passing mapped_len == NULL requires either a full mapping or a failure. - */ -static void *vring_map(MemoryRegion **mr, hwaddr phys, - hwaddr len, hwaddr *mapped_len, - bool is_write) -{ - MemoryRegionSection section = memory_region_find(get_system_memory(), phys, len); - uint64_t size; - - if (!section.mr) { - goto out; - } - - size = int128_get64(section.size); - assert(size); - - /* Passing mapped_len == NULL requires either a full mapping or a failure. */ - if (!mapped_len && size < len) { - goto out; - } - - if (is_write && section.readonly) { - goto out; - } - if (!memory_region_is_ram(section.mr)) { - goto out; - } - - /* Ignore regions with dirty logging, we cannot mark them dirty */ - if (memory_region_get_dirty_log_mask(section.mr)) { - goto out; - } - - if (mapped_len) { - *mapped_len = MIN(size, len); - } - - *mr = section.mr; - return memory_region_get_ram_ptr(section.mr) + section.offset_within_region; - -out: - memory_region_unref(section.mr); - *mr = NULL; - return NULL; -} - -static void vring_unmap(void *buffer, bool is_write) -{ - ram_addr_t addr; - MemoryRegion *mr; - - mr = qemu_ram_addr_from_host(buffer, &addr); - memory_region_unref(mr); -} - -/* Map the guest's vring to host memory */ -bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) -{ - struct vring *vr = &vring->vr; - hwaddr addr; - hwaddr size; - void *ptr; - - vring->broken = false; - vr->num = virtio_queue_get_num(vdev, n); - - addr = virtio_queue_get_desc_addr(vdev, n); - size = virtio_queue_get_desc_size(vdev, n); - /* Map the descriptor area as read only */ - ptr = vring_map(&vring->mr_desc, addr, size, NULL, false); - if (!ptr) { - error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring desc " - "at 0x%" HWADDR_PRIx, - size, addr); - goto out_err_desc; - } - vr->desc = ptr; - - addr = virtio_queue_get_avail_addr(vdev, n); - size = virtio_queue_get_avail_size(vdev, n); - /* Add the size of the used_event_idx */ - size += sizeof(uint16_t); - /* Map the driver area as read only */ - ptr = vring_map(&vring->mr_avail, addr, size, NULL, false); - if (!ptr) { - error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring avail " - "at 0x%" HWADDR_PRIx, - size, addr); - goto out_err_avail; - } - vr->avail = ptr; - - addr = virtio_queue_get_used_addr(vdev, n); - size = virtio_queue_get_used_size(vdev, n); - /* Add the size of the avail_event_idx */ - size += sizeof(uint16_t); - /* Map the device area as read-write */ - ptr = vring_map(&vring->mr_used, addr, size, NULL, true); - if (!ptr) { - error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring used " - "at 0x%" HWADDR_PRIx, - size, addr); - goto out_err_used; - } - vr->used = ptr; - - vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n); - vring->last_used_idx = vring_get_used_idx(vdev, vring); - vring->signalled_used = 0; - vring->signalled_used_valid = false; - - trace_vring_setup(virtio_queue_get_ring_addr(vdev, n), - vring->vr.desc, vring->vr.avail, vring->vr.used); - return true; - -out_err_used: - memory_region_unref(vring->mr_avail); -out_err_avail: - memory_region_unref(vring->mr_desc); -out_err_desc: - vring->broken = true; - return false; -} - -void vring_teardown(Vring *vring, VirtIODevice *vdev, int n) -{ - virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx); - virtio_queue_invalidate_signalled_used(vdev, n); - - memory_region_unref(vring->mr_desc); - memory_region_unref(vring->mr_avail); - memory_region_unref(vring->mr_used); -} - -/* Disable guest->host notifies */ -void vring_disable_notification(VirtIODevice *vdev, Vring *vring) -{ - if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { - vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); - } -} - -/* Enable guest->host notifies - * - * Return true if the vring is empty, false if there are more requests. - */ -bool vring_enable_notification(VirtIODevice *vdev, Vring *vring) -{ - if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { - vring_avail_event(&vring->vr) = vring->vr.avail->idx; - } else { - vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); - } - smp_mb(); /* ensure update is seen before reading avail_idx */ - return !vring_more_avail(vdev, vring); -} - -/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */ -bool vring_should_notify(VirtIODevice *vdev, Vring *vring) -{ - uint16_t old, new; - bool v; - /* Flush out used index updates. This is paired - * with the barrier that the Guest executes when enabling - * interrupts. */ - smp_mb(); - - if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && - unlikely(!vring_more_avail(vdev, vring))) { - return true; - } - - if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { - return !(vring_get_avail_flags(vdev, vring) & - VRING_AVAIL_F_NO_INTERRUPT); - } - old = vring->signalled_used; - v = vring->signalled_used_valid; - new = vring->signalled_used = vring->last_used_idx; - vring->signalled_used_valid = true; - - if (unlikely(!v)) { - return true; - } - - return vring_need_event(virtio_tswap16(vdev, vring_used_event(&vring->vr)), - new, old); -} - -typedef struct VirtQueueCurrentElement { - unsigned in_num; - unsigned out_num; - hwaddr addr[VIRTQUEUE_MAX_SIZE]; - struct iovec iov[VIRTQUEUE_MAX_SIZE]; -} VirtQueueCurrentElement; - -static int get_desc(Vring *vring, VirtQueueCurrentElement *elem, - struct vring_desc *desc) -{ - unsigned *num; - struct iovec *iov; - hwaddr *addr; - MemoryRegion *mr; - hwaddr len; - - if (desc->flags & VRING_DESC_F_WRITE) { - num = &elem->in_num; - iov = &elem->iov[elem->out_num + *num]; - addr = &elem->addr[elem->out_num + *num]; - } else { - num = &elem->out_num; - iov = &elem->iov[*num]; - addr = &elem->addr[*num]; - - /* If it's an output descriptor, they're all supposed - * to come before any input descriptors. */ - if (unlikely(elem->in_num)) { - error_report("Descriptor has out after in"); - return -EFAULT; - } - } - - while (desc->len) { - /* Stop for now if there are not enough iovecs available. */ - if (*num >= VIRTQUEUE_MAX_SIZE) { - error_report("Invalid SG num: %u", *num); - return -EFAULT; - } - - iov->iov_base = vring_map(&mr, desc->addr, desc->len, &len, - desc->flags & VRING_DESC_F_WRITE); - if (!iov->iov_base) { - error_report("Failed to map descriptor addr %#" PRIx64 " len %u", - (uint64_t)desc->addr, desc->len); - return -EFAULT; - } - - /* The MemoryRegion is looked up again and unref'ed later, leave the - * ref in place. */ - (iov++)->iov_len = len; - *addr++ = desc->addr; - desc->len -= len; - desc->addr += len; - *num += 1; - } - - return 0; -} - -static void copy_in_vring_desc(VirtIODevice *vdev, - const struct vring_desc *guest, - struct vring_desc *host) -{ - host->addr = virtio_ldq_p(vdev, &guest->addr); - host->len = virtio_ldl_p(vdev, &guest->len); - host->flags = virtio_lduw_p(vdev, &guest->flags); - host->next = virtio_lduw_p(vdev, &guest->next); -} - -static bool read_vring_desc(VirtIODevice *vdev, - hwaddr guest, - struct vring_desc *host) -{ - if (address_space_read(&address_space_memory, guest, MEMTXATTRS_UNSPECIFIED, - (uint8_t *)host, sizeof *host)) { - return false; - } - host->addr = virtio_tswap64(vdev, host->addr); - host->len = virtio_tswap32(vdev, host->len); - host->flags = virtio_tswap16(vdev, host->flags); - host->next = virtio_tswap16(vdev, host->next); - return true; -} - -/* This is stolen from linux/drivers/vhost/vhost.c. */ -static int get_indirect(VirtIODevice *vdev, Vring *vring, - VirtQueueCurrentElement *cur_elem, - struct vring_desc *indirect) -{ - struct vring_desc desc; - unsigned int i = 0, count, found = 0; - int ret; - - /* Sanity check */ - if (unlikely(indirect->len % sizeof(desc))) { - error_report("Invalid length in indirect descriptor: " - "len %#x not multiple of %#zx", - indirect->len, sizeof(desc)); - vring->broken = true; - return -EFAULT; - } - - count = indirect->len / sizeof(desc); - /* Buffers are chained via a 16 bit next field, so - * we can have at most 2^16 of these. */ - if (unlikely(count > USHRT_MAX + 1)) { - error_report("Indirect buffer length too big: %d", indirect->len); - vring->broken = true; - return -EFAULT; - } - - do { - /* Translate indirect descriptor */ - if (!read_vring_desc(vdev, indirect->addr + found * sizeof(desc), - &desc)) { - error_report("Failed to read indirect descriptor " - "addr %#" PRIx64 " len %zu", - (uint64_t)indirect->addr + found * sizeof(desc), - sizeof(desc)); - vring->broken = true; - return -EFAULT; - } - - /* Ensure descriptor has been loaded before accessing fields */ - barrier(); /* read_barrier_depends(); */ - - if (unlikely(++found > count)) { - error_report("Loop detected: last one at %u " - "indirect size %u", i, count); - vring->broken = true; - return -EFAULT; - } - - if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { - error_report("Nested indirect descriptor"); - vring->broken = true; - return -EFAULT; - } - - ret = get_desc(vring, cur_elem, &desc); - if (ret < 0) { - vring->broken |= (ret == -EFAULT); - return ret; - } - i = desc.next; - } while (desc.flags & VRING_DESC_F_NEXT); - return 0; -} - -static void vring_unmap_element(VirtQueueElement *elem) -{ - int i; - - /* This assumes that the iovecs, if changed, are never moved past - * the end of the valid area. This is true if iovec manipulations - * are done with iov_discard_front and iov_discard_back. - */ - for (i = 0; i < elem->out_num; i++) { - vring_unmap(elem->out_sg[i].iov_base, false); - } - - for (i = 0; i < elem->in_num; i++) { - vring_unmap(elem->in_sg[i].iov_base, true); - } -} - -/* This looks in the virtqueue and for the first available buffer, and converts - * it to an iovec for convenient access. Since descriptors consist of some - * number of output then some number of input descriptors, it's actually two - * iovecs, but we pack them into one and note how many of each there were. - * - * This function returns the descriptor number found, or vq->num (which is - * never a valid descriptor number) if none was found. A negative code is - * returned on error. - * - * Stolen from linux/drivers/vhost/vhost.c. - */ -void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) -{ - struct vring_desc desc; - unsigned int i, head, found = 0, num = vring->vr.num; - uint16_t avail_idx, last_avail_idx; - VirtQueueCurrentElement cur_elem; - VirtQueueElement *elem = NULL; - int ret; - - /* If there was a fatal error then refuse operation */ - if (vring->broken) { - ret = -EFAULT; - goto out; - } - - cur_elem.in_num = cur_elem.out_num = 0; - - /* Check it isn't doing very strange things with descriptor numbers. */ - last_avail_idx = vring->last_avail_idx; - avail_idx = vring_get_avail_idx(vdev, vring); - barrier(); /* load indices now and not again later */ - - if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) { - error_report("Guest moved used index from %u to %u", - last_avail_idx, avail_idx); - ret = -EFAULT; - goto out; - } - - /* If there's nothing new since last we looked. */ - if (avail_idx == last_avail_idx) { - ret = -EAGAIN; - goto out; - } - - /* Only get avail ring entries after they have been exposed by guest. */ - smp_rmb(); - - /* Grab the next descriptor number they're advertising, and increment - * the index we've seen. */ - head = vring_get_avail_ring(vdev, vring, last_avail_idx % num); - - /* If their number is silly, that's an error. */ - if (unlikely(head >= num)) { - error_report("Guest says index %u > %u is available", head, num); - ret = -EFAULT; - goto out; - } - - i = head; - do { - if (unlikely(i >= num)) { - error_report("Desc index is %u > %u, head = %u", i, num, head); - ret = -EFAULT; - goto out; - } - if (unlikely(++found > num)) { - error_report("Loop detected: last one at %u vq size %u head %u", - i, num, head); - ret = -EFAULT; - goto out; - } - copy_in_vring_desc(vdev, &vring->vr.desc[i], &desc); - - /* Ensure descriptor is loaded before accessing fields */ - barrier(); - - if (desc.flags & VRING_DESC_F_INDIRECT) { - ret = get_indirect(vdev, vring, &cur_elem, &desc); - if (ret < 0) { - goto out; - } - continue; - } - - ret = get_desc(vring, &cur_elem, &desc); - if (ret < 0) { - goto out; - } - - i = desc.next; - } while (desc.flags & VRING_DESC_F_NEXT); - - /* On success, increment avail index. */ - vring->last_avail_idx++; - if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { - vring_avail_event(&vring->vr) = - virtio_tswap16(vdev, vring->last_avail_idx); - } - - /* Now copy what we have collected and mapped */ - elem = virtqueue_alloc_element(sz, cur_elem.out_num, cur_elem.in_num); - elem->index = head; - for (i = 0; i < cur_elem.out_num; i++) { - elem->out_addr[i] = cur_elem.addr[i]; - elem->out_sg[i] = cur_elem.iov[i]; - } - for (i = 0; i < cur_elem.in_num; i++) { - elem->in_addr[i] = cur_elem.addr[cur_elem.out_num + i]; - elem->in_sg[i] = cur_elem.iov[cur_elem.out_num + i]; - } - - return elem; - -out: - assert(ret < 0); - if (ret == -EFAULT) { - vring->broken = true; - } - - for (i = 0; i < cur_elem.out_num + cur_elem.in_num; i++) { - vring_unmap(cur_elem.iov[i].iov_base, false); - } - - g_free(elem); - return NULL; -} - -/* After we've used one of their buffers, we tell them about it. - * - * Stolen from linux/drivers/vhost/vhost.c. - */ -void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, - int len) -{ - unsigned int head = elem->index; - uint16_t new; - - vring_unmap_element(elem); - - /* Don't touch vring if a fatal error occurred */ - if (vring->broken) { - return; - } - - /* The virtqueue contains a ring of used buffers. Get a pointer to the - * next entry in that used ring. */ - vring_set_used_ring_id(vdev, vring, vring->last_used_idx % vring->vr.num, - head); - vring_set_used_ring_len(vdev, vring, vring->last_used_idx % vring->vr.num, - len); - - /* Make sure buffer is written before we update index. */ - smp_wmb(); - - new = ++vring->last_used_idx; - vring_set_used_idx(vdev, vring, new); - if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) { - vring->signalled_used_valid = false; - } -} diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 7fde1370e0..7ed3dd9a13 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -611,6 +611,25 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) return -1; } +static bool vhost_user_can_merge(struct vhost_dev *dev, + uint64_t start1, uint64_t size1, + uint64_t start2, uint64_t size2) +{ + ram_addr_t ram_addr; + int mfd, rfd; + MemoryRegion *mr; + + mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr); + assert(mr); + mfd = qemu_get_ram_fd(ram_addr); + + mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr); + assert(mr); + rfd = qemu_get_ram_fd(ram_addr); + + return mfd == rfd; +} + const VhostOps user_ops = { .backend_type = VHOST_BACKEND_TYPE_USER, .vhost_backend_init = vhost_user_init, @@ -633,4 +652,5 @@ const VhostOps user_ops = { .vhost_set_vring_enable = vhost_user_set_vring_enable, .vhost_requires_shm_log = vhost_user_requires_shm_log, .vhost_migration_done = vhost_user_migration_done, + .vhost_backend_can_merge = vhost_user_can_merge, }; diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 7dff75547d..392d848819 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -260,6 +260,13 @@ static void vhost_dev_assign_memory(struct vhost_dev *dev, continue; } + if (dev->vhost_ops->vhost_backend_can_merge && + !dev->vhost_ops->vhost_backend_can_merge(dev, uaddr, size, + reg->userspace_addr, + reg->memory_size)) { + continue; + } + if (merged) { --to; assert(to >= 0); @@ -749,6 +756,27 @@ static void vhost_log_stop(MemoryListener *listener, /* FIXME: implement */ } +/* The vhost driver natively knows how to handle the vrings of non + * cross-endian legacy devices and modern devices. Only legacy devices + * exposed to a bi-endian guest may require the vhost driver to use a + * specific endianness. + */ +static inline bool vhost_needs_vring_endian(VirtIODevice *vdev) +{ + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { + return false; + } +#ifdef TARGET_IS_BIENDIAN +#ifdef HOST_WORDS_BIGENDIAN + return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE; +#else + return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; +#endif +#else + return false; +#endif +} + static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, bool is_big_endian, int vhost_vq_index) @@ -799,8 +827,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, return -errno; } - if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && - virtio_legacy_is_cross_endian(vdev)) { + if (vhost_needs_vring_endian(vdev)) { r = vhost_virtqueue_set_vring_endian_legacy(dev, virtio_is_big_endian(vdev), vhost_vq_index); @@ -855,6 +882,14 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, /* Clear and discard previous events if any. */ event_notifier_test_and_clear(&vq->masked_notifier); + /* Init vring in unmasked state, unless guest_notifier_mask + * will do it later. + */ + if (!vdev->use_guest_notifier_mask) { + /* TODO: check and handle errors. */ + vhost_virtqueue_mask(dev, vdev, idx, false); + } + return 0; fail_kick: @@ -896,8 +931,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, /* In the cross-endian case, we need to reset the vring endianness to * native as legacy devices expect so by default. */ - if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && - virtio_legacy_is_cross_endian(vdev)) { + if (vhost_needs_vring_endian(vdev)) { r = vhost_virtqueue_set_vring_endian_legacy(dev, !virtio_is_big_endian(vdev), vhost_vq_index); @@ -1148,6 +1182,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, struct vhost_vring_file file; if (mask) { + assert(vdev->use_guest_notifier_mask); file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier); } else { file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a382f43f92..e9c30e9615 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -305,6 +305,39 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) memcpy(config_data, &config, sizeof(struct virtio_balloon_config)); } +static int build_dimm_list(Object *obj, void *opaque) +{ + GSList **list = opaque; + + if (object_dynamic_cast(obj, TYPE_PC_DIMM)) { + DeviceState *dev = DEVICE(obj); + if (dev->realized) { /* only realized DIMMs matter */ + *list = g_slist_prepend(*list, dev); + } + } + + object_child_foreach(obj, build_dimm_list, opaque); + return 0; +} + +static ram_addr_t get_current_ram_size(void) +{ + GSList *list = NULL, *item; + ram_addr_t size = ram_size; + + build_dimm_list(qdev_get_machine(), &list); + for (item = list; item; item = g_slist_next(item)) { + Object *obj = OBJECT(item->data); + if (!strcmp(object_get_typename(obj), TYPE_PC_DIMM)) { + size += object_property_get_int(obj, PC_DIMM_SIZE_PROP, + &error_abort); + } + } + g_slist_free(list); + + return size; +} + static void virtio_balloon_set_config(VirtIODevice *vdev, const uint8_t *config_data) { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 5494ff4a49..440776c06c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -806,7 +806,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) /* If guest supports masking, set up irqfd now. * Otherwise, delay until unmasked in the frontend. */ - if (k->guest_notifier_mask) { + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); if (ret < 0) { kvm_virtio_pci_vq_vector_release(proxy, vector); @@ -822,7 +822,7 @@ undo: if (vector >= msix_nr_vectors_allocated(dev)) { continue; } - if (k->guest_notifier_mask) { + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } kvm_virtio_pci_vq_vector_release(proxy, vector); @@ -849,7 +849,7 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) /* If guest supports masking, clean up irqfd now. * Otherwise, it was cleaned when masked in the frontend. */ - if (k->guest_notifier_mask) { + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } kvm_virtio_pci_vq_vector_release(proxy, vector); @@ -882,7 +882,7 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, /* If guest supports masking, irqfd is already setup, unmask it. * Otherwise, set it up now. */ - if (k->guest_notifier_mask) { + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { k->guest_notifier_mask(vdev, queue_no, false); /* Test after unmasking to avoid losing events. */ if (k->guest_notifier_pending && @@ -905,7 +905,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, /* If guest supports masking, keep irqfd but mask it. * Otherwise, clean it up now. */ - if (k->guest_notifier_mask) { + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { k->guest_notifier_mask(vdev, queue_no, true); } else { kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); @@ -1022,7 +1022,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, event_notifier_cleanup(notifier); } - if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) { + if (!msix_enabled(&proxy->pci_dev) && + vdev->use_guest_notifier_mask && + vdc->guest_notifier_mask) { vdc->guest_notifier_mask(vdev, n, !assign); } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 90f25451d0..08275a9848 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1162,7 +1162,7 @@ void virtio_irq(VirtQueue *vq) virtio_notify_vector(vq->vdev, vq->vector); } -static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq) +bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq) { uint16_t old, new; bool v; @@ -1187,7 +1187,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq) void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) { - if (!vring_notify(vdev, vq)) { + if (!virtio_should_notify(vdev, vq)) { return; } @@ -1677,6 +1677,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev); vdev->device_endian = virtio_default_endian(); + vdev->use_guest_notifier_mask = true; } hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) @@ -1785,6 +1786,22 @@ static void virtio_queue_host_notifier_read(EventNotifier *n) } } +void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, + bool assign, bool set_handler) +{ + if (assign && set_handler) { + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_read); + } else { + aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL); + } + if (!assign) { + /* Test and clear notifier before after disabling event, + * in case poll callback didn't have time to run. */ + virtio_queue_host_notifier_read(&vq->host_notifier); + } +} + void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler) { diff --git a/include/block/accounting.h b/include/block/accounting.h index 0f46cb4ec1..2db2a009a1 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -25,8 +25,6 @@ #ifndef BLOCK_ACCOUNTING_H #define BLOCK_ACCOUNTING_H -#include <stdint.h> -#include <stdbool.h> #include "qemu/typedefs.h" #include "qemu/timed-average.h" diff --git a/include/block/nbd.h b/include/block/nbd.h index b197adca1c..b86a976984 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -19,7 +19,6 @@ #ifndef NBD_H #define NBD_H -#include <sys/types.h> #include "qemu-common.h" #include "qemu/option.h" diff --git a/include/block/snapshot.h b/include/block/snapshot.h index c6910da63a..e5c0553115 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -26,7 +26,6 @@ #define SNAPSHOT_H #include "qemu-common.h" -#include "qapi/error.h" #include "qemu/option.h" diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index f1b899cd5f..8a79505ada 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -12,7 +12,6 @@ #ifndef BLOCK_WRITE_THRESHOLD_H #define BLOCK_WRITE_THRESHOLD_H -#include <stdint.h> #include "qemu/typedefs.h" #include "qemu-common.h" diff --git a/include/config.h b/include/config.h index e20f78696a..992d761053 100644 --- a/include/config.h +++ b/include/config.h @@ -1,2 +1 @@ -#include "config-host.h" #include "config-target.h" diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h index f90ac79567..c04c3ac9b9 100644 --- a/include/crypto/cipher.h +++ b/include/crypto/cipher.h @@ -22,7 +22,6 @@ #define QCRYPTO_CIPHER_H__ #include "qemu-common.h" -#include "qapi/error.h" typedef struct QCryptoCipher QCryptoCipher; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 5e8d9a1372..aebccd1386 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -22,7 +22,6 @@ #define QCRYPTO_HASH_H__ #include "qemu-common.h" -#include "qapi/error.h" /* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */ diff --git a/include/crypto/init.h b/include/crypto/init.h index 5fc510c4f8..4836a37e3f 100644 --- a/include/crypto/init.h +++ b/include/crypto/init.h @@ -22,7 +22,6 @@ #define QCRYPTO_INIT_H__ #include "qemu-common.h" -#include "qapi/error.h" int qcrypto_init(Error **errp); diff --git a/include/crypto/secret.h b/include/crypto/secret.h index 913519ae27..60f2a502b7 100644 --- a/include/crypto/secret.h +++ b/include/crypto/secret.h @@ -22,7 +22,6 @@ #define QCRYPTO_SECRET_H__ #include "qemu-common.h" -#include "qapi/error.h" #include "qom/object.h" #define TYPE_QCRYPTO_SECRET "secret" diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h index 21761b7ce1..4bf1d2e255 100644 --- a/include/crypto/tlscreds.h +++ b/include/crypto/tlscreds.h @@ -22,7 +22,6 @@ #define QCRYPTO_TLSCRED_H__ #include "qemu-common.h" -#include "qapi/error.h" #include "qom/object.h" #ifdef CONFIG_GNUTLS diff --git a/include/elf.h b/include/elf.h index 1098d217ec..28d448bbcc 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1,7 +1,6 @@ #ifndef _QEMU_ELF_H #define _QEMU_ELF_H -#include <inttypes.h> /* 32-bit ELF base types. */ typedef uint32_t Elf32_Addr; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 83b1781afc..08e5093d0e 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -154,7 +154,6 @@ static inline void tswap64s(uint64_t *s) /* MMU memory access macros */ #if defined(CONFIG_USER_ONLY) -#include <assert.h> #include "exec/user/abitypes.h" /* On some host systems the guest address space is reserved on the host. diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 85aa4033e7..a0ad2acb43 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -54,7 +54,6 @@ 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/exec/cpu-defs.h b/include/exec/cpu-defs.h index 5093be26ac..854e7e3566 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -23,9 +23,6 @@ #error cpu.h included from common code #endif -#include "config.h" -#include <inttypes.h> -#include "qemu/osdep.h" #include "qemu/queue.h" #include "tcg-target.h" #ifndef CONFIG_USER_ONLY diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h index b009ccb11a..ec790432d5 100644 --- a/include/exec/helper-head.h +++ b/include/exec/helper-head.h @@ -18,7 +18,6 @@ #ifndef DEF_HELPER_H #define DEF_HELPER_H 1 -#include "qemu/osdep.h" #define HELPER(name) glue(helper_, name) diff --git a/include/exec/memory.h b/include/exec/memory.h index 032400aefa..d5284c2435 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -21,8 +21,6 @@ #define DIRTY_MEMORY_MIGRATION 2 #define DIRTY_MEMORY_NUM 3 /* num of dirty bits */ -#include <stdint.h> -#include <stdbool.h> #include "exec/cpu-common.h" #ifndef CONFIG_USER_ONLY #include "exec/hwaddr.h" @@ -31,7 +29,6 @@ #include "qemu/queue.h" #include "qemu/int128.h" #include "qemu/notify.h" -#include "qapi/error.h" #include "qom/object.h" #include "qemu/rcu.h" #include "qemu/typedefs.h" diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h index 3b67462726..ad1d60266e 100644 --- a/include/exec/user/thunk.h +++ b/include/exec/user/thunk.h @@ -19,7 +19,6 @@ #ifndef THUNK_H #define THUNK_H -#include <inttypes.h> #include "cpu.h" /* types enums definitions */ diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 575a7398cf..c937062530 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -86,9 +86,6 @@ this code that are retained. #include <sunmath.h> #endif -#include <inttypes.h> -#include "config-host.h" -#include "qemu/osdep.h" /* This 'flag' type must be able to hold at least 0 and 1. It should * probably be replaced with 'bool' but the uses would need to be audited @@ -362,10 +359,10 @@ extern const float16 float16_default_nan; /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ -int_fast16_t float32_to_int16(float32, float_status *status); -uint_fast16_t float32_to_uint16(float32, float_status *status); -int_fast16_t float32_to_int16_round_to_zero(float32, float_status *status); -uint_fast16_t float32_to_uint16_round_to_zero(float32, float_status *status); +int16_t float32_to_int16(float32, float_status *status); +uint16_t float32_to_uint16(float32, float_status *status); +int16_t float32_to_int16_round_to_zero(float32, float_status *status); +uint16_t float32_to_uint16_round_to_zero(float32, float_status *status); int32_t float32_to_int32(float32, float_status *status); int32_t float32_to_int32_round_to_zero(float32, float_status *status); uint32_t float32_to_uint32(float32, float_status *status); @@ -474,10 +471,10 @@ extern const float32 float32_default_nan; /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ -int_fast16_t float64_to_int16(float64, float_status *status); -uint_fast16_t float64_to_uint16(float64, float_status *status); -int_fast16_t float64_to_int16_round_to_zero(float64, float_status *status); -uint_fast16_t float64_to_uint16_round_to_zero(float64, float_status *status); +int16_t float64_to_int16(float64, float_status *status); +uint16_t float64_to_uint16(float64, float_status *status); +int16_t float64_to_int16_round_to_zero(float64, float_status *status); +uint16_t float64_to_uint16_round_to_zero(float64, float_status *status); int32_t float64_to_int32(float64, float_status *status); int32_t float64_to_int32_round_to_zero(float64, float_status *status); uint32_t float64_to_uint32(float64, float_status *status); diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index 2de30211f2..7462e20fe3 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -19,7 +19,6 @@ * <http://www.gnu.org/licenses/>. */ -#include "qapi/error.h" #include "qemu/typedefs.h" #include "qemu/notify.h" #include "qemu/option.h" diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index aa29d30d1f..d3e0c8fe87 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -1,9 +1,7 @@ #ifndef HW_ACPI_GEN_UTILS_H #define HW_ACPI_GEN_UTILS_H -#include <stdint.h> #include <glib.h> -#include "qemu/compiler.h" #include "hw/acpi/acpi-defs.h" /* Reserve RAM space for tables: add another order of magnitude. */ diff --git a/include/hw/acpi/bios-linker-loader.h b/include/hw/acpi/bios-linker-loader.h index 498c0af773..82f1af6433 100644 --- a/include/hw/acpi/bios-linker-loader.h +++ b/include/hw/acpi/bios-linker-loader.h @@ -2,8 +2,6 @@ #define BIOS_LINKER_LOADER_H #include <glib.h> -#include <stdbool.h> -#include <inttypes.h> GArray *bios_linker_loader_init(void); @@ -13,7 +11,7 @@ void bios_linker_loader_alloc(GArray *linker, bool alloc_fseg); void bios_linker_loader_add_checksum(GArray *linker, const char *file, - void *table, + GArray *table, void *start, unsigned size, uint8_t *checksum); diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 345fd8d92b..63fa198145 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -62,7 +62,6 @@ typedef struct ICH9LPCPMRegs { void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool smm_enabled, - bool enable_tco, qemu_irq sci_irq); void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base); diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h index f3526d4aaf..31b7820b6f 100644 --- a/include/hw/acpi/pcihp.h +++ b/include/hw/acpi/pcihp.h @@ -27,7 +27,6 @@ #ifndef HW_ACPI_PCIHP_H #define HW_ACPI_PCIHP_H -#include <inttypes.h> #include <qemu/typedefs.h> #include "hw/acpi/acpi.h" #include "migration/vmstate.h" diff --git a/include/hw/block/block.h b/include/hw/block/block.h index 8d7c4b413f..984660efd6 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -12,7 +12,6 @@ #define HW_BLOCK_COMMON_H #include "qemu-common.h" -#include "qapi/error.h" /* Configuration */ diff --git a/include/hw/boards.h b/include/hw/boards.h index 0f30959e2e..de3b3bdafd 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -84,7 +84,6 @@ struct MachineClass { no_cdrom:1, no_sdcard:1, has_dynamic_sysbus:1, - no_tco:1, pci_allow_0_address:1; int is_default; const char *default_machine_opts; diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h index b9d2b04b6e..b411434984 100644 --- a/include/hw/i386/ich9.h +++ b/include/hw/i386/ich9.h @@ -17,7 +17,7 @@ void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin); -void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled, bool enable_tco); +void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled); I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base); void ich9_generate_smi(void); diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h index 148cc1bbc8..fc95572394 100644 --- a/include/hw/i386/topology.h +++ b/include/hw/i386/topology.h @@ -38,8 +38,6 @@ * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). */ -#include <stdint.h> -#include <string.h> #include "qemu/bitops.h" diff --git a/include/hw/isa/apm.h b/include/hw/isa/apm.h index 3edea5f623..4839ff1df2 100644 --- a/include/hw/isa/apm.h +++ b/include/hw/isa/apm.h @@ -1,7 +1,6 @@ #ifndef APM_H #define APM_H -#include <stdint.h> #include "qemu-common.h" #include "hw/hw.h" #include "exec/memory.h" diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 664eaf6452..5d19975df5 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -2,8 +2,6 @@ #define FW_CFG_H #ifndef NO_QEMU_PROTOS -#include <stdint.h> -#include <stddef.h> #include "exec/hwaddr.h" #include "qemu/typedefs.h" diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index dedf277627..0be07c8352 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -6,7 +6,6 @@ #include "hw/qdev.h" #include "exec/memory.h" #include "sysemu/dma.h" -#include "qapi/error.h" /* PCI includes legacy ISA access. */ #include "hw/isa/isa.h" diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 93b621cef3..ed4aff6cd2 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -48,7 +48,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev); void pci_bridge_reset_reg(PCIDevice *dev); void pci_bridge_reset(DeviceState *qdev); -int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename); +void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename); void pci_bridge_exitfn(PCIDevice *pci_dev); diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h index 2fb83882be..c2ee4e2bdb 100644 --- a/include/hw/pci/pcie_aer.h +++ b/include/hw/pci/pcie_aer.h @@ -87,7 +87,7 @@ struct PCIEAERErr { extern const VMStateDescription vmstate_pcie_aer_log; -int pcie_aer_init(PCIDevice *dev, uint16_t offset); +int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size); void pcie_aer_exit(PCIDevice *dev); void pcie_aer_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); @@ -102,5 +102,6 @@ void pcie_aer_root_write_config(PCIDevice *dev, /* error injection */ int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); +void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg); #endif /* QEMU_PCIE_AER_H */ diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h index 2c871b947b..b2085543d7 100644 --- a/include/hw/pci/shpc.h +++ b/include/hw/pci/shpc.h @@ -4,7 +4,6 @@ #include "qemu-common.h" #include "exec/memory.h" #include "migration/vmstate.h" -#include "qapi/error.h" #include "hw/hotplug.h" #include "hw/pci/pci.h" diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index abcdee852b..c3ff99f975 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -7,7 +7,6 @@ #include "qemu/bitmap.h" #include "qom/object.h" #include "hw/irq.h" -#include "qapi/error.h" #include "hw/hotplug.h" enum { diff --git a/include/hw/vfio/vfio-amd-xgbe.h b/include/hw/vfio/vfio-amd-xgbe.h new file mode 100644 index 0000000000..9fff65e99d --- /dev/null +++ b/include/hw/vfio/vfio-amd-xgbe.h @@ -0,0 +1,51 @@ +/* + * VFIO AMD XGBE device + * + * Copyright Linaro Limited, 2015 + * + * Authors: + * Eric Auger <eric.auger@linaro.org> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef HW_VFIO_VFIO_AMD_XGBE_H +#define HW_VFIO_VFIO_AMD_XGBE_H + +#include "hw/vfio/vfio-platform.h" + +#define TYPE_VFIO_AMD_XGBE "vfio-amd-xgbe" + +/** + * This device exposes: + * - 5 MMIO regions: MAC, PCS, SerDes Rx/Tx regs, + SerDes Integration Registers 1/2 & 2/2 + * - 2 level sensitive IRQs and optional DMA channel IRQs + */ +struct VFIOAmdXgbeDevice { + VFIOPlatformDevice vdev; +}; + +typedef struct VFIOAmdXgbeDevice VFIOAmdXgbeDevice; + +struct VFIOAmdXgbeDeviceClass { + /*< private >*/ + VFIOPlatformDeviceClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; +}; + +typedef struct VFIOAmdXgbeDeviceClass VFIOAmdXgbeDeviceClass; + +#define VFIO_AMD_XGBE_DEVICE(obj) \ + OBJECT_CHECK(VFIOAmdXgbeDevice, (obj), TYPE_VFIO_AMD_XGBE) +#define VFIO_AMD_XGBE_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VFIOAmdXgbeDeviceClass, (klass), \ + TYPE_VFIO_AMD_XGBE) +#define VFIO_AMD_XGBE_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VFIOAmdXgbeDeviceClass, (obj), \ + TYPE_VFIO_AMD_XGBE) + +#endif diff --git a/include/hw/virtio/dataplane/vring-accessors.h b/include/hw/virtio/dataplane/vring-accessors.h deleted file mode 100644 index 815c19b6ef..0000000000 --- a/include/hw/virtio/dataplane/vring-accessors.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef VRING_ACCESSORS_H -#define VRING_ACCESSORS_H - -#include "standard-headers/linux/virtio_ring.h" -#include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-access.h" - -static inline uint16_t vring_get_used_idx(VirtIODevice *vdev, Vring *vring) -{ - return virtio_tswap16(vdev, vring->vr.used->idx); -} - -static inline void vring_set_used_idx(VirtIODevice *vdev, Vring *vring, - uint16_t idx) -{ - vring->vr.used->idx = virtio_tswap16(vdev, idx); -} - -static inline uint16_t vring_get_avail_idx(VirtIODevice *vdev, Vring *vring) -{ - return virtio_tswap16(vdev, vring->vr.avail->idx); -} - -static inline uint16_t vring_get_avail_ring(VirtIODevice *vdev, Vring *vring, - int i) -{ - return virtio_tswap16(vdev, vring->vr.avail->ring[i]); -} - -static inline void vring_set_used_ring_id(VirtIODevice *vdev, Vring *vring, - int i, uint32_t id) -{ - vring->vr.used->ring[i].id = virtio_tswap32(vdev, id); -} - -static inline void vring_set_used_ring_len(VirtIODevice *vdev, Vring *vring, - int i, uint32_t len) -{ - vring->vr.used->ring[i].len = virtio_tswap32(vdev, len); -} - -static inline uint16_t vring_get_used_flags(VirtIODevice *vdev, Vring *vring) -{ - return virtio_tswap16(vdev, vring->vr.used->flags); -} - -static inline uint16_t vring_get_avail_flags(VirtIODevice *vdev, Vring *vring) -{ - return virtio_tswap16(vdev, vring->vr.avail->flags); -} - -static inline void vring_set_used_flags(VirtIODevice *vdev, Vring *vring, - uint16_t flags) -{ - vring->vr.used->flags |= virtio_tswap16(vdev, flags); -} - -static inline void vring_clear_used_flags(VirtIODevice *vdev, Vring *vring, - uint16_t flags) -{ - vring->vr.used->flags &= virtio_tswap16(vdev, ~flags); -} - -static inline unsigned int vring_get_num(Vring *vring) -{ - return vring->vr.num; -} - -/* Are there more descriptors available? */ -static inline bool vring_more_avail(VirtIODevice *vdev, Vring *vring) -{ - return vring_get_avail_idx(vdev, vring) != vring->last_avail_idx; -} - -#endif diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h deleted file mode 100644 index e80985ee4c..0000000000 --- a/include/hw/virtio/dataplane/vring.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2012 Red Hat, Inc. and/or its affiliates - * Copyright IBM, Corp. 2012 - * - * Based on Linux 2.6.39 vhost code: - * Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2006 Rusty Russell IBM Corporation - * - * Author: Michael S. Tsirkin <mst@redhat.com> - * Stefan Hajnoczi <stefanha@redhat.com> - * - * Inspiration, some code, and most witty comments come from - * Documentation/virtual/lguest/lguest.c, by Rusty Russell - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#ifndef VRING_H -#define VRING_H - -#include "qemu-common.h" -#include "standard-headers/linux/virtio_ring.h" -#include "hw/virtio/virtio.h" - -typedef struct { - MemoryRegion *mr_desc; /* memory region for the vring desc */ - MemoryRegion *mr_avail; /* memory region for the vring avail */ - MemoryRegion *mr_used; /* memory region for the vring used */ - struct vring vr; /* virtqueue vring mapped to host memory */ - uint16_t last_avail_idx; /* last processed avail ring index */ - uint16_t last_used_idx; /* last processed used ring index */ - uint16_t signalled_used; /* EVENT_IDX state */ - bool signalled_used_valid; - bool broken; /* was there a fatal error? */ -} Vring; - -/* Fail future vring_pop() and vring_push() calls until reset */ -static inline void vring_set_broken(Vring *vring) -{ - vring->broken = true; -} - -bool vring_setup(Vring *vring, VirtIODevice *vdev, int n); -void vring_teardown(Vring *vring, VirtIODevice *vdev, int n); -void vring_disable_notification(VirtIODevice *vdev, Vring *vring); -bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); -bool vring_should_notify(VirtIODevice *vdev, Vring *vring); -void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz); -void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, - int len); - -#endif /* VRING_H */ diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index c59cc81915..95fcc96676 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -11,7 +11,6 @@ #ifndef VHOST_BACKEND_H_ #define VHOST_BACKEND_H_ -#include <stdbool.h> typedef enum VhostBackendType { VHOST_BACKEND_TYPE_NONE = 0, @@ -70,6 +69,9 @@ typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev, typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev); typedef int (*vhost_migration_done_op)(struct vhost_dev *dev, char *mac_addr); +typedef bool (*vhost_backend_can_merge_op)(struct vhost_dev *dev, + uint64_t start1, uint64_t size1, + uint64_t start2, uint64_t size2); typedef struct VhostOps { VhostBackendType backend_type; @@ -97,6 +99,7 @@ typedef struct VhostOps { vhost_set_vring_enable_op vhost_set_vring_enable; vhost_requires_shm_log_op vhost_requires_shm_log; vhost_migration_done_op vhost_migration_done; + vhost_backend_can_merge_op vhost_backend_can_merge; } VhostOps; extern const VhostOps user_ops; diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 8aec843c8f..8dc84f5203 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -19,32 +19,19 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) { +#if defined(TARGET_IS_BIENDIAN) + return virtio_is_big_endian(vdev); +#elif defined(TARGET_WORDS_BIGENDIAN) if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { /* Devices conforming to VIRTIO 1.0 or later are always LE. */ return false; } -#if defined(TARGET_IS_BIENDIAN) - return virtio_is_big_endian(vdev); -#elif defined(TARGET_WORDS_BIGENDIAN) return true; #else return false; #endif } -static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev) -{ -#ifdef TARGET_IS_BIENDIAN -#ifdef HOST_WORDS_BIGENDIAN - return !virtio_is_big_endian(vdev); -#else - return virtio_is_big_endian(vdev); -#endif -#else - return false; -#endif -} - static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa) { if (virtio_access_is_big_endian(vdev)) { @@ -143,15 +130,6 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr) } } -static inline bool virtio_needs_swap(VirtIODevice *vdev) -{ -#ifdef HOST_WORDS_BIGENDIAN - return virtio_access_is_big_endian(vdev) ? false : true; -#else - return virtio_access_is_big_endian(vdev) ? true : false; -#endif -} - static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s) { #ifdef HOST_WORDS_BIGENDIAN diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 199bb0ebd5..ae84d92107 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -53,9 +53,7 @@ typedef struct VirtIOBlock { unsigned short sector_mask; bool original_wce; VMChangeStateEntry *change; - /* Function to push to vq and notify guest */ - void (*complete_request)(struct VirtIOBlockReq *req, unsigned char status); - Notifier migration_state_notifier; + bool dataplane_started; struct VirtIOBlockDataPlane *dataplane; } VirtIOBlock; diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 2ce3b03bd4..0cabdb6822 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -94,6 +94,7 @@ typedef struct VirtIONet { uint64_t curr_guest_offloads; QEMUTimer *announce_timer; int announce_counter; + bool needs_vnet_hdr_swap; } VirtIONet; void virtio_net_set_netclient_name(VirtIONet *n, const char *name, diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index a8029aa017..209eaa4466 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -22,7 +22,6 @@ #include "hw/pci/pci.h" #include "hw/scsi/scsi.h" #include "sysemu/iothread.h" -#include "hw/virtio/dataplane/vring.h" #define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common" #define VIRTIO_SCSI_COMMON(obj) \ @@ -58,13 +57,6 @@ struct VirtIOSCSIConf { struct VirtIOSCSI; -typedef struct { - struct VirtIOSCSI *parent; - Vring vring; - EventNotifier host_notifier; - EventNotifier guest_notifier; -} VirtIOSCSIVring; - typedef struct VirtIOSCSICommon { VirtIODevice parent_obj; VirtIOSCSIConf conf; @@ -96,18 +88,12 @@ typedef struct VirtIOSCSI { QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) insert_notifiers; QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) remove_notifiers; - /* Vring is used instead of vq in dataplane code, because of the underlying - * memory layer thread safety */ - VirtIOSCSIVring *ctrl_vring; - VirtIOSCSIVring *event_vring; - VirtIOSCSIVring **cmd_vrings; bool dataplane_started; bool dataplane_starting; bool dataplane_stopping; bool dataplane_disabled; bool dataplane_fenced; Error *blocker; - Notifier migration_state_notifier; uint32_t host_features; } VirtIOSCSI; @@ -123,9 +109,6 @@ typedef struct VirtIOSCSIReq { QEMUSGList qsgl; QEMUIOVector resp_iov; - /* Set by dataplane code. */ - VirtIOSCSIVring *vring; - union { /* Used for two-stage request submission */ QTAILQ_ENTRY(VirtIOSCSIReq) next; @@ -168,8 +151,6 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread); void virtio_scsi_dataplane_start(VirtIOSCSI *s); void virtio_scsi_dataplane_stop(VirtIOSCSI *s); -void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req); -VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, - VirtIOSCSIVring *vring); +void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 108cdb0f48..2b5b248b0c 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -90,6 +90,7 @@ struct VirtIODevice VMChangeStateEntry *vmstate; char *bus_name; uint8_t device_endian; + bool use_guest_notifier_mask; QLIST_HEAD(, VirtQueue) *vector_queues; }; @@ -162,6 +163,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, unsigned int *out_bytes, unsigned max_in_bytes, unsigned max_out_bytes); +bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_save(VirtIODevice *vdev, QEMUFile *f); @@ -248,6 +250,8 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler); +void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, + bool assign, bool set_handler); void virtio_queue_notify_vq(VirtQueue *vq); void virtio_irq(VirtQueue *vq); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index df334818c1..bf3fe97927 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -6,7 +6,6 @@ * must not depend on any xen headers being present in * /usr/include/xen, so it can be included unconditionally. */ -#include <inttypes.h> #include "hw/irq.h" #include "qemu-common.h" diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 7a3cce0b8c..bd65e67054 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -1,10 +1,7 @@ #ifndef QEMU_HW_XEN_COMMON_H #define QEMU_HW_XEN_COMMON_H 1 -#include "config-host.h" -#include <stddef.h> -#include <inttypes.h> /* * If we have new enough libxenctrl then we do not want/need these compat diff --git a/include/io/channel.h b/include/io/channel.h index 3e17fe7129..0a1f1ce7fc 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -22,7 +22,6 @@ #define QIO_CHANNEL_H__ #include "qemu-common.h" -#include "qapi/error.h" #include "qom/object.h" #define TYPE_QIO_CHANNEL "qio-channel" diff --git a/include/io/task.h b/include/io/task.h index 2418714156..2e69d8a47f 100644 --- a/include/io/task.h +++ b/include/io/task.h @@ -22,7 +22,6 @@ #define QIO_TASK_H__ #include "qemu-common.h" -#include "qapi/error.h" #include "qom/object.h" typedef struct QIOTask QIOTask; diff --git a/include/libdecnumber/dconfig.h b/include/libdecnumber/dconfig.h index 2f0455a06a..0f7dccef1f 100644 --- a/include/libdecnumber/dconfig.h +++ b/include/libdecnumber/dconfig.h @@ -27,7 +27,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "config-host.h" #if defined(HOST_WORDS_BIGENDIAN) #define WORDS_BIGENDIAN 1 diff --git a/include/libdecnumber/decContext.h b/include/libdecnumber/decContext.h index c3e46f405f..01365e2313 100644 --- a/include/libdecnumber/decContext.h +++ b/include/libdecnumber/decContext.h @@ -56,9 +56,6 @@ #define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */ #define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */ - #include <stdint.h> - #include <stdio.h> /* for printf, etc. */ - #include <signal.h> /* for traps */ /* Extended flags setting -- set this to 0 to use only IEEE flags */ #define DECEXTFLAG 1 /* 1=enable extended flags */ diff --git a/include/libdecnumber/decNumberLocal.h b/include/libdecnumber/decNumberLocal.h index 71ed77bf21..94fb512923 100644 --- a/include/libdecnumber/decNumberLocal.h +++ b/include/libdecnumber/decNumberLocal.h @@ -42,8 +42,6 @@ #define DECVERSION "decNumber 3.53" /* Package Version [16 max.] */ #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ - #include <stdlib.h> /* for abs */ - #include <string.h> /* for memset, strcpy */ #include "libdecnumber/dconfig.h" /* Conditional code flag -- set this to match hardware platform */ diff --git a/include/migration/migration.h b/include/migration/migration.h index 74684ad929..85b6026d10 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -18,7 +18,6 @@ #include "qemu-common.h" #include "qemu/thread.h" #include "qemu/notify.h" -#include "qapi/error.h" #include "migration/vmstate.h" #include "qapi-types.h" #include "exec/cpu-common.h" @@ -159,6 +158,8 @@ struct MigrationState /* Flag set once the migration has been asked to enter postcopy */ bool start_postcopy; + /* Flag set after postcopy has sent the device state */ + bool postcopy_after_devices; /* Flag set once the migration thread is running (and needs joining) */ bool migration_thread_running; @@ -212,6 +213,8 @@ bool migration_has_finished(MigrationState *); bool migration_has_failed(MigrationState *); /* True if outgoing migration has entered postcopy phase */ bool migration_in_postcopy(MigrationState *); +/* ...and after the device transmission */ +bool migration_in_postcopy_after_devices(MigrationState *); MigrationState *migrate_get_current(void); void migrate_compress_threads_create(void); diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index b5d08d217d..3f6b4ed581 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -25,7 +25,6 @@ #define QEMU_FILE_H 1 #include "exec/cpu-common.h" -#include <stdint.h> /* This function writes a chunk of data to a file at the given position. * The pos argument can be ignored if the file is only being used for diff --git a/include/net/checksum.h b/include/net/checksum.h index 2d7a363d40..7de1acb79a 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -18,7 +18,6 @@ #ifndef QEMU_NET_CHECKSUM_H #define QEMU_NET_CHECKSUM_H -#include <stdint.h> struct iovec; uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq); diff --git a/include/net/eth.h b/include/net/eth.h index 84384febf2..18d0be3b16 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -26,8 +26,6 @@ #ifndef QEMU_ETH_H #define QEMU_ETH_H -#include <sys/types.h> -#include <string.h> #include "qemu/bswap.h" #include "qemu/iov.h" diff --git a/include/qapi/error.h b/include/qapi/error.h index e64fe54cf9..02e9dd20a7 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -115,9 +115,6 @@ #ifndef ERROR_H #define ERROR_H -#include <stdarg.h> -#include <stdbool.h> -#include "qemu/compiler.h" #include "qapi-types.h" /* diff --git a/include/qapi/qmp-event.h b/include/qapi/qmp-event.h index 8a8ffb5718..40fe3cbc12 100644 --- a/include/qapi/qmp-event.h +++ b/include/qapi/qmp-event.h @@ -14,7 +14,6 @@ #ifndef QMP_EVENT_H #define QMP_EVENT_H -#include "qapi/error.h" #include "qapi/qmp/qdict.h" typedef void (*QMPEventFuncEmit)(unsigned event, QDict *dict, Error **errp); diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index e389697f19..495520994c 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -16,7 +16,6 @@ #include "qapi/qmp/qobject.h" #include "qapi/qmp/qdict.h" -#include "qapi/error.h" typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h index cb456d53e5..afee7828cd 100644 --- a/include/qapi/qmp/json-lexer.h +++ b/include/qapi/qmp/json-lexer.h @@ -14,7 +14,6 @@ #ifndef QEMU_JSON_LEXER_H #define QEMU_JSON_LEXER_H -#include "glib-compat.h" typedef enum json_token_type { JSON_MIN = 100, diff --git a/include/qapi/qmp/json-parser.h b/include/qapi/qmp/json-parser.h index fea89f873a..9987f8ca85 100644 --- a/include/qapi/qmp/json-parser.h +++ b/include/qapi/qmp/json-parser.h @@ -16,7 +16,6 @@ #include "qemu-common.h" #include "qapi/qmp/qlist.h" -#include "qapi/error.h" QObject *json_parser_parse(GQueue *tokens, va_list *ap); QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp); diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h index 09b3d3ec15..00d8a23af8 100644 --- a/include/qapi/qmp/json-streamer.h +++ b/include/qapi/qmp/json-streamer.h @@ -14,8 +14,6 @@ #ifndef QEMU_JSON_STREAMER_H #define QEMU_JSON_STREAMER_H -#include <stdint.h> -#include "glib-compat.h" #include "qapi/qmp/json-lexer.h" typedef struct JSONToken { diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h index 836d078866..a41111c309 100644 --- a/include/qapi/qmp/qbool.h +++ b/include/qapi/qmp/qbool.h @@ -14,7 +14,6 @@ #ifndef QBOOL_H #define QBOOL_H -#include <stdbool.h> #include "qapi/qmp/qobject.h" typedef struct QBool { diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 6c2a0e501e..71b8eb0416 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -16,8 +16,6 @@ #include "qapi/qmp/qobject.h" #include "qapi/qmp/qlist.h" #include "qemu/queue.h" -#include <stdbool.h> -#include <stdint.h> #define QDICT_BUCKET_MAX 512 diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h index a8af2a89b2..b5d15836b5 100644 --- a/include/qapi/qmp/qfloat.h +++ b/include/qapi/qmp/qfloat.h @@ -14,7 +14,6 @@ #ifndef QFLOAT_H #define QFLOAT_H -#include <stdint.h> #include "qapi/qmp/qobject.h" typedef struct QFloat { diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h index 049e528079..3aaff768dd 100644 --- a/include/qapi/qmp/qint.h +++ b/include/qapi/qmp/qint.h @@ -13,7 +13,6 @@ #ifndef QINT_H #define QINT_H -#include <stdint.h> #include "qapi/qmp/qobject.h" typedef struct QInt { diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h index ee4d31a46a..02b1f2ce31 100644 --- a/include/qapi/qmp/qjson.h +++ b/include/qapi/qmp/qjson.h @@ -14,8 +14,6 @@ #ifndef QJSON_H #define QJSON_H -#include <stdarg.h> -#include "qemu/compiler.h" #include "qapi/qmp/qobject.h" #include "qapi/qmp/qstring.h" diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 74459ae14b..b8ddbca405 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -32,8 +32,6 @@ #ifndef QOBJECT_H #define QOBJECT_H -#include <stddef.h> -#include <assert.h> #include "qapi-types.h" struct QObject { diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index df7df558b2..10076b7c8c 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -13,7 +13,6 @@ #ifndef QSTRING_H #define QSTRING_H -#include <stdint.h> #include "qapi/qmp/qobject.h" typedef struct QString { diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index ea252f8e3a..2bd8f292b2 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -12,7 +12,6 @@ #ifndef QAPI_VISITOR_IMPL_H #define QAPI_VISITOR_IMPL_H -#include "qapi/error.h" #include "qapi/visitor.h" struct Visitor @@ -22,22 +21,23 @@ struct Visitor size_t size, Error **errp); void (*end_struct)(Visitor *v, Error **errp); - void (*start_implicit_struct)(Visitor *v, void **obj, size_t size, - Error **errp); - /* May be NULL */ - void (*end_implicit_struct)(Visitor *v); - void (*start_list)(Visitor *v, const char *name, Error **errp); /* Must be set */ - GenericList *(*next_list)(Visitor *v, GenericList **list); + GenericList *(*next_list)(Visitor *v, GenericList **list, size_t size); /* Must be set */ void (*end_list)(Visitor *v); + /* Optional, needed for input and dealloc visitors. */ + void (*start_alternate)(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp); + + /* Optional, needed for dealloc visitor. */ + void (*end_alternate)(Visitor *v); + + /* Must be set. */ void (*type_enum)(Visitor *v, const char *name, int *obj, const char *const strings[], Error **errp); - /* May be NULL; only needed for input visitors. */ - void (*get_next_type)(Visitor *v, const char *name, QType *type, - bool promote_int, Error **errp); /* Must be set. */ void (*type_int64)(Visitor *v, const char *name, int64_t *obj, @@ -58,8 +58,6 @@ struct Visitor /* May be NULL; most useful for input visitors. */ void (*optional)(Visitor *v, const char *name, bool *present); - - bool (*start_union)(Visitor *v, bool data_present, Error **errp); }; void input_type_enum(Visitor *v, const char *name, int *obj, diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 5e581dcf7e..1000da2bda 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -16,29 +16,61 @@ #include "qemu/typedefs.h" #include "qapi/qmp/qobject.h" -#include "qapi/error.h" -#include <stdlib.h> -typedef struct GenericList -{ - union { - void *value; - uint64_t padding; - }; +/* This struct is layout-compatible with all other *List structs + * created by the qapi generator. It is used as a typical + * singly-linked list. */ +typedef struct GenericList { struct GenericList *next; + char padding[]; } GenericList; +/* This struct is layout-compatible with all Alternate types + * created by the qapi generator. */ +typedef struct GenericAlternate { + QType type; + char padding[]; +} GenericAlternate; + void visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp); void visit_end_struct(Visitor *v, Error **errp); -void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, - Error **errp); -void visit_end_implicit_struct(Visitor *v); void visit_start_list(Visitor *v, const char *name, Error **errp); -GenericList *visit_next_list(Visitor *v, GenericList **list); +GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size); void visit_end_list(Visitor *v); +/* + * Start the visit of an alternate @obj with the given @size. + * + * @name specifies the relationship to the containing struct (ignored + * for a top level visit, the name of the key if this alternate is + * part of an object, or NULL if this alternate is part of a list). + * + * @obj must not be NULL. Input visitors will allocate @obj and + * determine the qtype of the next thing to be visited, stored in + * (*@obj)->type. Other visitors will leave @obj unchanged. + * + * If @promote_int, treat integers as QTYPE_FLOAT. + * + * If successful, this must be paired with visit_end_alternate(), even + * if visiting the contents of the alternate fails. + */ +void visit_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp); + +/* + * Finish visiting an alternate type. + * + * Must be called after a successful visit_start_alternate(), even if + * an error occurred in the meantime. + * + * TODO: Should all the visit_end_* interfaces take obj parameter, so + * that dealloc visitor need not track what was passed in visit_start? + */ +void visit_end_alternate(Visitor *v); + /** * Check if an optional member @name of an object needs visiting. * For input visitors, set *@present according to whether the @@ -47,14 +79,6 @@ void visit_end_list(Visitor *v); */ bool visit_optional(Visitor *v, const char *name, bool *present); -/** - * Determine the qtype of the item @name in the current object visit. - * For input visitors, set *@type to the correct qtype of a qapi - * alternate type; for other visitors, leave *@type unchanged. - * If @promote_int, treat integers as QTYPE_FLOAT. - */ -void visit_get_next_type(Visitor *v, const char *name, QType *type, - bool promote_int, Error **errp); void visit_type_enum(Visitor *v, const char *name, int *obj, const char *const strings[], Error **errp); void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp); @@ -80,6 +104,5 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp); void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp); void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp); -bool visit_start_union(Visitor *v, bool data_present, Error **errp); #endif diff --git a/include/qemu-common.h b/include/qemu-common.h index 59ab7598d8..ced2994402 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -12,7 +12,6 @@ #ifndef QEMU_COMMON_H #define QEMU_COMMON_H -#include "qemu/osdep.h" #include "qemu/typedefs.h" #include "qemu/fprintf-fn.h" diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 05b447c728..8f1d8d927d 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -15,7 +15,6 @@ #ifndef __QEMU_ATOMIC_H #define __QEMU_ATOMIC_H 1 -#include "qemu/compiler.h" /* Compiler barrier */ diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 86dd9cd5fc..0e33fa5d9d 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -13,10 +13,7 @@ #define BITMAP_H #include <glib.h> -#include <string.h> -#include <stdlib.h> -#include "qemu/osdep.h" #include "qemu/bitops.h" /* diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 8164225152..755fdd1293 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -12,8 +12,6 @@ #ifndef BITOPS_H #define BITOPS_H -#include <stdint.h> -#include <assert.h> #include "host-utils.h" #include "atomic.h" diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 07d88de746..95071ba9e8 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,15 +1,10 @@ #ifndef BSWAP_H #define BSWAP_H -#include "config-host.h" -#include <inttypes.h> -#include <limits.h> -#include <string.h> #include "fpu/softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H # include <sys/endian.h> -# include <sys/types.h> # include <machine/bswap.h> #elif defined(__FreeBSD__) # include <sys/endian.h> diff --git a/include/qemu/compatfd.h b/include/qemu/compatfd.h index fc3791520f..aa12ee9364 100644 --- a/include/qemu/compatfd.h +++ b/include/qemu/compatfd.h @@ -14,7 +14,6 @@ #ifndef QEMU_COMPATFD_H #define QEMU_COMPATFD_H -#include <signal.h> struct qemu_signalfd_siginfo { uint32_t ssi_signo; /* Signal number */ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index c5fbe28b02..8f1cc7ba67 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -3,7 +3,6 @@ #ifndef COMPILER_H #define COMPILER_H -#include "config-host.h" /*---------------------------------------------------------------------------- | The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler. diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h index d4ba20e049..3b8ecb0953 100644 --- a/include/qemu/config-file.h +++ b/include/qemu/config-file.h @@ -1,9 +1,7 @@ #ifndef QEMU_CONFIG_H #define QEMU_CONFIG_H -#include <stdio.h> #include "qemu/option.h" -#include "qapi/error.h" #include "qapi/qmp/qdict.h" QemuOptsList *qemu_find_opts(const char *group); diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 20c027a7fd..99b939846b 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -15,7 +15,6 @@ #ifndef QEMU_COROUTINE_H #define QEMU_COROUTINE_H -#include <stdbool.h> #include "qemu/typedefs.h" #include "qemu/queue.h" #include "qemu/timer.h" diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index 7ab235590e..7a2a363fb3 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -13,9 +13,6 @@ #ifndef QEMU_ERROR_H #define QEMU_ERROR_H -#include <stdarg.h> -#include <stdbool.h> -#include "qemu/compiler.h" typedef struct Location { /* all members are private to qemu-error.c */ diff --git a/include/qemu/fprintf-fn.h b/include/qemu/fprintf-fn.h index 9ddc90f1c5..b6bad35b1b 100644 --- a/include/qemu/fprintf-fn.h +++ b/include/qemu/fprintf-fn.h @@ -8,8 +8,6 @@ #ifndef QEMU_FPRINTF_FN_H #define QEMU_FPRINTF_FN_H 1 -#include "qemu/compiler.h" -#include <stdio.h> typedef int (*fprintf_function)(FILE *f, const char *fmt, ...) GCC_FMT_ATTR(2, 3); diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index bb94a00c5f..e29188c0ad 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -12,9 +12,6 @@ #ifndef HBITMAP_H #define HBITMAP_H 1 -#include <limits.h> -#include <stdint.h> -#include <stdbool.h> #include "bitops.h" #include "host-utils.h" diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 3ef97d503d..1cdae0d0ed 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -25,10 +25,7 @@ #ifndef HOST_UTILS_H #define HOST_UTILS_H 1 -#include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */ #include "qemu/bswap.h" -#include <limits.h> -#include <stdbool.h> #ifdef CONFIG_INT128 static inline void mulu64(uint64_t *plow, uint64_t *phigh, diff --git a/include/qemu/int128.h b/include/qemu/int128.h index fb782aaddd..c5988813df 100644 --- a/include/qemu/int128.h +++ b/include/qemu/int128.h @@ -1,9 +1,6 @@ #ifndef INT128_H #define INT128_H -#include <assert.h> -#include <stdint.h> -#include <stdbool.h> typedef struct Int128 Int128; diff --git a/include/qemu/log.h b/include/qemu/log.h index dda65fd3fa..40c24fda40 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -1,10 +1,6 @@ #ifndef QEMU_LOG_H #define QEMU_LOG_H -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include "qemu/compiler.h" /* Private global variables, don't use */ extern FILE *qemu_logfile; diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h index 53858ed43c..745a8c501e 100644 --- a/include/qemu/memfd.h +++ b/include/qemu/memfd.h @@ -1,8 +1,6 @@ #ifndef QEMU_MEMFD_H #define QEMU_MEMFD_H -#include "config-host.h" -#include <stdbool.h> #ifndef F_LINUX_SPECIFIC_BASE #define F_LINUX_SPECIFIC_BASE 1024 diff --git a/include/qemu/module.h b/include/qemu/module.h index 72d94984a2..85fafa2e79 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -14,7 +14,6 @@ #ifndef QEMU_MODULE_H #define QEMU_MODULE_H -#include "qemu/osdep.h" #define DSO_STAMP_FUN glue(qemu_stamp, CONFIG_STAMP) #define DSO_STAMP_FUN_STR stringify(DSO_STAMP_FUN) diff --git a/include/qemu/option.h b/include/qemu/option.h index 71f5f27ec8..8809ce1e75 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -26,9 +26,7 @@ #ifndef QEMU_OPTIONS_H #define QEMU_OPTIONS_H -#include <stdint.h> #include "qemu/queue.h" -#include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qemu/typedefs.h" diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index cc055c909e..4538fdca42 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -26,8 +26,25 @@ #define QEMU_OSDEP_H #include "config-host.h" +#ifdef NEED_CPU_H +#include "config-target.h" +#endif #include "qemu/compiler.h" +/* Older versions of C++ don't get definitions of various macros from + * stdlib.h unless we define these macros before first inclusion of + * that system header. + */ +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + /* The following block of code temporarily renames the daemon() function so the * compiler does not see the warning associated with it in stdlib.h on OSX */ @@ -84,13 +101,6 @@ extern int daemon(int, int); #include "qapi/error.h" -#if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10 -/* [u]int_fast*_t not in <sys/int_types.h> */ -typedef unsigned char uint_fast8_t; -typedef unsigned int uint_fast16_t; -typedef signed int int_fast16_t; -#endif - #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif diff --git a/include/qemu/range.h b/include/qemu/range.h index cfa021fd48..9fc547b9cb 100644 --- a/include/qemu/range.h +++ b/include/qemu/range.h @@ -1,7 +1,6 @@ #ifndef QEMU_RANGE_H #define QEMU_RANGE_H -#include <inttypes.h> #include <qemu/typedefs.h> #include "qemu/queue.h" diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index 7c7cca7f6f..56d3a682a9 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -23,15 +23,8 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ -#include <stdlib.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> #include <glib.h> -#include "qemu/compiler.h" #include "qemu/thread.h" #include "qemu/queue.h" #include "qemu/atomic.h" diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index cde2f5e0d6..0be68de87d 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -13,7 +13,6 @@ int inet_aton(const char *cp, struct in_addr *ia); #else -#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> @@ -26,7 +25,6 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif /* !_WIN32 */ -#include "qapi/error.h" #include "qapi-types.h" /* misc helpers */ diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 5114ec8e79..bdae6dfdbe 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -1,8 +1,6 @@ #ifndef __QEMU_THREAD_H #define __QEMU_THREAD_H 1 -#include <inttypes.h> -#include <stdbool.h> typedef struct QemuMutex QemuMutex; typedef struct QemuCond QemuCond; diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h index d0c98ed25b..9109657609 100644 --- a/include/qemu/throttle.h +++ b/include/qemu/throttle.h @@ -2,7 +2,7 @@ * QEMU throttling infrastructure * * Copyright (C) Nodalink, EURL. 2013-2014 - * Copyright (C) Igalia, S.L. 2015 + * Copyright (C) Igalia, S.L. 2015-2016 * * Authors: * Benoît Canet <benoit.canet@nodalink.com> @@ -25,7 +25,6 @@ #ifndef THROTTLE_H #define THROTTLE_H -#include <stdint.h> #include "qemu-common.h" #include "qemu/timer.h" @@ -42,16 +41,47 @@ typedef enum { } BucketType; /* - * The max parameter of the leaky bucket throttling algorithm can be used to - * allow the guest to do bursts. - * The max value is a pool of I/O that the guest can use without being throttled - * at all. Throttling is triggered once this pool is empty. + * This module implements I/O limits using the leaky bucket + * algorithm. The code is independent of the I/O units, but it is + * currently used for bytes per second and operations per second. + * + * Three parameters can be set by the user: + * + * - avg: the desired I/O limits in units per second. + * - max: the limit during bursts, also in units per second. + * - burst_length: the maximum length of the burst period, in seconds. + * + * Here's how it works: + * + * - The bucket level (number of performed I/O units) is kept in + * bkt.level and leaks at a rate of bkt.avg units per second. + * + * - The size of the bucket is bkt.max * bkt.burst_length. Once the + * bucket is full no more I/O is performed until the bucket leaks + * again. This is what makes the I/O rate bkt.avg. + * + * - The bkt.avg rate does not apply until the bucket is full, + * allowing the user to do bursts until then. The I/O limit during + * bursts is bkt.max. To enforce this limit we keep an additional + * bucket in bkt.burst_length that leaks at a rate of bkt.max units + * per second. + * + * - Because of all of the above, the user can perform I/O at a + * maximum of bkt.max units per second for at most bkt.burst_length + * seconds in a row. After that the bucket will be full and the I/O + * rate will go down to bkt.avg. + * + * - Since the bucket always leaks at a rate of bkt.avg, this also + * determines how much the user needs to wait before being able to + * do bursts again. */ typedef struct LeakyBucket { double avg; /* average goal in units per second */ double max; /* leaky bucket max burst in units */ double level; /* bucket level in units */ + double burst_level; /* bucket level in units (for computing bursts) */ + unsigned burst_length; /* max length of the burst period, in seconds */ } LeakyBucket; /* The following structure is used to configure a ThrottleState @@ -84,12 +114,6 @@ void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta); int64_t throttle_compute_wait(LeakyBucket *bkt); -/* expose timer computation function for unit tests */ -bool throttle_compute_timer(ThrottleState *ts, - bool is_write, - int64_t now, - int64_t *next_timestamp); - /* init/destroy cycle */ void throttle_init(ThrottleState *ts); @@ -112,11 +136,7 @@ bool throttle_timers_are_initialized(ThrottleTimers *tt); /* configuration */ bool throttle_enabled(ThrottleConfig *cfg); -bool throttle_conflicting(ThrottleConfig *cfg); - -bool throttle_is_valid(ThrottleConfig *cfg); - -bool throttle_max_is_missing_limit(ThrottleConfig *cfg); +bool throttle_is_valid(ThrottleConfig *cfg, Error **errp); void throttle_config(ThrottleState *ts, ThrottleTimers *tt, @@ -124,6 +144,8 @@ void throttle_config(ThrottleState *ts, void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg); +void throttle_config_init(ThrottleConfig *cfg); + /* usage */ bool throttle_schedule_timer(ThrottleState *ts, ThrottleTimers *tt, diff --git a/include/qemu/timed-average.h b/include/qemu/timed-average.h index 364bf88f70..08245e7a10 100644 --- a/include/qemu/timed-average.h +++ b/include/qemu/timed-average.h @@ -25,7 +25,6 @@ #ifndef TIMED_AVERAGE_H #define TIMED_AVERAGE_H -#include <stdint.h> #include "qemu/timer.h" diff --git a/include/qemu/xattr.h b/include/qemu/xattr.h index f910d96eaf..83cf98cbd8 100644 --- a/include/qemu/xattr.h +++ b/include/qemu/xattr.h @@ -18,7 +18,6 @@ * in /usr/include/sys, and don't have ENOATTR. */ -#include "config-host.h" #ifdef CONFIG_LIBATTR # include <attr/xattr.h> diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ff54600e71..1df7cb4073 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -20,7 +20,6 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H -#include <signal.h> #include <setjmp.h> #include "hw/qdev-core.h" #include "disas/bfd.h" diff --git a/include/qom/object.h b/include/qom/object.h index 33abce930b..eda16df005 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -15,11 +15,8 @@ #define QEMU_OBJECT_H #include <glib.h> -#include <stdint.h> -#include <stdbool.h> #include "qemu/queue.h" #include "qemu/typedefs.h" -#include "qapi/error.h" struct TypeImpl; typedef struct TypeImpl *Type; diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index ec303316bb..66c5cf22e1 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -14,7 +14,6 @@ #define BLOCK_BACKEND_H #include "qemu/typedefs.h" -#include "qapi/error.h" /* * TODO Have to include block/block.h for a bunch of block layer diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index b06a0607a9..16432f3508 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -11,7 +11,6 @@ #define BLOCKDEV_H #include "block/block.h" -#include "qapi/error.h" #include "qemu/queue.h" void blockdev_mark_auto_del(BlockBackend *blk); diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index 359e14304f..705650aad4 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -16,6 +16,32 @@ void *create_device_tree(int *sizep); void *load_device_tree(const char *filename_path, int *sizep); +#ifdef CONFIG_LINUX +/** + * load_device_tree_from_sysfs: reads the device tree information in the + * /proc/device-tree directory and return the corresponding binary blob + * buffer pointer. Asserts in case of error. + */ +void *load_device_tree_from_sysfs(void); +#endif + +/** + * qemu_fdt_node_path: return the paths of nodes matching a given + * name and compat string + * @fdt: pointer to the dt blob + * @name: node name + * @compat: compatibility string + * @errp: handle to an error object + * + * returns a newly allocated NULL-terminated array of node paths. + * Use g_strfreev() to free it. If one or more nodes were found, the + * array contains the path of each node and the last element equals to + * NULL. If there is no error but no matching node was found, the + * returned array contains a single element equal to NULL. If an error + * was encountered when parsing the blob, the function returns NULL + */ +char **qemu_fdt_node_path(void *fdt, const char *name, char *compat, + Error **errp); int qemu_fdt_setprop(void *fdt, const char *node_path, const char *property, const void *val, int size); @@ -28,10 +54,33 @@ int qemu_fdt_setprop_string(void *fdt, const char *node_path, int qemu_fdt_setprop_phandle(void *fdt, const char *node_path, const char *property, const char *target_node_path); +/** + * qemu_fdt_getprop: retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @node_path: node path + * @property: name of the property to find + * @lenp: fdt error if any or length of the property on success + * @errp: handle to an error object + * + * returns a pointer to the property on success and NULL on failure + */ const void *qemu_fdt_getprop(void *fdt, const char *node_path, - const char *property, int *lenp); + const char *property, int *lenp, + Error **errp); +/** + * qemu_fdt_getprop_cell: retrieve the value of a given 4 byte property + * @fdt: pointer to the device tree blob + * @node_path: node path + * @property: name of the property to find + * @lenp: fdt error if any or -EINVAL if the property size is different from + * 4 bytes, or 4 (expected length of the property) upon success. + * @errp: handle to an error object + * + * returns the property value on success + */ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path, - const char *property); + const char *property, int *lenp, + Error **errp); uint32_t qemu_fdt_get_phandle(void *fdt, const char *path); uint32_t qemu_fdt_alloc_phandle(void *fdt); int qemu_fdt_nop_node(void *fdt, const char *node_path); diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h index efa8b9993a..b0fbb9bb35 100644 --- a/include/sysemu/dma.h +++ b/include/sysemu/dma.h @@ -10,7 +10,6 @@ #ifndef DMA_H #define DMA_H -#include <stdio.h> #include "exec/memory.h" #include "exec/address-spaces.h" #include "hw/hw.h" diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h index 1ce439415d..a19801d20b 100644 --- a/include/sysemu/hostmem.h +++ b/include/sysemu/hostmem.h @@ -14,7 +14,6 @@ #include "sysemu/sysemu.h" /* for MAX_NODES */ #include "qom/object.h" -#include "qapi/error.h" #include "exec/memory.h" #include "qemu/option.h" #include "qemu/bitmap.h" diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 7741f91f9c..6695fa7cfd 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -14,8 +14,6 @@ #ifndef QEMU_KVM_H #define QEMU_KVM_H -#include <errno.h> -#include "config-host.h" #include "qemu/queue.h" #include "qom/cpu.h" #include "exec/memattrs.h" diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index a6392bc50f..bb184c9cfe 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -1,7 +1,6 @@ #ifndef SYSEMU_NUMA_H #define SYSEMU_NUMA_H -#include <stdint.h> #include "qemu/bitmap.h" #include "qemu/option.h" #include "sysemu/sysemu.h" diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index f1315213f1..5b9c4d6143 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -26,7 +26,6 @@ #ifndef QEMU_OS_POSIX_H #define QEMU_OS_POSIX_H -#include <sys/time.h> void os_set_line_buffering(void); void os_set_proc_name(const char *s); diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index 05473b75a5..70aa40aa72 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -15,7 +15,6 @@ #define QTEST_H #include "qemu-common.h" -#include "qapi/error.h" extern bool qtest_allowed; diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index abb4688200..e4108e8b1a 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -12,10 +12,7 @@ * */ -#include <stdbool.h> -#include <stdint.h> #include "qapi-types.h" -#include "qapi/error.h" #include "qemu/typedefs.h" /* replay clock kinds */ diff --git a/include/sysemu/rng.h b/include/sysemu/rng.h index 0a27c9b88c..858be8cef4 100644 --- a/include/sysemu/rng.h +++ b/include/sysemu/rng.h @@ -15,7 +15,6 @@ #include "qom/object.h" #include "qemu-common.h" -#include "qapi/error.h" #define TYPE_RNG_BACKEND "rng-backend" #define RNG_BACKEND(obj) \ diff --git a/include/sysemu/seccomp.h b/include/sysemu/seccomp.h index 1189fa241d..cfc06008cb 100644 --- a/include/sysemu/seccomp.h +++ b/include/sysemu/seccomp.h @@ -16,7 +16,6 @@ #define QEMU_SECCOMP_H #include <seccomp.h> -#include "qemu/osdep.h" int seccomp_start(void); #endif diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 0a366be0f2..e3ec80020f 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -15,7 +15,6 @@ #include "qom/object.h" #include "qemu-common.h" -#include "qapi/error.h" #include "qapi-types.h" #include "qemu/option.h" #include "sysemu/tpm.h" diff --git a/include/sysemu/xen-mapcache.h b/include/sysemu/xen-mapcache.h index c59804060b..c849489fb2 100644 --- a/include/sysemu/xen-mapcache.h +++ b/include/sysemu/xen-mapcache.h @@ -9,7 +9,6 @@ #ifndef XEN_MAPCACHE_H #define XEN_MAPCACHE_H -#include <stdlib.h> typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr start_addr, ram_addr_t size, diff --git a/include/ui/console.h b/include/ui/console.h index c8f9f7e65e..6631b9690a 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -7,7 +7,6 @@ #include "qemu/notify.h" #include "qemu/typedefs.h" #include "qapi-types.h" -#include "qapi/error.h" #ifdef CONFIG_OPENGL # include <epoxy/gl.h> diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index 8c84398001..03fcf4bba2 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -3,10 +3,23 @@ #include <epoxy/gl.h> #include <epoxy/egl.h> +#include <gbm.h> extern EGLDisplay *qemu_egl_display; extern EGLConfig qemu_egl_config; +#ifdef CONFIG_OPENGL_DMABUF + +extern int qemu_egl_rn_fd; +extern struct gbm_device *qemu_egl_rn_gbm_dev; +extern EGLContext qemu_egl_rn_ctx; + +int qemu_egl_rendernode_open(void); +int egl_rendernode_init(void); +int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc); + +#endif + EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win); int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug); diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index f9ce357ff3..2dabe49f41 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -18,7 +18,6 @@ #ifndef QEMU_SPICE_H #define QEMU_SPICE_H -#include "config-host.h" #ifdef CONFIG_SPICE diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index b25328a6ba..69a222b543 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -24,6 +24,14 @@ #include "ui/console.h" #include "sysemu/sysemu.h" +#if defined(CONFIG_OPENGL_DMABUF) +# if SPICE_SERVER_VERSION >= 0x000d00 /* release 0.13.0 */ +# define HAVE_SPICE_GL 1 +# include "ui/egl-helpers.h" +# include "ui/egl-context.h" +# endif +#endif + #define NUM_MEMSLOTS 8 #define MEMSLOT_GENERATION_BITS 8 #define MEMSLOT_SLOT_BITS 8 @@ -50,6 +58,7 @@ enum { QXL_COOKIE_TYPE_IO, QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + QXL_COOKIE_TYPE_GL_DRAW_DONE, }; typedef struct QXLCookie { @@ -104,6 +113,13 @@ struct SimpleSpiceDisplay { QEMUCursor *cursor; int mouse_x, mouse_y; QEMUBH *cursor_bh; + +#ifdef HAVE_SPICE_GL + /* opengl rendering */ + QEMUBH *gl_unblock_bh; + QEMUTimer *gl_unblock_timer; + int dmabuf_fd; +#endif }; struct SimpleSpiceUpdate { diff --git a/io/channel-util.c b/io/channel-util.c index f96907cb5c..0fb4bd0837 100644 --- a/io/channel-util.c +++ b/io/channel-util.c @@ -18,6 +18,7 @@ * */ +#include "qemu/osdep.h" #include "io/channel-util.h" #include "io/channel-file.h" #include "io/channel-socket.h" diff --git a/linux-user/aarch64/syscall_nr.h b/linux-user/aarch64/syscall_nr.h index 74f42758fb..59511d855d 100644 --- a/linux-user/aarch64/syscall_nr.h +++ b/linux-user/aarch64/syscall_nr.h @@ -262,7 +262,6 @@ #define TARGET_NR_process_vm_writev 271 #define TARGET_NR_kcmp 272 #define TARGET_NR_finit_module 273 - #define TARGET_NR_sched_setattr 274 #define TARGET_NR_sched_getattr 275 #define TARGET_NR_renameat2 276 @@ -274,63 +273,5 @@ #define TARGET_NR_userfaultfd 282 #define TARGET_NR_membarrier 283 #define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 -#define TARGET_NR_open 1024 -#define TARGET_NR_link 1025 -#define TARGET_NR_unlink 1026 -#define TARGET_NR_mknod 1027 -#define TARGET_NR_chmod 1028 -#define TARGET_NR_chown 1029 -#define TARGET_NR_mkdir 1030 -#define TARGET_NR_rmdir 1031 -#define TARGET_NR_lchown 1032 -#define TARGET_NR_access 1033 -#define TARGET_NR_rename 1034 -#define TARGET_NR_readlink 1035 -#define TARGET_NR_symlink 1036 -#define TARGET_NR_utimes 1037 -#define TARGET_NR_stat 1038 -#define TARGET_NR_lstat 1039 -#define TARGET_NR_pipe 1040 -#define TARGET_NR_dup2 1041 -#define TARGET_NR_epoll_create 1042 -#define TARGET_NR_inotify_init 1043 -#define TARGET_NR_eventfd 1044 -#define TARGET_NR_signalfd 1045 -#define TARGET_NR_sendfile64 1046 -#define TARGET_NR_ftruncate64 1047 -#define TARGET_NR_truncate64 1048 -#define TARGET_NR_stat64 1049 -#define TARGET_NR_lstat64 1050 -#define TARGET_NR_fstat64 1051 -#define TARGET_NR_fcntl64 1052 -/* #define TARGET_NR_fadvise64 1053 */ -#define TARGET_NR_newfstatat 1054 -#define TARGET_NR_fstatfs64 1055 -#define TARGET_NR_statfs64 1056 -#define TARGET_NR_lseek64 1057 -#define TARGET_NR_mmap64 1058 -#define TARGET_NR_alarm 1059 -#define TARGET_NR_getpgrp 1060 -#define TARGET_NR_pause 1061 -#define TARGET_NR_time 1062 -#define TARGET_NR_utime 1063 -#define TARGET_NR_creat 1064 -#define TARGET_NR_getdents 1065 -#define TARGET_NR_futimesat 1066 -#define TARGET_NR_select 1067 -#define TARGET_NR_poll 1068 -#define TARGET_NR_epoll_wait 1069 -#define TARGET_NR_ustat 1070 -#define TARGET_NR_vfork 1071 -#define TARGET_NR_oldwait4 1072 -#define TARGET_NR_recv 1073 -#define TARGET_NR_send 1074 -#define TARGET_NR_bdflush 1075 -#define TARGET_NR_umount 1076 -#define TARGET_NR_uselib 1077 -#define TARGET_NR__sysctl 1078 -#define TARGET_NR_fork 1079 -#define TARGET_NR_syscalls (__NR_fork+1) - -#define TARGET_NR_sigreturn 1999 diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/target_syscall.h index dc72a15c5e..f458018048 100644 --- a/linux-user/aarch64/syscall.h +++ b/linux-user/aarch64/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + struct target_pt_regs { uint64_t regs[31]; uint64_t sp; @@ -11,3 +14,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index dde8d5c6ad..00e14bb6b3 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -444,3 +444,9 @@ #define TARGET_NR_process_vm_writev 505 #define TARGET_NR_kcmp 506 #define TARGET_NR_finit_module 507 +#define TARGET_NR_sched_setattr 508 +#define TARGET_NR_sched_getattr 509 +#define TARGET_NR_renameat2 510 +#define TARGET_NR_getrandom 511 +#define TARGET_NR_memfd_create 512 +#define TARGET_NR_execveat 513 diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/target_syscall.h index 245cff2545..3db4b16f6b 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + /* default linux values for the selectors */ #define __USER_DS (1) @@ -255,3 +258,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h index bb9ac6554e..7e114eee8a 100644 --- a/linux-user/arm/nwfpe/fpa11.h +++ b/linux-user/arm/nwfpe/fpa11.h @@ -21,9 +21,6 @@ #ifndef __FPA11_H__ #define __FPA11_H__ -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> #include <cpu.h> diff --git a/linux-user/arm/syscall.h b/linux-user/arm/target_syscall.h index 3844a96112..ea863db0b9 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/target_syscall.h @@ -1,3 +1,5 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -48,3 +50,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/cris/syscall_nr.h b/linux-user/cris/syscall_nr.h index 694bd02fa5..44f0b645b4 100644 --- a/linux-user/cris/syscall_nr.h +++ b/linux-user/cris/syscall_nr.h @@ -336,3 +336,27 @@ #define TARGET_NR_preadv 333 #define TARGET_NR_pwritev 334 #define TARGET_NR_setns 335 +#define TARGET_NR_name_to_handle_at 336 +#define TARGET_NR_open_by_handle_at 337 +#define TARGET_NR_rt_tgsigqueueinfo 338 +#define TARGET_NR_perf_event_open 339 +#define TARGET_NR_recvmmsg 340 +#define TARGET_NR_accept4 341 +#define TARGET_NR_fanotify_init 342 +#define TARGET_NR_fanotify_mark 343 +#define TARGET_NR_prlimit64 344 +#define TARGET_NR_clock_adjtime 345 +#define TARGET_NR_syncfs 346 +#define TARGET_NR_sendmmsg 347 +#define TARGET_NR_process_vm_readv 348 +#define TARGET_NR_process_vm_writev 349 +#define TARGET_NR_kcmp 350 +#define TARGET_NR_finit_module 351 +#define TARGET_NR_sched_setattr 352 +#define TARGET_NR_sched_getattr 353 +#define TARGET_NR_renameat2 354 +#define TARGET_NR_seccomp 355 +#define TARGET_NR_getrandom 356 +#define TARGET_NR_memfd_create 357 +#define TARGET_NR_bpf 358 +#define TARGET_NR_execveat 359 diff --git a/linux-user/cris/syscall.h b/linux-user/cris/target_syscall.h index 2957b0d6ae..2957b0d6ae 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/target_syscall.h diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index c8f7302194..bc1bc233ed 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -324,7 +324,7 @@ #define TARGET_NR_epoll_pwait 319 #define TARGET_NR_utimensat 320 #define TARGET_NR_signalfd 321 -#define TARGET_NR_timerfd 322 +#define TARGET_NR_timerfd_create 322 #define TARGET_NR_eventfd 323 #define TARGET_NR_fallocate 324 #define TARGET_NR_timerfd_settime 325 @@ -353,3 +353,30 @@ #define TARGET_NR_process_vm_writev 348 #define TARGET_NR_kcmp 349 #define TARGET_NR_finit_module 350 +#define TARGET_NR_sched_setattr 351 +#define TARGET_NR_sched_getattr 352 +#define TARGET_NR_renameat2 353 +#define TARGET_NR_seccomp 354 +#define TARGET_NR_getrandom 355 +#define TARGET_NR_memfd_create 356 +#define TARGET_NR_bpf 357 +#define TARGET_NR_execveat 358 +#define TARGET_NR_socket 359 +#define TARGET_NR_socketpair 360 +#define TARGET_NR_bind 361 +#define TARGET_NR_connect 362 +#define TARGET_NR_listen 363 +#define TARGET_NR_accept4 364 +#define TARGET_NR_getsockopt 365 +#define TARGET_NR_setsockopt 366 +#define TARGET_NR_getsockname 367 +#define TARGET_NR_getpeername 368 +#define TARGET_NR_sendto 369 +#define TARGET_NR_sendmsg 370 +#define TARGET_NR_recvfrom 371 +#define TARGET_NR_recvmsg 372 +#define TARGET_NR_shutdown 373 +#define TARGET_NR_userfaultfd 374 +#define TARGET_NR_membarrier 375 +#define TARGET_NR_mlock2 376 +#define TARGET_NR_copy_file_range 377 diff --git a/linux-user/i386/syscall.h b/linux-user/i386/target_syscall.h index 906aaac0b1..0ac84dc02f 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + /* default linux values for the selectors */ #define __USER_CS (0x23) #define __USER_DS (0x2B) @@ -150,3 +153,5 @@ struct target_vm86plus_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h index a2daba034a..4b50fb29b6 100644 --- a/linux-user/m68k/syscall_nr.h +++ b/linux-user/m68k/syscall_nr.h @@ -317,7 +317,7 @@ #define TARGET_NR_epoll_pwait 315 #define TARGET_NR_utimensat 316 #define TARGET_NR_signalfd 317 -#define TARGET_NR_timerfd 318 +#define TARGET_NR_timerfd_create 318 #define TARGET_NR_eventfd 319 #define TARGET_NR_fallocate 320 #define TARGET_NR_timerfd_settime 321 diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/target_syscall.h index 9218493a44..97a4cc0cbd 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/target_syscall.h @@ -1,3 +1,5 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -23,3 +25,5 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_FUTURE 2 void do_m68k_simcall(CPUM68KState *, int); + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/main.c b/linux-user/main.c index e719a2da02..2a692e0f0b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4160,7 +4160,7 @@ int main(int argc, char **argv, char **envp) cpu_model = "or1200"; #elif defined(TARGET_PPC) # ifdef TARGET_PPC64 - cpu_model = "POWER7"; + cpu_model = "POWER8"; # else cpu_model = "750"; # endif diff --git a/linux-user/microblaze/syscall_nr.h b/linux-user/microblaze/syscall_nr.h index 6f530f9d1e..0704449bae 100644 --- a/linux-user/microblaze/syscall_nr.h +++ b/linux-user/microblaze/syscall_nr.h @@ -382,3 +382,11 @@ #define TARGET_NR_process_vm_writev 378 #define TARGET_NR_kcmp 379 #define TARGET_NR_finit_module 380 +#define TARGET_NR_sched_setattr 381 +#define TARGET_NR_sched_getattr 382 +#define TARGET_NR_renameat2 383 +#define TARGET_NR_seccomp 384 +#define TARGET_NR_getrandom 385 +#define TARGET_NR_memfd_create 386 +#define TARGET_NR_bpf 387 +#define TARGET_NR_execveat 388 diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/target_syscall.h index 3c1ed27c04..3c1ed27c04 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/target_syscall.h diff --git a/linux-user/mips/syscall.h b/linux-user/mips/target_syscall.h index 35ca23b166..68db160e53 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/target_syscall.h @@ -1,3 +1,5 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -231,3 +233,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h index 004232a8a2..746cc267e9 100644 --- a/linux-user/mips64/syscall_nr.h +++ b/linux-user/mips64/syscall_nr.h @@ -316,6 +316,18 @@ #define TARGET_NR_process_vm_writev (TARGET_NR_Linux + 310) #define TARGET_NR_kcmp (TARGET_NR_Linux + 311) #define TARGET_NR_finit_module (TARGET_NR_Linux + 312) +#define TARGET_NR_sched_setattr (TARGET_NR_Linux + 313) +#define TARGET_NR_sched_getattr (TARGET_NR_Linux + 314) +#define TARGET_NR_renameat2 (TARGET_NR_Linux + 315) +#define TARGET_NR_seccomp (TARGET_NR_Linux + 316) +#define TARGET_NR_getrandom (TARGET_NR_Linux + 317) +#define TARGET_NR_memfd_create (TARGET_NR_Linux + 318) +#define TARGET_NR_bpf (TARGET_NR_Linux + 319) +#define TARGET_NR_execveat (TARGET_NR_Linux + 320) +#define TARGET_NR_userfaultfd (TARGET_NR_Linux + 321) +#define TARGET_NR_membarrier (TARGET_NR_Linux + 322) +#define TARGET_NR_mlock2 (TARGET_NR_Linux + 323) + #else /* * Linux 64-bit syscalls are in the range from 5000 to 5999. @@ -630,4 +642,15 @@ #define TARGET_NR_kcmp (TARGET_NR_Linux + 306) #define TARGET_NR_finit_module (TARGET_NR_Linux + 307) #define TARGET_NR_getdents64 (TARGET_NR_Linux + 308) +#define TARGET_NR_sched_setattr (TARGET_NR_Linux + 309) +#define TARGET_NR_sched_getattr (TARGET_NR_Linux + 310) +#define TARGET_NR_renameat2 (TARGET_NR_Linux + 311) +#define TARGET_NR_seccomp (TARGET_NR_Linux + 312) +#define TARGET_NR_getrandom (TARGET_NR_Linux + 313) +#define TARGET_NR_memfd_create (TARGET_NR_Linux + 314) +#define TARGET_NR_bpf (TARGET_NR_Linux + 315) +#define TARGET_NR_execveat (TARGET_NR_Linux + 316) +#define TARGET_NR_userfaultfd (TARGET_NR_Linux + 317) +#define TARGET_NR_membarrier (TARGET_NR_Linux + 318) +#define TARGET_NR_mlock2 (TARGET_NR_Linux + 319) #endif diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/target_syscall.h index 6733107ddb..0e0c2d232f 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/target_syscall.h @@ -1,3 +1,5 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -228,3 +230,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h index 4c386eae98..6b1c7d265e 100644 --- a/linux-user/openrisc/syscall_nr.h +++ b/linux-user/openrisc/syscall_nr.h @@ -382,9 +382,18 @@ #define TARGET_NR_process_vm_writev 271 #define TARGET_NR_kcmp 272 #define TARGET_NR_finit_module 273 - -#undef TARGET_NR_syscalls -#define TARGET_NR_syscalls 274 +#define TARGET_NR_sched_setattr 274 +#define TARGET_NR_sched_getattr 275 +#define TARGET_NR_renameat2 276 +#define TARGET_NR_seccomp 277 +#define TARGET_NR_getrandom 278 +#define TARGET_NR_memfd_create 279 +#define TARGET_NR_bpf 280 +#define TARGET_NR_execveat 281 +#define TARGET_NR_userfaultfd 282 +#define TARGET_NR_membarrier 283 +#define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 /* * All syscalls below here should go away really, @@ -411,9 +420,6 @@ #define TARGET_NR_3264_stat 1038 #define TARGET_NR_3264_lstat 1039 -#undef TARGET_NR_syscalls -#define TARGET_NR_syscalls (TARGET_NR_3264_lstat+1) - #define TARGET_NR_pipe 1040 #define TARGET_NR_dup2 1041 #define TARGET_NR_epoll_create 1042 @@ -421,10 +427,6 @@ #define TARGET_NR_eventfd 1044 #define TARGET_NR_signalfd 1045 -#undef TARGET_NR_syscalls -#define TARGET_NR_syscalls (TARGET_NR_signalfd+1) - - #define TARGET_NR_sendfile 1046 #define TARGET_NR_ftruncate 1047 #define TARGET_NR_truncate 1048 @@ -441,9 +443,6 @@ #define TARGET_NR_lseek 1057 #define TARGET_NR_mmap 1058 -#undef TARGET_NR_syscalls -#define TARGET_NR_syscalls (TARGET_NR_mmap+1) - #define TARGET_NR_alarm 1059 #define __ARCH_WANT_SYS_ALARM #define TARGET_NR_getpgrp 1060 @@ -477,9 +476,6 @@ #define TARGET_NR_fork 1079 -#undef TARGET_NR_syscalls -#define TARGET_NR_syscalls (TARGET_NR_fork+1) - /* * 32 bit systems traditionally used different diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/target_syscall.h index 8ac03656d4..19aeffc95d 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + struct target_pt_regs { union { struct { @@ -27,3 +30,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index 1e1736e11d..46ed8a68ce 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -319,7 +319,7 @@ #define TARGET_NR_epoll_pwait 303 #define TARGET_NR_utimensat 304 #define TARGET_NR_signalfd 305 -#define TARGET_NR_timerfd 306 +#define TARGET_NR_timerfd_create 306 #define TARGET_NR_eventfd 307 #define TARGET_NR_sync_file_range2 308 #define TARGET_NR_fallocate 309 @@ -368,3 +368,27 @@ #define TARGET_NR_process_vm_writev 352 #define TARGET_NR_finit_module 353 #define TARGET_NR_kcmp 354 +#define TARGET_NR_sched_setattr 355 +#define TARGET_NR_sched_getattr 356 +#define TARGET_NR_renameat2 357 +#define TARGET_NR_seccomp 358 +#define TARGET_NR_getrandom 359 +#define TARGET_NR_memfd_create 360 +#define TARGET_NR_bpf 361 +#define TARGET_NR_execveat 362 +#define TARGET_NR_switch_endian 363 +#define TARGET_NR_userfaultfd 364 +#define TARGET_NR_membarrier 365 +#define TARGET_NR_semop 366 +#define TARGET_NR_semget 367 +#define TARGET_NR_semctl 368 +#define TARGET_NR_semtimedop 369 +#define TARGET_NR_msgsnd 370 +#define TARGET_NR_msgrcv 371 +#define TARGET_NR_msgget 372 +#define TARGET_NR_msgctl 373 +#define TARGET_NR_shmat 374 +#define TARGET_NR_shmdt 375 +#define TARGET_NR_shmget 376 +#define TARGET_NR_shmctl 377 +#define TARGET_NR_mlock2 378 diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/target_syscall.h index 0daf5cd2df..35cab59462 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/target_syscall.h @@ -17,6 +17,9 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + /* XXX: ABSOLUTELY BUGGY: * for now, this is quite just a cut-and-paste from i386 target... */ @@ -73,3 +76,5 @@ struct target_revectored_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index bd90cc3799..26b0ba2736 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -1,22 +1,19 @@ #ifndef QEMU_H #define QEMU_H -#include <signal.h> -#include <string.h> #include "cpu.h" #include "exec/cpu_ldst.h" #undef DEBUG_REMAP #ifdef DEBUG_REMAP -#include <stdlib.h> #endif /* DEBUG_REMAP */ #include "exec/user/abitypes.h" #include "exec/user/thunk.h" #include "syscall_defs.h" -#include "syscall.h" +#include "target_syscall.h" #include "exec/gdbstub.h" #include "qemu/queue.h" diff --git a/linux-user/s390x/syscall_nr.h b/linux-user/s390x/syscall_nr.h index 7c0b8b2eaa..1a66c5561d 100644 --- a/linux-user/s390x/syscall_nr.h +++ b/linux-user/s390x/syscall_nr.h @@ -271,6 +271,36 @@ #define TARGET_NR_s390_runtime_instr 342 #define TARGET_NR_kcmp 343 #define TARGET_NR_finit_module 344 +#define TARGET_NR_sched_setattr 345 +#define TARGET_NR_sched_getattr 346 +#define TARGET_NR_renameat2 347 +#define TARGET_NR_seccomp 348 +#define TARGET_NR_getrandom 349 +#define TARGET_NR_memfd_create 350 +#define TARGET_NR_bpf 351 +#define TARGET_NR_s390_pci_mmio_write 352 +#define TARGET_NR_s390_pci_mmio_read 353 +#define TARGET_NR_execveat 354 +#define TARGET_NR_userfaultfd 355 +#define TARGET_NR_membarrier 356 +#define TARGET_NR_recvmmsg 357 +#define TARGET_NR_sendmmsg 358 +#define TARGET_NR_socket 359 +#define TARGET_NR_socketpair 360 +#define TARGET_NR_bind 361 +#define TARGET_NR_connect 362 +#define TARGET_NR_listen 363 +#define TARGET_NR_accept4 364 +#define TARGET_NR_getsockopt 365 +#define TARGET_NR_setsockopt 366 +#define TARGET_NR_getsockname 367 +#define TARGET_NR_getpeername 368 +#define TARGET_NR_sendto 369 +#define TARGET_NR_sendmsg 370 +#define TARGET_NR_recvfrom 371 +#define TARGET_NR_recvmsg 372 +#define TARGET_NR_shutdown 373 +#define TARGET_NR_mlock2 374 /* * There are some system calls that are not present on 64 bit, some diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/target_syscall.h index 35f170af25..02061efc78 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + /* this typedef defines how a Program Status Word looks like */ typedef struct { abi_ulong mask; @@ -27,3 +30,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index bdf8742c69..50099846d2 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -323,7 +323,7 @@ #define TARGET_NR_epoll_pwait 319 #define TARGET_NR_utimensat 320 #define TARGET_NR_signalfd 321 -#define TARGET_NR_timerfd 322 +#define TARGET_NR_timerfd_create 322 #define TARGET_NR_eventfd 323 #define TARGET_NR_fallocate 324 #define TARGET_NR_timerfd_settime 325 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/target_syscall.h index 7aa4f239c5..9f3381bc9b 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + struct target_pt_regs { unsigned long regs[16]; unsigned long pc; @@ -15,3 +18,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 181cd32653..732b1052a4 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -278,7 +278,7 @@ #define TARGET_NR_epoll_pwait 309 #define TARGET_NR_utimensat 310 #define TARGET_NR_signalfd 311 -#define TARGET_NR_timerfd 312 +#define TARGET_NR_timerfd_create 312 #define TARGET_NR_eventfd 313 #define TARGET_NR_fallocate 314 #define TARGET_NR_timerfd_settime 315 @@ -309,3 +309,17 @@ #define TARGET_NR_kern_features 340 #define TARGET_NR_kcmp 341 #define TARGET_NR_finit_module 342 +#define TARGET_NR_sched_setattr 343 +#define TARGET_NR_sched_getattr 344 +#define TARGET_NR_renameat2 345 +#define TARGET_NR_seccomp 346 +#define TARGET_NR_getrandom 347 +#define TARGET_NR_memfd_create 348 +#define TARGET_NR_bpf 349 +#define TARGET_NR_execveat 350 +#define TARGET_NR_membarrier 351 +#define TARGET_NR_userfaultfd 352 +#define TARGET_NR_bind 353 +#define TARGET_NR_listen 354 +#define TARGET_NR_setsockopt 355 +#define TARGET_NR_mlock2 356 diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/target_syscall.h index 58573b92ea..a73fa6dae1 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + struct target_pt_regs { abi_ulong psr; abi_ulong pc; @@ -18,3 +21,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index 34a984cc88..2b49ead267 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -341,3 +341,17 @@ #define TARGET_NR_kern_features 340 #define TARGET_NR_kcmp 341 #define TARGET_NR_finit_module 342 +#define TARGET_NR_sched_setattr 343 +#define TARGET_NR_sched_getattr 344 +#define TARGET_NR_renameat2 345 +#define TARGET_NR_seccomp 346 +#define TARGET_NR_getrandom 347 +#define TARGET_NR_memfd_create 348 +#define TARGET_NR_bpf 349 +#define TARGET_NR_execveat 350 +#define TARGET_NR_membarrier 351 +#define TARGET_NR_userfaultfd 352 +#define TARGET_NR_bind 353 +#define TARGET_NR_listen 354 +#define TARGET_NR_setsockopt 355 +#define TARGET_NR_mlock2 356 diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/target_syscall.h index 8398d3f463..eb827fcac1 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + struct target_pt_regs { abi_ulong u_regs[16]; abi_ulong tstate; @@ -19,3 +22,5 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + +#endif /* TARGET_SYSCALL_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 54ce14a611..951753143c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -249,6 +249,9 @@ _syscall2(int, ioprio_get, int, which, int, who) #if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set) _syscall3(int, ioprio_set, int, which, int, who, int, ioprio) #endif +#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom) +_syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags) +#endif static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, @@ -318,8 +321,8 @@ static void fd_trans_register(int fd, TargetFdTrans *trans) if (fd >= target_fd_max) { oldmax = target_fd_max; target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */ - target_fd_trans = g_realloc(target_fd_trans, - target_fd_max * sizeof(TargetFdTrans)); + target_fd_trans = g_renew(TargetFdTrans *, + target_fd_trans, target_fd_max); memset((void *)(target_fd_trans + oldmax), 0, (target_fd_max - oldmax) * sizeof(TargetFdTrans *)); } @@ -2598,8 +2601,9 @@ static abi_long do_socketcall(int num, abi_ulong vptr) #define N_SHM_REGIONS 32 static struct shm_region { - abi_ulong start; - abi_ulong size; + abi_ulong start; + abi_ulong size; + bool in_use; } shm_regions[N_SHM_REGIONS]; struct target_semid_ds @@ -3291,7 +3295,8 @@ static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE)); for (i = 0; i < N_SHM_REGIONS; i++) { - if (shm_regions[i].start == 0) { + if (!shm_regions[i].in_use) { + shm_regions[i].in_use = true; shm_regions[i].start = raddr; shm_regions[i].size = shm_info.shm_segsz; break; @@ -3308,8 +3313,8 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) int i; for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == shmaddr) { - shm_regions[i].start = 0; + if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) { + shm_regions[i].in_use = false; page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0); break; } @@ -5229,7 +5234,6 @@ static inline int target_to_host_mlockall_arg(int arg) } #endif -#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat) static inline abi_long host_to_target_stat64(void *cpu_env, abi_ulong target_addr, struct stat *host_st) @@ -5292,7 +5296,6 @@ static inline abi_long host_to_target_stat64(void *cpu_env, return 0; } -#endif /* ??? Using host futex calls even when target atomic operations are not really atomic probably breaks things. However implementing @@ -7541,6 +7544,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(shutdown(arg1, arg2)); break; #endif +#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom) + case TARGET_NR_getrandom: + p = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (!p) { + goto efault; + } + ret = get_errno(getrandom(p, arg2, arg3)); + unlock_user(p, arg1, ret); + break; +#endif #ifdef TARGET_NR_socket case TARGET_NR_socket: ret = do_socket(arg1, arg2, arg3); diff --git a/linux-user/tilegx/syscall_nr.h b/linux-user/tilegx/syscall_nr.h index 1dca348378..87fb72c554 100644 --- a/linux-user/tilegx/syscall_nr.h +++ b/linux-user/tilegx/syscall_nr.h @@ -274,6 +274,10 @@ #define TARGET_NR_memfd_create 279 #define TARGET_NR_bpf 280 #define TARGET_NR_execveat 281 +#define TARGET_NR_userfaultfd 282 +#define TARGET_NR_membarrier 283 +#define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 #define TARGET_NR_open 1024 #define TARGET_NR_link 1025 diff --git a/linux-user/tilegx/syscall.h b/linux-user/tilegx/target_syscall.h index a938d4e90c..a938d4e90c 100644 --- a/linux-user/tilegx/syscall.h +++ b/linux-user/tilegx/target_syscall.h diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/target_syscall.h index 385a97562d..385a97562d 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/target_syscall.h diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index 7c59e3a09e..16397b3e8f 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -281,7 +281,7 @@ #define TARGET_NR_utimensat 280 #define TARGET_NR_epoll_pwait 281 #define TARGET_NR_signalfd 282 -#define TARGET_NR_timerfd 283 +#define TARGET_NR_timerfd_create 283 #define TARGET_NR_eventfd 284 #define TARGET_NR_fallocate 285 #define TARGET_NR_timerfd_settime 286 @@ -312,3 +312,16 @@ #define TARGET_NR_process_vm_writev 311 #define TARGET_NR_kcmp 312 #define TARGET_NR_finit_module 313 +#define TARGET_NR_sched_setattr 314 +#define TARGET_NR_sched_getattr 315 +#define TARGET_NR_renameat2 316 +#define TARGET_NR_seccomp 317 +#define TARGET_NR_getrandom 318 +#define TARGET_NR_memfd_create 319 +#define TARGET_NR_kexec_file_load 320 +#define TARGET_NR_bpf 321 +#define TARGET_NR_execveat 322 +#define TARGET_NR_userfaultfd 323 +#define TARGET_NR_membarrier 324 +#define TARGET_NR_mlock2 325 +#define TARGET_NR_copy_file_range 326 diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/target_syscall.h index 88b3c3fe31..feecd32d50 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/target_syscall.h @@ -1,3 +1,6 @@ +#ifndef TARGET_SYSCALL_H +#define TARGET_SYSCALL_H + #define __USER_CS (0x33) #define __USER_DS (0x2B) @@ -100,3 +103,5 @@ struct target_msqid64_ds { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 + +#endif /* TARGET_SYSCALL_H */ diff --git a/migration/block.c b/migration/block.c index a444058cf7..72883d7c64 100644 --- a/migration/block.c +++ b/migration/block.c @@ -54,17 +54,25 @@ typedef struct BlkMigDevState { int shared_base; int64_t total_sectors; QSIMPLEQ_ENTRY(BlkMigDevState) entry; + Error *blocker; /* Only used by migration thread. Does not need a lock. */ int bulk_completed; int64_t cur_sector; int64_t cur_dirty; - /* Protected by block migration lock. */ + /* Data in the aio_bitmap is protected by block migration lock. + * Allocation and free happen during setup and cleanup respectively. + */ unsigned long *aio_bitmap; + + /* Protected by block migration lock. */ int64_t completed_sectors; + + /* During migration this is protected by iothread lock / AioContext. + * Allocation and free happen during setup and cleanup respectively. + */ BdrvDirtyBitmap *dirty_bitmap; - Error *blocker; } BlkMigDevState; typedef struct BlkMigBlock { @@ -100,7 +108,7 @@ typedef struct BlkMigState { int prev_progress; int bulk_completed; - /* Lock must be taken _inside_ the iothread lock. */ + /* Lock must be taken _inside_ the iothread lock and any AioContexts. */ QemuMutex lock; } BlkMigState; @@ -264,11 +272,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) if (bmds->shared_base) { qemu_mutex_lock_iothread(); + aio_context_acquire(bdrv_get_aio_context(bs)); while (cur_sector < total_sectors && !bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; } + aio_context_release(bdrv_get_aio_context(bs)); qemu_mutex_unlock_iothread(); } @@ -302,11 +312,21 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) block_mig_state.submitted++; blk_mig_unlock(); + /* We do not know if bs is under the main thread (and thus does + * not acquire the AioContext when doing AIO) or rather under + * dataplane. Thus acquire both the iothread mutex and the + * AioContext. + * + * This is ugly and will disappear when we make bdrv_* thread-safe, + * without the need to acquire the AioContext. + */ qemu_mutex_lock_iothread(); + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, cur_sector, nr_sectors); + aio_context_release(bdrv_get_aio_context(bmds->bs)); qemu_mutex_unlock_iothread(); bmds->cur_sector = cur_sector + nr_sectors; @@ -321,8 +341,10 @@ static int set_dirty_tracking(void) int ret; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE, NULL, NULL); + aio_context_release(bdrv_get_aio_context(bmds->bs)); if (!bmds->dirty_bitmap) { ret = -errno; goto fail; @@ -333,18 +355,24 @@ static int set_dirty_tracking(void) fail: QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->dirty_bitmap) { + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap); + aio_context_release(bdrv_get_aio_context(bmds->bs)); } } return ret; } +/* Called with iothread lock taken. */ + static void unset_dirty_tracking(void) { BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap); + aio_context_release(bdrv_get_aio_context(bmds->bs)); } } @@ -444,7 +472,7 @@ static void blk_mig_reset_dirty_cursor(void) } } -/* Called with iothread lock taken. */ +/* Called with iothread lock and AioContext taken. */ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, int is_async) @@ -527,7 +555,9 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async) int ret = 1; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); ret = mig_save_device_dirty(f, bmds, is_async); + aio_context_release(bdrv_get_aio_context(bmds->bs)); if (ret <= 0) { break; } @@ -585,7 +615,9 @@ static int64_t get_remaining_dirty(void) int64_t dirty = 0; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + aio_context_acquire(bdrv_get_aio_context(bmds->bs)); dirty += bdrv_get_dirty_count(bmds->dirty_bitmap); + aio_context_release(bdrv_get_aio_context(bmds->bs)); } return dirty << BDRV_SECTOR_BITS; @@ -597,21 +629,28 @@ static void block_migration_cleanup(void *opaque) { BlkMigDevState *bmds; BlkMigBlock *blk; + AioContext *ctx; bdrv_drain_all(); unset_dirty_tracking(); - blk_mig_lock(); while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); bdrv_op_unblock_all(bmds->bs, bmds->blocker); error_free(bmds->blocker); + + /* Save ctx, because bmds->bs can disappear during bdrv_unref. */ + ctx = bdrv_get_aio_context(bmds->bs); + aio_context_acquire(ctx); bdrv_unref(bmds->bs); + aio_context_release(ctx); + g_free(bmds->aio_bitmap); g_free(bmds); } + blk_mig_lock(); while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); g_free(blk->buf); @@ -633,13 +672,12 @@ static int block_save_setup(QEMUFile *f, void *opaque) /* start track dirty blocks */ ret = set_dirty_tracking(); + qemu_mutex_unlock_iothread(); + if (ret) { - qemu_mutex_unlock_iothread(); return ret; } - qemu_mutex_unlock_iothread(); - ret = flush_blks(f); blk_mig_reset_dirty_cursor(); qemu_put_be64(f, BLK_MIG_FLAG_EOS); @@ -761,17 +799,18 @@ static void block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, uint64_t pending; qemu_mutex_lock_iothread(); + pending = get_remaining_dirty(); + qemu_mutex_unlock_iothread(); + blk_mig_lock(); - pending = get_remaining_dirty() + - block_mig_state.submitted * BLOCK_SIZE + - block_mig_state.read_done * BLOCK_SIZE; + pending += block_mig_state.submitted * BLOCK_SIZE + + block_mig_state.read_done * BLOCK_SIZE; + blk_mig_unlock(); /* Report at least one block pending during bulk phase */ if (pending <= max_size && !block_mig_state.bulk_completed) { pending = max_size + BLOCK_SIZE; } - blk_mig_unlock(); - qemu_mutex_unlock_iothread(); DPRINTF("Enter save live pending %" PRIu64 "\n", pending); /* We don't do postcopy */ @@ -786,6 +825,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) int64_t addr; BlockDriverState *bs, *bs_prev = NULL; BlockBackend *blk; + Error *local_err = NULL; uint8_t *buf; int64_t total_sectors = 0; int nr_sectors; @@ -824,6 +864,12 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) device_name); return -EINVAL; } + + bdrv_invalidate_cache(bs, &local_err); + if (local_err) { + error_report_err(local_err); + return -EINVAL; + } } if (total_sectors - addr < BDRV_SECTORS_PER_DIRTY_CHUNK) { diff --git a/migration/migration.c b/migration/migration.c index a64cfcdb07..fc5e50b0be 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -905,6 +905,11 @@ bool migration_in_postcopy(MigrationState *s) return (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE); } +bool migration_in_postcopy_after_devices(MigrationState *s) +{ + return migration_in_postcopy(s) && s->postcopy_after_devices; +} + MigrationState *migrate_init(const MigrationParams *params) { MigrationState *s = migrate_get_current(); @@ -930,6 +935,7 @@ MigrationState *migrate_init(const MigrationParams *params) s->setup_time = 0; s->dirty_sync_count = 0; s->start_postcopy = false; + s->postcopy_after_devices = false; s->migration_thread_running = false; s->last_req_rb = NULL; @@ -1489,6 +1495,14 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running) goto fail_closefb; } qemu_fclose(fb); + + /* Send a notify to give a chance for anything that needs to happen + * at the transition to postcopy and after the device state; in particular + * spice needs to trigger a transition now + */ + ms->postcopy_after_devices = true; + notifier_list_notify(&migration_state_notifiers, ms); + ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - time_at_stop; qemu_mutex_unlock_iothread(); diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index db6ab65ced..d09b4ee308 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -16,16 +16,12 @@ #include "qemu/coroutine.h" #include "qemu/iov.h" -#include <errno.h> -#include <string.h> #ifndef _WIN32 #include <sys/ioctl.h> #endif #if defined(__sun__) || defined(__HAIKU__) #include <sys/ioccom.h> #endif -#include <ctype.h> -#include <inttypes.h> #ifdef __linux__ #include <linux/fs.h> diff --git a/net/tap-linux.h b/net/tap-linux.h index 01dc6f8a2d..1dc3a9f279 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -16,7 +16,6 @@ #ifndef QEMU_TAP_LINUX_H #define QEMU_TAP_LINUX_H -#include <stdint.h> #ifdef __linux__ #include <linux/ioctl.h> diff --git a/net/util.h b/net/util.h index 10c7da95f0..60b73d372d 100644 --- a/net/util.h +++ b/net/util.h @@ -25,7 +25,6 @@ #ifndef QEMU_NET_UTIL_H #define QEMU_NET_UTIL_H -#include <stdint.h> int net_parse_macaddr(uint8_t *macaddr, const char *p); diff --git a/pc-bios/README b/pc-bios/README index 9f65ffa46f..5a8a93193e 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20151103. + built from git tag qemu-slof-20160223. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml Binary files differdeleted file mode 100644 index d71b3a328c..0000000000 --- a/pc-bios/q35-acpi-dsdt.aml +++ /dev/null diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 90f30996f9..f2384939ef 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/qapi/block-core.json b/qapi/block-core.json index 33012b86c1..9bf1b22b72 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -273,17 +273,41 @@ # # @image: the info of image used (since: 1.6) # -# @bps_max: #optional total max in bytes (Since 1.7) +# @bps_max: #optional total throughput limit during bursts, +# in bytes (Since 1.7) # -# @bps_rd_max: #optional read max in bytes (Since 1.7) +# @bps_rd_max: #optional read throughput limit during bursts, +# in bytes (Since 1.7) # -# @bps_wr_max: #optional write max in bytes (Since 1.7) +# @bps_wr_max: #optional write throughput limit during bursts, +# in bytes (Since 1.7) # -# @iops_max: #optional total I/O operations max (Since 1.7) +# @iops_max: #optional total I/O operations per second during bursts, +# in bytes (Since 1.7) # -# @iops_rd_max: #optional read I/O operations max (Since 1.7) +# @iops_rd_max: #optional read I/O operations per second during bursts, +# in bytes (Since 1.7) # -# @iops_wr_max: #optional write I/O operations max (Since 1.7) +# @iops_wr_max: #optional write I/O operations per second during bursts, +# in bytes (Since 1.7) +# +# @bps_max_length: #optional maximum length of the @bps_max burst +# period, in seconds. (Since 2.6) +# +# @bps_rd_max_length: #optional maximum length of the @bps_rd_max +# burst period, in seconds. (Since 2.6) +# +# @bps_wr_max_length: #optional maximum length of the @bps_wr_max +# burst period, in seconds. (Since 2.6) +# +# @iops_max_length: #optional maximum length of the @iops burst +# period, in seconds. (Since 2.6) +# +# @iops_rd_max_length: #optional maximum length of the @iops_rd_max +# burst period, in seconds. (Since 2.6) +# +# @iops_wr_max_length: #optional maximum length of the @iops_wr_max +# burst period, in seconds. (Since 2.6) # # @iops_size: #optional an I/O size in bytes (Since 1.7) # @@ -308,6 +332,9 @@ '*bps_max': 'int', '*bps_rd_max': 'int', '*bps_wr_max': 'int', '*iops_max': 'int', '*iops_rd_max': 'int', '*iops_wr_max': 'int', + '*bps_max_length': 'int', '*bps_rd_max_length': 'int', + '*bps_wr_max_length': 'int', '*iops_max_length': 'int', + '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int', '*iops_size': 'int', '*group': 'str', 'cache': 'BlockdevCacheInfo', 'write_threshold': 'int' } } @@ -1294,21 +1321,57 @@ # # @iops: total I/O operations per second # -# @ops_rd: read I/O operations per second +# @iops_rd: read I/O operations per second # # @iops_wr: write I/O operations per second # -# @bps_max: #optional total max in bytes (Since 1.7) +# @bps_max: #optional total throughput limit during bursts, +# in bytes (Since 1.7) +# +# @bps_rd_max: #optional read throughput limit during bursts, +# in bytes (Since 1.7) +# +# @bps_wr_max: #optional write throughput limit during bursts, +# in bytes (Since 1.7) +# +# @iops_max: #optional total I/O operations per second during bursts, +# in bytes (Since 1.7) +# +# @iops_rd_max: #optional read I/O operations per second during bursts, +# in bytes (Since 1.7) +# +# @iops_wr_max: #optional write I/O operations per second during bursts, +# in bytes (Since 1.7) +# +# @bps_max_length: #optional maximum length of the @bps_max burst +# period, in seconds. It must only +# be set if @bps_max is set as well. +# Defaults to 1. (Since 2.6) # -# @bps_rd_max: #optional read max in bytes (Since 1.7) +# @bps_rd_max_length: #optional maximum length of the @bps_rd_max +# burst period, in seconds. It must only +# be set if @bps_rd_max is set as well. +# Defaults to 1. (Since 2.6) # -# @bps_wr_max: #optional write max in bytes (Since 1.7) +# @bps_wr_max_length: #optional maximum length of the @bps_wr_max +# burst period, in seconds. It must only +# be set if @bps_wr_max is set as well. +# Defaults to 1. (Since 2.6) # -# @iops_max: #optional total I/O operations max (Since 1.7) +# @iops_max_length: #optional maximum length of the @iops burst +# period, in seconds. It must only +# be set if @iops_max is set as well. +# Defaults to 1. (Since 2.6) # -# @iops_rd_max: #optional read I/O operations max (Since 1.7) +# @iops_rd_max_length: #optional maximum length of the @iops_rd_max +# burst period, in seconds. It must only +# be set if @iops_rd_max is set as well. +# Defaults to 1. (Since 2.6) # -# @iops_wr_max: #optional write I/O operations max (Since 1.7) +# @iops_wr_max_length: #optional maximum length of the @iops_wr_max +# burst period, in seconds. It must only +# be set if @iops_wr_max is set as well. +# Defaults to 1. (Since 2.6) # # @iops_size: #optional an I/O size in bytes (Since 1.7) # @@ -1325,6 +1388,9 @@ '*bps_max': 'int', '*bps_rd_max': 'int', '*bps_wr_max': 'int', '*iops_max': 'int', '*iops_rd_max': 'int', '*iops_wr_max': 'int', + '*bps_max_length': 'int', '*bps_rd_max_length': 'int', + '*bps_wr_max_length': 'int', '*iops_max_length': 'int', + '*iops_rd_max_length': 'int', '*iops_wr_max_length': 'int', '*iops_size': 'int', '*group': 'str' } } ## diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index d54f75b5e7..73e4acea7b 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -157,17 +157,11 @@ opts_start_struct(Visitor *v, const char *name, void **obj, } -static gboolean -ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data) -{ - return TRUE; -} - - static void opts_end_struct(Visitor *v, Error **errp) { OptsVisitor *ov = to_ov(v); + GHashTableIter iter; GQueue *any; if (--ov->depth > 0) { @@ -175,8 +169,8 @@ opts_end_struct(Visitor *v, Error **errp) } /* we should have processed all (distinct) QemuOpt instances */ - any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL); - if (any) { + g_hash_table_iter_init(&iter, ov->unprocessed_opts); + if (g_hash_table_iter_next(&iter, NULL, (void **)&any)) { const QemuOpt *first; first = g_queue_peek_head(any); @@ -221,7 +215,7 @@ opts_start_list(Visitor *v, const char *name, Error **errp) static GenericList * -opts_next_list(Visitor *v, GenericList **list) +opts_next_list(Visitor *v, GenericList **list, size_t size) { OptsVisitor *ov = to_ov(v); GenericList **link; @@ -264,7 +258,7 @@ opts_next_list(Visitor *v, GenericList **list) abort(); } - *link = g_malloc0(sizeof **link); + *link = g_malloc0(size); return *link; } diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index 2659d3fcca..69221794ec 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -76,16 +76,15 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp) } } -static void qapi_dealloc_start_implicit_struct(Visitor *v, - void **obj, - size_t size, - Error **errp) +static void qapi_dealloc_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp) { QapiDeallocVisitor *qov = to_qov(v); qapi_dealloc_push(qov, obj); } -static void qapi_dealloc_end_implicit_struct(Visitor *v) +static void qapi_dealloc_end_alternate(Visitor *v) { QapiDeallocVisitor *qov = to_qov(v); void **obj = qapi_dealloc_pop(qov); @@ -100,7 +99,8 @@ static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp) qapi_dealloc_push(qov, NULL); } -static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp) +static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp, + size_t size) { GenericList *list = *listp; QapiDeallocVisitor *qov = to_qov(v); @@ -168,31 +168,6 @@ static void qapi_dealloc_type_enum(Visitor *v, const char *name, int *obj, { } -/* If there's no data present, the dealloc visitor has nothing to free. - * Thus, indicate to visitor code that the subsequent union fields can - * be skipped. This is not an error condition, since the cleanup of the - * rest of an object can continue unhindered, so leave errp unset in - * these cases. - * - * NOTE: In cases where we're attempting to deallocate an object that - * may have missing fields, the field indicating the union type may - * be missing. In such a case, it's possible we don't have enough - * information to differentiate data_present == false from a case where - * data *is* present but happens to be a scalar with a value of 0. - * This is okay, since in the case of the dealloc visitor there's no - * work that needs to done in either situation. - * - * The current inability in QAPI code to more thoroughly verify a union - * type in such cases will likely need to be addressed if we wish to - * implement this interface for other types of visitors in the future, - * however. - */ -static bool qapi_dealloc_start_union(Visitor *v, bool data_present, - Error **errp) -{ - return data_present; -} - Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v) { return &v->visitor; @@ -211,8 +186,8 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v->visitor.start_struct = qapi_dealloc_start_struct; v->visitor.end_struct = qapi_dealloc_end_struct; - v->visitor.start_implicit_struct = qapi_dealloc_start_implicit_struct; - v->visitor.end_implicit_struct = qapi_dealloc_end_implicit_struct; + v->visitor.start_alternate = qapi_dealloc_start_alternate; + v->visitor.end_alternate = qapi_dealloc_end_alternate; v->visitor.start_list = qapi_dealloc_start_list; v->visitor.next_list = qapi_dealloc_next_list; v->visitor.end_list = qapi_dealloc_end_list; @@ -223,7 +198,6 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v->visitor.type_str = qapi_dealloc_type_str; v->visitor.type_number = qapi_dealloc_type_number; v->visitor.type_any = qapi_dealloc_type_anything; - v->visitor.start_union = qapi_dealloc_start_union; QTAILQ_INIT(&v->stack); diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index f856286461..856606b253 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -30,29 +30,15 @@ void visit_end_struct(Visitor *v, Error **errp) v->end_struct(v, errp); } -void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, - Error **errp) -{ - if (v->start_implicit_struct) { - v->start_implicit_struct(v, obj, size, errp); - } -} - -void visit_end_implicit_struct(Visitor *v) -{ - if (v->end_implicit_struct) { - v->end_implicit_struct(v); - } -} - void visit_start_list(Visitor *v, const char *name, Error **errp) { v->start_list(v, name, errp); } -GenericList *visit_next_list(Visitor *v, GenericList **list) +GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size) { - return v->next_list(v, list); + assert(list && size >= sizeof(GenericList)); + return v->next_list(v, list, size); } void visit_end_list(Visitor *v) @@ -60,28 +46,29 @@ void visit_end_list(Visitor *v) v->end_list(v); } -bool visit_start_union(Visitor *v, bool data_present, Error **errp) +void visit_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp) { - if (v->start_union) { - return v->start_union(v, data_present, errp); + assert(obj && size >= sizeof(GenericAlternate)); + if (v->start_alternate) { + v->start_alternate(v, name, obj, size, promote_int, errp); } - return true; } -bool visit_optional(Visitor *v, const char *name, bool *present) +void visit_end_alternate(Visitor *v) { - if (v->optional) { - v->optional(v, name, present); + if (v->end_alternate) { + v->end_alternate(v); } - return *present; } -void visit_get_next_type(Visitor *v, const char *name, QType *type, - bool promote_int, Error **errp) +bool visit_optional(Visitor *v, const char *name, bool *present) { - if (v->get_next_type) { - v->get_next_type(v, name, type, promote_int, errp); + if (v->optional) { + v->optional(v, name, present); } + return *present; } void visit_type_enum(Visitor *v, const char *name, int *obj, diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 362a1a33a8..e6598327c3 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -90,12 +90,6 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp) qiv->nb_stack++; } -/** Only for qmp_input_pop. */ -static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey) -{ - *(const char **)user_pkey = (const char *)key; - return TRUE; -} static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp) { @@ -104,9 +98,11 @@ static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp) if (qiv->strict) { GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h; if (top_ht) { - if (g_hash_table_size(top_ht)) { - const char *key; - g_hash_table_find(top_ht, always_true, &key); + GHashTableIter iter; + const char *key; + + g_hash_table_iter_init(&iter, top_ht); + if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { error_setg(errp, QERR_QMP_EXTRA_MEMBER, key); } g_hash_table_unref(top_ht); @@ -147,14 +143,6 @@ static void qmp_input_end_struct(Visitor *v, Error **errp) qmp_input_pop(qiv, errp); } -static void qmp_input_start_implicit_struct(Visitor *v, void **obj, - size_t size, Error **errp) -{ - if (obj) { - *obj = g_malloc0(size); - } -} - static void qmp_input_start_list(Visitor *v, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); @@ -169,7 +157,8 @@ static void qmp_input_start_list(Visitor *v, const char *name, Error **errp) qmp_input_push(qiv, qobj, errp); } -static GenericList *qmp_input_next_list(Visitor *v, GenericList **list) +static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, + size_t size) { QmpInputVisitor *qiv = to_qiv(v); GenericList *entry; @@ -188,7 +177,7 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list) return NULL; } - entry = g_malloc0(sizeof(*entry)); + entry = g_malloc0(size); if (first) { *list = entry; } else { @@ -205,19 +194,22 @@ static void qmp_input_end_list(Visitor *v) qmp_input_pop(qiv, &error_abort); } -static void qmp_input_get_next_type(Visitor *v, const char *name, QType *type, - bool promote_int, Error **errp) +static void qmp_input_start_alternate(Visitor *v, const char *name, + GenericAlternate **obj, size_t size, + bool promote_int, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, false); if (!qobj) { + *obj = NULL; error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); return; } - *type = qobject_type(qobj); - if (promote_int && *type == QTYPE_QINT) { - *type = QTYPE_QFLOAT; + *obj = g_malloc0(size); + (*obj)->type = qobject_type(qobj); + if (promote_int && (*obj)->type == QTYPE_QINT) { + (*obj)->type = QTYPE_QFLOAT; } } @@ -348,10 +340,10 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.start_struct = qmp_input_start_struct; v->visitor.end_struct = qmp_input_end_struct; - v->visitor.start_implicit_struct = qmp_input_start_implicit_struct; v->visitor.start_list = qmp_input_start_list; v->visitor.next_list = qmp_input_next_list; v->visitor.end_list = qmp_input_end_list; + v->visitor.start_alternate = qmp_input_start_alternate; v->visitor.type_enum = input_type_enum; v->visitor.type_int64 = qmp_input_type_int64; v->visitor.type_uint64 = qmp_input_type_uint64; @@ -360,7 +352,6 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) v->visitor.type_number = qmp_input_type_number; v->visitor.type_any = qmp_input_type_any; v->visitor.optional = qmp_input_optional; - v->visitor.get_next_type = qmp_input_get_next_type; qmp_input_push(v, obj, NULL); qobject_incref(obj); diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index f47eefa626..d44c676317 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -126,7 +126,8 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp) qmp_output_push(qov, list); } -static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp) +static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp, + size_t size) { GenericList *list = *listp; QmpOutputVisitor *qov = to_qov(v); diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 18b9339768..59eb5dc4e3 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -139,7 +139,7 @@ start_list(Visitor *v, const char *name, Error **errp) } } -static GenericList *next_list(Visitor *v, GenericList **list) +static GenericList *next_list(Visitor *v, GenericList **list, size_t size) { StringInputVisitor *siv = to_siv(v); GenericList **link; @@ -173,7 +173,7 @@ static GenericList *next_list(Visitor *v, GenericList **list) link = &(*list)->next; } - *link = g_malloc0(sizeof **link); + *link = g_malloc0(size); return *link; } diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index b980bd3265..c2e5c5b92b 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -276,7 +276,7 @@ start_list(Visitor *v, const char *name, Error **errp) sov->head = true; } -static GenericList *next_list(Visitor *v, GenericList **list) +static GenericList *next_list(Visitor *v, GenericList **list, size_t size) { StringOutputVisitor *sov = to_sov(v); GenericList *ret = NULL; diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 95677745f9..e7cded6e24 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,68 +10,68 @@ STEXI ETEXI DEF("check", img_check, - "check [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename") + "check [-q] [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename") STEXI -@item check [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} +@item check [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} ETEXI DEF("create", img_create, - "create [-q] [-f fmt] [-o options] filename [size]") + "create [-q] [--object objectdef] [--image-opts] [-f fmt] [-o options] filename [size]") STEXI -@item create [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] +@item create [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ETEXI DEF("commit", img_commit, - "commit [-q] [-f fmt] [-t cache] [-b base] [-d] [-p] filename") + "commit [-q] [--object objectdef] [--image-opts] [-f fmt] [-t cache] [-b base] [-d] [-p] filename") STEXI -@item commit [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename} +@item commit [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename} ETEXI DEF("compare", img_compare, - "compare [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2") + "compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2") STEXI -@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2} +@item compare [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2} ETEXI DEF("convert", img_convert, - "convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename") + "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, - "info [-f fmt] [--output=ofmt] [--backing-chain] filename") + "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename") STEXI -@item info [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} +@item info [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} ETEXI DEF("map", img_map, - "map [-f fmt] [--output=ofmt] filename") + "map [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] filename") STEXI -@item map [-f @var{fmt}] [--output=@var{ofmt}] @var{filename} +@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename} ETEXI DEF("snapshot", img_snapshot, - "snapshot [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename") + "snapshot [--object objectdef] [--image-opts] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename") STEXI -@item snapshot [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} +@item snapshot [--object @var{objectdef}] [--image-opts] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} ETEXI DEF("rebase", img_rebase, - "rebase [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [--object objectdef] [--image-opts] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI -@item rebase [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +@item rebase [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI DEF("resize", img_resize, - "resize [-q] filename [+ | -]size") + "resize [--object objectdef] [--image-opts] [-q] filename [+ | -]size") STEXI -@item resize [-q] @var{filename} [+ | -]@var{size} +@item resize [--object @var{objectdef}] [--image-opts] [-q] @var{filename} [+ | -]@var{size} ETEXI DEF("amend", img_amend, - "amend [-p] [-q] [-f fmt] [-t cache] -o options filename") + "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename") STEXI -@item amend [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename} +@item amend [--object @var{objectdef}] [--image-opts] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename} @end table ETEXI diff --git a/qemu-img.c b/qemu-img.c index 7030107da2..2edb139073 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -27,8 +27,10 @@ #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" #include "qemu-common.h" +#include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/error-report.h" +#include "qom/object_interfaces.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" #include "block/block_int.h" @@ -47,6 +49,8 @@ typedef struct img_cmd_t { enum { OPTION_OUTPUT = 256, OPTION_BACKING_CHAIN = 257, + OPTION_OBJECT = 258, + OPTION_IMAGE_OPTS = 259, }; typedef enum OutputFormat { @@ -94,6 +98,10 @@ static void QEMU_NORETURN help(void) "\n" "Command parameters:\n" " 'filename' is a disk image filename\n" + " 'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n" + " manual page for a description of the object properties. The most common\n" + " object type is a 'secret', which is used to supply passwords and/or\n" + " encryption keys.\n" " 'fmt' is the disk image format. It is guessed automatically in most cases\n" " 'cache' is the cache mode used to write the output disk image, the valid\n" " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n" @@ -154,6 +162,24 @@ static void QEMU_NORETURN help(void) exit(EXIT_SUCCESS); } +static QemuOptsList qemu_object_opts = { + .name = "object", + .implied_opt_name = "qom-type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), + .desc = { + { } + }, +}; + +static QemuOptsList qemu_source_opts = { + .name = "source", + .implied_opt_name = "file", + .head = QTAILQ_HEAD_INITIALIZER(qemu_source_opts.head), + .desc = { + { } + }, +}; + static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...) { int ret = 0; @@ -196,13 +222,56 @@ static int print_block_option_help(const char *filename, const char *fmt) return 0; } -static BlockBackend *img_open(const char *id, const char *filename, - const char *fmt, int flags, - bool require_io, bool quiet) + +static int img_open_password(BlockBackend *blk, const char *filename, + bool require_io, bool quiet) { - BlockBackend *blk; BlockDriverState *bs; char password[256]; + + bs = blk_bs(blk); + if (bdrv_is_encrypted(bs) && require_io) { + qprintf(quiet, "Disk image '%s' is encrypted.\n", filename); + if (qemu_read_password(password, sizeof(password)) < 0) { + error_report("No password given"); + return -1; + } + if (bdrv_set_key(bs, password) < 0) { + error_report("invalid password"); + return -1; + } + } + return 0; +} + + +static BlockBackend *img_open_opts(const char *id, + const char *optstr, + QemuOpts *opts, int flags, + bool require_io, bool quiet) +{ + QDict *options; + Error *local_err = NULL; + BlockBackend *blk; + options = qemu_opts_to_qdict(opts, NULL); + blk = blk_new_open(id, NULL, NULL, options, flags, &local_err); + if (!blk) { + error_reportf_err(local_err, "Could not open '%s'", optstr); + return NULL; + } + + if (img_open_password(blk, optstr, require_io, quiet) < 0) { + blk_unref(blk); + return NULL; + } + return blk; +} + +static BlockBackend *img_open_file(const char *id, const char *filename, + const char *fmt, int flags, + bool require_io, bool quiet) +{ + BlockBackend *blk; Error *local_err = NULL; QDict *options = NULL; @@ -214,27 +283,43 @@ static BlockBackend *img_open(const char *id, const char *filename, blk = blk_new_open(id, filename, NULL, options, flags, &local_err); if (!blk) { error_reportf_err(local_err, "Could not open '%s': ", filename); - goto fail; + return NULL; } - bs = blk_bs(blk); - if (bdrv_is_encrypted(bs) && require_io) { - qprintf(quiet, "Disk image '%s' is encrypted.\n", filename); - if (qemu_read_password(password, sizeof(password)) < 0) { - error_report("No password given"); - goto fail; - } - if (bdrv_set_key(bs, password) < 0) { - error_report("invalid password"); - goto fail; - } + if (img_open_password(blk, filename, require_io, quiet) < 0) { + blk_unref(blk); + return NULL; } return blk; -fail: - blk_unref(blk); - return NULL; } + +static BlockBackend *img_open(const char *id, + bool image_opts, + const char *filename, + const char *fmt, int flags, + bool require_io, bool quiet) +{ + BlockBackend *blk; + if (image_opts) { + QemuOpts *opts; + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + return NULL; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + return NULL; + } + blk = img_open_opts(id, filename, opts, flags, true, quiet); + } else { + blk = img_open_file(id, filename, fmt, flags, true, quiet); + } + return blk; +} + + static int add_old_style_options(const char *fmt, QemuOpts *opts, const char *base_filename, const char *base_fmt) @@ -275,7 +360,13 @@ static int img_create(int argc, char **argv) bool quiet = false; for(;;) { - c = getopt(argc, argv, "F:b:f:he6o:q"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "F:b:f:he6o:q", + long_options, NULL); if (c == -1) { break; } @@ -317,6 +408,14 @@ static int img_create(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + goto fail; + } + } break; } } @@ -332,6 +431,13 @@ static int img_create(int argc, char **argv) } optind++; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + goto fail; + } + /* Get image size, if specified */ if (optind < argc) { int64_t sval; @@ -489,6 +595,8 @@ static int img_check(int argc, char **argv) int flags = BDRV_O_FLAGS | BDRV_O_CHECK; ImageCheck *check; bool quiet = false; + Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -500,6 +608,8 @@ static int img_check(int argc, char **argv) {"format", required_argument, 0, 'f'}, {"repair", required_argument, 0, 'r'}, {"output", required_argument, 0, OPTION_OUTPUT}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:r:T:q", @@ -536,6 +646,17 @@ static int img_check(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -552,13 +673,20 @@ static int img_check(int argc, char **argv) return 1; } + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + ret = bdrv_parse_cache_flags(cache, &flags); if (ret < 0) { error_report("Invalid source cache option: %s", cache); return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); if (!blk) { return 1; } @@ -670,12 +798,20 @@ static int img_commit(int argc, char **argv) bool progress = false, quiet = false, drop = false; Error *local_err = NULL; CommonBlockJobCBInfo cbi; + bool image_opts = false; fmt = NULL; cache = BDRV_DEFAULT_CACHE; base = NULL; for(;;) { - c = getopt(argc, argv, "f:ht:b:dpq"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "f:ht:b:dpq", + long_options, NULL); if (c == -1) { break; } @@ -704,6 +840,17 @@ static int img_commit(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -717,6 +864,13 @@ static int img_commit(int argc, char **argv) } filename = argv[optind++]; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + flags = BDRV_O_RDWR | BDRV_O_UNMAP; ret = bdrv_parse_cache_flags(cache, &flags); if (ret < 0) { @@ -724,7 +878,7 @@ static int img_commit(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); if (!blk) { return 1; } @@ -973,10 +1127,19 @@ static int img_compare(int argc, char **argv) int64_t nb_sectors; int c, pnum; uint64_t progress_base; + Error *local_err = NULL; + bool image_opts = false; cache = BDRV_DEFAULT_CACHE; for (;;) { - c = getopt(argc, argv, "hf:F:T:pqs"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "hf:F:T:pqs", + long_options, NULL); if (c == -1) { break; } @@ -1003,6 +1166,18 @@ static int img_compare(int argc, char **argv) case 's': strict = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + ret = 2; + goto out4; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -1018,6 +1193,14 @@ static int img_compare(int argc, char **argv) filename1 = argv[optind++]; filename2 = argv[optind++]; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + ret = 2; + goto out4; + } + /* Initialize before goto out */ qemu_progress_init(progress, 2.0); @@ -1029,18 +1212,18 @@ static int img_compare(int argc, char **argv) goto out3; } - blk1 = img_open("image_1", filename1, fmt1, flags, true, quiet); + blk1 = img_open("image_1", image_opts, filename1, fmt1, flags, true, quiet); if (!blk1) { ret = 2; goto out3; } - bs1 = blk_bs(blk1); - blk2 = img_open("image_2", filename2, fmt2, flags, true, quiet); + blk2 = img_open("image_2", image_opts, filename2, fmt2, flags, true, quiet); if (!blk2) { ret = 2; goto out2; } + bs1 = blk_bs(blk1); bs2 = blk_bs(blk2); buf1 = blk_blockalign(blk1, IO_BUF_SIZE); @@ -1225,6 +1408,7 @@ out2: blk_unref(blk1); out3: qemu_progress_end(); +out4: return ret; } @@ -1546,6 +1730,7 @@ static int img_convert(int argc, char **argv) Error *local_err = NULL; QemuOpts *sn_opts = NULL; ImgConvertState state; + bool image_opts = false; fmt = NULL; out_fmt = "raw"; @@ -1555,7 +1740,14 @@ static int img_convert(int argc, char **argv) compress = 0; skip_create = 0; for(;;) { - c = getopt(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn", + long_options, NULL); if (c == -1) { break; } @@ -1646,16 +1838,32 @@ static int img_convert(int argc, char **argv) case 'n': skip_create = 1; break; + case OPTION_OBJECT: + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + goto fail_getopt; + } + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + goto fail_getopt; + } + /* Initialize before goto out */ if (quiet) { progress = 0; } qemu_progress_init(progress, 1.0); - bs_n = argc - optind - 1; out_filename = bs_n >= 1 ? argv[argc - 1] : NULL; @@ -1693,8 +1901,8 @@ static int img_convert(int argc, char **argv) for (bs_i = 0; bs_i < bs_n; bs_i++) { char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i) : g_strdup("source"); - blk[bs_i] = img_open(id, argv[optind + bs_i], fmt, src_flags, - true, quiet); + blk[bs_i] = img_open(id, image_opts, argv[optind + bs_i], + fmt, src_flags, true, quiet); g_free(id); if (!blk[bs_i]) { ret = -1; @@ -1835,7 +2043,13 @@ static int img_convert(int argc, char **argv) goto out; } - out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet); + /* XXX we should allow --image-opts to trigger use of + * img_open() here, but then we have trouble with + * the bdrv_create() call which takes different params. + * Not critical right now, so fix can wait... + */ + out_blk = img_open_file("target", out_filename, + out_fmt, flags, true, quiet); if (!out_blk) { ret = -1; goto out; @@ -2001,7 +2215,8 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) * image file. If there was an error a message will have been printed to * stderr. */ -static ImageInfoList *collect_image_info_list(const char *filename, +static ImageInfoList *collect_image_info_list(bool image_opts, + const char *filename, const char *fmt, bool chain) { @@ -2025,8 +2240,9 @@ static ImageInfoList *collect_image_info_list(const char *filename, } g_hash_table_insert(filenames, (gpointer)filename, NULL); - blk = img_open("image", filename, fmt, - BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); + blk = img_open("image", image_opts, filename, fmt, + BDRV_O_FLAGS | BDRV_O_NO_BACKING, + false, false); if (!blk) { goto err; } @@ -2077,6 +2293,8 @@ static int img_info(int argc, char **argv) bool chain = false; const char *filename, *fmt, *output; ImageInfoList *list; + Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -2087,6 +2305,8 @@ static int img_info(int argc, char **argv) {"format", required_argument, 0, 'f'}, {"output", required_argument, 0, OPTION_OUTPUT}, {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2108,6 +2328,17 @@ static int img_info(int argc, char **argv) case OPTION_BACKING_CHAIN: chain = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -2124,7 +2355,14 @@ static int img_info(int argc, char **argv) return 1; } - list = collect_image_info_list(filename, fmt, chain); + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + + list = collect_image_info_list(image_opts, filename, fmt, chain); if (!list) { return 1; } @@ -2194,6 +2432,7 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num, int64_t ret; int depth; BlockDriverState *file; + bool has_offset; /* As an optimization, we could cache the current range of unallocated * clusters in each file of the chain, and avoid querying the same @@ -2220,17 +2459,20 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num, depth++; } - e->start = sector_num * BDRV_SECTOR_SIZE; - e->length = nb_sectors * BDRV_SECTOR_SIZE; - e->data = !!(ret & BDRV_BLOCK_DATA); - e->zero = !!(ret & BDRV_BLOCK_ZERO); - e->offset = ret & BDRV_BLOCK_OFFSET_MASK; - e->has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); - e->depth = depth; - if (file && e->has_offset) { - e->has_filename = true; - e->filename = file->filename; - } + has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); + + *e = (MapEntry) { + .start = sector_num * BDRV_SECTOR_SIZE, + .length = nb_sectors * BDRV_SECTOR_SIZE, + .data = !!(ret & BDRV_BLOCK_DATA), + .zero = !!(ret & BDRV_BLOCK_ZERO), + .offset = ret & BDRV_BLOCK_OFFSET_MASK, + .has_offset = has_offset, + .depth = depth, + .has_filename = file && has_offset, + .filename = file && has_offset ? file->filename : NULL, + }; + return 0; } @@ -2265,6 +2507,8 @@ static int img_map(int argc, char **argv) int64_t length; MapEntry curr = { .length = 0 }, next; int ret = 0; + Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -2274,6 +2518,8 @@ static int img_map(int argc, char **argv) {"help", no_argument, 0, 'h'}, {"format", required_argument, 0, 'f'}, {"output", required_argument, 0, OPTION_OUTPUT}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2292,6 +2538,17 @@ static int img_map(int argc, char **argv) case OPTION_OUTPUT: output = optarg; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -2308,7 +2565,15 @@ static int img_map(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false); + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + + blk = img_open("image", image_opts, filename, fmt, + BDRV_O_FLAGS, true, false); if (!blk) { return 1; } @@ -2370,11 +2635,19 @@ static int img_snapshot(int argc, char **argv) qemu_timeval tv; bool quiet = false; Error *err = NULL; + bool image_opts = false; bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR; /* Parse commandline parameters */ for(;;) { - c = getopt(argc, argv, "la:c:d:hq"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "la:c:d:hq", + long_options, NULL); if (c == -1) { break; } @@ -2418,6 +2691,17 @@ static int img_snapshot(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -2426,8 +2710,16 @@ static int img_snapshot(int argc, char **argv) } filename = argv[optind++]; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &err)) { + error_report_err(err); + return 1; + } + /* Open the image */ - blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet); + blk = img_open("image", image_opts, filename, NULL, + bdrv_oflags, true, quiet); if (!blk) { return 1; } @@ -2491,6 +2783,7 @@ static int img_rebase(int argc, char **argv) int progress = 0; bool quiet = false; Error *local_err = NULL; + bool image_opts = false; /* Parse commandline parameters */ fmt = NULL; @@ -2499,7 +2792,14 @@ static int img_rebase(int argc, char **argv) out_baseimg = NULL; out_basefmt = NULL; for(;;) { - c = getopt(argc, argv, "hf:F:b:upt:T:q"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "hf:F:b:upt:T:q", + long_options, NULL); if (c == -1) { break; } @@ -2532,6 +2832,17 @@ static int img_rebase(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -2547,6 +2858,13 @@ static int img_rebase(int argc, char **argv) } filename = argv[optind++]; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + qemu_progress_init(progress, 2.0); qemu_progress_print(0, 100); @@ -2570,7 +2888,7 @@ static int img_rebase(int argc, char **argv) * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ - blk = img_open("image", filename, fmt, flags, true, quiet); + blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); if (!blk) { ret = -1; goto out; @@ -2807,6 +3125,8 @@ static int img_resize(int argc, char **argv) bool quiet = false; BlockBackend *blk = NULL; QemuOpts *param; + Error *local_err = NULL; + static QemuOptsList resize_options = { .name = "resize_options", .head = QTAILQ_HEAD_INITIALIZER(resize_options.head), @@ -2820,6 +3140,7 @@ static int img_resize(int argc, char **argv) } }, }; + bool image_opts = false; /* Remove size from argv manually so that negative numbers are not treated * as options by getopt. */ @@ -2833,7 +3154,14 @@ static int img_resize(int argc, char **argv) /* Parse getopt arguments */ fmt = NULL; for(;;) { - c = getopt(argc, argv, "f:hq"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "f:hq", + long_options, NULL); if (c == -1) { break; } @@ -2848,6 +3176,17 @@ static int img_resize(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: { + QemuOpts *opts; + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + return 1; + } + } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -2855,6 +3194,13 @@ static int img_resize(int argc, char **argv) } filename = argv[optind++]; + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + return 1; + } + /* Choose grow, shrink, or absolute resize mode */ switch (size[0]) { case '+': @@ -2882,8 +3228,8 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - blk = img_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, - true, quiet); + blk = img_open("image", image_opts, filename, fmt, + BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!blk) { ret = -1; goto out; @@ -2942,10 +3288,19 @@ static int img_amend(int argc, char **argv) bool quiet = false, progress = false; BlockBackend *blk = NULL; BlockDriverState *bs = NULL; + Error *local_err = NULL; + bool image_opts = false; cache = BDRV_DEFAULT_CACHE; for (;;) { - c = getopt(argc, argv, "ho:f:t:pq"); + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "ho:f:t:pq", + long_options, NULL); if (c == -1) { break; } @@ -2981,6 +3336,17 @@ static int img_amend(int argc, char **argv) case 'q': quiet = true; break; + case OPTION_OBJECT: + opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!opts) { + ret = -1; + goto out_no_progress; + } + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -2988,6 +3354,14 @@ static int img_amend(int argc, char **argv) error_exit("Must specify options (-o)"); } + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_err)) { + error_report_err(local_err); + ret = -1; + goto out_no_progress; + } + if (quiet) { progress = false; } @@ -3014,7 +3388,7 @@ static int img_amend(int argc, char **argv) goto out; } - blk = img_open("image", filename, fmt, flags, true, quiet); + blk = img_open("image", image_opts, filename, fmt, flags, true, quiet); if (!blk) { ret = -1; goto out; @@ -3111,6 +3485,9 @@ int main(int argc, char **argv) } cmdname = argv[1]; + qemu_add_opts(&qemu_object_opts); + qemu_add_opts(&qemu_source_opts); + /* find the command */ for (cmd = img_cmds; cmd->name != NULL; cmd++) { if (!strcmp(cmdname, cmd->name)) { diff --git a/qemu-img.texi b/qemu-img.texi index 7163a108e2..afaebdd408 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -24,6 +24,20 @@ Command parameters: @table @var @item filename is a disk image filename + +@item --object @var{objectdef} + +is a QEMU user creatable object definition. See the @code{qemu(1)} manual +page for a description of the object properties. The most common object +type is a @code{secret}, which is used to supply passwords and/or encryption +keys. + +@item --image-opts + +Indicates that the @var{filename} parameter is to be interpreted as a +full option string, not a plain filename. This parameter is mutually +exclusive with the @var{-f} and @var{-F} parameters. + @item fmt is the disk image format. It is guessed automatically in most cases. See below for a description of the supported disk formats. @@ -18,6 +18,7 @@ #include "qemu/config-file.h" #include "qemu/readline.h" #include "qapi/qmp/qstring.h" +#include "qom/object_interfaces.h" #include "sysemu/block-backend.h" #include "block/block_int.h" #include "trace/control.h" @@ -31,6 +32,7 @@ static BlockBackend *qemuio_blk; /* qemu-io commands passed using -c */ static int ncmdline; static char **cmdline; +static bool imageOpts; static ReadLineState *readline_state; @@ -150,6 +152,10 @@ static int open_f(BlockBackend *blk, int argc, char **argv) readonly = 1; break; case 'o': + if (imageOpts) { + printf("--image-opts and 'open -o' are mutually exclusive\n"); + return 0; + } if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { qemu_opts_reset(&empty_opts); return 0; @@ -165,6 +171,14 @@ static int open_f(BlockBackend *blk, int argc, char **argv) flags |= BDRV_O_RDWR; } + if (imageOpts && (optind == argc - 1)) { + if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) { + qemu_opts_reset(&empty_opts); + return 0; + } + optind++; + } + qopts = qemu_opts_find(&empty_opts, NULL); opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; qemu_opts_reset(&empty_opts); @@ -200,6 +214,8 @@ static void usage(const char *name) "Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n" "QEMU Disk exerciser\n" "\n" +" --object OBJECTDEF define an object such as 'secret' for\n" +" passwords and/or encryption keys\n" " -c, --cmd STRING execute command with its arguments\n" " from the given string\n" " -f, --format FMT specifies the block driver to use\n" @@ -361,24 +377,51 @@ static void reenable_tty_echo(void) qemu_set_tty_echo(STDIN_FILENO, true); } +enum { + OPTION_OBJECT = 256, + OPTION_IMAGE_OPTS = 257, +}; + +static QemuOptsList qemu_object_opts = { + .name = "object", + .implied_opt_name = "qom-type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), + .desc = { + { } + }, +}; + + +static QemuOptsList file_opts = { + .name = "file", + .implied_opt_name = "file", + .head = QTAILQ_HEAD_INITIALIZER(file_opts.head), + .desc = { + /* no elements => accept any params */ + { /* end of list */ } + }, +}; + int main(int argc, char **argv) { int readonly = 0; const char *sopt = "hVc:d:f:rsnmgkt:T:"; const struct option lopt[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "offset", 1, NULL, 'o' }, - { "cmd", 1, NULL, 'c' }, - { "format", 1, NULL, 'f' }, - { "read-only", 0, NULL, 'r' }, - { "snapshot", 0, NULL, 's' }, - { "nocache", 0, NULL, 'n' }, - { "misalign", 0, NULL, 'm' }, - { "native-aio", 0, NULL, 'k' }, - { "discard", 1, NULL, 'd' }, - { "cache", 1, NULL, 't' }, - { "trace", 1, NULL, 'T' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "offset", required_argument, NULL, 'o' }, + { "cmd", required_argument, NULL, 'c' }, + { "format", required_argument, NULL, 'f' }, + { "read-only", no_argument, NULL, 'r' }, + { "snapshot", no_argument, NULL, 's' }, + { "nocache", no_argument, NULL, 'n' }, + { "misalign", no_argument, NULL, 'm' }, + { "native-aio", no_argument, NULL, 'k' }, + { "discard", required_argument, NULL, 'd' }, + { "cache", required_argument, NULL, 't' }, + { "trace", required_argument, NULL, 'T' }, + { "object", required_argument, NULL, OPTION_OBJECT }, + { "image-opts", no_argument, NULL, OPTION_IMAGE_OPTS }, { NULL, 0, NULL, 0 } }; int c; @@ -386,6 +429,7 @@ int main(int argc, char **argv) int flags = BDRV_O_UNMAP; Error *local_error = NULL; QDict *opts = NULL; + const char *format = NULL; #ifdef CONFIG_POSIX signal(SIGPIPE, SIG_IGN); @@ -395,6 +439,7 @@ int main(int argc, char **argv) qemu_init_exec_dir(argv[0]); module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_object_opts); bdrv_init(); while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { @@ -412,10 +457,7 @@ int main(int argc, char **argv) } break; case 'f': - if (!opts) { - opts = qdict_new(); - } - qdict_put(opts, "driver", qstring_from_str(optarg)); + format = optarg; break; case 'c': add_user_command(optarg); @@ -446,6 +488,17 @@ int main(int argc, char **argv) case 'h': usage(progname); exit(0); + case OPTION_OBJECT: { + QemuOpts *qopts; + qopts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!qopts) { + exit(1); + } + } break; + case OPTION_IMAGE_OPTS: + imageOpts = true; + break; default: usage(progname); exit(1); @@ -457,11 +510,23 @@ int main(int argc, char **argv) exit(1); } + if (format && imageOpts) { + error_report("--image-opts and -f are mutually exclusive"); + exit(1); + } + if (qemu_init_main_loop(&local_error)) { error_report_err(local_error); exit(1); } + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, &local_error)) { + error_report_err(local_error); + exit(1); + } + /* initialize commands */ qemuio_add_command(&quit_cmd); qemuio_add_command(&open_cmd); @@ -482,7 +547,21 @@ int main(int argc, char **argv) } if ((argc - optind) == 1) { - openfile(argv[optind], flags, opts); + if (imageOpts) { + QemuOpts *qopts = NULL; + qopts = qemu_opts_parse_noisily(&file_opts, argv[optind], false); + if (!qopts) { + exit(1); + } + opts = qemu_opts_to_qdict(qopts, NULL); + openfile(NULL, flags, opts); + } else { + if (format) { + opts = qdict_new(); + qdict_put(opts, "driver", qstring_from_str(format)); + } + openfile(argv[optind], flags, opts); + } } command_loop(); diff --git a/qemu-nbd.c b/qemu-nbd.c index 933ca4a368..5fe94d0e7b 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -31,18 +31,17 @@ #include "io/channel-socket.h" #include <getopt.h> -#include <sys/types.h> -#include <signal.h> #include <libgen.h> #include <pthread.h> #define SOCKET_PATH "/var/lock/qemu-nbd-%s" -#define QEMU_NBD_OPT_CACHE 1 -#define QEMU_NBD_OPT_AIO 2 -#define QEMU_NBD_OPT_DISCARD 3 -#define QEMU_NBD_OPT_DETECT_ZEROES 4 -#define QEMU_NBD_OPT_OBJECT 5 -#define QEMU_NBD_OPT_TLSCREDS 6 +#define QEMU_NBD_OPT_CACHE 256 +#define QEMU_NBD_OPT_AIO 257 +#define QEMU_NBD_OPT_DISCARD 258 +#define QEMU_NBD_OPT_DETECT_ZEROES 259 +#define QEMU_NBD_OPT_OBJECT 260 +#define QEMU_NBD_OPT_TLSCREDS 261 +#define QEMU_NBD_OPT_IMAGE_OPTS 262 static NBDExport *exp; static bool newproto; @@ -105,6 +104,7 @@ static void usage(const char *name) " --aio=MODE set AIO mode (native or threads)\n" " --discard=MODE set discard mode (ignore, unmap)\n" " --detect-zeroes=MODE set detect-zeroes mode (off, on, unmap)\n" +" --image-opts treat FILE as a full set of image options\n" "\n" "Report bugs to <qemu-devel@nongnu.org>\n" , name, NBD_DEFAULT_PORT, "DEVICE"); @@ -394,6 +394,16 @@ static SocketAddress *nbd_build_socket_address(const char *sockpath, } +static QemuOptsList file_opts = { + .name = "file", + .implied_opt_name = "file", + .head = QTAILQ_HEAD_INITIALIZER(file_opts.head), + .desc = { + /* no elements => accept any params */ + { /* end of list */ } + }, +}; + static QemuOptsList qemu_object_opts = { .name = "object", .implied_opt_name = "qom-type", @@ -451,30 +461,32 @@ int main(int argc, char **argv) const char *sn_id_or_name = NULL; const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:"; struct option lopt[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "bind", 1, NULL, 'b' }, - { "port", 1, NULL, 'p' }, - { "socket", 1, NULL, 'k' }, - { "offset", 1, NULL, 'o' }, - { "read-only", 0, NULL, 'r' }, - { "partition", 1, NULL, 'P' }, - { "connect", 1, NULL, 'c' }, - { "disconnect", 0, NULL, 'd' }, - { "snapshot", 0, NULL, 's' }, - { "load-snapshot", 1, NULL, 'l' }, - { "nocache", 0, NULL, 'n' }, - { "cache", 1, NULL, QEMU_NBD_OPT_CACHE }, - { "aio", 1, NULL, QEMU_NBD_OPT_AIO }, - { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD }, - { "detect-zeroes", 1, NULL, QEMU_NBD_OPT_DETECT_ZEROES }, - { "shared", 1, NULL, 'e' }, - { "format", 1, NULL, 'f' }, - { "persistent", 0, NULL, 't' }, - { "verbose", 0, NULL, 'v' }, - { "object", 1, NULL, QEMU_NBD_OPT_OBJECT }, - { "export-name", 1, NULL, 'x' }, - { "tls-creds", 1, NULL, QEMU_NBD_OPT_TLSCREDS }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "bind", required_argument, NULL, 'b' }, + { "port", required_argument, NULL, 'p' }, + { "socket", required_argument, NULL, 'k' }, + { "offset", required_argument, NULL, 'o' }, + { "read-only", no_argument, NULL, 'r' }, + { "partition", required_argument, NULL, 'P' }, + { "connect", required_argument, NULL, 'c' }, + { "disconnect", no_argument, NULL, 'd' }, + { "snapshot", no_argument, NULL, 's' }, + { "load-snapshot", required_argument, NULL, 'l' }, + { "nocache", no_argument, NULL, 'n' }, + { "cache", required_argument, NULL, QEMU_NBD_OPT_CACHE }, + { "aio", required_argument, NULL, QEMU_NBD_OPT_AIO }, + { "discard", required_argument, NULL, QEMU_NBD_OPT_DISCARD }, + { "detect-zeroes", required_argument, NULL, + QEMU_NBD_OPT_DETECT_ZEROES }, + { "shared", required_argument, NULL, 'e' }, + { "format", required_argument, NULL, 'f' }, + { "persistent", no_argument, NULL, 't' }, + { "verbose", no_argument, NULL, 'v' }, + { "object", required_argument, NULL, QEMU_NBD_OPT_OBJECT }, + { "export-name", required_argument, NULL, 'x' }, + { "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS }, + { "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS }, { NULL, 0, NULL, 0 } }; int ch; @@ -493,6 +505,7 @@ int main(int argc, char **argv) QDict *options = NULL; const char *export_name = NULL; const char *tlscredsid = NULL; + bool imageOpts = false; /* The client thread uses SIGTERM to interrupt the server. A signal * handler ensures that "qemu-nbd -v -c" exits with a nice status code. @@ -672,6 +685,9 @@ int main(int argc, char **argv) case QEMU_NBD_OPT_TLSCREDS: tlscredsid = optarg; break; + case QEMU_NBD_OPT_IMAGE_OPTS: + imageOpts = true; + break; } } @@ -800,13 +816,29 @@ int main(int argc, char **argv) bdrv_init(); atexit(bdrv_close_all); - if (fmt) { - options = qdict_new(); - qdict_put(options, "driver", qstring_from_str(fmt)); + srcpath = argv[optind]; + if (imageOpts) { + QemuOpts *opts; + if (fmt) { + error_report("--image-opts and -f are mutually exclusive"); + exit(EXIT_FAILURE); + } + opts = qemu_opts_parse_noisily(&file_opts, srcpath, true); + if (!opts) { + qemu_opts_reset(&file_opts); + exit(EXIT_FAILURE); + } + options = qemu_opts_to_qdict(opts, NULL); + qemu_opts_reset(&file_opts); + blk = blk_new_open("hda", NULL, NULL, options, flags, &local_err); + } else { + if (fmt) { + options = qdict_new(); + qdict_put(options, "driver", qstring_from_str(fmt)); + } + blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err); } - srcpath = argv[optind]; - blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err); if (!blk) { error_reportf_err(local_err, "Failed to blk_new_open '%s': ", argv[optind]); diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 227a73ca36..9f23343450 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -13,7 +13,8 @@ Export a QEMU disk image using the NBD protocol. @c man end @c man begin OPTIONS -@var{filename} is a disk image filename. +@var{filename} is a disk image filename, or a set of block +driver options if @var{--image-opts} is specified. @var{dev} is an NBD device. @@ -33,6 +34,10 @@ The offset into the image The interface to bind to (default @samp{0.0.0.0}) @item -k, --socket=@var{path} Use a unix socket with path @var{path} +@item --image-opts +Treat @var{filename} as a set of image options, instead of a plain +filename. If this flag is specified, the @var{-f} flag should +not be used, instead the '@code{format=}' option should be set. @item -f, --format=@var{fmt} Force the use of the block driver for format @var{fmt} instead of auto-detecting diff --git a/qemu-options.hx b/qemu-options.hx index 7e6762ed19..599db9474c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1051,6 +1051,7 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice, " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n" " [,disable-agent-file-xfer][,agent-mouse=[on|off]]\n" " [,playback-compression=[on|off]][,seamless-migration=[on|off]]\n" + " [,gl=[on|off]]\n" " enable spice\n" " at least one of {port, tls-port} is mandatory\n", QEMU_ARCH_ALL) @@ -1142,6 +1143,9 @@ Enable/disable audio stream compression (using celt 0.5.1). Default is on. @item seamless-migration=[on|off] Enable/disable spice seamless migration. Default is off. +@item gl=[on|off] +Enable/disable OpenGL context. Default is off. + @end table ETEXI diff --git a/qemu-tech.texi b/qemu-tech.texi index 022017d55d..bdb2285f4e 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -385,7 +385,7 @@ ops (see @code{target-i386/translate.c}). Some optimizations can be performed at this stage, including liveness analysis and trivial constant expression evaluation. TCG ops are then implemented in the host CPU back end, also known as TCG target (see -@code{tcg/i386/tcg-target.c}). For more information, please take a +@code{tcg/i386/tcg-target.inc.c}). For more information, please take a look at @code{tcg/README}. @node Condition code optimisations diff --git a/qga/vss-win32.h b/qga/vss-win32.h index 298927dfa5..4d1d15081e 100644 --- a/qga/vss-win32.h +++ b/qga/vss-win32.h @@ -13,7 +13,6 @@ #ifndef VSS_WIN32_H #define VSS_WIN32_H -#include "qapi/error.h" bool vss_init(bool init_requester); void vss_deinit(bool deinit_requester); diff --git a/qga/vss-win32/requester.h b/qga/vss-win32/requester.h index c3093cf4b6..ad2bf3df61 100644 --- a/qga/vss-win32/requester.h +++ b/qga/vss-win32/requester.h @@ -14,7 +14,6 @@ #define VSS_WIN32_REQUESTER_H #include <basetyps.h> /* STDAPI */ -#include "qemu/compiler.h" #ifdef __cplusplus extern "C" { diff --git a/qga/vss-win32/vss-common.h b/qga/vss-win32/vss-common.h index ce14e14290..91dae0c38d 100644 --- a/qga/vss-win32/vss-common.h +++ b/qga/vss-win32/vss-common.h @@ -14,7 +14,6 @@ #define VSS_WIN32_H #define __MIDL_user_allocate_free_DEFINED__ -#include "config-host.h" #include <windows.h> #include <shlwapi.h> diff --git a/qmp-commands.hx b/qmp-commands.hx index daaafe5aef..13f158d568 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2033,7 +2033,7 @@ EQMP { .name = "block_set_io_throttle", - .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,iops_size:l?,group:s?", + .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,bps_max_length:l?,bps_rd_max_length:l?,bps_wr_max_length:l?,iops_max_length:l?,iops_rd_max_length:l?,iops_wr_max_length:l?,iops_size:l?,group:s?", .mhandler.cmd_new = qmp_marshal_block_set_io_throttle, }, @@ -2052,14 +2052,20 @@ Arguments: - "iops": total I/O operations per second (json-int) - "iops_rd": read I/O operations per second (json-int) - "iops_wr": write I/O operations per second (json-int) -- "bps_max": total max in bytes (json-int) -- "bps_rd_max": read max in bytes (json-int) -- "bps_wr_max": write max in bytes (json-int) -- "iops_max": total I/O operations max (json-int) -- "iops_rd_max": read I/O operations max (json-int) -- "iops_wr_max": write I/O operations max (json-int) -- "iops_size": I/O size in bytes when limiting (json-int) -- "group": throttle group name (json-string) +- "bps_max": total throughput limit during bursts, in bytes (json-int, optional) +- "bps_rd_max": read throughput limit during bursts, in bytes (json-int, optional) +- "bps_wr_max": write throughput limit during bursts, in bytes (json-int, optional) +- "iops_max": total I/O operations per second during bursts (json-int, optional) +- "iops_rd_max": read I/O operations per second during bursts (json-int, optional) +- "iops_wr_max": write I/O operations per second during bursts (json-int, optional) +- "bps_max_length": maximum length of the @bps_max burst period, in seconds (json-int, optional) +- "bps_rd_max_length": maximum length of the @bps_rd_max burst period, in seconds (json-int, optional) +- "bps_wr_max_length": maximum length of the @bps_wr_max burst period, in seconds (json-int, optional) +- "iops_max_length": maximum length of the @iops_max burst period, in seconds (json-int, optional) +- "iops_rd_max_length": maximum length of the @iops_rd_max burst period, in seconds (json-int, optional) +- "iops_wr_max_length": maximum length of the @iops_wr_max burst period, in seconds (json-int, optional) +- "iops_size": I/O size in bytes when limiting (json-int, optional) +- "group": throttle group name (json-string, optional) Example: @@ -2076,6 +2082,7 @@ Example: "iops_max": 0, "iops_rd_max": 0, "iops_wr_max": 0, + "bps_max_length": 60, "iops_size": 0 } } <- { "return": {} } @@ -18,6 +18,7 @@ * <http://www.gnu.org/licenses/gpl-2.0.html> */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "qom/cpu.h" #include "sysemu/kvm.h" diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 77e0d292c7..5438ebdb9c 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -12,7 +12,6 @@ * */ -#include <stdio.h> enum ReplayEvents { /* for instruction event */ diff --git a/replay/replay.c b/replay/replay.c index 9cac178697..f8739c26c8 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -262,6 +262,14 @@ void replay_configure(QemuOpts *opts) const char *fname; const char *rr; ReplayMode mode = REPLAY_MODE_NONE; + Location loc; + + if (!opts) { + return; + } + + loc_push_none(&loc); + qemu_opts_loc_restore(opts); rr = qemu_opt_get(opts, "rr"); if (!rr) { @@ -283,6 +291,8 @@ void replay_configure(QemuOpts *opts) } replay_enable(fname, mode); + + loc_pop(&loc); } void replay_start(void) diff --git a/roms/SLOF b/roms/SLOF -Subproject b4c93802a5b2c72f096649c497ec9ff5708e445 +Subproject e3d05727a074619fc12d0a67f05cf2c42c875cc @@ -102,7 +102,7 @@ LD_REL := $(CC) -nostdlib -Wl,-r modules: %$(EXESUF): %.o - $(call LINK,$^) + $(call LINK,$(filter %.o %.a %.mo, $^)) %.a: $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@") diff --git a/scripts/clean-includes b/scripts/clean-includes index 1af1f824b8..a1faa60710 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -1,7 +1,8 @@ #!/bin/sh -e # # Clean up QEMU #include lines by ensuring that qemu/osdep.h -# is the first include listed. +# is the first include listed in .c files, and no headers provided +# by osdep.h itself are redundantly included in either .c or .h files. # # Copyright (c) 2015 Linaro Limited # @@ -14,14 +15,25 @@ # Usage: # clean-includes [--git subjectprefix] file ... +# or +# clean-includes [--git subjectprefix] --all # # If the --git subjectprefix option is given, then after making # the changes to the files this script will create a git commit # with the subject line "subjectprefix: Clean up includes" # and a boilerplate commit message. +# +# Using --all will cause clean-includes to run on the whole source +# tree (excluding certain directories which are known not to need +# handling). # This script requires Coccinelle to be installed. +# .c files will have the osdep.h included added, and redundant +# includes removed. +# .h files will have redundant includes (including includes of osdep.h) +# removed. +# Other files (including C++ and ObjectiveC) can't be handled by this script. # The following one-liner may be handy for finding files to run this on. # However some caution is required regarding files that might be part @@ -34,6 +46,9 @@ GIT=no +# Extended regular expression defining files to ignore when using --all +XDIRREGEX='^(tests/tcg|tests/multiboot|pc-bios|disas/libvixl)' + if [ $# -ne 0 ] && [ "$1" = "--git" ]; then if [ $# -eq 1 ]; then echo "--git option requires an argument" @@ -46,11 +61,16 @@ if [ $# -ne 0 ] && [ "$1" = "--git" ]; then fi if [ $# -eq 0 ]; then - echo "Usage: clean-includes [--git subjectprefix] foo.c ..." + echo "Usage: clean-includes [--git subjectprefix] [--all | foo.c ...]" echo "(modifies the files in place)" exit 1 fi +if [ "$1" = "--all" ]; then + # We assume there are no files in the tree with spaces in their name + set -- $(git ls-files '*.[ch]' | grep -E -v "$XDIRREGEX") +fi + # Annoyingly coccinelle won't read a scriptfile unless its # name ends '.cocci', so write it out to a tempfile with the # right kind of name. @@ -73,13 +93,49 @@ EOT for f in "$@"; do - # First, use coccinelle to add qemu/osdep.h before the first existing include - # (this will add two lines if the file uses both "..." and <...> #includes, - # but we will remove the extras in the next step) - spatch --in-place --no-show-diff --cocci-file "$COCCIFILE" "$f" - - # Now remove any duplicate osdep.h includes - perl -n -i -e 'print if !/#include "qemu\/osdep.h"/ || !$n++;' "$f" + case "$f" in + *.inc.c) + # These aren't standalone C source files + echo "SKIPPING $f (not a standalone source file)" + continue + ;; + *.c) + MODE=c + ;; + *include/qemu/osdep.h | \ + *include/qemu/compiler.h | \ + *include/config.h | \ + *include/standard-headers/ ) + # Removing include lines from osdep.h itself would be counterproductive. + echo "SKIPPING $f (special case header)" + continue + ;; + *include/standard-headers/*) + echo "SKIPPING $f (autogenerated header)" + continue + ;; + *.h) + MODE=h + ;; + *) + echo "WARNING: ignoring $f (cannot handle non-C files)" + continue + ;; + esac + + if [ "$MODE" = "c" ]; then + # First, use Coccinelle to add qemu/osdep.h before the first existing include + # (this will add two lines if the file uses both "..." and <...> #includes, + # but we will remove the extras in the next step) + spatch --in-place --no-show-diff --cocci-file "$COCCIFILE" "$f" + + # Now remove any duplicate osdep.h includes + perl -n -i -e 'print if !/#include "qemu\/osdep.h"/ || !$n++;' "$f" + else + # Remove includes of osdep.h itself + perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || + ! (grep { $_ eq $1 } qw ("qemu/osdep.h"))' "$f" + fi # Remove includes that osdep.h already provides perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 7b0dca8c72..eac90d2fe9 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -2,7 +2,7 @@ # QAPI types generator # # Copyright IBM, Corp. 2011 -# Copyright (c) 2013-2015 Red Hat Inc. +# Copyright (c) 2013-2016 Red Hat Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> @@ -14,6 +14,11 @@ from qapi import * +# variants must be emitted before their container; track what has already +# been output +objects_seen = set() + + def gen_fwd_object_or_array(name): return mcgen(''' @@ -26,11 +31,8 @@ def gen_array(name, element_type): return mcgen(''' struct %(c_name)s { - union { - %(c_type)s value; - uint64_t padding; - }; %(c_name)s *next; + %(c_type)s value; }; ''', c_name=c_name(name), c_type=element_type.c_type()) @@ -52,11 +54,23 @@ def gen_struct_fields(members): def gen_object(name, base, members, variants): - ret = mcgen(''' + if name in objects_seen: + return '' + objects_seen.add(name) + + ret = '' + if variants: + for v in variants.variants: + if (isinstance(v.type, QAPISchemaObjectType) and + not v.type.is_implicit()): + ret += gen_object(v.type.name, v.type.base, + v.type.local_members, v.type.variants) + + ret += mcgen(''' struct %(c_name)s { ''', - c_name=c_name(name)) + c_name=c_name(name)) if base: ret += mcgen(''' @@ -118,11 +132,12 @@ def gen_variants(variants): for var in variants.variants: # Ugly special case for simple union TODO get rid of it - typ = var.simple_union_type() or var.type + simple_union_type = var.simple_union_type() + typ = simple_union_type or var.type ret += mcgen(''' %(c_type)s %(c_name)s; ''', - c_type=typ.c_type(), + c_type=typ.c_type(is_unboxed=not simple_union_type), c_name=c_name(var.name)) ret += mcgen(''' diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 0cc9b08b14..2308268a62 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,10 +15,6 @@ from qapi import * import re -# visit_type_FOO_implicit() is emitted as needed; track if it has already -# been output. -implicit_structs_seen = set() - # visit_type_FOO_fields() is always emitted; track if a forward declaration # or implementation has already been output. struct_fields_seen = set() @@ -35,52 +31,31 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error ** def gen_visit_fields_decl(typ): - ret = '' - if typ.name not in struct_fields_seen: - ret += mcgen(''' - -static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp); -''', - c_type=typ.c_name()) - struct_fields_seen.add(typ.name) - return ret - - -def gen_visit_implicit_struct(typ): - if typ in implicit_structs_seen: + if typ.name in struct_fields_seen: return '' - implicit_structs_seen.add(typ) - - ret = gen_visit_fields_decl(typ) - - ret += mcgen(''' - -static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp) -{ - Error *err = NULL; + struct_fields_seen.add(typ.name) + return mcgen(''' - visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err); - if (!err) { - visit_type_%(c_type)s_fields(v, obj, errp); - visit_end_implicit_struct(v); - } - error_propagate(errp, err); -} +static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp); ''', c_type=typ.c_name()) - return ret -def gen_visit_struct_fields(name, base, members): +def gen_visit_struct_fields(name, base, members, variants): ret = '' if base: ret += gen_visit_fields_decl(base) + if variants: + for var in variants.variants: + # Ugly special case for simple union TODO get rid of it + if not var.simple_union_type(): + ret += gen_visit_fields_decl(var.type) struct_fields_seen.add(name) ret += mcgen(''' -static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp) +static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp) { Error *err = NULL; @@ -89,57 +64,61 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e if base: ret += mcgen(''' - visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err); + visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err); ''', c_type=base.c_name()) ret += gen_err_check() - ret += gen_visit_fields(members, prefix='(*obj)->') + ret += gen_visit_fields(members, prefix='obj->') - # 'goto out' produced for base, and by gen_visit_fields() for each member - if base or members: + if variants: ret += mcgen(''' + switch (obj->%(c_name)s) { +''', + c_name=c_name(variants.tag_member.name)) -out: -''') - ret += mcgen(''' - error_propagate(errp, err); -} + for var in variants.variants: + # TODO ugly special case for simple union + simple_union_type = var.simple_union_type() + ret += mcgen(''' + case %(case)s: +''', + case=c_enum_const(variants.tag_member.type.name, + var.name, + variants.tag_member.type.prefix)) + if simple_union_type: + ret += mcgen(''' + visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err); +''', + c_type=simple_union_type.c_name(), + c_name=c_name(var.name)) + else: + ret += mcgen(''' + visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err); +''', + c_type=var.type.c_name(), + c_name=c_name(var.name)) + ret += mcgen(''' + break; ''') - return ret - -def gen_visit_struct(name, base, members): - ret = gen_visit_struct_fields(name, base, members) - - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to - # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj - # rather than leaving it non-NULL. As currently written, the caller must - # call qapi_free_FOO() to avoid a memory leak of the partial FOO. - ret += mcgen(''' + ret += mcgen(''' + default: + abort(); + } +''') -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) -{ - Error *err = NULL; + # 'goto out' produced for base, by gen_visit_fields() for each member, + # and if variants were present + if base or members or variants: + ret += mcgen(''' - visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err); - if (err) { - goto out; - } - if (!*obj) { - goto out_obj; - } - visit_type_%(c_name)s_fields(v, obj, &err); - error_propagate(errp, err); - err = NULL; -out_obj: - visit_end_struct(v, &err); out: +''') + ret += mcgen(''' error_propagate(errp, err); } -''', - c_name=c_name(name)) - +''') return ret @@ -161,7 +140,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error } for (prev = (GenericList **)obj; - !err && (i = visit_next_list(v, prev)) != NULL; + !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL; prev = &i) { %(c_name)s *native_i = (%(c_name)s *)i; visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err); @@ -190,45 +169,62 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error def gen_visit_alternate(name, variants): promote_int = 'true' + ret = '' for var in variants.variants: if var.type.alternate_qtype() == 'QTYPE_QINT': promote_int = 'false' + if isinstance(var.type, QAPISchemaObjectType): + ret += gen_visit_fields_decl(var.type) - ret = mcgen(''' + ret += mcgen(''' void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { Error *err = NULL; - visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err); + visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj), + %(promote_int)s, &err); if (err) { goto out; } - visit_get_next_type(v, name, &(*obj)->type, %(promote_int)s, &err); - if (err) { - goto out_obj; - } switch ((*obj)->type) { ''', - c_name=c_name(name), promote_int=promote_int) + c_name=c_name(name), promote_int=promote_int) for var in variants.variants: ret += mcgen(''' case %(case)s: +''', + case=var.type.alternate_qtype()) + if isinstance(var.type, QAPISchemaObjectType): + ret += mcgen(''' + visit_start_struct(v, name, NULL, 0, &err); + if (err) { + break; + } + visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err); + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +''', + c_type=var.type.c_name(), + c_name=c_name(var.name)) + else: + ret += mcgen(''' visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err); - break; ''', - case=var.type.alternate_qtype(), - c_type=var.type.c_name(), - c_name=c_name(var.name)) + c_type=var.type.c_name(), + c_name=c_name(var.name)) + ret += mcgen(''' + break; +''') ret += mcgen(''' default: error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "%(name)s"); } -out_obj: - visit_end_implicit_struct(v); + visit_end_alternate(v); out: error_propagate(errp, err); } @@ -238,17 +234,13 @@ out: return ret -def gen_visit_union(name, base, variants): - ret = '' - - if base: - ret += gen_visit_fields_decl(base) - - for var in variants.variants: - # Ugly special case for simple union TODO get rid of it - if not var.simple_union_type(): - ret += gen_visit_implicit_struct(var.type) +def gen_visit_object(name, base, members, variants): + ret = gen_visit_struct_fields(name, base, members, variants) + # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to + # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj + # rather than leaving it non-NULL. As currently written, the caller must + # call qapi_free_FOO() to avoid a memory leak of the partial FOO. ret += mcgen(''' void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) @@ -262,66 +254,16 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { goto out_obj; } -''', - c_name=c_name(name)) - - if base: - ret += mcgen(''' - visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err); -''', - c_name=base.c_name()) - else: - ret += mcgen(''' - visit_type_%(c_type)s(v, "%(name)s", &(*obj)->%(c_name)s, &err); -''', - c_type=variants.tag_member.type.c_name(), - c_name=c_name(variants.tag_member.name), - name=variants.tag_member.name) - ret += gen_err_check(label='out_obj') - ret += mcgen(''' - if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) { - goto out_obj; - } - switch ((*obj)->%(c_name)s) { -''', - c_name=c_name(variants.tag_member.name)) - - for var in variants.variants: - # TODO ugly special case for simple union - simple_union_type = var.simple_union_type() - ret += mcgen(''' - case %(case)s: -''', - case=c_enum_const(variants.tag_member.type.name, - var.name)) - if simple_union_type: - ret += mcgen(''' - visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err); -''', - c_type=simple_union_type.c_name(), - c_name=c_name(var.name)) - else: - ret += mcgen(''' - visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err); -''', - c_type=var.type.c_name(), - c_name=c_name(var.name)) - ret += mcgen(''' - break; -''') - - ret += mcgen(''' - default: - abort(); - } -out_obj: + visit_type_%(c_name)s_fields(v, *obj, &err); error_propagate(errp, err); err = NULL; +out_obj: visit_end_struct(v, &err); out: error_propagate(errp, err); } -''') +''', + c_name=c_name(name)) return ret @@ -375,14 +317,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): def visit_object_type(self, name, info, base, members, variants): self.decl += gen_visit_decl(name) - if variants: - if members: - # Members other than variants.tag_member not implemented - assert len(members) == 1 - assert members[0] == variants.tag_member - self.defn += gen_visit_union(name, base, variants) - else: - self.defn += gen_visit_struct(name, base, members) + self.defn += gen_visit_object(name, base, members, variants) def visit_alternate_type(self, name, info, variants): self.decl += gen_visit_decl(name) diff --git a/scripts/qapi.py b/scripts/qapi.py index f40dc9e777..8497777d94 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -590,7 +590,10 @@ def check_union(expr, expr_info): "Discriminator '%s' must be of enumeration " "type" % discriminator) - # Check every branch + # Check every branch; don't allow an empty union + if len(members) == 0: + raise QAPIExprError(expr_info, + "Union '%s' cannot have empty 'data'" % name) for (key, value) in members.items(): check_name(expr_info, "Member of union '%s'" % name, key) @@ -613,7 +616,11 @@ def check_alternate(expr, expr_info): members = expr['data'] types_seen = {} - # Check every branch + # Check every branch; require at least two branches + if len(members) < 2: + raise QAPIExprError(expr_info, + "Alternate '%s' should have at least two branches " + "in 'data'" % name) for (key, value) in members.items(): check_name(expr_info, "Member of alternate '%s'" % name, key) @@ -622,7 +629,10 @@ def check_alternate(expr, expr_info): value, allow_metas=['built-in', 'union', 'struct', 'enum']) qtype = find_alternate_member_qtype(value) - assert qtype + if not qtype: + raise QAPIExprError(expr_info, + "Alternate '%s' member '%s' cannot use " + "type '%s'" % (name, key, value)) if qtype in types_seen: raise QAPIExprError(expr_info, "Alternate '%s' member '%s' can't " @@ -814,7 +824,7 @@ class QAPISchemaVisitor(object): class QAPISchemaType(QAPISchemaEntity): - def c_type(self, is_param=False): + def c_type(self, is_param=False, is_unboxed=False): return c_name(self.name) + pointer_suffix def c_null(self): @@ -847,7 +857,7 @@ class QAPISchemaBuiltinType(QAPISchemaType): def c_name(self): return self.name - def c_type(self, is_param=False): + def c_type(self, is_param=False, is_unboxed=False): if is_param and self.name == 'str': return 'const ' + self._c_type_name return self._c_type_name @@ -881,7 +891,7 @@ class QAPISchemaEnumType(QAPISchemaType): # See QAPISchema._make_implicit_enum_type() return self.name.endswith('Kind') - def c_type(self, is_param=False): + def c_type(self, is_param=False, is_unboxed=False): return c_name(self.name) def member_names(self): @@ -977,9 +987,11 @@ class QAPISchemaObjectType(QAPISchemaType): assert not self.is_implicit() return QAPISchemaType.c_name(self) - def c_type(self, is_param=False): + def c_type(self, is_param=False, is_unboxed=False): assert not self.is_implicit() - return QAPISchemaType.c_type(self) + if is_unboxed: + return c_name(self.name) + return c_name(self.name) + pointer_suffix def json_type(self): return 'object' @@ -1059,6 +1071,7 @@ class QAPISchemaObjectTypeVariants(object): assert bool(tag_member) != bool(tag_name) assert (isinstance(tag_name, str) or isinstance(tag_member, QAPISchemaObjectTypeMember)) + assert len(variants) > 0 for v in variants: assert isinstance(v, QAPISchemaObjectTypeVariant) self.tag_name = tag_name diff --git a/scripts/tracetool/format/ust_events_c.py b/scripts/tracetool/format/ust_events_c.py index bc970936be..9967c7a82e 100644 --- a/scripts/tracetool/format/ust_events_c.py +++ b/scripts/tracetool/format/ust_events_c.py @@ -22,6 +22,8 @@ def generate(events, backend): out('/* This file is autogenerated by tracetool, do not edit. */', '', + '#include "qemu/osdep.h"', + '', '#define TRACEPOINT_DEFINE', '#define TRACEPOINT_CREATE_PROBES', '', diff --git a/slirp/slirp.h b/slirp/slirp.h index 239fe2917a..07c13b4725 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -1,11 +1,9 @@ #ifndef __COMMON_H__ #define __COMMON_H__ -#include "config-host.h" #include "slirp_config.h" #ifdef _WIN32 -# include <inttypes.h> typedef char *caddr_t; @@ -23,43 +21,31 @@ typedef char *caddr_t; # endif #endif -#include <sys/types.h> #ifdef HAVE_SYS_BITYPES_H # include <sys/bitypes.h> #endif -#include <sys/time.h> #ifdef HAVE_UNISTD_H -# include <unistd.h> #endif #ifdef HAVE_STDLIB_H -# include <stdlib.h> #endif -#include <stdio.h> -#include <errno.h> #ifndef HAVE_MEMMOVE #define memmove(x, y, z) bcopy(y, x, z) #endif #if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> #else # ifdef HAVE_SYS_TIME_H -# include <sys/time.h> # else -# include <time.h> # endif #endif #ifdef HAVE_STRING_H -# include <string.h> #else -# include <strings.h> #endif #ifndef _WIN32 @@ -82,11 +68,9 @@ void *malloc(size_t arg); void free(void *ptr); #endif -#include <fcntl.h> #ifndef NO_UNIX_SOCKETS #include <sys/un.h> #endif -#include <signal.h> #ifdef HAVE_SYS_SIGNAL_H # include <sys/signal.h> #endif @@ -115,12 +99,10 @@ void free(void *ptr); #endif #ifdef __STDC__ -#include <stdarg.h> #else #include <varargs.h> #endif -#include <sys/stat.h> /* Avoid conflicting with the libc insque() and remque(), which have different prototypes. */ diff --git a/stubs/qmp_pc_dimm_device_list.c b/stubs/qmp_pc_dimm_device_list.c index a4af7fe473..def211564d 100644 --- a/stubs/qmp_pc_dimm_device_list.c +++ b/stubs/qmp_pc_dimm_device_list.c @@ -6,8 +6,3 @@ 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-alpha/cpu.h b/target-alpha/cpu.h index bcd8076abb..420f2a53fe 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -20,7 +20,6 @@ #if !defined (__CPU_ALPHA_H__) #define __CPU_ALPHA_H__ -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 64 diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 16238216f4..3cbda73578 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -19,7 +19,6 @@ #ifndef CPU_ARM_H #define CPU_ARM_H -#include "config.h" #include "kvm-consts.h" diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h index 943bf8980a..a2c9518592 100644 --- a/target-arm/kvm-consts.h +++ b/target-arm/kvm-consts.h @@ -15,7 +15,6 @@ #define ARM_KVM_CONSTS_H #ifdef CONFIG_KVM -#include "qemu/compiler.h" #include <linux/kvm.h> #include <linux/psci.h> diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 32204607ca..415cf91436 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -20,7 +20,6 @@ #ifndef CPU_CRIS_H #define CPU_CRIS_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 32 diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 5f9d960b25..cb750176c0 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -22,7 +22,6 @@ #include "qom/cpu.h" #include "cpu.h" -#include "qapi/error.h" #include "qemu/notify.h" #ifdef TARGET_X86_64 diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 912a376b82..0f38d1eae3 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -16,10 +16,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <inttypes.h> +#include "qemu/osdep.h" #include "cpu.h" #include "sysemu/kvm.h" diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 03c00d55a3..5148c8252d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -19,7 +19,6 @@ #ifndef CPU_I386_H #define CPU_I386_H -#include "config.h" #include "qemu-common.h" #include "standard-headers/asm-x86/hyperv.h" diff --git a/target-i386/mpx_helper.c b/target-i386/mpx_helper.c index 8c6c2e7227..4d1785ecef 100644 --- a/target-i386/mpx_helper.c +++ b/target-i386/mpx_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 2b7620c7da..f220fc0bb9 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -24,7 +24,6 @@ #define CPUArchState struct CPULM32State -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" struct CPULM32State; diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 224c16967c..48b4c872fc 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -24,7 +24,6 @@ #define CPUArchState struct CPUM68KState -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 6b212ab7f0..2f7335eaa7 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -19,7 +19,6 @@ #ifndef CPU_MICROBLAZE_H #define CPU_MICROBLAZE_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 32 diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 17817c3c57..bd23c2a054 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -7,7 +7,6 @@ #define CPUArchState struct CPUMIPSState -#include "config.h" #include "qemu-common.h" #include "mips-defs.h" #include "exec/cpu-defs.h" @@ -19,19 +18,19 @@ typedef struct r4k_tlb_t r4k_tlb_t; struct r4k_tlb_t { target_ulong VPN; uint32_t PageMask; - uint_fast8_t ASID; - uint_fast16_t G:1; - uint_fast16_t C0:3; - uint_fast16_t C1:3; - uint_fast16_t V0:1; - uint_fast16_t V1:1; - uint_fast16_t D0:1; - uint_fast16_t D1:1; - uint_fast16_t XI0:1; - uint_fast16_t XI1:1; - uint_fast16_t RI0:1; - uint_fast16_t RI1:1; - uint_fast16_t EHINV:1; + uint8_t ASID; + unsigned int G:1; + unsigned int C0:3; + unsigned int C1:3; + unsigned int V0:1; + unsigned int V1:1; + unsigned int D0:1; + unsigned int D1:1; + unsigned int XI0:1; + unsigned int XI1:1; + unsigned int RI0:1; + unsigned int RI1:1; + unsigned int EHINV:1; uint64_t PFN[2]; }; diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h index a612744011..4ee207796c 100644 --- a/target-moxie/cpu.h +++ b/target-moxie/cpu.h @@ -19,7 +19,6 @@ #ifndef _CPU_MOXIE_H #define _CPU_MOXIE_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 32 diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index eb71607395..4b63f25804 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -27,7 +27,6 @@ /* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */ struct OpenRISCCPU; -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" #include "fpu/softfloat.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 892f4dc949..2b10597fa9 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -19,7 +19,6 @@ #if !defined (__CPU_PPC_H__) #define __CPU_PPC_H__ -#include "config.h" #include "qemu-common.h" //#define PPC_EMULATE_32BITS_HYPV diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 70ca29637f..d67c169ba3 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -23,6 +23,7 @@ #include <linux/kvm.h> #include "qemu-common.h" +#include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" @@ -512,6 +513,10 @@ int kvm_arch_init_vcpu(CPUState *cs) /* Synchronize sregs with kvm */ ret = kvm_arch_sync_sregs(cpu); if (ret) { + if (ret == -EINVAL) { + error_report("Register sync failed... If you're using kvm-hv.ko," + " only \"-cpu host\" is possible"); + } return ret; } @@ -1993,7 +1998,8 @@ void kvmppc_set_papr(PowerPCCPU *cpu) ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0); if (ret) { - cpu_abort(cs, "This KVM version does not support PAPR\n"); + error_report("This vCPU type or KVM version does not support PAPR"); + exit(1); } /* Update the capability flag so we sync the right information @@ -2013,7 +2019,8 @@ void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_EPR, 0, mpic_proxy); if (ret && mpic_proxy) { - cpu_abort(cs, "This KVM version does not support EPR\n"); + error_report("This KVM version does not support EPR"); + exit(1); } } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index aaa828c055..fd64c44f4d 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -249,15 +249,47 @@ static inline int kvmppc_enable_hwrng(void) #endif #ifndef CONFIG_KVM + #define kvmppc_eieio() do { } while (0) -#else + +static inline void kvmppc_dcbst_range(PowerPCCPU *cpu, uint8_t *addr, int len) +{ +} + +static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len) +{ +} + +#else /* CONFIG_KVM */ + #define kvmppc_eieio() \ do { \ if (kvm_enabled()) { \ asm volatile("eieio" : : : "memory"); \ } \ } while (0) -#endif + +/* Store data cache blocks back to memory */ +static inline void kvmppc_dcbst_range(PowerPCCPU *cpu, uint8_t *addr, int len) +{ + uint8_t *p; + + for (p = addr; p < addr + len; p += cpu->env.dcache_line_size) { + asm volatile("dcbst 0,%0" : : "r"(p) : "memory"); + } +} + +/* Invalidate instruction cache blocks */ +static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len) +{ + uint8_t *p; + + for (p = addr; p < addr + len; p += cpu->env.icache_line_size) { + asm volatile("icbi 0,%0" : : "r"(p)); + } +} + +#endif /* CONFIG_KVM */ #ifndef KVM_INTERRUPT_SET #define KVM_INTERRUPT_SET -1 diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 06ca60b25f..6ae5699e0b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -22,7 +22,6 @@ #ifndef CPU_S390X_H #define CPU_S390X_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 64 diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 5b022c5973..3b23e967bb 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -19,7 +19,6 @@ #ifndef _CPU_SH4_H #define _CPU_SH4_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 32 diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 58ff4743b4..dc46122758 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -1,7 +1,6 @@ #ifndef CPU_SPARC_H #define CPU_SPARC_H -#include "config.h" #include "qemu-common.h" #include "qemu/bswap.h" diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 536c4b50d5..00d61ee16a 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -43,7 +43,8 @@ static TCGv_ptr cpu_env, cpu_regwptr; static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst; static TCGv_i32 cpu_cc_op; static TCGv_i32 cpu_psr; -static TCGv cpu_fsr, cpu_pc, cpu_npc, cpu_gregs[8]; +static TCGv cpu_fsr, cpu_pc, cpu_npc; +static TCGv cpu_regs[32]; static TCGv cpu_y; #ifndef CONFIG_USER_ONLY static TCGv cpu_tbr; @@ -273,36 +274,31 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr) static inline TCGv gen_load_gpr(DisasContext *dc, int reg) { - if (reg == 0 || reg >= 8) { + if (reg > 0) { + assert(reg < 32); + return cpu_regs[reg]; + } else { TCGv t = get_temp_tl(dc); - if (reg == 0) { - tcg_gen_movi_tl(t, 0); - } else { - tcg_gen_ld_tl(t, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } + tcg_gen_movi_tl(t, 0); return t; - } else { - return cpu_gregs[reg]; } } static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v) { if (reg > 0) { - if (reg < 8) { - tcg_gen_mov_tl(cpu_gregs[reg], v); - } else { - tcg_gen_st_tl(v, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } + assert(reg < 32); + tcg_gen_mov_tl(cpu_regs[reg], v); } } static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) { - if (reg == 0 || reg >= 8) { - return get_temp_tl(dc); + if (reg > 0) { + assert(reg < 32); + return cpu_regs[reg]; } else { - return cpu_gregs[reg]; + return get_temp_tl(dc); } } @@ -2158,9 +2154,13 @@ static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); - t = gen_dest_gpr(dc, rd + 1); + /* ??? Work around an apparent bug in Ubuntu gcc 4.8.2-10ubuntu2+12, + whereby "rd + 1" elicits "error: array subscript is above array". + Since we have already asserted that rd is even, the semantics + are unchanged. */ + t = gen_dest_gpr(dc, rd | 1); tcg_gen_trunc_i64_tl(t, t64); - gen_store_gpr(dc, rd + 1, t); + gen_store_gpr(dc, rd | 1, t); tcg_gen_shri_i64(t64, t64, 32); tcg_gen_trunc_i64_tl(hi, t64); @@ -5329,106 +5329,98 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) void gen_intermediate_code_init(CPUSPARCState *env) { - unsigned int i; static int inited; - static const char * const gregnames[8] = { - NULL, // g0 not used - "g1", - "g2", - "g3", - "g4", - "g5", - "g6", - "g7", + static const char gregnames[32][4] = { + "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", }; - static const char * const fregnames[32] = { + static const char fregnames[32][4] = { "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14", "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30", "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", }; - /* init various static tables */ - if (!inited) { - inited = 1; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - cpu_regwptr = tcg_global_mem_new_ptr(cpu_env, - offsetof(CPUSPARCState, regwptr), - "regwptr"); + static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = { #ifdef TARGET_SPARC64 - cpu_xcc = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, xcc), - "xcc"); - cpu_asi = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, asi), - "asi"); - cpu_fprs = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSPARCState, fprs), - "fprs"); - cpu_gsr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, gsr), - "gsr"); - cpu_tick_cmpr = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, tick_cmpr), - "tick_cmpr"); - cpu_stick_cmpr = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, stick_cmpr), - "stick_cmpr"); - cpu_hstick_cmpr = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, hstick_cmpr), - "hstick_cmpr"); - cpu_hintp = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, hintp), - "hintp"); - cpu_htba = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, htba), - "htba"); - cpu_hver = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, hver), - "hver"); - cpu_ssr = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, ssr), "ssr"); - cpu_ver = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, version), "ver"); - cpu_softint = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSPARCState, softint), - "softint"); + { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" }, + { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" }, + { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" }, + { &cpu_softint, offsetof(CPUSPARCState, softint), "softint" }, #else - cpu_wim = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, wim), - "wim"); + { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" }, #endif - cpu_cond = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, cond), - "cond"); - cpu_cc_src = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, cc_src), - "cc_src"); - cpu_cc_src2 = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, cc_src2), - "cc_src2"); - cpu_cc_dst = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, cc_dst), - "cc_dst"); - cpu_cc_op = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSPARCState, cc_op), - "cc_op"); - cpu_psr = tcg_global_mem_new_i32(cpu_env, offsetof(CPUSPARCState, psr), - "psr"); - cpu_fsr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, fsr), - "fsr"); - cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, pc), - "pc"); - cpu_npc = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, npc), - "npc"); - cpu_y = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, y), "y"); + { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" }, + { &cpu_psr, offsetof(CPUSPARCState, psr), "psr" }, + }; + + static const struct { TCGv *ptr; int off; const char *name; } rtl[] = { +#ifdef TARGET_SPARC64 + { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" }, + { &cpu_tick_cmpr, offsetof(CPUSPARCState, tick_cmpr), "tick_cmpr" }, + { &cpu_stick_cmpr, offsetof(CPUSPARCState, stick_cmpr), "stick_cmpr" }, + { &cpu_hstick_cmpr, offsetof(CPUSPARCState, hstick_cmpr), + "hstick_cmpr" }, + { &cpu_hintp, offsetof(CPUSPARCState, hintp), "hintp" }, + { &cpu_htba, offsetof(CPUSPARCState, htba), "htba" }, + { &cpu_hver, offsetof(CPUSPARCState, hver), "hver" }, + { &cpu_ssr, offsetof(CPUSPARCState, ssr), "ssr" }, + { &cpu_ver, offsetof(CPUSPARCState, version), "ver" }, +#endif + { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" }, + { &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" }, + { &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" }, + { &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" }, + { &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" }, + { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" }, + { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" }, + { &cpu_y, offsetof(CPUSPARCState, y), "y" }, #ifndef CONFIG_USER_ONLY - cpu_tbr = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, tbr), - "tbr"); + { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" }, #endif - for (i = 1; i < 8; i++) { - cpu_gregs[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUSPARCState, gregs[i]), - gregnames[i]); - } - for (i = 0; i < TARGET_DPREGS; i++) { - cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUSPARCState, fpr[i]), - fregnames[i]); - } + }; + + unsigned int i; + + /* init various static tables */ + if (inited) { + return; + } + inited = 1; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + cpu_regwptr = tcg_global_mem_new_ptr(cpu_env, + offsetof(CPUSPARCState, regwptr), + "regwptr"); + + for (i = 0; i < ARRAY_SIZE(r32); ++i) { + *r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name); + } + + for (i = 0; i < ARRAY_SIZE(rtl); ++i) { + *rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name); + } + + TCGV_UNUSED(cpu_regs[0]); + for (i = 1; i < 8; ++i) { + cpu_regs[i] = tcg_global_mem_new(cpu_env, + offsetof(CPUSPARCState, gregs[i]), + gregnames[i]); + } + + for (i = 8; i < 32; ++i) { + cpu_regs[i] = tcg_global_mem_new(cpu_regwptr, + (i - 8) * sizeof(target_ulong), + gregnames[i]); + } + + for (i = 0; i < TARGET_DPREGS; i++) { + cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUSPARCState, fpr[i]), + fregnames[i]); } } diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h index 03df107a67..022cad186a 100644 --- a/target-tilegx/cpu.h +++ b/target-tilegx/cpu.h @@ -19,7 +19,6 @@ #ifndef CPU_TILEGX_H #define CPU_TILEGX_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 64 diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h index 20a12f3a40..5fee376674 100644 --- a/target-tricore/cpu.h +++ b/target-tricore/cpu.h @@ -20,7 +20,6 @@ #define __TRICORE_CPU_H__ #include "tricore-defs.h" -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" #include "fpu/softfloat.h" @@ -271,6 +270,7 @@ enum { TRAPC_ASSERT = 5, TRAPC_SYSCALL = 6, TRAPC_NMI = 7, + TRAPC_IRQ = 8 }; /* Class 0 TIN */ diff --git a/target-tricore/helper.c b/target-tricore/helper.c index a8fd418b42..7d96daddb1 100644 --- a/target-tricore/helper.c +++ b/target-tricore/helper.c @@ -127,9 +127,9 @@ uint32_t psw_read(CPUTriCoreState *env) void psw_write(CPUTriCoreState *env, uint32_t val) { env->PSW_USB_C = (val & MASK_USB_C); - env->PSW_USB_V = (val & MASK_USB_V << 1); - env->PSW_USB_SV = (val & MASK_USB_SV << 2); - env->PSW_USB_AV = ((val & MASK_USB_AV) << 3); - env->PSW_USB_SAV = ((val & MASK_USB_SAV) << 4); + env->PSW_USB_V = (val & MASK_USB_V) << 1; + env->PSW_USB_SV = (val & MASK_USB_SV) << 2; + env->PSW_USB_AV = (val & MASK_USB_AV) << 3; + env->PSW_USB_SAV = (val & MASK_USB_SAV) << 4; env->PSW = val; } diff --git a/target-tricore/helper.h b/target-tricore/helper.h index cc221f1a9b..2c8ed78940 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -132,6 +132,7 @@ DEF_HELPER_2(lducx, void, env, i32) DEF_HELPER_2(stlcx, void, env, i32) DEF_HELPER_2(stucx, void, env, i32) DEF_HELPER_1(svlcx, void, env) +DEF_HELPER_1(svucx, void, env) DEF_HELPER_1(rslcx, void, env) /* Address mode helper */ DEF_HELPER_1(br_update, i32, i32) @@ -139,3 +140,5 @@ DEF_HELPER_2(circ_update, i32, i32, i32) /* PSW cache helper */ DEF_HELPER_2(psw_write, void, env, i32) DEF_HELPER_1(psw_read, i32, env) +/* Exceptions */ +DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 3aa6326edd..55f6724da8 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -21,6 +21,93 @@ #include "exec/cpu_ldst.h" #include <zlib.h> /* for crc32 */ + +/* Exception helpers */ + +static void QEMU_NORETURN +raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin, + uintptr_t pc, uint32_t fcd_pc) +{ + CPUState *cs = CPU(tricore_env_get_cpu(env)); + /* in case we come from a helper-call we need to restore the PC */ + if (pc) { + cpu_restore_state(cs, pc); + } + + /* Tin is loaded into d[15] */ + env->gpr_d[15] = tin; + + if (class == TRAPC_CTX_MNG && tin == TIN3_FCU) { + /* upper context cannot be saved, if the context list is empty */ + } else { + helper_svucx(env); + } + + /* The return address in a[11] is updated */ + if (class == TRAPC_CTX_MNG && tin == TIN3_FCD) { + env->SYSCON |= MASK_SYSCON_FCD_SF; + /* when we run out of CSAs after saving a context a FCD trap is taken + and the return address is the start of the trap handler which used + the last CSA */ + env->gpr_a[11] = fcd_pc; + } else if (class == TRAPC_SYSCALL) { + env->gpr_a[11] = env->PC + 4; + } else { + env->gpr_a[11] = env->PC; + } + /* The stack pointer in A[10] is set to the Interrupt Stack Pointer (ISP) + when the processor was not previously using the interrupt stack + (in case of PSW.IS = 0). The stack pointer bit is set for using the + interrupt stack: PSW.IS = 1. */ + if ((env->PSW & MASK_PSW_IS) == 0) { + env->gpr_a[10] = env->ISP; + } + env->PSW |= MASK_PSW_IS; + /* The I/O mode is set to Supervisor mode, which means all permissions + are enabled: PSW.IO = 10 B .*/ + env->PSW |= (2 << 10); + + /*The current Protection Register Set is set to 0: PSW.PRS = 00 B .*/ + env->PSW &= ~MASK_PSW_PRS; + + /* The Call Depth Counter (CDC) is cleared, and the call depth limit is + set for 64: PSW.CDC = 0000000 B .*/ + env->PSW &= ~MASK_PSW_CDC; + + /* Call Depth Counter is enabled, PSW.CDE = 1. */ + env->PSW |= MASK_PSW_CDE; + + /* Write permission to global registers A[0], A[1], A[8], A[9] is + disabled: PSW.GW = 0. */ + env->PSW &= ~MASK_PSW_GW; + + /*The interrupt system is globally disabled: ICR.IE = 0. The ‘old’ + ICR.IE and ICR.CCPN are saved */ + + /* PCXI.PIE = ICR.IE */ + env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) + + ((env->ICR & MASK_ICR_IE) << 15)); + /* PCXI.PCPN = ICR.CCPN */ + env->PCXI = (env->PCXI & 0xffffff) + + ((env->ICR & MASK_ICR_CCPN) << 24); + /* Update PC using the trap vector table */ + env->PC = env->BTV | (class << 5); + + cpu_loop_exit(cs); +} + +void helper_raise_exception_sync(CPUTriCoreState *env, uint32_t class, + uint32_t tin) +{ + raise_exception_sync_internal(env, class, tin, 0, 0); +} + +static void raise_exception_sync_helper(CPUTriCoreState *env, uint32_t class, + uint32_t tin, uintptr_t pc) +{ + raise_exception_sync_internal(env, class, tin, pc, 0); +} + /* Addressing mode helper */ static uint16_t reverse16(uint16_t val) @@ -2279,7 +2366,7 @@ static bool cdc_zero(target_ulong *psw) static void save_context_upper(CPUTriCoreState *env, int ea) { cpu_stl_data(env, ea, env->PCXI); - cpu_stl_data(env, ea+4, env->PSW); + cpu_stl_data(env, ea+4, psw_read(env)); cpu_stl_data(env, ea+8, env->gpr_a[10]); cpu_stl_data(env, ea+12, env->gpr_a[11]); cpu_stl_data(env, ea+16, env->gpr_d[8]); @@ -2369,11 +2456,13 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc) /* if (FCX == 0) trap(FCU); */ if (env->FCX == 0) { /* FCU trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCU, GETPC()); } /* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */ if (psw & MASK_PSW_CDE) { if (cdc_increment(&psw)) { /* CDO trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CDO, GETPC()); } } /* PSW.CDE = 1;*/ @@ -2409,6 +2498,7 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc) /* if (tmp_FCX == LCX) trap(FCD);*/ if (tmp_FCX == env->LCX) { /* FCD trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCD, GETPC()); } psw_write(env, psw); } @@ -2421,18 +2511,25 @@ void helper_ret(CPUTriCoreState *env) psw = psw_read(env); /* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/ - if (env->PSW & MASK_PSW_CDE) { - if (cdc_decrement(&(env->PSW))) { + if (psw & MASK_PSW_CDE) { + if (cdc_decrement(&psw)) { /* CDU trap */ + psw_write(env, psw); + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CDU, GETPC()); } } /* if (PCXI[19: 0] == 0) then trap(CSU); */ if ((env->PCXI & 0xfffff) == 0) { /* CSU trap */ + psw_write(env, psw); + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC()); } /* if (PCXI.UL == 0) then trap(CTYP); */ if ((env->PCXI & MASK_PCXI_UL) == 0) { /* CTYP trap */ + cdc_increment(&psw); /* restore to the start of helper */ + psw_write(env, psw); + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CTYP, GETPC()); } /* PC = {A11 [31: 1], 1’b0}; */ env->PC = env->gpr_a[11] & 0xfffffffe; @@ -2467,6 +2564,7 @@ void helper_bisr(CPUTriCoreState *env, uint32_t const9) if (env->FCX == 0) { /* FCU trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCU, GETPC()); } tmp_FCX = env->FCX; @@ -2498,6 +2596,7 @@ void helper_bisr(CPUTriCoreState *env, uint32_t const9) if (tmp_FCX == env->LCX) { /* FCD trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCD, GETPC()); } } @@ -2509,14 +2608,17 @@ void helper_rfe(CPUTriCoreState *env) /* if (PCXI[19: 0] == 0) then trap(CSU); */ if ((env->PCXI & 0xfffff) == 0) { /* raise csu trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC()); } /* if (PCXI.UL == 0) then trap(CTYP); */ if ((env->PCXI & MASK_PCXI_UL) == 0) { /* raise CTYP trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CTYP, GETPC()); } /* if (!cdc_zero() AND PSW.CDE) then trap(NEST); */ if (!cdc_zero(&(env->PSW)) && (env->PSW & MASK_PSW_CDE)) { - /* raise MNG trap */ + /* raise NEST trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_NEST, GETPC()); } env->PC = env->gpr_a[11] & ~0x1; /* ICR.IE = PCXI.PIE; */ @@ -2592,6 +2694,7 @@ void helper_svlcx(CPUTriCoreState *env) if (env->FCX == 0) { /* FCU trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCU, GETPC()); } /* tmp_FCX = FCX; */ tmp_FCX = env->FCX; @@ -2622,6 +2725,50 @@ void helper_svlcx(CPUTriCoreState *env) /* if (tmp_FCX == LCX) trap(FCD);*/ if (tmp_FCX == env->LCX) { /* FCD trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCD, GETPC()); + } +} + +void helper_svucx(CPUTriCoreState *env) +{ + target_ulong tmp_FCX; + target_ulong ea; + target_ulong new_FCX; + + if (env->FCX == 0) { + /* FCU trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCU, GETPC()); + } + /* tmp_FCX = FCX; */ + tmp_FCX = env->FCX; + /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */ + ea = ((env->FCX & MASK_FCX_FCXS) << 12) + + ((env->FCX & MASK_FCX_FCXO) << 6); + /* new_FCX = M(EA, word); */ + new_FCX = cpu_ldl_data(env, ea); + /* M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], + A[12], A[13], A[14], A[15], D[12], D[13], D[14], + D[15]}; */ + save_context_upper(env, ea); + + /* PCXI.PCPN = ICR.CCPN; */ + env->PCXI = (env->PCXI & 0xffffff) + + ((env->ICR & MASK_ICR_CCPN) << 24); + /* PCXI.PIE = ICR.IE; */ + env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) + + ((env->ICR & MASK_ICR_IE) << 15)); + /* PCXI.UL = 1; */ + env->PCXI |= MASK_PCXI_UL; + + /* PCXI[19: 0] = FCX[19: 0]; */ + env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff); + /* FCX[19: 0] = new_FCX[19: 0]; */ + env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff); + + /* if (tmp_FCX == LCX) trap(FCD);*/ + if (tmp_FCX == env->LCX) { + /* FCD trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_FCD, GETPC()); } } @@ -2632,10 +2779,12 @@ void helper_rslcx(CPUTriCoreState *env) /* if (PCXI[19: 0] == 0) then trap(CSU); */ if ((env->PCXI & 0xfffff) == 0) { /* CSU trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CSU, GETPC()); } /* if (PCXI.UL == 1) then trap(CTYP); */ if ((env->PCXI & MASK_PCXI_UL) != 0) { /* CTYP trap */ + raise_exception_sync_helper(env, TRAPC_CTX_MNG, TIN3_CTYP, GETPC()); } /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */ ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) + diff --git a/target-tricore/translate.c b/target-tricore/translate.c index a70fdf741e..6d7f55359b 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -216,6 +216,15 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, #define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \ ((offset & 0x0fffff) << 1)) +/* For two 32-bit registers used a 64-bit register, the first + registernumber needs to be even. Otherwise we trap. */ +static inline void generate_trap(DisasContext *ctx, int class, int tin); +#define CHECK_REG_PAIR(reg) do { \ + if (reg & 0x1) { \ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_OPD); \ + } \ +} while (0) + /* Functions for load/save to/from memory */ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, @@ -301,6 +310,7 @@ static void gen_ldmst(DisasContext *ctx, int ereg, TCGv ea) TCGv temp = tcg_temp_new(); TCGv temp2 = tcg_temp_new(); + CHECK_REG_PAIR(ereg); /* temp = (M(EA, word) */ tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); /* temp = temp & ~E[a][63:32]) */ @@ -3244,6 +3254,19 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) } } +static void generate_trap(DisasContext *ctx, int class, int tin) +{ + TCGv_i32 classtemp = tcg_const_i32(class); + TCGv_i32 tintemp = tcg_const_i32(tin); + + gen_save_pc(ctx->pc); + gen_helper_raise_exception_sync(cpu_env, classtemp, tintemp); + ctx->bstate = BS_EXCP; + + tcg_temp_free(classtemp); + tcg_temp_free(tintemp); +} + static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1, TCGv r2, int16_t address) { @@ -3542,7 +3565,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, } break; default: - printf("Branch Error at %x\n", ctx->pc); + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } ctx->bstate = BS_BRANCH; } @@ -3617,7 +3640,9 @@ static void decode_src_opc(CPUTriCoreState *env, DisasContext *ctx, int op1) if (tricore_feature(env, TRICORE_FEATURE_16)) { tcg_gen_movi_tl(cpu_gpr_d[r1], const4); tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC1_16_SRC_SH: gen_shi(cpu_gpr_d[r1], cpu_gpr_d[r1], const4); @@ -3625,6 +3650,8 @@ static void decode_src_opc(CPUTriCoreState *env, DisasContext *ctx, int op1) case OPC1_16_SRC_SHA: gen_shaci(cpu_gpr_d[r1], cpu_gpr_d[r1], const4); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3708,6 +3735,8 @@ static void decode_srr_opc(DisasContext *ctx, int op1) case OPC1_16_SRR_XOR: tcg_gen_xor_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3747,6 +3776,8 @@ static void decode_ssr_opc(DisasContext *ctx, int op1) tcg_gen_qemu_st_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LEUL); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], 4); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3784,6 +3815,8 @@ static void decode_sc_opc(DisasContext *ctx, int op1) case OPC1_16_SC_SUB_A: tcg_gen_subi_tl(cpu_gpr_a[10], cpu_gpr_a[10], const16); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3824,6 +3857,8 @@ static void decode_slr_opc(DisasContext *ctx, int op1) tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LESL); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], 4); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3861,6 +3896,8 @@ static void decode_sro_opc(DisasContext *ctx, int op1) case OPC1_16_SRO_ST_W: gen_offset_st(ctx, cpu_gpr_d[15], cpu_gpr_a[r2], address * 4, MO_LESL); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3885,6 +3922,9 @@ static void decode_sr_system(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_16_SR_FRET: gen_fret(ctx); + break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -3927,6 +3967,8 @@ static void decode_sr_accu(CPUTriCoreState *env, DisasContext *ctx) case OPC2_16_SR_SAT_HU: gen_saturate_u(cpu_gpr_d[r1], cpu_gpr_d[r1], 0xffff); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4137,6 +4179,8 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx) r1 = MASK_OP_SR_S1D(ctx->opcode); tcg_gen_not_tl(cpu_gpr_d[r1], cpu_gpr_d[r1]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4163,14 +4207,18 @@ static void decode_abs_ldw(CPUTriCoreState *env, DisasContext *ctx) tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); break; case OPC2_32_ABS_LD_D: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); break; case OPC2_32_ABS_LD_DA: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); break; case OPC2_32_ABS_LD_W: tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); @@ -4202,6 +4250,8 @@ static void decode_abs_ldb(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_ABS_LD_HU: tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); @@ -4227,6 +4277,8 @@ static void decode_abs_ldst_swap(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_ABS_SWAP_W: gen_swap(ctx, r1, temp); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); @@ -4253,6 +4305,8 @@ static void decode_abs_ldst_context(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_ABS_STUCX: gen_helper_1arg(stucx, EA_ABS_FORMAT(off18)); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4274,15 +4328,18 @@ static void decode_abs_store(CPUTriCoreState *env, DisasContext *ctx) tcg_gen_qemu_st_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); break; case OPC2_32_ABS_ST_D: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); break; case OPC2_32_ABS_ST_DA: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); break; case OPC2_32_ABS_ST_W: tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); break; - + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -4307,6 +4364,8 @@ static void decode_abs_storeb_h(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_ABS_ST_H: tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -4349,6 +4408,8 @@ static void decode_bit_andacc(CPUTriCoreState *env, DisasContext *ctx) gen_bit_2op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl, &tcg_gen_and_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4381,6 +4442,8 @@ static void decode_bit_logical_t(CPUTriCoreState *env, DisasContext *ctx) gen_bit_1op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4438,6 +4501,8 @@ static void decode_bit_logical_t2(CPUTriCoreState *env, DisasContext *ctx) gen_bit_1op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_xor_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4477,6 +4542,8 @@ static void decode_bit_orand(CPUTriCoreState *env, DisasContext *ctx) gen_bit_2op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl, &tcg_gen_or_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4513,6 +4580,8 @@ static void decode_bit_sh_logic1(CPUTriCoreState *env, DisasContext *ctx) gen_bit_1op(temp, cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], 1); tcg_gen_add_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], temp); @@ -4552,6 +4621,8 @@ static void decode_bit_sh_logic2(CPUTriCoreState *env, DisasContext *ctx) gen_bit_1op(temp, cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_xor_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], 1); tcg_gen_add_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], temp); @@ -4596,20 +4667,25 @@ static void decode_bo_addrmode_post_pre_base(CPUTriCoreState *env, break; case OPC2_32_BO_CACHEI_WI_SHORTOFF: case OPC2_32_BO_CACHEI_W_SHORTOFF: - /* TODO: Raise illegal opcode trap, - if !tricore_feature(TRICORE_FEATURE_131) */ + if (!tricore_feature(env, TRICORE_FEATURE_131)) { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_BO_CACHEI_W_POSTINC: case OPC2_32_BO_CACHEI_WI_POSTINC: if (tricore_feature(env, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_BO_CACHEI_W_PREINC: case OPC2_32_BO_CACHEI_WI_PREINC: if (tricore_feature(env, TRICORE_FEATURE_131)) { tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_BO_ST_A_SHORTOFF: gen_offset_st(ctx, cpu_gpr_a[r1], cpu_gpr_a[r2], off10, MO_LESL); @@ -4634,14 +4710,17 @@ static void decode_bo_addrmode_post_pre_base(CPUTriCoreState *env, gen_st_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_UB); break; case OPC2_32_BO_ST_D_SHORTOFF: + CHECK_REG_PAIR(r1); gen_offset_st_2regs(cpu_gpr_d[r1+1], cpu_gpr_d[r1], cpu_gpr_a[r2], off10, ctx); break; case OPC2_32_BO_ST_D_POSTINC: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], cpu_gpr_a[r2], ctx); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_ST_D_PREINC: + CHECK_REG_PAIR(r1); temp = tcg_temp_new(); tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); @@ -4649,14 +4728,17 @@ static void decode_bo_addrmode_post_pre_base(CPUTriCoreState *env, tcg_temp_free(temp); break; case OPC2_32_BO_ST_DA_SHORTOFF: + CHECK_REG_PAIR(r1); gen_offset_st_2regs(cpu_gpr_a[r1+1], cpu_gpr_a[r1], cpu_gpr_a[r2], off10, ctx); break; case OPC2_32_BO_ST_DA_POSTINC: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], cpu_gpr_a[r2], ctx); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_ST_DA_PREINC: + CHECK_REG_PAIR(r1); temp = tcg_temp_new(); tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); @@ -4705,6 +4787,8 @@ static void decode_bo_addrmode_post_pre_base(CPUTriCoreState *env, case OPC2_32_BO_ST_W_PREINC: gen_st_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_LEUL); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4724,7 +4808,7 @@ static void decode_bo_addrmode_bitreverse_circular(CPUTriCoreState *env, temp = tcg_temp_new(); temp2 = tcg_temp_new(); temp3 = tcg_const_i32(off10); - + CHECK_REG_PAIR(r2); tcg_gen_ext16u_tl(temp, cpu_gpr_a[r2+1]); tcg_gen_add_tl(temp2, cpu_gpr_a[r2], temp); @@ -4756,10 +4840,12 @@ static void decode_bo_addrmode_bitreverse_circular(CPUTriCoreState *env, gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; case OPC2_32_BO_ST_D_BR: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp2, ctx); gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]); break; case OPC2_32_BO_ST_D_CIRC: + CHECK_REG_PAIR(r1); tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp2, ctx->mem_idx, MO_LEUL); tcg_gen_shri_tl(temp2, cpu_gpr_a[r2+1], 16); tcg_gen_addi_tl(temp, temp, 4); @@ -4769,10 +4855,12 @@ static void decode_bo_addrmode_bitreverse_circular(CPUTriCoreState *env, gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; case OPC2_32_BO_ST_DA_BR: + CHECK_REG_PAIR(r1); gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp2, ctx); gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]); break; case OPC2_32_BO_ST_DA_CIRC: + CHECK_REG_PAIR(r1); tcg_gen_qemu_st_tl(cpu_gpr_a[r1], temp2, ctx->mem_idx, MO_LEUL); tcg_gen_shri_tl(temp2, cpu_gpr_a[r2+1], 16); tcg_gen_addi_tl(temp, temp, 4); @@ -4807,6 +4895,8 @@ static void decode_bo_addrmode_bitreverse_circular(CPUTriCoreState *env, tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp2, ctx->mem_idx, MO_LEUL); gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -4861,14 +4951,17 @@ static void decode_bo_addrmode_ld_post_pre_base(CPUTriCoreState *env, gen_ld_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_SB); break; case OPC2_32_BO_LD_D_SHORTOFF: + CHECK_REG_PAIR(r1); gen_offset_ld_2regs(cpu_gpr_d[r1+1], cpu_gpr_d[r1], cpu_gpr_a[r2], off10, ctx); break; case OPC2_32_BO_LD_D_POSTINC: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], cpu_gpr_a[r2], ctx); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_LD_D_PREINC: + CHECK_REG_PAIR(r1); temp = tcg_temp_new(); tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); @@ -4876,14 +4969,17 @@ static void decode_bo_addrmode_ld_post_pre_base(CPUTriCoreState *env, tcg_temp_free(temp); break; case OPC2_32_BO_LD_DA_SHORTOFF: + CHECK_REG_PAIR(r1); gen_offset_ld_2regs(cpu_gpr_a[r1+1], cpu_gpr_a[r1], cpu_gpr_a[r2], off10, ctx); break; case OPC2_32_BO_LD_DA_POSTINC: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], cpu_gpr_a[r2], ctx); tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_LD_DA_PREINC: + CHECK_REG_PAIR(r1); temp = tcg_temp_new(); tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10); gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); @@ -4937,6 +5033,8 @@ static void decode_bo_addrmode_ld_post_pre_base(CPUTriCoreState *env, case OPC2_32_BO_LD_W_PREINC: gen_ld_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_LEUL); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -4957,7 +5055,7 @@ static void decode_bo_addrmode_ld_bitreverse_circular(CPUTriCoreState *env, temp = tcg_temp_new(); temp2 = tcg_temp_new(); temp3 = tcg_const_i32(off10); - + CHECK_REG_PAIR(r2); tcg_gen_ext16u_tl(temp, cpu_gpr_a[r2+1]); tcg_gen_add_tl(temp2, cpu_gpr_a[r2], temp); @@ -4988,10 +5086,12 @@ static void decode_bo_addrmode_ld_bitreverse_circular(CPUTriCoreState *env, gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; case OPC2_32_BO_LD_D_BR: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp2, ctx); gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]); break; case OPC2_32_BO_LD_D_CIRC: + CHECK_REG_PAIR(r1); tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp2, ctx->mem_idx, MO_LEUL); tcg_gen_shri_tl(temp2, cpu_gpr_a[r2+1], 16); tcg_gen_addi_tl(temp, temp, 4); @@ -5001,10 +5101,12 @@ static void decode_bo_addrmode_ld_bitreverse_circular(CPUTriCoreState *env, gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; case OPC2_32_BO_LD_DA_BR: + CHECK_REG_PAIR(r1); gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp2, ctx); gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]); break; case OPC2_32_BO_LD_DA_CIRC: + CHECK_REG_PAIR(r1); tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp2, ctx->mem_idx, MO_LEUL); tcg_gen_shri_tl(temp2, cpu_gpr_a[r2+1], 16); tcg_gen_addi_tl(temp, temp, 4); @@ -5047,6 +5149,8 @@ static void decode_bo_addrmode_ld_bitreverse_circular(CPUTriCoreState *env, tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp2, ctx->mem_idx, MO_LEUL); gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -5139,6 +5243,8 @@ static void decode_bo_addrmode_stctx_post_pre_base(CPUTriCoreState *env, tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); gen_swapmsk(ctx, r1, cpu_gpr_a[r2]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -5161,7 +5267,7 @@ static void decode_bo_addrmode_ldmst_bitreverse_circular(CPUTriCoreState *env, temp = tcg_temp_new(); temp2 = tcg_temp_new(); temp3 = tcg_const_i32(off10); - + CHECK_REG_PAIR(r2); tcg_gen_ext16u_tl(temp, cpu_gpr_a[r2+1]); tcg_gen_add_tl(temp2, cpu_gpr_a[r2], temp); @@ -5198,6 +5304,8 @@ static void decode_bo_addrmode_ldmst_bitreverse_circular(CPUTriCoreState *env, gen_swapmsk(ctx, r1, temp2); gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); @@ -5235,7 +5343,7 @@ static void decode_bol_opc(CPUTriCoreState *env, DisasContext *ctx, int32_t op1) if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_a[r1], cpu_gpr_a[r2], address, MO_LEUL); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_ST_W_LONGOFF: @@ -5245,44 +5353,46 @@ static void decode_bol_opc(CPUTriCoreState *env, DisasContext *ctx, int32_t op1) if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_BU_LONGOFF: if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_UB); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_H_LONGOFF: if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_LD_HU_LONGOFF: if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUW); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_ST_B_LONGOFF: if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_BOL_ST_H_LONGOFF: if (tricore_feature(env, TRICORE_FEATURE_16)) { gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW); } else { - /* raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5348,6 +5458,8 @@ static void decode_rc_logical_shift(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RC_XOR: tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -5546,6 +5658,8 @@ static void decode_rc_accumulator(CPUTriCoreState *env, DisasContext *ctx) gen_accumulating_condi(TCG_COND_NE, cpu_gpr_d[r2], cpu_gpr_d[r1], const9, &tcg_gen_xor_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -5565,6 +5679,8 @@ static void decode_rc_serviceroutine(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RC_SYSCALL: /* TODO: Add exception generation */ break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5585,6 +5701,7 @@ static void decode_rc_mul(CPUTriCoreState *env, DisasContext *ctx) gen_muli_i32s(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); break; case OPC2_32_RC_MUL_64: + CHECK_REG_PAIR(r2); gen_muli_i64s(cpu_gpr_d[r2], cpu_gpr_d[r2+1], cpu_gpr_d[r1], const9); break; case OPC2_32_RC_MULS_32: @@ -5592,12 +5709,15 @@ static void decode_rc_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RC_MUL_U_64: const9 = MASK_OP_RC_CONST9(ctx->opcode); + CHECK_REG_PAIR(r2); gen_muli_i64u(cpu_gpr_d[r2], cpu_gpr_d[r2+1], cpu_gpr_d[r1], const9); break; case OPC2_32_RC_MULS_U_32: const9 = MASK_OP_RC_CONST9(ctx->opcode); gen_mulsui_i32(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5619,6 +5739,7 @@ static void decode_rcpw_insert(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RCPW_IMASK: + CHECK_REG_PAIR(r2); /* if pos + width > 31 undefined result */ if (pos + width <= 31) { tcg_gen_movi_tl(cpu_gpr_d[r2+1], ((1u << width) - 1) << pos); @@ -5633,6 +5754,8 @@ static void decode_rcpw_insert(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(temp); } break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5674,6 +5797,8 @@ static void decode_rcrw_insert(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(temp3); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -5720,6 +5845,8 @@ static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(temp); tcg_temp_free(temp2); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5741,6 +5868,8 @@ static void decode_rcr_madd(CPUTriCoreState *env, DisasContext *ctx) gen_maddi32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MADD_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_maddi64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; @@ -5748,10 +5877,14 @@ static void decode_rcr_madd(CPUTriCoreState *env, DisasContext *ctx) gen_maddsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MADDS_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_maddsi_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; case OPC2_32_RCR_MADD_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); const9 = MASK_OP_RCR_CONST9(ctx->opcode); gen_maddui64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); @@ -5761,10 +5894,14 @@ static void decode_rcr_madd(CPUTriCoreState *env, DisasContext *ctx) gen_maddsui_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MADDS_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); const9 = MASK_OP_RCR_CONST9(ctx->opcode); gen_maddsui_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5786,6 +5923,8 @@ static void decode_rcr_msub(CPUTriCoreState *env, DisasContext *ctx) gen_msubi32_d(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MSUB_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubi64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; @@ -5793,10 +5932,14 @@ static void decode_rcr_msub(CPUTriCoreState *env, DisasContext *ctx) gen_msubsi_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MSUBS_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubsi_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; case OPC2_32_RCR_MSUB_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); const9 = MASK_OP_RCR_CONST9(ctx->opcode); gen_msubui64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); @@ -5806,10 +5949,14 @@ static void decode_rcr_msub(CPUTriCoreState *env, DisasContext *ctx) gen_msubsui_32(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r3], const9); break; case OPC2_32_RCR_MSUBS_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); const9 = MASK_OP_RCR_CONST9(ctx->opcode); gen_msubsui_64(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], const9); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -5844,13 +5991,11 @@ static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx, break; case OPC1_32_RLC_MOV_64: if (tricore_feature(env, TRICORE_FEATURE_16)) { - if ((r2 & 0x1) != 0) { - /* TODO: raise OPD trap */ - } + CHECK_REG_PAIR(r2); tcg_gen_movi_tl(cpu_gpr_d[r2], const16); tcg_gen_movi_tl(cpu_gpr_d[r2+1], const16 >> 15); } else { - /* TODO: raise illegal opcode trap */ + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; case OPC1_32_RLC_MOV_U: @@ -5867,6 +6012,8 @@ static void decode_rlc_opc(CPUTriCoreState *env, DisasContext *ctx, const16 = MASK_OP_RLC_CONST16(ctx->opcode); gen_mtcr(env, ctx, cpu_gpr_d[r1], const16); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6183,6 +6330,8 @@ static void decode_rr_accumulator(CPUTriCoreState *env, DisasContext *ctx) gen_accumulating_cond(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], &tcg_gen_xor_tl); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6257,6 +6406,8 @@ static void decode_rr_logical_shift(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RR_XOR: tcg_gen_xor_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -6324,6 +6475,8 @@ static void decode_rr_address(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RR_SUB_A: tcg_gen_sub_tl(cpu_gpr_a[r3], cpu_gpr_a[r1], cpu_gpr_a[r2]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6351,6 +6504,8 @@ static void decode_rr_idirect(CPUTriCoreState *env, DisasContext *ctx) gen_fcall_save_ctx(ctx); tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_gen_exit_tb(0); ctx->bstate = BS_BRANCH; @@ -6373,9 +6528,11 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) gen_helper_bmerge(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_BSPLIT: + CHECK_REG_PAIR(r3); gen_bsplit(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; case OPC2_32_RR_DVINIT_B: + CHECK_REG_PAIR(r3); gen_dvinit_b(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; @@ -6383,7 +6540,7 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) temp = tcg_temp_new(); temp2 = tcg_temp_new(); temp3 = tcg_temp_new(); - + CHECK_REG_PAIR(r3); tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 8); /* reset av */ tcg_gen_movi_tl(cpu_PSW_AV, 0); @@ -6413,6 +6570,7 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(temp3); break; case OPC2_32_RR_DVINIT_H: + CHECK_REG_PAIR(r3); gen_dvinit_h(env, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; @@ -6420,7 +6578,7 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) temp = tcg_temp_new(); temp2 = tcg_temp_new(); temp3 = tcg_temp_new(); - + CHECK_REG_PAIR(r3); tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 16); /* reset av */ tcg_gen_movi_tl(cpu_PSW_AV, 0); @@ -6451,6 +6609,7 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RR_DVINIT: temp = tcg_temp_new(); temp2 = tcg_temp_new(); + CHECK_REG_PAIR(r3); /* overflow = ((D[b] == 0) || ((D[b] == 0xFFFFFFFF) && (D[a] == 0x80000000))) */ tcg_gen_setcondi_tl(TCG_COND_EQ, temp, cpu_gpr_d[r2], 0xffffffff); @@ -6487,25 +6646,34 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx) gen_helper_parity(cpu_gpr_d[r3], cpu_gpr_d[r1]); break; case OPC2_32_RR_UNPACK: + CHECK_REG_PAIR(r3); gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; case OPC2_32_RR_CRC32: if (tricore_feature(env, TRICORE_FEATURE_161)) { gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_RR_DIV: if (tricore_feature(env, TRICORE_FEATURE_16)) { GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_RR_DIV_U: if (tricore_feature(env, TRICORE_FEATURE_16)) { GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); - } /* TODO: else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6527,6 +6695,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RR1_MUL_H_32_LL: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_LL(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]); @@ -6534,6 +6703,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MUL_H_32_LU: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_LU(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]); @@ -6541,6 +6711,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MUL_H_32_UL: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_UL(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]); @@ -6548,6 +6719,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MUL_H_32_UU: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_UU(mul_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); gen_calc_usb_mul_h(cpu_gpr_d[r3], cpu_gpr_d[r3+1]); @@ -6555,6 +6727,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MULM_H_64_LL: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_LL(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); /* reset V bit */ @@ -6565,6 +6738,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MULM_H_64_LU: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_LU(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); /* reset V bit */ @@ -6575,6 +6749,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MULM_H_64_UL: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_UL(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); /* reset V bit */ @@ -6585,6 +6760,7 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RR1_MULM_H_64_UU: temp64 = tcg_temp_new_i64(); + CHECK_REG_PAIR(r3); GEN_HELPER_UU(mulm_h, temp64, cpu_gpr_d[r1], cpu_gpr_d[r2], n); tcg_gen_extr_i64_i32(cpu_gpr_d[r3], cpu_gpr_d[r3+1], temp64); /* reset V bit */ @@ -6610,6 +6786,8 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) GEN_HELPER_UU(mulr_h, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n); gen_calc_usb_mulr_h(cpu_gpr_d[r3]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(n); } @@ -6636,6 +6814,7 @@ static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], cpu_gpr_d[r2], n, 32); break; case OPC2_32_RR1_MUL_Q_64: + CHECK_REG_PAIR(r3); gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], n, 0); break; @@ -6644,6 +6823,7 @@ static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); break; case OPC2_32_RR1_MUL_Q_64_L: + CHECK_REG_PAIR(r3); tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, n, 0); break; @@ -6652,6 +6832,7 @@ static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); break; case OPC2_32_RR1_MUL_Q_64_U: + CHECK_REG_PAIR(r3); tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, n, 0); break; @@ -6675,6 +6856,8 @@ static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); gen_mulr_q(cpu_gpr_d[r3], temp, temp2, n); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -6695,6 +6878,7 @@ static void decode_rr2_mul(CPUTriCoreState *env, DisasContext *ctx) gen_mul_i32s(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR2_MUL_64: + CHECK_REG_PAIR(r3); gen_mul_i64s(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; @@ -6703,6 +6887,7 @@ static void decode_rr2_mul(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2]); break; case OPC2_32_RR2_MUL_U_64: + CHECK_REG_PAIR(r3); gen_mul_i64u(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; @@ -6710,6 +6895,8 @@ static void decode_rr2_mul(CPUTriCoreState *env, DisasContext *ctx) gen_helper_mul_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6750,6 +6937,7 @@ static void decode_rrpw_extract_insert(CPUTriCoreState *env, DisasContext *ctx) } break; case OPC2_32_RRPW_IMASK: + CHECK_REG_PAIR(r3); if (pos + width <= 31) { tcg_gen_movi_tl(cpu_gpr_d[r3+1], ((1u << width) - 1) << pos); tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], pos); @@ -6761,6 +6949,8 @@ static void decode_rrpw_extract_insert(CPUTriCoreState *env, DisasContext *ctx) width, pos); } break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6806,6 +6996,8 @@ static void decode_rrr_cond_select(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r1], cpu_gpr_d[r2]); tcg_temp_free(temp); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6821,32 +7013,41 @@ static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx) r3 = MASK_OP_RRR_S3(ctx->opcode); r4 = MASK_OP_RRR_D(ctx->opcode); + CHECK_REG_PAIR(r3); + switch (op2) { case OPC2_32_RRR_DVADJ: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(dvadj, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_DVSTEP: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(dvstep, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_DVSTEP_U: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(dvstep_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_IXMAX: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(ixmax, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_IXMAX_U: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(ixmax_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_IXMIN: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(ixmin, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR_IXMIN_U: + CHECK_REG_PAIR(r4); GEN_HELPER_RRR(ixmin_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; @@ -6854,6 +7055,8 @@ static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx) gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6874,6 +7077,8 @@ static void decode_rrr2_madd(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADD_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; @@ -6882,10 +7087,14 @@ static void decode_rrr2_madd(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; @@ -6894,9 +7103,13 @@ static void decode_rrr2_madd(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MADDS_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6917,6 +7130,8 @@ static void decode_rrr2_msub(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUB_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; @@ -6925,6 +7140,8 @@ static void decode_rrr2_msub(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; @@ -6937,9 +7154,13 @@ static void decode_rrr2_msub(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUBS_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -6958,66 +7179,98 @@ static void decode_rrr1_madd(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RRR1_MADD_H_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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; @@ -7053,6 +7306,8 @@ static void decode_rrr1_madd(CPUTriCoreState *env, DisasContext *ctx) gen_maddr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -7078,6 +7333,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2], n, 32, env); break; case OPC2_32_RRR1_MADD_Q_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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); @@ -7088,6 +7345,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16, env); break; case OPC2_32_RRR1_MADD_Q_64_L: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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, @@ -7099,6 +7358,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16, env); break; case OPC2_32_RRR1_MADD_Q_64_U: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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, @@ -7110,6 +7371,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16add32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MADD_Q_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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], @@ -7121,6 +7384,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16add32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MADD_Q_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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], @@ -7131,6 +7396,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2], n, 32); break; case OPC2_32_RRR1_MADDS_Q_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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); @@ -7141,6 +7408,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16); break; case OPC2_32_RRR1_MADDS_Q_64_L: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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, @@ -7152,6 +7421,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16); break; case OPC2_32_RRR1_MADDS_Q_64_U: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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, @@ -7163,6 +7434,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16adds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MADDS_Q_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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], @@ -7174,16 +7447,20 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16adds32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MADDS_Q_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r3); 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; @@ -7207,6 +7484,8 @@ static void decode_rrr1_maddq_h(CPUTriCoreState *env, DisasContext *ctx) 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; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -7226,77 +7505,109 @@ static void decode_rrr1_maddsu_h(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RRR1_MADDSU_H_32_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); 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); @@ -7333,6 +7644,8 @@ static void decode_rrr1_maddsu_h(CPUTriCoreState *env, DisasContext *ctx) gen_maddsur32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -7350,66 +7663,98 @@ static void decode_rrr1_msub(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RRR1_MSUB_H_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msub_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_MSUB_H_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msub_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_MSUB_H_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msub_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_MSUB_H_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msub_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_MSUBS_H_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubs_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_MSUBS_H_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubs_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_MSUBS_H_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubs_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_MSUBS_H_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubs_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_MSUBM_H_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubm_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_MSUBM_H_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubm_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_MSUBM_H_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubm_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_MSUBM_H_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubm_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_MSUBMS_H_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubms_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_MSUBMS_H_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubms_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_MSUBMS_H_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubms_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_MSUBMS_H_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubms_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; @@ -7445,6 +7790,8 @@ static void decode_rrr1_msub(CPUTriCoreState *env, DisasContext *ctx) gen_msubr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -7470,6 +7817,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2], n, 32, env); break; case OPC2_32_RRR1_MSUB_Q_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msub64_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); @@ -7480,6 +7829,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16, env); break; case OPC2_32_RRR1_MSUB_Q_64_L: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); gen_msub64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, @@ -7491,6 +7842,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16, env); break; case OPC2_32_RRR1_MSUB_Q_64_U: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); gen_msub64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, @@ -7502,6 +7855,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16sub32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MSUB_Q_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); gen_m16sub64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], @@ -7513,6 +7868,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16sub32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MSUB_Q_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); gen_m16sub64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], @@ -7523,6 +7880,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) cpu_gpr_d[r2], n, 32); break; case OPC2_32_RRR1_MSUBS_Q_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubs64_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); @@ -7533,6 +7892,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16); break; case OPC2_32_RRR1_MSUBS_Q_64_L: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); gen_msubs64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, @@ -7544,6 +7905,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) temp, n, 16); break; case OPC2_32_RRR1_MSUBS_Q_64_U: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); gen_msubs64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], temp, @@ -7555,6 +7918,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16subs32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MSUBS_Q_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); gen_m16subs64_q(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3], @@ -7566,16 +7931,20 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) gen_m16subs32_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; case OPC2_32_RRR1_MSUBS_Q_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); gen_m16subs64_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_MSUBR_H_64_UL: + CHECK_REG_PAIR(r3); gen_msubr64_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_MSUBRS_H_64_UL: + CHECK_REG_PAIR(r3); gen_msubr64s_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; @@ -7599,6 +7968,8 @@ static void decode_rrr1_msubq_h(CPUTriCoreState *env, DisasContext *ctx) tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); gen_msubrs_q(cpu_gpr_d[r4], cpu_gpr_d[r3], temp, temp2, n); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); tcg_temp_free(temp2); @@ -7618,77 +7989,109 @@ static void decode_rrr1_msubad_h(CPUTriCoreState *env, DisasContext *ctx) switch (op2) { case OPC2_32_RRR1_MSUBAD_H_32_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubad_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_MSUBAD_H_32_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubad_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_MSUBAD_H_32_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubad_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_MSUBAD_H_32_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubad_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_MSUBADS_H_32_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubads_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_MSUBADS_H_32_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubads_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_MSUBADS_H_32_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubads_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_MSUBADS_H_32_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubads_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_MSUBADM_H_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadm_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_MSUBADM_H_64_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadm_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_MSUBADM_H_64_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadm_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_MSUBADM_H_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadm_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_MSUBADMS_H_64_LL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadms_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_MSUBADMS_H_64_LU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadms_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_MSUBADMS_H_64_UL: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadms_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_MSUBADMS_H_64_UU: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubadms_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); @@ -7725,6 +8128,8 @@ static void decode_rrr1_msubad_h(CPUTriCoreState *env, DisasContext *ctx) gen_msubadr32s_h(cpu_gpr_d[r4], cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], n, MODE_UU); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -7758,6 +8163,7 @@ static void decode_rrrr_extract_insert(CPUTriCoreState *env, DisasContext *ctx) break; case OPC2_32_RRRR_EXTR: case OPC2_32_RRRR_EXTR_U: + CHECK_REG_PAIR(r3); tcg_gen_andi_tl(tmp_width, cpu_gpr_d[r3+1], 0x1f); tcg_gen_andi_tl(tmp_pos, cpu_gpr_d[r3], 0x1f); tcg_gen_add_tl(tmp_pos, tmp_pos, tmp_width); @@ -7771,11 +8177,14 @@ static void decode_rrrr_extract_insert(CPUTriCoreState *env, DisasContext *ctx) } break; case OPC2_32_RRRR_INSERT: + CHECK_REG_PAIR(r3); tcg_gen_andi_tl(tmp_width, cpu_gpr_d[r3+1], 0x1f); tcg_gen_andi_tl(tmp_pos, cpu_gpr_d[r3], 0x1f); gen_insert(cpu_gpr_d[r4], cpu_gpr_d[r1], cpu_gpr_d[r2], tmp_width, tmp_pos); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(tmp_pos); tcg_temp_free(tmp_width); @@ -7836,6 +8245,8 @@ static void decode_rrrw_extract_insert(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(temp2); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } tcg_temp_free(temp); } @@ -7907,14 +8318,24 @@ static void decode_sys_interrupts(CPUTriCoreState *env, DisasContext *ctx) (ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) { tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); } /* else raise privilege trap */ - } /* else raise illegal opcode trap */ + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } break; case OPC2_32_SYS_TRAPSV: - /* TODO: raise sticky overflow trap */ + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_GE, cpu_PSW_SV, 0, l1); + generate_trap(ctx, TRAPC_ASSERT, TIN5_SOVF); + gen_set_label(l1); break; case OPC2_32_SYS_TRAPV: - /* TODO: raise overflow trap */ + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_GE, cpu_PSW_V, 0, l1); + generate_trap(ctx, TRAPC_ASSERT, TIN5_OVF); + gen_set_label(l1); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } @@ -8121,6 +8542,8 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) temp2 = tcg_temp_new(); /* width*/ temp3 = tcg_temp_new(); /* pos */ + CHECK_REG_PAIR(r3); + tcg_gen_andi_tl(temp2, cpu_gpr_d[r3+1], 0x1f); tcg_gen_andi_tl(temp3, cpu_gpr_d[r3], 0x1f); @@ -8252,6 +8675,8 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) tcg_gen_mov_tl(cpu_PSW_AV, cpu_PSW_V); tcg_gen_mov_tl(cpu_PSW_SAV, cpu_PSW_V); break; + default: + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } } diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h index 01c370c30d..9c1fbf9b77 100644 --- a/target-unicore32/cpu.h +++ b/target-unicore32/cpu.h @@ -19,7 +19,6 @@ #define CPUArchState struct CPUUniCore32State -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" #include "fpu/softfloat.h" diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 15ce0107d6..d0bd9dada8 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -33,7 +33,6 @@ #define CPUArchState struct CPUXtensaState -#include "config.h" #include "qemu-common.h" #include "exec/cpu-defs.h" #include "fpu/softfloat.h" diff --git a/tcg/README b/tcg/README index 34c0775cff..f4a8ac170b 100644 --- a/tcg/README +++ b/tcg/README @@ -460,8 +460,9 @@ function tcg_gen_xxx(args). 4) Backend -tcg-target.h contains the target specific definitions. tcg-target.c -contains the target specific code. +tcg-target.h contains the target specific definitions. tcg-target.inc.c +contains the target specific code; it is #included by tcg/tcg.c, rather +than being a standalone C file. 4.1) Assumptions diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.inc.c index 8467d5d8b9..0ed10a9741 100644 --- a/tcg/aarch64/tcg-target.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -10,7 +10,6 @@ * See the COPYING file in the top-level directory for details. */ -#include "qemu/osdep.h" #include "tcg-be-ldst.h" #include "qemu/bitops.h" diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.inc.c index 146ac00f63..3edf6a6f97 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.inc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "elf.h" #include "tcg-be-ldst.h" diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.inc.c index d90636cb4e..9187d34caf 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.inc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-ldst.h" #ifndef NDEBUG diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.inc.c index 62d654943c..62d654943c 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.inc.c diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.inc.c index 2dc4998719..297bd00910 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.inc.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-ldst.h" #ifdef HOST_WORDS_BIGENDIAN diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.inc.c index c593344db1..8c1c2dfa9b 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.inc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-ldst.h" #if defined _CALL_DARWIN || defined __APPLE__ diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.inc.c index 58520fa22b..fbf97bb2e1 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.inc.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-ldst.h" /* We only support generating code for 64-bit mode. */ diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.inc.c index d3100ab557..54df1bc424 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.inc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-null.h" #ifndef NDEBUG @@ -62,7 +62,8 @@ #include "elf.h" #include "exec/log.h" -/* Forward declarations for functions declared in tcg-target.c and used here. */ +/* Forward declarations for functions declared in tcg-target.inc.c and + used here. */ static void tcg_target_init(TCGContext *s); static void tcg_target_qemu_prologue(TCGContext *s); static void patch_reloc(tcg_insn_unit *code_ptr, int type, @@ -96,7 +97,7 @@ static void tcg_register_jit_int(void *buf, size_t size, size_t debug_frame_size) __attribute__((unused)); -/* Forward declarations for functions declared and used in tcg-target.c. */ +/* Forward declarations for functions declared and used in tcg-target.inc.c. */ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str); static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, intptr_t arg2); @@ -250,7 +251,7 @@ TCGLabel *gen_new_label(void) return l; } -#include "tcg-target.c" +#include "tcg-target.inc.c" /* pool based memory allocation */ void *tcg_malloc_internal(TCGContext *s, int size) @@ -318,6 +319,8 @@ static const TCGHelperInfo all_helpers[] = { #include "exec/helper-tcg.h" }; +static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; + void tcg_context_init(TCGContext *s) { int op, total_args, n, i; @@ -360,6 +363,21 @@ void tcg_context_init(TCGContext *s) } tcg_target_init(s); + + /* Reverse the order of the saved registers, assuming they're all at + the start of tcg_target_reg_alloc_order. */ + for (n = 0; n < ARRAY_SIZE(tcg_target_reg_alloc_order); ++n) { + int r = tcg_target_reg_alloc_order[n]; + if (tcg_regset_test_reg(tcg_target_call_clobber_regs, r)) { + break; + } + } + for (i = 0; i < n; ++i) { + indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[n - 1 - i]; + } + for (; i < ARRAY_SIZE(tcg_target_reg_alloc_order); ++i) { + indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i]; + } } void tcg_prologue_init(TCGContext *s) @@ -506,17 +524,23 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, TCGContext *s = &tcg_ctx; TCGTemp *base_ts = &s->temps[GET_TCGV_PTR(base)]; TCGTemp *ts = tcg_global_alloc(s); - int bigendian = 0; + int indirect_reg = 0, bigendian = 0; #ifdef HOST_WORDS_BIGENDIAN bigendian = 1; #endif + if (!base_ts->fixed_reg) { + indirect_reg = 1; + base_ts->indirect_base = 1; + } + if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { TCGTemp *ts2 = tcg_global_alloc(s); char buf[64]; ts->base_type = TCG_TYPE_I64; ts->type = TCG_TYPE_I32; + ts->indirect_reg = indirect_reg; ts->mem_allocated = 1; ts->mem_base = base_ts; ts->mem_offset = offset + bigendian * 4; @@ -527,6 +551,7 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, tcg_debug_assert(ts2 == ts + 1); ts2->base_type = TCG_TYPE_I64; ts2->type = TCG_TYPE_I32; + ts2->indirect_reg = indirect_reg; ts2->mem_allocated = 1; ts2->mem_base = base_ts; ts2->mem_offset = offset + (1 - bigendian) * 4; @@ -536,6 +561,7 @@ int tcg_global_mem_new_internal(TCGType type, TCGv_ptr base, } else { ts->base_type = type; ts->type = type; + ts->indirect_reg = indirect_reg; ts->mem_allocated = 1; ts->mem_base = base_ts; ts->mem_offset = offset; @@ -1602,7 +1628,7 @@ static void dump_regs(TCGContext *s) static void check_regs(TCGContext *s) { - TCGReg reg; + int reg; int k; TCGTemp *ts; char buf[64]; @@ -1652,8 +1678,10 @@ static void temp_allocate_frame(TCGContext *s, int temp) s->current_frame_offset += sizeof(tcg_target_long); } +static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet); + /* sync register 'reg' by saving it to the corresponding temporary */ -static inline void tcg_reg_sync(TCGContext *s, TCGReg reg) +static void tcg_reg_sync(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) { TCGTemp *ts = s->reg_to_temp[reg]; @@ -1661,6 +1689,11 @@ static inline void tcg_reg_sync(TCGContext *s, TCGReg reg) if (!ts->mem_coherent && !ts->fixed_reg) { if (!ts->mem_allocated) { temp_allocate_frame(s, temp_idx(s, ts)); + } else if (ts->indirect_reg) { + tcg_regset_set_reg(allocated_regs, ts->reg); + temp_load(s, ts->mem_base, + tcg_target_available_regs[TCG_TYPE_PTR], + allocated_regs); } tcg_out_st(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); } @@ -1668,38 +1701,41 @@ static inline void tcg_reg_sync(TCGContext *s, TCGReg reg) } /* free register 'reg' by spilling the corresponding temporary if necessary */ -static void tcg_reg_free(TCGContext *s, TCGReg reg) +static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs) { TCGTemp *ts = s->reg_to_temp[reg]; if (ts != NULL) { - tcg_reg_sync(s, reg); + tcg_reg_sync(s, reg, allocated_regs); ts->val_type = TEMP_VAL_MEM; s->reg_to_temp[reg] = NULL; } } /* Allocate a register belonging to reg1 & ~reg2 */ -static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2) +static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs, + TCGRegSet allocated_regs, bool rev) { - int i; + int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order); + const int *order; TCGReg reg; TCGRegSet reg_ct; - tcg_regset_andnot(reg_ct, reg1, reg2); + tcg_regset_andnot(reg_ct, desired_regs, allocated_regs); + order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order; /* first try free registers */ - for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { - reg = tcg_target_reg_alloc_order[i]; + for(i = 0; i < n; i++) { + reg = order[i]; if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL) return reg; } /* XXX: do better spill choice */ - for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) { - reg = tcg_target_reg_alloc_order[i]; + for(i = 0; i < n; i++) { + reg = order[i]; if (tcg_regset_test_reg(reg_ct, reg)) { - tcg_reg_free(s, reg); + tcg_reg_free(s, reg, allocated_regs); return reg; } } @@ -1718,12 +1754,18 @@ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs, case TEMP_VAL_REG: return; case TEMP_VAL_CONST: - reg = tcg_reg_alloc(s, desired_regs, allocated_regs); + reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); tcg_out_movi(s, ts->type, reg, ts->val); ts->mem_coherent = 0; break; case TEMP_VAL_MEM: - reg = tcg_reg_alloc(s, desired_regs, allocated_regs); + reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base); + if (ts->indirect_reg) { + tcg_regset_set_reg(allocated_regs, reg); + temp_load(s, ts->mem_base, + tcg_target_available_regs[TCG_TYPE_PTR], + allocated_regs); + } tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset); ts->mem_coherent = 1; break; @@ -1761,7 +1803,7 @@ static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) temp_load(s, ts, tcg_target_available_regs[ts->type], allocated_regs); /* fallthrough */ case TEMP_VAL_REG: - tcg_reg_sync(s, ts->reg); + tcg_reg_sync(s, ts->reg, allocated_regs); break; case TEMP_VAL_DEAD: case TEMP_VAL_MEM: @@ -1777,13 +1819,16 @@ static inline void temp_save(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs) { #ifdef USE_LIVENESS_ANALYSIS - /* The liveness analysis already ensures that globals are back - in memory. Keep an assert for safety. */ - tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); -#else + /* ??? Liveness does not yet incorporate indirect bases. */ + if (!ts->indirect_base) { + /* The liveness analysis already ensures that globals are back + in memory. Keep an assert for safety. */ + tcg_debug_assert(ts->val_type == TEMP_VAL_MEM || ts->fixed_reg); + return; + } +#endif temp_sync(s, ts, allocated_regs); temp_dead(s, ts); -#endif } /* save globals to their canonical location and assume they can be @@ -1808,12 +1853,15 @@ static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) for (i = 0; i < s->nb_globals; i++) { TCGTemp *ts = &s->temps[i]; #ifdef USE_LIVENESS_ANALYSIS - tcg_debug_assert(ts->val_type != TEMP_VAL_REG - || ts->fixed_reg - || ts->mem_coherent); -#else - temp_sync(s, ts, allocated_regs); + /* ??? Liveness does not yet incorporate indirect bases. */ + if (!ts->indirect_base) { + tcg_debug_assert(ts->val_type != TEMP_VAL_REG + || ts->fixed_reg + || ts->mem_coherent); + continue; + } #endif + temp_sync(s, ts, allocated_regs); } } @@ -1829,12 +1877,15 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) temp_save(s, ts, allocated_regs); } else { #ifdef USE_LIVENESS_ANALYSIS - /* The liveness analysis already ensures that temps are dead. - Keep an assert for safety. */ - assert(ts->val_type == TEMP_VAL_DEAD); -#else - temp_dead(s, ts); + /* ??? Liveness does not yet incorporate indirect bases. */ + if (!ts->indirect_base) { + /* The liveness analysis already ensures that temps are dead. + Keep an assert for safety. */ + assert(ts->val_type == TEMP_VAL_DEAD); + continue; + } #endif + temp_dead(s, ts); } } @@ -1907,6 +1958,12 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, if (!ots->mem_allocated) { temp_allocate_frame(s, args[0]); } + if (ots->indirect_reg) { + tcg_regset_set_reg(allocated_regs, ts->reg); + temp_load(s, ots->mem_base, + tcg_target_available_regs[TCG_TYPE_PTR], + allocated_regs); + } tcg_out_st(s, otype, ts->reg, ots->mem_base->reg, ots->mem_offset); if (IS_DEAD_ARG(1)) { temp_dead(s, ts); @@ -1939,7 +1996,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, input one. */ tcg_regset_set_reg(allocated_regs, ts->reg); ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], - allocated_regs); + allocated_regs, ots->indirect_base); } tcg_out_mov(s, otype, ots->reg, ts->reg); } @@ -1947,7 +2004,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, ots->mem_coherent = 0; s->reg_to_temp[ots->reg] = ots; if (NEED_SYNC_ARG(0)) { - tcg_reg_sync(s, ots->reg); + tcg_reg_sync(s, ots->reg, allocated_regs); } } } @@ -2024,7 +2081,8 @@ static void tcg_reg_alloc_op(TCGContext *s, allocate_in_reg: /* allocate a new register matching the constraint and move the temporary register into it */ - reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs, + ts->indirect_base); tcg_out_mov(s, ts->type, reg, ts->reg); } new_args[i] = reg; @@ -2047,7 +2105,7 @@ static void tcg_reg_alloc_op(TCGContext *s, /* XXX: permit generic clobber register list ? */ for (i = 0; i < TCG_TARGET_NB_REGS; i++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { - tcg_reg_free(s, i); + tcg_reg_free(s, i, allocated_regs); } } } @@ -2073,7 +2131,8 @@ static void tcg_reg_alloc_op(TCGContext *s, tcg_regset_test_reg(arg_ct->u.regs, reg)) { goto oarg_end; } - reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs, + ts->indirect_base); } tcg_regset_set_reg(allocated_regs, reg); /* if a fixed register is used, then a move will be done afterwards */ @@ -2104,7 +2163,7 @@ static void tcg_reg_alloc_op(TCGContext *s, tcg_out_mov(s, ts->type, ts->reg, reg); } if (NEED_SYNC_ARG(i)) { - tcg_reg_sync(s, reg); + tcg_reg_sync(s, reg, allocated_regs); } if (IS_DEAD_ARG(i)) { temp_dead(s, ts); @@ -2175,7 +2234,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, if (arg != TCG_CALL_DUMMY_ARG) { ts = &s->temps[arg]; reg = tcg_target_call_iarg_regs[i]; - tcg_reg_free(s, reg); + tcg_reg_free(s, reg, allocated_regs); if (ts->val_type == TEMP_VAL_REG) { if (ts->reg != reg) { @@ -2203,7 +2262,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, /* clobber call registers */ for (i = 0; i < TCG_TARGET_NB_REGS; i++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { - tcg_reg_free(s, i); + tcg_reg_free(s, i, allocated_regs); } } @@ -2239,7 +2298,7 @@ static void tcg_reg_alloc_call(TCGContext *s, int nb_oargs, int nb_iargs, ts->mem_coherent = 0; s->reg_to_temp[reg] = ts; if (NEED_SYNC_ARG(i)) { - tcg_reg_sync(s, reg); + tcg_reg_sync(s, reg, allocated_regs); } if (IS_DEAD_ARG(i)) { temp_dead(s, ts); @@ -453,6 +453,8 @@ typedef struct TCGTemp { TCGType base_type:8; TCGType type:8; unsigned int fixed_reg:1; + unsigned int indirect_reg:1; + unsigned int indirect_base:1; unsigned int mem_coherent:1; unsigned int mem_allocated:1; unsigned int temp_local:1; /* If true, the temp is saved across @@ -566,7 +568,7 @@ struct TCGContext { TBContext tb_ctx; - /* The TCGBackendData structure is private to tcg-target.c. */ + /* The TCGBackendData structure is private to tcg-target.inc.c. */ struct TCGBackendData *be; TCGTempSet free_temps[TCG_TYPE_COUNT * 2]; diff --git a/tcg/tci/README b/tcg/tci/README index dc57f076b5..3786b0915b 100644 --- a/tcg/tci/README +++ b/tcg/tci/README @@ -21,7 +21,7 @@ This is what TCI (Tiny Code Interpreter) does. 2) Implementation Like each TCG host frontend, TCI implements the code generator in -tcg-target.c, tcg-target.h. Both files are in directory tcg/tci. +tcg-target.inc.c, tcg-target.h. Both files are in directory tcg/tci. The additional file tcg/tci.c adds the interpreter. @@ -123,7 +123,7 @@ u1 = linux-user-test works would also improve speed for hosts which support byte alignment). * A better disassembler for the pseudo code would be nice (a very primitive - disassembler is included in tcg-target.c). + disassembler is included in tcg-target.inc.c). * It might be useful to have a runtime option which selects the native TCG or TCI, so QEMU would have to include two TCGs. Today, selecting TCI diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 77e5952781..3942f9cccf 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -40,7 +40,6 @@ #if !defined(TCG_TARGET_H) #define TCG_TARGET_H -#include "config-host.h" #define TCG_TARGET_INTERPRETER 1 #define TCG_TARGET_INSN_UNIT_SIZE 1 diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.inc.c index 16ce048361..4afe4d7a8d 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.inc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "qemu/osdep.h" #include "tcg-be-null.h" /* TODO list: diff --git a/tests/Makefile b/tests/Makefile index c1c605fc63..04e34b5c7e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -173,6 +173,7 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) check-qtest-i386-y += tests/bios-tables-test$(EXESUF) +check-qtest-i386-y += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF) check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF) @@ -241,6 +242,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) check-qtest-generic-y += tests/qom-test$(EXESUF) +qapi-schema += alternate-any.json qapi-schema += alternate-array.json qapi-schema += alternate-base.json qapi-schema += alternate-clash.json @@ -518,7 +520,9 @@ tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) -tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) +tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ + tests/boot-sector.o $(libqos-obj-y) +tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 7155fecdbf..0a80ddf04b 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -18,6 +18,7 @@ #include "hw/acpi/acpi-defs.h" #include "hw/smbios/smbios.h" #include "qemu/bitmap.h" +#include "boot-sector.h" #define MACHINE_PC "pc" #define MACHINE_Q35 "q35" @@ -51,13 +52,6 @@ typedef struct { struct smbios_21_entry_point smbios_ep_table; } test_data; -#define LOW(x) ((x) & 0xff) -#define HIGH(x) ((x) >> 8) - -#define SIGNATURE 0xdead -#define SIGNATURE_OFFSET 0x10 -#define BOOT_SECTOR_ADDRESS 0x7c00 - #define ACPI_READ_FIELD(field, addr) \ do { \ switch (sizeof(field)) { \ @@ -117,35 +111,6 @@ typedef struct { g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \ } while (0) -/* Boot sector code: write SIGNATURE into memory, - * then halt. - * Q35 machine requires a minimum 0x7e000 bytes disk. - * (bug or feature?) - */ -static uint8_t boot_sector[0x7e000] = { - /* 7c00: mov $0xdead,%ax */ - [0x00] = 0xb8, - [0x01] = LOW(SIGNATURE), - [0x02] = HIGH(SIGNATURE), - /* 7c03: mov %ax,0x7c10 */ - [0x03] = 0xa3, - [0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), - [0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), - /* 7c06: cli */ - [0x06] = 0xfa, - /* 7c07: hlt */ - [0x07] = 0xf4, - /* 7c08: jmp 0x7c07=0x7c0a-3 */ - [0x08] = 0xeb, - [0x09] = LOW(-3), - /* We mov 0xdead here: set value to make debugging easier */ - [SIGNATURE_OFFSET] = LOW(0xface), - [SIGNATURE_OFFSET + 1] = HIGH(0xface), - /* End of boot sector marker */ - [0x1FE] = 0x55, - [0x1FF] = 0xAA, -}; - static const char *disk = "tests/acpi-test-disk.raw"; static const char *data_dir = "tests/acpi-test-data"; #ifdef CONFIG_IASL @@ -737,10 +702,6 @@ static void test_smbios_structs(test_data *data) static void test_acpi_one(const char *params, test_data *data) { char *args; - uint8_t signature_low; - uint8_t signature_high; - uint16_t signature; - int i; args = g_strdup_printf("-net none -display none %s " "-drive id=hd0,if=none,file=%s,format=raw " @@ -749,24 +710,7 @@ static void test_acpi_one(const char *params, test_data *data) qtest_start(args); - /* Wait at most 1 minute */ -#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) -#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) - - /* Poll until code has run and modified memory. Once it has we know BIOS - * initialization is done. TODO: check that IP reached the halt - * instruction. - */ - for (i = 0; i < TEST_CYCLES; ++i) { - signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); - signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); - signature = (signature_high << 8) | signature_low; - if (signature == SIGNATURE) { - break; - } - g_usleep(TEST_DELAY); - } - g_assert_cmphex(signature, ==, SIGNATURE); + boot_sector_test(); test_acpi_rsdp_address(data); test_acpi_rsdp_table(data); @@ -840,15 +784,11 @@ static void test_acpi_q35_tcg_bridge(void) int main(int argc, char *argv[]) { const char *arch = qtest_get_arch(); - FILE *f = fopen(disk, "w"); int ret; - if (!f) { - fprintf(stderr, "Couldn't open \"%s\": %s", disk, strerror(errno)); - return 1; - } - fwrite(boot_sector, 1, sizeof boot_sector, f); - fclose(f); + ret = boot_sector_init(disk); + if(ret) + return ret; g_test_init(&argc, &argv, NULL); @@ -859,6 +799,6 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/tcg/bridge", test_acpi_q35_tcg_bridge); } ret = g_test_run(); - unlink(disk); + boot_sector_cleanup(disk); return ret; } diff --git a/tests/boot-sector.c b/tests/boot-sector.c new file mode 100644 index 0000000000..3ffe2987ff --- /dev/null +++ b/tests/boot-sector.c @@ -0,0 +1,118 @@ +/* + * QEMU boot sector testing helpers. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com> + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "boot-sector.h" +#include "qemu-common.h" +#include "libqtest.h" + +#define LOW(x) ((x) & 0xff) +#define HIGH(x) ((x) >> 8) + +#define SIGNATURE 0xdead +#define SIGNATURE_OFFSET 0x10 +#define BOOT_SECTOR_ADDRESS 0x7c00 + +/* Boot sector code: write SIGNATURE into memory, + * then halt. + * Q35 machine requires a minimum 0x7e000 bytes disk. + * (bug or feature?) + */ +static uint8_t boot_sector[0x7e000] = { + /* The first sector will be placed at RAM address 00007C00, and + * the BIOS transfers control to 00007C00 + */ + + /* Data Segment register should be initialized, since pxe + * boot loader can leave it dirty. + */ + + /* 7c00: move $0000,%ax */ + [0x00] = 0xb8, + [0x01] = 0x00, + [0x02] = 0x00, + /* 7c03: move %ax,%ds */ + [0x03] = 0x8e, + [0x04] = 0xd8, + + /* 7c05: mov $0xdead,%ax */ + [0x05] = 0xb8, + [0x06] = LOW(SIGNATURE), + [0x07] = HIGH(SIGNATURE), + /* 7c08: mov %ax,0x7c10 */ + [0x08] = 0xa3, + [0x09] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + [0x0a] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + + /* 7c0b cli */ + [0x0b] = 0xfa, + /* 7c0c: hlt */ + [0x0c] = 0xf4, + /* 7c0e: jmp 0x7c07=0x7c0f-3 */ + [0x0d] = 0xeb, + [0x0e] = LOW(-3), + /* We mov 0xdead here: set value to make debugging easier */ + [SIGNATURE_OFFSET] = LOW(0xface), + [SIGNATURE_OFFSET + 1] = HIGH(0xface), + /* End of boot sector marker */ + [0x1FE] = 0x55, + [0x1FF] = 0xAA, +}; + +/* Create boot disk file. */ +int boot_sector_init(const char *fname) +{ + FILE *f = fopen(fname, "w"); + + if (!f) { + fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); + return 1; + } + fwrite(boot_sector, 1, sizeof boot_sector, f); + fclose(f); + return 0; +} + +/* Loop until signature in memory is OK. */ +void boot_sector_test(void) +{ + uint8_t signature_low; + uint8_t signature_high; + uint16_t signature; + int i; + + /* Wait at most 1 minute */ +#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) +#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) + + /* Poll until code has run and modified memory. Once it has we know BIOS + * initialization is done. TODO: check that IP reached the halt + * instruction. + */ + for (i = 0; i < TEST_CYCLES; ++i) { + signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); + signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + signature = (signature_high << 8) | signature_low; + if (signature == SIGNATURE) { + break; + } + g_usleep(TEST_DELAY); + } + + g_assert_cmphex(signature, ==, SIGNATURE); +} + +/* unlink boot disk file. */ +void boot_sector_cleanup(const char *fname) +{ + unlink(fname); +} diff --git a/tests/boot-sector.h b/tests/boot-sector.h new file mode 100644 index 0000000000..38be0290e3 --- /dev/null +++ b/tests/boot-sector.h @@ -0,0 +1,26 @@ +/* + * QEMU boot sector testing helpers. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com> + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TEST_BOOT_SECTOR +#define TEST_BOOT_SECTOR + +/* Create boot disk file. */ +int boot_sector_init(const char *fname); + +/* Loop until signature in memory is OK. */ +void boot_sector_test(void); + +/* unlink boot disk file. */ +void boot_sector_cleanup(const char *fname); + +#endif /* TEST_BOOT_SECTOR */ diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 69dc4d7ca9..71dd7a6e5a 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -25,9 +25,6 @@ * THE SOFTWARE. */ -#include <stdint.h> -#include <stdlib.h> -#include <stdbool.h> #include "libqos/libqos.h" #include "libqos/pci.h" #include "libqos/malloc-pc.h" diff --git a/tests/libqos/fw_cfg.h b/tests/libqos/fw_cfg.h index 61b1548b4e..e8371b2317 100644 --- a/tests/libqos/fw_cfg.h +++ b/tests/libqos/fw_cfg.h @@ -13,8 +13,6 @@ #ifndef LIBQOS_FW_CFG_H #define LIBQOS_FW_CFG_H -#include <stdint.h> -#include <sys/types.h> typedef struct QFWCFG QFWCFG; diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h index c21f1dcbd5..6e648f922a 100644 --- a/tests/libqos/i2c.h +++ b/tests/libqos/i2c.h @@ -9,7 +9,6 @@ #ifndef LIBQOS_I2C_H #define LIBQOS_I2C_H -#include <stdint.h> typedef struct I2CAdapter I2CAdapter; struct I2CAdapter { diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h index 0c6c9b7f30..ae9dac8f61 100644 --- a/tests/libqos/malloc.h +++ b/tests/libqos/malloc.h @@ -13,8 +13,6 @@ #ifndef LIBQOS_MALLOC_H #define LIBQOS_MALLOC_H -#include <stdint.h> -#include <sys/types.h> #include "qemu/queue.h" typedef enum { diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index dfaee9ec37..c06add8dbf 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -13,7 +13,6 @@ #ifndef LIBQOS_PCI_H #define LIBQOS_PCI_H -#include <stdint.h> #include "libqtest.h" #define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) diff --git a/tests/libqtest.h b/tests/libqtest.h index ebdd5bbe53..37f37adbf7 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -17,13 +17,7 @@ #ifndef LIBQTEST_H #define LIBQTEST_H -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdarg.h> -#include <sys/types.h> #include "qapi/qmp/qdict.h" -#include "glib-compat.h" typedef struct QTestState QTestState; diff --git a/tests/pxe-test.c b/tests/pxe-test.c new file mode 100644 index 0000000000..875e4c4a26 --- /dev/null +++ b/tests/pxe-test.c @@ -0,0 +1,68 @@ +/* + * PXE test cases. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com>, + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include <glib/gstdio.h> +#include "qemu-common.h" +#include "libqtest.h" +#include "boot-sector.h" + +#define NETNAME "net0" + +static const char *disk = "tests/pxe-test-disk.raw"; + +static void test_pxe_one(const char *params) +{ + char *args; + + args = g_strdup_printf("-machine accel=tcg " + "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s " + "%s ", + disk, params); + + qtest_start(args); + boot_sector_test(); + qtest_quit(global_qtest); + g_free(args); +} + +static void test_pxe_e1000(void) +{ + test_pxe_one("-device e1000,netdev=" NETNAME); +} + +static void test_pxe_virtio_pci(void) +{ + test_pxe_one("-device virtio-net-pci,netdev=" NETNAME); +} + +int main(int argc, char *argv[]) +{ + int ret; + const char *arch = qtest_get_arch(); + + ret = boot_sector_init(disk); + if(ret) + return ret; + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("pxe/e1000", test_pxe_e1000); + qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + } + ret = g_test_run(); + boot_sector_cleanup(disk); + return ret; +} diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err new file mode 100644 index 0000000000..aaa0154731 --- /dev/null +++ b/tests/qapi-schema/alternate-any.err @@ -0,0 +1 @@ +tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any' diff --git a/tests/qapi-schema/alternate-any.exit b/tests/qapi-schema/alternate-any.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/alternate-any.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/alternate-any.json b/tests/qapi-schema/alternate-any.json new file mode 100644 index 0000000000..e47a73a116 --- /dev/null +++ b/tests/qapi-schema/alternate-any.json @@ -0,0 +1,4 @@ +# we do not allow the 'any' type as an alternate branch +{ 'alternate': 'Alt', + 'data': { 'one': 'any', + 'two': 'int' } } diff --git a/tests/qapi-schema/alternate-any.out b/tests/qapi-schema/alternate-any.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/alternate-any.out diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err index e69de29bb2..bb06c5bfec 100644 --- a/tests/qapi-schema/alternate-empty.err +++ b/tests/qapi-schema/alternate-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' diff --git a/tests/qapi-schema/alternate-empty.exit b/tests/qapi-schema/alternate-empty.exit index 573541ac97..d00491fd7e 100644 --- a/tests/qapi-schema/alternate-empty.exit +++ b/tests/qapi-schema/alternate-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json index db3820f841..fff15baf16 100644 --- a/tests/qapi-schema/alternate-empty.json +++ b/tests/qapi-schema/alternate-empty.json @@ -1,2 +1,2 @@ -# FIXME - alternates should list at least two types to be useful +# alternates must list at least two types to be useful { 'alternate': 'Alt', 'data': { 'i': 'int' } } diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out index f78f174111..e69de29bb2 100644 --- a/tests/qapi-schema/alternate-empty.out +++ b/tests/qapi-schema/alternate-empty.out @@ -1,5 +0,0 @@ -object :empty -alternate Alt - case i: int -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err index e69de29bb2..15754f54eb 100644 --- a/tests/qapi-schema/flat-union-empty.err +++ b/tests/qapi-schema/flat-union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/flat-union-empty.exit b/tests/qapi-schema/flat-union-empty.exit index 573541ac97..d00491fd7e 100644 --- a/tests/qapi-schema/flat-union-empty.exit +++ b/tests/qapi-schema/flat-union-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json index 67dd2978eb..77f1d9abfb 100644 --- a/tests/qapi-schema/flat-union-empty.json +++ b/tests/qapi-schema/flat-union-empty.json @@ -1,4 +1,4 @@ -# FIXME - flat unions should not be empty +# flat unions cannot be empty { 'enum': 'Empty', 'data': [ ] } { 'struct': 'Base', 'data': { 'type': 'Empty' } } { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } } diff --git a/tests/qapi-schema/flat-union-empty.out b/tests/qapi-schema/flat-union-empty.out index eade2d5ac6..e69de29bb2 100644 --- a/tests/qapi-schema/flat-union-empty.out +++ b/tests/qapi-schema/flat-union-empty.out @@ -1,9 +0,0 @@ -object :empty -object Base - member type: Empty optional=False -enum Empty [] -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE -object Union - base Base - tag type diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 4b895275c7..632964a6ec 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -73,17 +73,22 @@ 'base': 'UserDefZero', 'data': { 'string': 'str', 'enum1': 'EnumOne' } } +{ 'struct': 'UserDefUnionBase2', + 'base': 'UserDefZero', + 'data': { 'string': 'str', 'enum1': 'QEnumTwo' } } + # this variant of UserDefFlatUnion defaults to a union that uses fields with # allocated types to test corner cases in the cleanup/dealloc visitor { 'union': 'UserDefFlatUnion2', - 'base': 'UserDefUnionBase', + 'base': 'UserDefUnionBase2', 'discriminator': 'enum1', 'data': { 'value1' : 'UserDefC', # intentional forward reference - 'value2' : 'UserDefB', - 'value3' : 'UserDefA' } } + 'value2' : 'UserDefB' } } +{ 'struct': 'WrapAlternate', + 'data': { 'alt': 'UserDefAlternate' } } { 'alternate': 'UserDefAlternate', - 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } } + 'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } } { 'struct': 'UserDefC', 'data': { 'string1': 'str', 'string2': 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 2c546b708a..f5e2a73c30 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -105,7 +105,7 @@ object UserDefA member boolean: bool optional=False member a_b: int optional=True alternate UserDefAlternate - case uda: UserDefA + case udfu: UserDefFlatUnion case s: str case i: int object UserDefB @@ -121,11 +121,10 @@ object UserDefFlatUnion case value2: UserDefB case value3: UserDefB object UserDefFlatUnion2 - base UserDefUnionBase + base UserDefUnionBase2 tag enum1 case value1: UserDefC case value2: UserDefB - case value3: UserDefA object UserDefNativeListUnion member type: UserDefNativeListUnionKind optional=False case integer: :obj-intList-wrapper @@ -167,8 +166,14 @@ object UserDefUnionBase base UserDefZero member string: str optional=False member enum1: EnumOne optional=False +object UserDefUnionBase2 + base UserDefZero + member string: str optional=False + member enum1: QEnumTwo optional=False object UserDefZero member integer: int optional=False +object WrapAlternate + member alt: UserDefAlternate optional=False event __ORG.QEMU_X-EVENT __org.qemu_x-Struct alternate __org.qemu_x-Alt case __org.qemu_x-branch: str diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err index e69de29bb2..12c20221bd 100644 --- a/tests/qapi-schema/union-empty.err +++ b/tests/qapi-schema/union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/union-empty.exit b/tests/qapi-schema/union-empty.exit index 573541ac97..d00491fd7e 100644 --- a/tests/qapi-schema/union-empty.exit +++ b/tests/qapi-schema/union-empty.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json index 1785007113..1f0b13ca21 100644 --- a/tests/qapi-schema/union-empty.json +++ b/tests/qapi-schema/union-empty.json @@ -1,2 +1,2 @@ -# FIXME - unions should not be empty +# unions cannot be empty { 'union': 'Union', 'data': { } } diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out index bdf17e5b29..e69de29bb2 100644 --- a/tests/qapi-schema/union-empty.out +++ b/tests/qapi-schema/union-empty.out @@ -1,6 +0,0 @@ -object :empty -enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] - prefix QTYPE -object Union - member type: UnionKind optional=False -enum UnionKind [] diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index 3788534d67..77dec0d1fc 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -45,11 +45,20 @@ function do_run_qemu() echo } +# Remove QMP events from (pretty-printed) output. Doesn't handle +# nested dicts correctly, but we don't get any of those in this test. +_filter_qmp_events() +{ + tr '\n' '\t' | sed -e \ + 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ + | tr '\t' '\n' +} + function run_qemu() { do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \ | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \ - | _filter_generated_node_ids + | _filter_generated_node_ids | _filter_qmp_events } size=128M diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out index ae3fccb15f..7e25a49029 100644 --- a/tests/qemu-iotests/067.out +++ b/tests/qemu-iotests/067.out @@ -70,34 +70,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -105,14 +77,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === -drive/device_add and device_del === @@ -186,34 +150,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -221,14 +157,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === drive_add/device_add and device_del === @@ -305,34 +233,6 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ ] } @@ -340,14 +240,6 @@ Testing: "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - === blockdev_add/device_add and device_del === @@ -425,34 +317,6 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "return": [ { "io-status": "ok", @@ -506,12 +370,4 @@ Testing: "return": { } } -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "SHUTDOWN" -} - *** done diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 index c0e9e2b0b5..ce8e13cb49 100755 --- a/tests/qemu-iotests/093 +++ b/tests/qemu-iotests/093 @@ -3,7 +3,7 @@ # Tests for IO throttling # # Copyright (C) 2015 Red Hat, Inc. -# Copyright (C) 2015 Igalia, S.L. +# Copyright (C) 2015-2016 Igalia, S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,6 +21,8 @@ import iotests +nsec_per_sec = 1000000000 + class ThrottleTestCase(iotests.QMPTestCase): test_img = "null-aio://" max_drives = 3 @@ -42,16 +44,7 @@ class ThrottleTestCase(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - def do_test_throttle(self, ndrives, seconds, params): - def check_limit(limit, num): - # IO throttling algorithm is discrete, allow 10% error so the test - # is more robust - return limit == 0 or \ - (num < seconds * limit * 1.1 / ndrives - and num > seconds * limit * 0.9 / ndrives) - - nsec_per_sec = 1000000000 - + def configure_throttle(self, ndrives, params): params['group'] = 'test' # Set the I/O throttling parameters to all drives @@ -60,13 +53,21 @@ class ThrottleTestCase(iotests.QMPTestCase): result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) self.assert_qmp(result, 'return', {}) + def do_test_throttle(self, ndrives, seconds, params): + def check_limit(limit, num): + # IO throttling algorithm is discrete, allow 10% error so the test + # is more robust + return limit == 0 or \ + (num < seconds * limit * 1.1 / ndrives + and num > seconds * limit * 0.9 / ndrives) + # Set vm clock to a known value ns = seconds * nsec_per_sec self.vm.qtest("clock_step %d" % ns) - # Submit enough requests. They will drain bps_max and iops_max, but the - # rest requests won't get executed until we advance the virtual clock - # with qtest interface + # Submit enough requests so the throttling mechanism kicks + # in. The throttled requests won't be executed until we + # advance the virtual clock. rq_size = 512 rd_nr = max(params['bps'] / rq_size / 2, params['bps_rd'] / rq_size, @@ -142,8 +143,44 @@ class ThrottleTestCase(iotests.QMPTestCase): for tk in params: limits = dict([(k, 0) for k in params]) limits[tk] = params[tk] * ndrives + self.configure_throttle(ndrives, limits) self.do_test_throttle(ndrives, 5, limits) + def test_burst(self): + params = {"bps": 4096, + "bps_rd": 4096, + "bps_wr": 4096, + "iops": 10, + "iops_rd": 10, + "iops_wr": 10, + } + ndrives = 1 + # Pick each out of all possible params and test + for tk in params: + rate = params[tk] * ndrives + burst_rate = rate * 7 + burst_length = 4 + + # Configure the throttling settings + settings = dict([(k, 0) for k in params]) + settings[tk] = rate + settings['%s_max' % tk] = burst_rate + settings['%s_max_length' % tk] = burst_length + self.configure_throttle(ndrives, settings) + + # Wait for the bucket to empty so we can do bursts + wait_ns = nsec_per_sec * burst_length * burst_rate / rate + self.vm.qtest("clock_step %d" % wait_ns) + + # Test I/O at the max burst rate + limits = dict([(k, 0) for k in params]) + limits[tk] = burst_rate + self.do_test_throttle(ndrives, burst_length, limits) + + # Now test I/O at the normal rate + limits[tk] = rate + self.do_test_throttle(ndrives, 5, limits) + class ThrottleTestCoroutine(ThrottleTestCase): test_img = "null-co://" diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out index fbc63e62f8..89968f35d7 100644 --- a/tests/qemu-iotests/093.out +++ b/tests/qemu-iotests/093.out @@ -1,5 +1,5 @@ -.. +.... ---------------------------------------------------------------------- -Ran 2 tests +Ran 4 tests OK diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index f78c3175a3..05e4506676 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -1,6 +1,10 @@ #!/bin/bash # -# Test case for ejecting a BB with an NBD server attached to it +# Test case for ejecting a BlockBackend with an NBD server attached to it +# +# Verify that the NBD server stops offering the drive when ejecting a +# BlockDriverState tree from a BlockBackend (that is, a medium from a +# drive) exposed via an NBD server. # # Copyright (C) 2016 Red Hat, Inc. # @@ -49,7 +53,7 @@ _make_test_img 64k $QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io keep_stderr=y \ -_launch_qemu -drive if=ide,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ +_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ 2> >(_filter_nbd) _send_qemu_cmd $QEMU_HANDLE \ diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out index 72f1b4cf1c..0409cd0174 100644 --- a/tests/qemu-iotests/140.out +++ b/tests/qemu-iotests/140.out @@ -7,7 +7,6 @@ wrote 65536/65536 bytes at offset 0 {"return": {}} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "drv", "tray-open": true}} {"return": {}} can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: No export with name 'drv' available no file open, try 'help open' diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 new file mode 100755 index 0000000000..7d8febb8ce --- /dev/null +++ b/tests/qemu-iotests/145 @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Test the combination of -incoming and snapshot=on +# +# Copyright (C) 2016 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + true +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +_make_test_img 1M +echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | _filter_qemu + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/145.out b/tests/qemu-iotests/145.out new file mode 100644 index 0000000000..75b5c8ac36 --- /dev/null +++ b/tests/qemu-iotests/145.out @@ -0,0 +1,5 @@ +QA output created by 145 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 65df029d7d..47fd40c546 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -147,3 +147,4 @@ 142 auto 143 auto quick 144 rw auto quick +145 auto quick diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index c72cdad563..b05da5baa1 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -1,7 +1,7 @@ /* * QMP Input Visitor unit-tests. * - * Copyright (C) 2011, 2015 Red Hat Inc. + * Copyright (C) 2011-2016 Red Hat Inc. * * Authors: * Luiz Capitulino <lcapitulino@redhat.com> @@ -295,7 +295,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data, g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1); g_assert_cmpstr(tmp->string, ==, "str"); g_assert_cmpint(tmp->integer, ==, 41); - g_assert_cmpint(tmp->u.value1->boolean, ==, true); + g_assert_cmpint(tmp->u.value1.boolean, ==, true); base = qapi_UserDefFlatUnion_base(tmp); g_assert(&base->enum1 == &tmp->enum1); @@ -309,6 +309,7 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, Visitor *v; Error *err = NULL; UserDefAlternate *tmp; + WrapAlternate *wrap; v = visitor_input_test_init(data, "42"); visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); @@ -322,10 +323,44 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, g_assert_cmpstr(tmp->u.s, ==, "string"); qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "{'integer':1, 'string':'str', " + "'enum1':'value1', 'boolean':true}"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QDICT); + g_assert_cmpint(tmp->u.udfu.integer, ==, 1); + g_assert_cmpstr(tmp->u.udfu.string, ==, "str"); + g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1); + g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true); + g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false); + qapi_free_UserDefAlternate(tmp); + v = visitor_input_test_init(data, "false"); visit_type_UserDefAlternate(v, NULL, &tmp, &err); error_free_or_abort(&err); qapi_free_UserDefAlternate(tmp); + + v = visitor_input_test_init(data, "{ 'alt': 42 }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QINT); + g_assert_cmpint(wrap->alt->u.i, ==, 42); + qapi_free_WrapAlternate(wrap); + + v = visitor_input_test_init(data, "{ 'alt': 'string' }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING); + g_assert_cmpstr(wrap->alt->u.s, ==, "string"); + qapi_free_WrapAlternate(wrap); + + v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', " + "'enum1':'value1', 'boolean':true} }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT); + g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1); + g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str"); + g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1); + g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true); + g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false); + qapi_free_WrapAlternate(wrap); } static void test_visitor_in_alternate_number(TestInputVisitorData *data, diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index 965f298e11..a7f8b45c77 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -1,7 +1,7 @@ /* * QMP Output Visitor unit-tests. * - * Copyright (C) 2011, 2015 Red Hat Inc. + * Copyright (C) 2011-2016 Red Hat Inc. * * Authors: * Luiz Capitulino <lcapitulino@redhat.com> @@ -403,9 +403,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); tmp->enum1 = ENUM_ONE_VALUE1; tmp->string = g_strdup("str"); - tmp->u.value1 = g_malloc0(sizeof(UserDefA)); tmp->integer = 41; - tmp->u.value1->boolean = true; + tmp->u.value1.boolean = true; visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort); arg = qmp_output_get_qobject(data->qov); @@ -427,6 +426,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, { QObject *arg; UserDefAlternate *tmp; + QDict *qdict; tmp = g_new0(UserDefAlternate, 1); tmp->type = QTYPE_QINT; @@ -453,6 +453,27 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, qapi_free_UserDefAlternate(tmp); qobject_decref(arg); + + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QDICT; + tmp->u.udfu.integer = 1; + tmp->u.udfu.string = g_strdup("str"); + tmp->u.udfu.enum1 = ENUM_ONE_VALUE1; + tmp->u.udfu.u.value1.boolean = true; + + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); + arg = qmp_output_get_qobject(data->qov); + + g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT); + qdict = qobject_to_qdict(arg); + g_assert_cmpint(qdict_size(qdict), ==, 4); + g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1); + g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); + g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); + g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); + + qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); } static void test_visitor_out_empty(TestOutputVisitorData *data, diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 858f1aa43f..59675fa57b 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -35,6 +35,9 @@ static bool double_cmp(double x, double y) /* tests for single bucket operations */ static void test_leak_bucket(void) { + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* set initial value */ bkt.avg = 150; bkt.max = 15; @@ -57,13 +60,33 @@ static void test_leak_bucket(void) g_assert(bkt.avg == 150); g_assert(bkt.max == 15); g_assert(double_cmp(bkt.level, 0)); + + /* check that burst_level leaks correctly */ + bkt.burst_level = 6; + bkt.max = 250; + bkt.burst_length = 2; /* otherwise burst_level will not leak */ + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 3.5)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 1)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); } static void test_compute_wait(void) { + unsigned i; int64_t wait; int64_t result; + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* no operation limit set */ bkt.avg = 0; bkt.max = 15; @@ -93,6 +116,27 @@ static void test_compute_wait(void) /* time required to do half an operation */ result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2; g_assert(wait == result); + + /* Perform I/O for 2.2 seconds at a rate of bkt.max */ + bkt.burst_length = 2; + bkt.level = 0; + bkt.avg = 10; + bkt.max = 200; + for (i = 0; i < 22; i++) { + double units = bkt.max / 10; + bkt.level += units; + bkt.burst_level += units; + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 10); + wait = throttle_compute_wait(&bkt); + g_assert(double_cmp(bkt.burst_level, 0)); + g_assert(double_cmp(bkt.level, (i + 1) * (bkt.max - bkt.avg) / 10)); + /* We can do bursts for the 2 seconds we have configured in + * burst_length. We have 100 extra miliseconds of burst + * because bkt.level has been leaking during this time. + * After that, we have to wait. */ + result = i < 21 ? 0 : 1.8 * NANOSECONDS_PER_SECOND; + g_assert(wait == result); + } } /* functions to test ThrottleState initialization/destroy methods */ @@ -222,6 +266,8 @@ static void set_cfg_value(bool is_max, int index, int value) { if (is_max) { cfg.buckets[index].max = value; + /* If max is set, avg should never be 0 */ + cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1); } else { cfg.buckets[index].avg = value; } @@ -231,17 +277,17 @@ static void test_enabled(void) { int i; - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); g_assert(!throttle_enabled(&cfg)); for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, 150); g_assert(throttle_enabled(&cfg)); } for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, -150); g_assert(!throttle_enabled(&cfg)); } @@ -254,32 +300,32 @@ static void test_conflicts_for_one_set(bool is_max, int read, int write) { - memset(&cfg, 0, sizeof(cfg)); - g_assert(!throttle_conflicting(&cfg)); + throttle_config_init(&cfg); + g_assert(throttle_is_valid(&cfg, NULL)); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); } static void test_conflicting_config(void) @@ -313,9 +359,9 @@ static void test_is_valid_for_value(int value, bool should_be_valid) int is_max, index; for (is_max = 0; is_max < 2; is_max++) { for (index = 0; index < BUCKETS_COUNT; index++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, index, value); - g_assert(throttle_is_valid(&cfg) == should_be_valid); + g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid); } } } @@ -335,18 +381,18 @@ static void test_max_is_missing_limit(void) int i; for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); cfg.buckets[i].max = 100; cfg.buckets[i].avg = 0; - g_assert(throttle_max_is_missing_limit(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); cfg.buckets[i].max = 0; cfg.buckets[i].avg = 0; - g_assert(!throttle_max_is_missing_limit(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); cfg.buckets[i].max = 0; cfg.buckets[i].avg = 100; - g_assert(!throttle_max_is_missing_limit(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); } } @@ -550,7 +596,7 @@ static void test_groups(void) g_assert(bdrv1->throttle_state == bdrv3->throttle_state); /* Setting the config of a group member affects the whole group */ - memset(&cfg1, 0, sizeof(cfg1)); + throttle_config_init(&cfg1); cfg1.buckets[THROTTLE_BPS_READ].avg = 500000; cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000; cfg1.buckets[THROTTLE_OPS_READ].avg = 20000; diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 9a1ad5a1bb..0779ba2602 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -37,6 +37,7 @@ #include <sys/eventfd.h> #include <arpa/inet.h> #include <netdb.h> +#include <qemu/osdep.h> #include <linux/vhost.h> @@ -176,6 +177,8 @@ typedef struct VubrVirtq { #define VHOST_MEMORY_MAX_NREGIONS 8 #define VHOST_USER_F_PROTOCOL_FEATURES 30 +/* v1.0 compliant. */ +#define VIRTIO_F_VERSION_1 32 #define VHOST_LOG_PAGE 4096 @@ -284,6 +287,7 @@ typedef struct VubrDev { struct sockaddr_in backend_udp_dest; int ready; uint64_t features; + int hdrlen; } VubrDev; static const char *vubr_request_str[] = { @@ -410,7 +414,7 @@ vubr_message_read(int conn_fd, VhostUserMsg *vmsg) if (vmsg->size > sizeof(vmsg->payload)) { fprintf(stderr, "Error: too big message request: %d, size: vmsg->size: %u, " - "while sizeof(vmsg->payload) = %lu\n", + "while sizeof(vmsg->payload) = %zu\n", vmsg->request, vmsg->size, sizeof(vmsg->payload)); exit(1); } @@ -474,7 +478,8 @@ vubr_backend_udp_recvbuf(VubrDev *dev, uint8_t *buf, size_t buflen) static void vubr_consume_raw_packet(VubrDev *dev, uint8_t *buf, uint32_t len) { - int hdrlen = sizeof(struct virtio_net_hdr_v1); + int hdrlen = dev->hdrlen; + DPRINT(" hdrlen = %d\n", dev->hdrlen); if (VHOST_USER_BRIDGE_DEBUG) { print_buffer(buf, len); @@ -536,6 +541,7 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len) struct vring_avail *avail = vq->avail; struct vring_used *used = vq->used; uint64_t log_guest_addr = vq->log_guest_addr; + int32_t remaining_len = len; unsigned int size = vq->size; @@ -550,36 +556,49 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len) uint16_t d_index = avail->ring[a_index]; int i = d_index; + uint32_t written_len = 0; - DPRINT("Post packet to guest on vq:\n"); - DPRINT(" size = %d\n", vq->size); - DPRINT(" last_avail_index = %d\n", vq->last_avail_index); - DPRINT(" last_used_index = %d\n", vq->last_used_index); - DPRINT(" a_index = %d\n", a_index); - DPRINT(" u_index = %d\n", u_index); - DPRINT(" d_index = %d\n", d_index); - DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr); - DPRINT(" desc[%d].len = %d\n", i, desc[i].len); - DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags); - DPRINT(" avail->idx = %d\n", avail_index); - DPRINT(" used->idx = %d\n", used->idx); - - if (!(desc[i].flags & VRING_DESC_F_WRITE)) { - /* FIXME: we should find writable descriptor. */ - fprintf(stderr, "Error: descriptor is not writable. Exiting.\n"); - exit(1); - } + do { + DPRINT("Post packet to guest on vq:\n"); + DPRINT(" size = %d\n", vq->size); + DPRINT(" last_avail_index = %d\n", vq->last_avail_index); + DPRINT(" last_used_index = %d\n", vq->last_used_index); + DPRINT(" a_index = %d\n", a_index); + DPRINT(" u_index = %d\n", u_index); + DPRINT(" d_index = %d\n", d_index); + DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr); + DPRINT(" desc[%d].len = %d\n", i, desc[i].len); + DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags); + DPRINT(" avail->idx = %d\n", avail_index); + DPRINT(" used->idx = %d\n", used->idx); + + if (!(desc[i].flags & VRING_DESC_F_WRITE)) { + /* FIXME: we should find writable descriptor. */ + fprintf(stderr, "Error: descriptor is not writable. Exiting.\n"); + exit(1); + } - void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr); - uint32_t chunk_len = desc[i].len; + void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); + uint32_t chunk_len = desc[i].len; + uint32_t chunk_write_len = MIN(remaining_len, chunk_len); - if (len <= chunk_len) { - memcpy(chunk_start, buf, len); - vubr_log_write(dev, desc[i].addr, len); - } else { - fprintf(stderr, - "Received too long packet from the backend. Dropping...\n"); - return; + memcpy(chunk_start, buf + written_len, chunk_write_len); + vubr_log_write(dev, desc[i].addr, chunk_write_len); + remaining_len -= chunk_write_len; + written_len += chunk_write_len; + + if ((remaining_len == 0) || !(desc[i].flags & VRING_DESC_F_NEXT)) { + break; + } + + i = desc[i].next; + } while (1); + + if (remaining_len > 0) { + fprintf(stderr, + "Too long packet for RX, remaining_len = %d, Dropping...\n", + remaining_len); + return; } /* Add descriptor to the used ring. */ @@ -622,7 +641,7 @@ vubr_process_desc(VubrDev *dev, VubrVirtq *vq) DPRINT("Chunks: "); i = d_index; do { - void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr); + void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); uint32_t chunk_len = desc[i].len; assert(!(desc[i].flags & VRING_DESC_F_WRITE)); @@ -687,7 +706,7 @@ vubr_backend_recv_cb(int sock, void *ctx) VubrVirtq *rx_vq = &dev->vq[0]; uint8_t buf[4096]; struct virtio_net_hdr_v1 *hdr = (struct virtio_net_hdr_v1 *)buf; - int hdrlen = sizeof(struct virtio_net_hdr_v1); + int hdrlen = dev->hdrlen; int buflen = sizeof(buf); int len; @@ -696,6 +715,7 @@ vubr_backend_recv_cb(int sock, void *ctx) } DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n"); + DPRINT(" hdrlen = %d\n", hdrlen); uint16_t avail_index = atomic_mb_read(&rx_vq->avail->idx); @@ -707,10 +727,12 @@ vubr_backend_recv_cb(int sock, void *ctx) return; } + memset(buf, 0, hdrlen); + /* TODO: support mergeable buffers. */ + if (hdrlen == 12) + hdr->num_buffers = 1; len = vubr_backend_udp_recvbuf(dev, buf + hdrlen, buflen - hdrlen); - *hdr = (struct virtio_net_hdr_v1) { }; - hdr->num_buffers = 1; vubr_post_buffer(dev, rx_vq, buf, len + hdrlen); } @@ -758,7 +780,15 @@ static int vubr_set_features_exec(VubrDev *dev, VhostUserMsg *vmsg) { DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + dev->features = vmsg->payload.u64; + if ((dev->features & (1ULL << VIRTIO_F_VERSION_1)) || + (dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) { + dev->hdrlen = 12; + } else { + dev->hdrlen = 10; + } + return 0; } @@ -831,7 +861,7 @@ vubr_set_mem_table_exec(VubrDev *dev, VhostUserMsg *vmsg) if (mmap_addr == MAP_FAILED) { vubr_die("mmap"); } - dev_region->mmap_addr = (uint64_t) mmap_addr; + dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr; DPRINT(" mmap_addr: 0x%016"PRIx64"\n", dev_region->mmap_addr); close(vmsg->fds[i]); @@ -905,9 +935,9 @@ vubr_set_vring_addr_exec(VubrDev *dev, VhostUserMsg *vmsg) DPRINT(" avail_user_addr: 0x%016llx\n", vra->avail_user_addr); DPRINT(" log_guest_addr: 0x%016llx\n", vra->log_guest_addr); - vq->desc = (struct vring_desc *)qva_to_va(dev, vra->desc_user_addr); - vq->used = (struct vring_used *)qva_to_va(dev, vra->used_user_addr); - vq->avail = (struct vring_avail *)qva_to_va(dev, vra->avail_user_addr); + vq->desc = (struct vring_desc *)(uintptr_t)qva_to_va(dev, vra->desc_user_addr); + vq->used = (struct vring_used *)(uintptr_t)qva_to_va(dev, vra->used_user_addr); + vq->avail = (struct vring_avail *)(uintptr_t)qva_to_va(dev, vra->avail_user_addr); vq->log_guest_addr = vra->log_guest_addr; DPRINT("Setting virtq addresses:\n"); diff --git a/trace-events b/trace-events index f986c81dad..61a133f6ee 100644 --- a/trace-events +++ b/trace-events @@ -127,9 +127,6 @@ virtio_blk_data_plane_start(void *s) "dataplane %p" virtio_blk_data_plane_stop(void *s) "dataplane %p" virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u" -# hw/virtio/dataplane/vring.c -vring_setup(uint64_t physical, void *desc, void *avail, void *used) "vring physical %#"PRIx64" desc %p avail %p used %p" - # thread-pool.c thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p" thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d" diff --git a/trace/control-internal.h b/trace/control-internal.h index 07cb1c1685..dcf67f505a 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -10,7 +10,6 @@ #ifndef TRACE__CONTROL_INTERNAL_H #define TRACE__CONTROL_INTERNAL_H -#include <string.h> extern TraceEvent trace_events[]; diff --git a/trace/ftrace.h b/trace/ftrace.h index 863e052e90..92372e3caa 100644 --- a/trace/ftrace.h +++ b/trace/ftrace.h @@ -1,7 +1,6 @@ #ifndef TRACE_FTRACE_H #define TRACE_FTRACE_H -#include <stdbool.h> #define MAX_TRACE_STRLEN 512 diff --git a/trace/simple.h b/trace/simple.h index 8d1a32eba0..1e7de45575 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -11,9 +11,6 @@ #ifndef TRACE_SIMPLE_H #define TRACE_SIMPLE_H -#include <stdint.h> -#include <stdbool.h> -#include <stdio.h> #include "trace/generated-events.h" diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 4c83834615..54be44ccea 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -1,6 +1,8 @@ #include "qemu/osdep.h" #include <glob.h> +#include <dirent.h> +#include "config-host.h" #include "ui/egl-helpers.h" EGLDisplay *qemu_egl_display; @@ -20,6 +22,133 @@ static int egl_debug; /* ---------------------------------------------------------------------- */ +#ifdef CONFIG_OPENGL_DMABUF + +int qemu_egl_rn_fd; +struct gbm_device *qemu_egl_rn_gbm_dev; +EGLContext qemu_egl_rn_ctx; + +int qemu_egl_rendernode_open(void) +{ + DIR *dir; + struct dirent *e; + int r, fd; + char *p; + + dir = opendir("/dev/dri"); + if (!dir) { + return -1; + } + + fd = -1; + while ((e = readdir(dir))) { + if (e->d_type != DT_CHR) { + continue; + } + + if (strncmp(e->d_name, "renderD", 7)) { + continue; + } + + r = asprintf(&p, "/dev/dri/%s", e->d_name); + if (r < 0) { + return -1; + } + + r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); + if (r < 0) { + free(p); + continue; + } + fd = r; + free(p); + break; + } + + closedir(dir); + if (fd < 0) { + return -1; + } + return fd; +} + +int egl_rendernode_init(void) +{ + qemu_egl_rn_fd = -1; + + qemu_egl_rn_fd = qemu_egl_rendernode_open(); + if (qemu_egl_rn_fd == -1) { + fprintf(stderr, "egl: no drm render node available\n"); + goto err; + } + + qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd); + if (!qemu_egl_rn_gbm_dev) { + fprintf(stderr, "egl: gbm_create_device failed\n"); + goto err; + } + + qemu_egl_init_dpy((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, false, false); + + if (!epoxy_has_egl_extension(qemu_egl_display, + "EGL_KHR_surfaceless_context")) { + fprintf(stderr, "egl: EGL_KHR_surfaceless_context not supported\n"); + goto err; + } + if (!epoxy_has_egl_extension(qemu_egl_display, + "EGL_MESA_image_dma_buf_export")) { + fprintf(stderr, "egl: EGL_MESA_image_dma_buf_export not supported\n"); + goto err; + } + + qemu_egl_rn_ctx = qemu_egl_init_ctx(); + if (!qemu_egl_rn_ctx) { + fprintf(stderr, "egl: egl_init_ctx failed\n"); + goto err; + } + + return 0; + +err: + if (qemu_egl_rn_gbm_dev) { + gbm_device_destroy(qemu_egl_rn_gbm_dev); + } + if (qemu_egl_rn_fd != -1) { + close(qemu_egl_rn_fd); + } + + return -1; +} + +int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc) +{ + EGLImageKHR image; + EGLint num_planes, fd; + + image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), + EGL_GL_TEXTURE_2D_KHR, + (EGLClientBuffer)(unsigned long)tex_id, + NULL); + if (!image) { + return -1; + } + + eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, + &num_planes, NULL); + if (num_planes != 1) { + eglDestroyImageKHR(qemu_egl_display, image); + return -1; + } + eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); + eglDestroyImageKHR(qemu_egl_display, image); + + return fd; +} + +#endif /* CONFIG_OPENGL_DMABUF */ + +/* ---------------------------------------------------------------------- */ + EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win) { EGLSurface esurface; @@ -1613,7 +1613,7 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp) chr->chr_set_echo = gd_vc_chr_set_echo; /* Temporary, until gd_vc_vte_init runs. */ - chr->opaque = g_new(VirtualConsole, 1); + chr->opaque = g_new0(VirtualConsole, 1); /* defer OPENED events until our vc is fully initialized */ chr->explicit_be_open = true; diff --git a/ui/spice-core.c b/ui/spice-core.c index 4dbd99ab19..a68a665a9a 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -494,9 +494,14 @@ static QemuOptsList qemu_spice_opts = { },{ .name = "playback-compression", .type = QEMU_OPT_BOOL, - }, { + },{ .name = "seamless-migration", .type = QEMU_OPT_BOOL, +#ifdef HAVE_SPICE_GL + },{ + .name = "gl", + .type = QEMU_OPT_BOOL, +#endif }, { /* end of list */ } }, @@ -568,7 +573,8 @@ static void migration_state_notifier(Notifier *notifier, void *data) if (migration_in_setup(s)) { spice_server_migrate_start(spice_server); - } else if (migration_has_finished(s)) { + } else if (migration_has_finished(s) || + migration_in_postcopy_after_devices(s)) { spice_server_migrate_end(spice_server, true); spice_have_target_host = false; } else if (migration_has_failed(s)) { @@ -819,6 +825,14 @@ void qemu_spice_init(void) #if SPICE_SERVER_VERSION >= 0x000c02 qemu_spice_register_ports(); #endif + +#ifdef HAVE_SPICE_GL + if (qemu_opt_get_bool(opts, "gl", 0)) { + if (egl_rendernode_init() == 0) { + display_opengl = 1; + } + } +#endif } int qemu_spice_add_interface(SpiceBaseInstance *sin) diff --git a/ui/spice-display.c b/ui/spice-display.c index 8a5b3258bd..242ab5f468 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -460,6 +460,13 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ssd->notify++; + + qemu_mutex_lock(&ssd->lock); + if (ssd->cursor) { + g_free(ssd->ptr_define); + ssd->ptr_define = qemu_spice_create_cursor_update(ssd, ssd->cursor, 0); + } + qemu_mutex_unlock(&ssd->lock); } static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) @@ -467,8 +474,6 @@ static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) if (ssd->cursor) { assert(ssd->dcl.con); dpy_cursor_define(ssd->dcl.con, ssd->cursor); - cursor_put(ssd->cursor); - ssd->cursor = NULL; } if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { assert(ssd->dcl.con); @@ -563,7 +568,7 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) static int interface_req_cmd_notification(QXLInstance *sin) { - dprint(1, "%s/%d:\n", __func__, sin->id); + dprint(2, "%s/%d:\n", __func__, sin->id); return 1; } @@ -616,7 +621,7 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) static int interface_req_cursor_notification(QXLInstance *sin) { - dprint(1, "%s:\n", __FUNCTION__); + dprint(2, "%s:\n", __func__); return 1; } @@ -645,9 +650,23 @@ static void interface_update_area_complete(QXLInstance *sin, /* called from spice server thread context only */ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) { - /* should never be called, used in qxl native mode only */ - fprintf(stderr, "%s: abort()\n", __func__); - abort(); + QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; + + switch (cookie->type) { +#ifdef HAVE_SPICE_GL + case QXL_COOKIE_TYPE_GL_DRAW_DONE: + { + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + qemu_bh_schedule(ssd->gl_unblock_bh); + break; + } +#endif + default: + /* should never be called, used in qxl native mode only */ + fprintf(stderr, "%s: abort()\n", __func__); + abort(); + } + g_free(cookie); } static void interface_set_client_capabilities(QXLInstance *sin, @@ -750,6 +769,11 @@ static void display_mouse_define(DisplayChangeListener *dcl, SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); qemu_mutex_lock(&ssd->lock); + if (c) { + cursor_get(c); + } + cursor_put(ssd->cursor); + ssd->cursor = c; ssd->hot_x = c->hot_x; ssd->hot_y = c->hot_y; g_free(ssd->ptr_move); @@ -769,20 +793,128 @@ static const DisplayChangeListenerOps display_listener_ops = { .dpy_cursor_define = display_mouse_define, }; +#ifdef HAVE_SPICE_GL + +static void qemu_spice_gl_block(SimpleSpiceDisplay *ssd, bool block) +{ + uint64_t timeout; + + if (block) { + timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + timeout += 1000; /* one sec */ + timer_mod(ssd->gl_unblock_timer, timeout); + } else { + timer_del(ssd->gl_unblock_timer); + } + graphic_hw_gl_block(ssd->dcl.con, block); +} + +static void qemu_spice_gl_unblock_bh(void *opaque) +{ + SimpleSpiceDisplay *ssd = opaque; + + qemu_spice_gl_block(ssd, false); +} + +static void qemu_spice_gl_block_timer(void *opaque) +{ + fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n"); +} + +static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + qemu_egl_rn_ctx); + return qemu_egl_create_context(dcl, params); +} + +static void qemu_spice_gl_scanout(DisplayChangeListener *dcl, + uint32_t tex_id, + bool y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + EGLint stride = 0, fourcc = 0; + int fd = -1; + + if (tex_id) { + fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc); + if (fd < 0) { + fprintf(stderr, "%s: failed to get fd for texture\n", __func__); + return; + } + dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__, + w, h, stride, fourcc); + } else { + dprint(1, "%s: no texture (no framebuffer)\n", __func__); + } + + assert(!tex_id || fd >= 0); + + /* note: spice server will close the fd */ + spice_qxl_gl_scanout(&ssd->qxl, fd, + surface_width(ssd->ds), + surface_height(ssd->ds), + stride, fourcc, y_0_top); +} + +static void qemu_spice_gl_update(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + uint64_t cookie; + + dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); + qemu_spice_gl_block(ssd, true); + cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); + spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie); +} + +static const DisplayChangeListenerOps display_listener_gl_ops = { + .dpy_name = "spice-egl", + .dpy_gfx_update = display_update, + .dpy_gfx_switch = display_switch, + .dpy_gfx_check_format = qemu_pixman_check_format, + .dpy_refresh = display_refresh, + .dpy_mouse_set = display_mouse_set, + .dpy_cursor_define = display_mouse_define, + + .dpy_gl_ctx_create = qemu_spice_gl_create_context, + .dpy_gl_ctx_destroy = qemu_egl_destroy_context, + .dpy_gl_ctx_make_current = qemu_egl_make_context_current, + .dpy_gl_ctx_get_current = qemu_egl_get_current_context, + + .dpy_gl_scanout = qemu_spice_gl_scanout, + .dpy_gl_update = qemu_spice_gl_update, +}; + +#endif /* HAVE_SPICE_GL */ + static void qemu_spice_display_init_one(QemuConsole *con) { SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1); qemu_spice_display_init_common(ssd); + ssd->dcl.ops = &display_listener_ops; +#ifdef HAVE_SPICE_GL + if (display_opengl) { + ssd->dcl.ops = &display_listener_gl_ops; + ssd->dmabuf_fd = -1; + ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); + ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, + qemu_spice_gl_block_timer, ssd); + } +#endif + ssd->dcl.con = con; + ssd->qxl.base.sif = &dpy_interface.base; qemu_spice_add_display_interface(&ssd->qxl, con); assert(ssd->worker); - qemu_spice_create_host_memslot(ssd); - ssd->dcl.ops = &display_listener_ops; - ssd->dcl.con = con; register_displaychangelistener(&ssd->dcl); } diff --git a/ui/vnc-palette.h b/ui/vnc-palette.h index d02f0236c1..1bd4318f53 100644 --- a/ui/vnc-palette.h +++ b/ui/vnc-palette.h @@ -31,8 +31,6 @@ #include "qapi/qmp/qlist.h" #include "qemu/queue.h" -#include <stdint.h> -#include <stdbool.h> #define VNC_PALETTE_HASH_SIZE 256 #define VNC_PALETTE_MAX_SIZE 256 @@ -38,7 +38,6 @@ #include "io/channel-socket.h" #include "io/channel-tls.h" #include <zlib.h> -#include <stdbool.h> #include "keymaps.h" #include "vnc-palette.h" diff --git a/util/throttle.c b/util/throttle.c index 2f9b23d925..371c769455 100644 --- a/util/throttle.c +++ b/util/throttle.c @@ -41,6 +41,14 @@ void throttle_leak_bucket(LeakyBucket *bkt, int64_t delta_ns) /* make the bucket leak */ bkt->level = MAX(bkt->level - leak, 0); + + /* if we allow bursts for more than one second we also need to + * keep track of bkt->burst_level so the bkt->max goal per second + * is attained */ + if (bkt->burst_length > 1) { + leak = (bkt->max * (double) delta_ns) / NANOSECONDS_PER_SECOND; + bkt->burst_level = MAX(bkt->burst_level - leak, 0); + } } /* Calculate the time delta since last leak and make proportionals leaks @@ -91,13 +99,24 @@ int64_t throttle_compute_wait(LeakyBucket *bkt) return 0; } - extra = bkt->level - bkt->max; + /* If the bucket is full then we have to wait */ + extra = bkt->level - bkt->max * bkt->burst_length; + if (extra > 0) { + return throttle_do_compute_wait(bkt->avg, extra); + } - if (extra <= 0) { - return 0; + /* If the bucket is not full yet we have to make sure that we + * fulfill the goal of bkt->max units per second. */ + if (bkt->burst_length > 1) { + /* We use 1/10 of the max value to smooth the throttling. + * See throttle_fix_bucket() for more details. */ + extra = bkt->burst_level - bkt->max / 10; + if (extra > 0) { + return throttle_do_compute_wait(bkt->max, extra); + } } - return throttle_do_compute_wait(bkt->avg, extra); + return 0; } /* This function compute the time that must be waited while this IO @@ -137,10 +156,10 @@ static int64_t throttle_compute_wait_for(ThrottleState *ts, * @next_timestamp: the resulting timer * @ret: true if a timer must be set */ -bool throttle_compute_timer(ThrottleState *ts, - bool is_write, - int64_t now, - int64_t *next_timestamp) +static bool throttle_compute_timer(ThrottleState *ts, + bool is_write, + int64_t now, + int64_t *next_timestamp) { int64_t wait; @@ -171,10 +190,24 @@ void throttle_timers_attach_aio_context(ThrottleTimers *tt, tt->write_timer_cb, tt->timer_opaque); } +/* + * Initialize the ThrottleConfig structure to a valid state + * @cfg: the config to initialize + */ +void throttle_config_init(ThrottleConfig *cfg) +{ + unsigned i; + memset(cfg, 0, sizeof(*cfg)); + for (i = 0; i < BUCKETS_COUNT; i++) { + cfg->buckets[i].burst_length = 1; + } +} + /* To be called first on the ThrottleState */ void throttle_init(ThrottleState *ts) { memset(ts, 0, sizeof(ThrottleState)); + throttle_config_init(&ts->cfg); } /* To be called first on the ThrottleTimers */ @@ -248,13 +281,14 @@ bool throttle_enabled(ThrottleConfig *cfg) return false; } -/* return true if any two throttling parameters conflicts - * +/* check if a throttling configuration is valid * @cfg: the throttling configuration to inspect - * @ret: true if any conflict detected else false + * @ret: true if valid else false + * @errp: error object */ -bool throttle_conflicting(ThrottleConfig *cfg) +bool throttle_is_valid(ThrottleConfig *cfg, Error **errp) { + int i; bool bps_flag, ops_flag; bool bps_max_flag, ops_max_flag; @@ -274,42 +308,40 @@ bool throttle_conflicting(ThrottleConfig *cfg) (cfg->buckets[THROTTLE_OPS_READ].max || cfg->buckets[THROTTLE_OPS_WRITE].max); - return bps_flag || ops_flag || bps_max_flag || ops_max_flag; -} - -/* check if a throttling configuration is valid - * @cfg: the throttling configuration to inspect - * @ret: true if valid else false - */ -bool throttle_is_valid(ThrottleConfig *cfg) -{ - int i; + if (bps_flag || ops_flag || bps_max_flag || ops_max_flag) { + error_setg(errp, "bps/iops/max total values and read/write values" + " cannot be used at the same time"); + return false; + } for (i = 0; i < BUCKETS_COUNT; i++) { if (cfg->buckets[i].avg < 0 || cfg->buckets[i].max < 0 || cfg->buckets[i].avg > THROTTLE_VALUE_MAX || cfg->buckets[i].max > THROTTLE_VALUE_MAX) { + error_setg(errp, "bps/iops/max values must be within [0, %lld]", + THROTTLE_VALUE_MAX); return false; } - } - return true; -} + if (!cfg->buckets[i].burst_length) { + error_setg(errp, "the burst length cannot be 0"); + return false; + } -/* check if bps_max/iops_max is used without bps/iops - * @cfg: the throttling configuration to inspect - */ -bool throttle_max_is_missing_limit(ThrottleConfig *cfg) -{ - int i; + if (cfg->buckets[i].burst_length > 1 && !cfg->buckets[i].max) { + error_setg(errp, "burst length set without burst rate"); + return false; + } - for (i = 0; i < BUCKETS_COUNT; i++) { if (cfg->buckets[i].max && !cfg->buckets[i].avg) { - return true; + error_setg(errp, "bps_max/iops_max require corresponding" + " bps/iops values"); + return false; } } - return false; + + return true; } /* fix bucket parameters */ @@ -318,7 +350,7 @@ static void throttle_fix_bucket(LeakyBucket *bkt) double min; /* zero bucket level */ - bkt->level = 0; + bkt->level = bkt->burst_level = 0; /* The following is done to cope with the Linux CFQ block scheduler * which regroup reads and writes by block of 100ms in the guest. @@ -421,22 +453,36 @@ bool throttle_schedule_timer(ThrottleState *ts, */ void throttle_account(ThrottleState *ts, bool is_write, uint64_t size) { + const BucketType bucket_types_size[2][2] = { + { THROTTLE_BPS_TOTAL, THROTTLE_BPS_READ }, + { THROTTLE_BPS_TOTAL, THROTTLE_BPS_WRITE } + }; + const BucketType bucket_types_units[2][2] = { + { THROTTLE_OPS_TOTAL, THROTTLE_OPS_READ }, + { THROTTLE_OPS_TOTAL, THROTTLE_OPS_WRITE } + }; double units = 1.0; + unsigned i; /* if cfg.op_size is defined and smaller than size we compute unit count */ if (ts->cfg.op_size && size > ts->cfg.op_size) { units = (double) size / ts->cfg.op_size; } - ts->cfg.buckets[THROTTLE_BPS_TOTAL].level += size; - ts->cfg.buckets[THROTTLE_OPS_TOTAL].level += units; + for (i = 0; i < 2; i++) { + LeakyBucket *bkt; - if (is_write) { - ts->cfg.buckets[THROTTLE_BPS_WRITE].level += size; - ts->cfg.buckets[THROTTLE_OPS_WRITE].level += units; - } else { - ts->cfg.buckets[THROTTLE_BPS_READ].level += size; - ts->cfg.buckets[THROTTLE_OPS_READ].level += units; + bkt = &ts->cfg.buckets[bucket_types_size[is_write][i]]; + bkt->level += size; + if (bkt->burst_length > 1) { + bkt->burst_level += size; + } + + bkt = &ts->cfg.buckets[bucket_types_units[is_write][i]]; + bkt->level += units; + if (bkt->burst_length > 1) { + bkt->burst_level += units; + } } } @@ -2762,6 +2762,33 @@ static const QEMUOption *lookup_opt(int argc, char **argv, return popt; } +static MachineClass *select_machine(void) +{ + MachineClass *machine_class = find_default_machine(); + const char *optarg; + QemuOpts *opts; + Location loc; + + loc_push_none(&loc); + + opts = qemu_get_machine_opts(); + qemu_opts_loc_restore(opts); + + optarg = qemu_opt_get(opts, "type"); + if (optarg) { + machine_class = machine_parse(optarg); + } + + if (!machine_class) { + error_report("No machine specified, and there is no default"); + error_printf("Use -machine help to list supported machines\n"); + exit(1); + } + + loc_pop(&loc); + return machine_class; +} + static int machine_set_property(void *opaque, const char *name, const char *value, Error **errp) @@ -2838,6 +2865,10 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, const char *maxmem_str, *slots_str; const ram_addr_t default_ram_size = mc->default_ram_size; QemuOpts *opts = qemu_find_opts_singleton("memory"); + Location loc; + + loc_push_none(&loc); + qemu_opts_loc_restore(opts); sz = 0; mem_str = qemu_opt_get(opts, "size"); @@ -2912,6 +2943,8 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, "'%s' option", slots_str ? "maxmem" : "slots"); exit(EXIT_FAILURE); } + + loc_pop(&loc); } int main(int argc, char **argv, char **envp) @@ -3000,7 +3033,6 @@ int main(int argc, char **argv, char **envp) os_setup_early_signal_handling(); module_call_init(MODULE_INIT_MACHINE); - machine_class = find_default_machine(); cpu_model = NULL; snapshot = 0; cyls = heads = secs = 0; @@ -3983,25 +4015,18 @@ int main(int argc, char **argv, char **envp) } } } + /* + * Clear error location left behind by the loop. + * Best done right after the loop. Do not insert code here! + */ + loc_set_none(); replay_configure(icount_opts); - opts = qemu_get_machine_opts(); - optarg = qemu_opt_get(opts, "type"); - if (optarg) { - machine_class = machine_parse(optarg); - } - - if (machine_class == NULL) { - error_report("No machine specified, and there is no default"); - error_printf("Use -machine help to list supported machines\n"); - exit(1); - } + machine_class = select_machine(); set_memory_options(&ram_slots, &maxram_size, machine_class); - loc_set_none(); - os_daemonize(); if (qemu_init_main_loop(&main_loop_err)) { |