diff options
137 files changed, 3427 insertions, 998 deletions
diff --git a/.travis.yml b/.travis.yml index ad66e5bca3..0ac170b467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,3 +98,6 @@ matrix: EXTRA_PKGS="liblttng-ust-dev liburcu-dev" EXTRA_CONFIG="--enable-trace-backends=ust" compiler: gcc + - env: TARGETS=i386-softmmu,x86_64-softmmu + EXTRA_CONFIG="--enable-modules" + compiler: gcc diff --git a/MAINTAINERS b/MAINTAINERS index 430688dcab..fd335a47bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -599,6 +599,11 @@ F: hw/net/opencores_eth.c Devices ------- +EDU +M: Jiri Slaby <jslaby@suse.cz> +S: Maintained +F: hw/misc/edu.c + IDE M: Kevin Wolf <kwolf@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com> diff --git a/block.c b/block.c index cbe4a32a5a..d45e4ddf31 100644 --- a/block.c +++ b/block.c @@ -2207,7 +2207,6 @@ int bdrv_commit(BlockDriverState *bs) int n, ro, open_flags; int ret = 0; uint8_t *buf = NULL; - char filename[PATH_MAX]; if (!drv) return -ENOMEDIUM; @@ -2222,8 +2221,6 @@ int bdrv_commit(BlockDriverState *bs) } ro = bs->backing_hd->read_only; - /* Use pstrcpy (not strncpy): filename must be NUL-terminated. */ - pstrcpy(filename, sizeof(filename), bs->backing_hd->filename); open_flags = bs->backing_hd->open_flags; if (ro) { diff --git a/block/mirror.c b/block/mirror.c index 9019d1ba56..405616422b 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -378,7 +378,8 @@ static void coroutine_fn mirror_run(void *opaque) int64_t sector_num, end, sectors_per_chunk, length; uint64_t last_pause_ns; BlockDriverInfo bdi; - char backing_filename[1024]; + char backing_filename[2]; /* we only need 2 characters because we are only + checking for a NULL string */ int ret = 0; int n; diff --git a/block/qapi.c b/block/qapi.c index a6fd6f7ab2..75c388e90b 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -175,7 +175,6 @@ void bdrv_query_image_info(BlockDriverState *bs, { int64_t size; const char *backing_filename; - char backing_filename2[1024]; BlockDriverInfo bdi; int ret; Error *err = NULL; @@ -211,13 +210,14 @@ void bdrv_query_image_info(BlockDriverState *bs, backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { + char *backing_filename2 = g_malloc0(PATH_MAX); info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; - bdrv_get_full_backing_filename(bs, backing_filename2, - sizeof(backing_filename2), &err); + bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); if (err) { error_propagate(errp, err); qapi_free_ImageInfo(info); + g_free(backing_filename2); return; } @@ -231,6 +231,7 @@ void bdrv_query_image_info(BlockDriverState *bs, info->backing_filename_format = g_strdup(bs->backing_format); info->has_backing_filename_format = true; } + g_free(backing_filename2); } ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err); diff --git a/block/qcow.c b/block/qcow.c index ece22697a6..ccbe9e0d2c 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -215,7 +215,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; - if (len > 1023) { + if (len > 1023 || len > sizeof(bs->backing_file)) { error_setg(errp, "Backing file name too long"); ret = -EINVAL; goto fail; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 1fea5142d0..183177d518 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1651,6 +1651,14 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, continue; } + if (offset_into_cluster(s, l2_offset)) { + qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" + PRIx64 " unaligned (L1 index: %#x)", + l2_offset, i); + ret = -EIO; + goto fail; + } + if (is_active_l1) { /* get active L2 tables from cache */ ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset, @@ -1709,6 +1717,19 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, } } + if (offset_into_cluster(s, offset)) { + qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset " + "%#" PRIx64 " unaligned (L2 offset: %#" + PRIx64 ", L2 index: %#x)", offset, + l2_offset, j); + if (!preallocated) { + qcow2_free_clusters(bs, offset, s->cluster_size, + QCOW2_DISCARD_ALWAYS); + } + ret = -EIO; + goto fail; + } + ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size); if (ret < 0) { if (!preallocated) { diff --git a/block/qcow2.c b/block/qcow2.c index e4e690a42b..dbaf016bc7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -868,7 +868,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; - if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) { + if (len > MIN(1023, s->cluster_size - header.backing_file_offset) || + len > sizeof(bs->backing_file)) { error_setg(errp, "Backing file name too long"); ret = -EINVAL; goto fail; diff --git a/block/vhdx.c b/block/vhdx.c index 06f2b1a0cb..bb3ed45d5c 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1174,7 +1174,18 @@ static void vhdx_update_bat_table_entry(BlockDriverState *bs, BDRVVHDXState *s, { /* The BAT entry is a uint64, with 44 bits for the file offset in units of * 1MB, and 3 bits for the block state. */ - s->bat[sinfo->bat_idx] = sinfo->file_offset; + if ((state == PAYLOAD_BLOCK_ZERO) || + (state == PAYLOAD_BLOCK_UNDEFINED) || + (state == PAYLOAD_BLOCK_NOT_PRESENT) || + (state == PAYLOAD_BLOCK_UNMAPPED)) { + s->bat[sinfo->bat_idx] = 0; /* For PAYLOAD_BLOCK_ZERO, the + FileOffsetMB field is denoted as + 'reserved' in the v1.0 spec. If it is + non-zero, MS Hyper-V will fail to read + the disk image */ + } else { + s->bat[sinfo->bat_idx] = sinfo->file_offset; + } s->bat[sinfo->bat_idx] |= state & VHDX_BAT_STATE_BIT_MASK; diff --git a/block/vmdk.c b/block/vmdk.c index 52cb8888e5..7d079adc4a 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -785,13 +785,14 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, const char *desc_file_path, Error **errp) { int ret; + int matches; char access[11]; char type[11]; char fname[512]; const char *p = desc; int64_t sectors = 0; int64_t flat_offset; - char extent_path[PATH_MAX]; + char *extent_path; BlockDriverState *extent_file; BDRVVmdkState *s = bs->opaque; VmdkExtent *extent; @@ -805,23 +806,23 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, * RW [size in sectors] VMFSSPARSE "file-name.vmdk" */ flat_offset = -1; - ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, - access, §ors, type, fname, &flat_offset); - if (ret < 4 || strcmp(access, "RW")) { + matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, + access, §ors, type, fname, &flat_offset); + if (matches < 4 || strcmp(access, "RW")) { goto next_line; } else if (!strcmp(type, "FLAT")) { - if (ret != 5 || flat_offset < 0) { + if (matches != 5 || flat_offset < 0) { error_setg(errp, "Invalid extent lines: \n%s", p); return -EINVAL; } } else if (!strcmp(type, "VMFS")) { - if (ret == 4) { + if (matches == 4) { flat_offset = 0; } else { error_setg(errp, "Invalid extent lines:\n%s", p); return -EINVAL; } - } else if (ret != 4) { + } else if (matches != 4) { error_setg(errp, "Invalid extent lines:\n%s", p); return -EINVAL; } @@ -841,11 +842,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, return -EINVAL; } + extent_path = g_malloc0(PATH_MAX); path_combine(extent_path, sizeof(extent_path), desc_file_path, fname); extent_file = NULL; ret = bdrv_open(&extent_file, extent_path, NULL, NULL, bs->open_flags | BDRV_O_PROTOCOL, NULL, errp); + g_free(extent_path); if (ret) { return ret; } @@ -1795,10 +1798,15 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) int ret = 0; bool flat, split, compress; GString *ext_desc_lines; - char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; + char *path = g_malloc0(PATH_MAX); + char *prefix = g_malloc0(PATH_MAX); + char *postfix = g_malloc0(PATH_MAX); + char *desc_line = g_malloc0(BUF_SIZE); + char *ext_filename = g_malloc0(PATH_MAX); + char *desc_filename = g_malloc0(PATH_MAX); const int64_t split_size = 0x80000000; /* VMDK has constant split size */ const char *desc_extent_line; - char parent_desc_line[BUF_SIZE] = ""; + char *parent_desc_line = g_malloc0(BUF_SIZE); uint32_t parent_cid = 0xffffffff; uint32_t number_heads = 16; bool zeroed_grain = false; @@ -1914,33 +1922,27 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) } parent_cid = vmdk_read_cid(bs, 0); bdrv_unref(bs); - snprintf(parent_desc_line, sizeof(parent_desc_line), + snprintf(parent_desc_line, BUF_SIZE, "parentFileNameHint=\"%s\"", backing_file); } /* Create extents */ filesize = total_size; while (filesize > 0) { - char desc_line[BUF_SIZE]; - char ext_filename[PATH_MAX]; - char desc_filename[PATH_MAX]; int64_t size = filesize; if (split && size > split_size) { size = split_size; } if (split) { - snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s", + snprintf(desc_filename, PATH_MAX, "%s-%c%03d%s", prefix, flat ? 'f' : 's', ++idx, postfix); } else if (flat) { - snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s", - prefix, postfix); + snprintf(desc_filename, PATH_MAX, "%s-flat%s", prefix, postfix); } else { - snprintf(desc_filename, sizeof(desc_filename), "%s%s", - prefix, postfix); + snprintf(desc_filename, PATH_MAX, "%s%s", prefix, postfix); } - snprintf(ext_filename, sizeof(ext_filename), "%s%s", - path, desc_filename); + snprintf(ext_filename, PATH_MAX, "%s%s", path, desc_filename); if (vmdk_create_extent(ext_filename, size, flat, compress, zeroed_grain, opts, errp)) { @@ -1950,7 +1952,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) filesize -= size; /* Format description line */ - snprintf(desc_line, sizeof(desc_line), + snprintf(desc_line, BUF_SIZE, desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); g_string_append(ext_desc_lines, desc_line); } @@ -2005,6 +2007,13 @@ exit: g_free(backing_file); g_free(fmt); g_free(desc); + g_free(path); + g_free(prefix); + g_free(postfix); + g_free(desc_line); + g_free(ext_filename); + g_free(desc_filename); + g_free(parent_desc_line); g_string_free(ext_desc_lines, true); return ret; } diff --git a/block/vvfat.c b/block/vvfat.c index e34a789699..a1a44f0ef5 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2909,8 +2909,8 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) array_init(&(s->commits), sizeof(commit_t)); - s->qcow_filename = g_malloc(1024); - ret = get_tmp_filename(s->qcow_filename, 1024); + s->qcow_filename = g_malloc(PATH_MAX); + ret = get_tmp_filename(s->qcow_filename, PATH_MAX); if (ret < 0) { error_setg_errno(errp, -ret, "can't create temporary file"); goto err; diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 93fd9e4259..2bf57eb1fc 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -351,8 +351,10 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * _regs->gpr[1] = infop->start_stack; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) - entry = ldq_raw(infop->entry) + infop->load_addr; - toc = ldq_raw(infop->entry + 8) + infop->load_addr; + get_user_u64(entry, infop->entry); + entry += infop->load_addr; + get_user_u64(toc, infop->entry + 8); + toc += infop->load_addr; _regs->gpr[2] = toc; infop->entry = entry; #endif @@ -365,8 +367,9 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * get_user_ual(_regs->gpr[3], pos); pos += sizeof(abi_ulong); _regs->gpr[4] = pos; - for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) - tmp = ldl(pos); + for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) { + get_user_ual(tmp, pos); + } _regs->gpr[5] = pos; } diff --git a/configure b/configure index 7539645521..f185dd0838 100755 --- a/configure +++ b/configure @@ -1877,6 +1877,32 @@ int main(void) { xc_gnttab_open(NULL, 0); xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, 0, NULL); + return 0; +} +EOF + compile_prog "" "$xen_libs" + then + xen_ctrl_version=450 + xen=yes + + elif + cat > $TMPC <<EOF && +#include <xenctrl.h> +#include <xenstore.h> +#include <stdint.h> +#include <xen/hvm/hvm_info_table.h> +#if !defined(HVM_MAX_VCPUS) +# error HVM_MAX_VCPUS not defined +#endif +int main(void) { + xc_interface *xc; + xs_daemon_open(); + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_gnttab_open(NULL, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); return 0; } EOF @@ -4283,6 +4309,9 @@ if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" fi echo "xen support $xen" +if test "$xen" = "yes" ; then + echo "xen ctrl version $xen_ctrl_version" +fi echo "brlapi support $brlapi" echo "bluez support $bluez" echo "Documentation $docs" @@ -4909,6 +4938,7 @@ echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak if test "$sparse" = "yes" ; then echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak + echo "CPP := REAL_CC=\"\$(CPP)\" cgcc" >> $config_host_mak echo "CXX := REAL_CC=\"\$(CXX)\" cgcc" >> $config_host_mak echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak diff --git a/default-configs/pci.mak b/default-configs/pci.mak index a186c39c0e..030cdc7d3d 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -32,3 +32,4 @@ CONFIG_PCI_TESTDEV=y CONFIG_NVME_PCI=y CONFIG_SD=y CONFIG_SDHCI=y +CONFIG_EDU=y diff --git a/disas/sparc.c b/disas/sparc.c index 8e755d1ba2..f4e356573e 100644 --- a/disas/sparc.c +++ b/disas/sparc.c @@ -80,19 +80,6 @@ typedef struct sparc_opcode_arch short supported; } sparc_opcode_arch; -static const struct sparc_opcode_arch sparc_opcode_archs[]; - -/* Return the bitmask of supported architectures for ARCH. */ -#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) - -/* Non-zero if ARCH1 conflicts with ARCH2. - IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ -#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ - (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ - != SPARC_OPCODE_SUPPORTED (ARCH1)) \ - && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ - != SPARC_OPCODE_SUPPORTED (ARCH2))) - /* Structure of an opcode table entry. */ typedef struct sparc_opcode @@ -301,25 +288,6 @@ static const char *sparc_decode_sparclet_cpreg (int); otherwise. */ #define v9notv9a (MASK_V9) -/* Table of opcode architectures. - The order is defined in opcode/sparc.h. */ - -static const struct sparc_opcode_arch sparc_opcode_archs[] = -{ - { "v6", MASK_V6 }, - { "v7", MASK_V6 | MASK_V7 }, - { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, - { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, - { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, - /* ??? Don't some v8 privileged insns conflict with v9? */ - { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, - /* v9 with ultrasparc additions */ - { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, - /* v9 with cheetah additions */ - { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B }, - { NULL, 0 } -}; - /* Branch condition field. */ #define COND(x) (((x) & 0xf) << 25) diff --git a/docs/multiseat.txt b/docs/multiseat.txt index 67151e0849..b963665ef2 100644 --- a/docs/multiseat.txt +++ b/docs/multiseat.txt @@ -7,7 +7,7 @@ host side First you must compile qemu with a user interface supporting multihead/multiseat and input event routing. Right now this -list includes sdl2 and gtk (both 2+3): +list includes sdl2, gtk (both 2+3) and vnc: ./configure --enable-sdl --with-sdlabi=2.0 @@ -16,16 +16,16 @@ or ./configure --enable-gtk -Next put together the qemu command line: +Next put together the qemu command line (sdk/gtk): qemu -enable-kvm -usb $memory $disk $whatever \ -display [ sdl | gtk ] \ -vga std \ -device usb-tablet -That is it for the first head, which will use the standard vga, the +That is it for the first seat, which will use the standard vga, the standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the -additional switches for the second head: +additional switches for the second seat: -device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \ -device secondary-vga,bus=head.2,addr=02.0,id=video.2 \ @@ -47,6 +47,16 @@ in a separate tab. You can either simply switch tabs to switch heads, or use the "View / Detach tab" menu item to move one of the displays to its own window so you can see both display devices side-by-side. +For vnc some additional configuration on the command line is needed. +We'll create two vnc server instances, and bind the second one to the +second seat, simliar to input devices: + + -display vnc=:1,id=primary \ + -display vnc=:2,id=secondary,display=video.2 + +Connecting to vnc display :1 gives you access to the first seat, and +likewise connecting to vnc display :2 shows the second seat. + Note on spice: Spice handles multihead just fine. But it can't do multiseat. For tablet events the event source is sent to the spice agent. But qemu can't figure it, so it can't do input routing. diff --git a/docs/specs/edu.txt b/docs/specs/edu.txt new file mode 100644 index 0000000000..7f8146780b --- /dev/null +++ b/docs/specs/edu.txt @@ -0,0 +1,110 @@ + +EDU device +========== + +Copyright (c) 2014-2015 Jiri Slaby + +This document is licensed under the GPLv2 (or later). + +This is an educational device for writing (kernel) drivers. Its original +intention was to support the Linux kernel lectures taught at the Masaryk +University. Students are given this virtual device and are expected to write a +driver with I/Os, IRQs, DMAs and such. + +The devices behaves very similar to the PCI bridge present in the COMBO6 cards +developed under the Liberouter wings. Both PCI device ID and PCI space is +inherited from that device. + +Command line switches: + -device edu[,dma_mask=mask] + + dma_mask makes the virtual device work with DMA addresses with the given + mask. For educational purposes, the device supports only 28 bits (256 MiB) + by default. Students shall set dma_mask for the device in the OS driver + properly. + +PCI specs +--------- + +PCI ID: 1234:11e8 + +PCI Region 0: + I/O memory, 1 MB in size. Users are supposed to communicate with the card + through this memory. + +MMIO area spec +-------------- + +Only size == 4 accesses are allowed for addresses < 0x80. size == 4 or +size == 8 for the rest. + +0x00 (RO) : identification (0xRRrr00edu) + RR -- major version + rr -- minor version + +0x04 (RW) : card liveness check + It is a simple value inversion (~ C operator). + +0x08 (RW) : factorial computation + The stored value is taken and factorial of it is put back here. + This happens only after factorial bit in the status register (0x20 + below) is cleared. + +0x20 (RW) : status register, bitwise OR + 0x01 -- computing factorial (RO) + 0x80 -- raise interrupt 0x01 after finishing factorial computation + +0x24 (RO) : interrupt status register + It contains values which raised the interrupt (see interrupt raise + register below). + +0x60 (WO) : interrupt raise register + Raise an interrupt. The value will be put to the interrupt status + register (using bitwise OR). + +0x64 (WO) : interrupt acknowledge register + Clear an interrupt. The value will be cleared from the interrupt + status register. This needs to be done from the ISR to stop + generating interrupts. + +0x80 (RW) : DMA source address + Where to perform the DMA from. + +0x88 (RW) : DMA destination address + Where to perform the DMA to. + +0x90 (RW) : DMA transfer count + The size of the area to perform the DMA on. + +0x98 (RW) : DMA command register, bitwise OR + 0x01 -- start transfer + 0x02 -- direction (0: from RAM to EDU, 1: from EDU to RAM) + 0x04 -- raise interrupt 0x100 after finishing the DMA + +IRQ controller +-------------- +An IRQ is generated when written to the interrupt raise register. The value +appears in interrupt status register when the interrupt is raised and has to +be written to the interrupt acknowledge register to lower it. + +DMA controller +-------------- +One has to specify, source, destination, size, and start the transfer. One +4096 bytes long buffer at offset 0x40000 is available in the EDU device. I.e. +one can perform DMA to/from this space when programmed properly. + +Example of transferring a 100 byte block to and from the buffer using a given +PCI address 'addr': +addr -> DMA source address +0x40000 -> DMA destination address +100 -> DMA transfer count +1 -> DMA command register +while (DMA command register & 1) + ; + +0x40000 -> DMA source address +addr+100 -> DMA destination address +100 -> DMA transfer count +3 -> DMA command register +while (DMA command register & 1) + ; diff --git a/exec.c b/exec.c index 081818e6e8..6b79ad1d11 100644 --- a/exec.c +++ b/exec.c @@ -553,7 +553,6 @@ void cpu_exec_init(CPUArchState *env) } } -#if defined(TARGET_HAS_ICE) #if defined(CONFIG_USER_ONLY) static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) { @@ -569,7 +568,6 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) } } #endif -#endif /* TARGET_HAS_ICE */ #if defined(CONFIG_USER_ONLY) void cpu_watchpoint_remove_all(CPUState *cpu, int mask) @@ -689,7 +687,6 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp, int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, CPUBreakpoint **breakpoint) { -#if defined(TARGET_HAS_ICE) CPUBreakpoint *bp; bp = g_malloc(sizeof(*bp)); @@ -710,15 +707,11 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, *breakpoint = bp; } return 0; -#else - return -ENOSYS; -#endif } /* Remove a specific breakpoint. */ int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags) { -#if defined(TARGET_HAS_ICE) CPUBreakpoint *bp; QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { @@ -728,27 +721,21 @@ int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags) } } return -ENOENT; -#else - return -ENOSYS; -#endif } /* Remove a specific breakpoint by reference. */ void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint) { -#if defined(TARGET_HAS_ICE) QTAILQ_REMOVE(&cpu->breakpoints, breakpoint, entry); breakpoint_invalidate(cpu, breakpoint->pc); g_free(breakpoint); -#endif } /* Remove all matching breakpoints. */ void cpu_breakpoint_remove_all(CPUState *cpu, int mask) { -#if defined(TARGET_HAS_ICE) CPUBreakpoint *bp, *next; QTAILQ_FOREACH_SAFE(bp, &cpu->breakpoints, entry, next) { @@ -756,14 +743,12 @@ void cpu_breakpoint_remove_all(CPUState *cpu, int mask) cpu_breakpoint_remove_by_ref(cpu, bp); } } -#endif } /* enable or disable single step mode. EXCP_DEBUG is returned by the CPU loop after each instruction */ void cpu_single_step(CPUState *cpu, int enabled) { -#if defined(TARGET_HAS_ICE) if (cpu->singlestep_enabled != enabled) { cpu->singlestep_enabled = enabled; if (kvm_enabled()) { @@ -775,7 +760,6 @@ void cpu_single_step(CPUState *cpu, int enabled) tb_flush(env); } } -#endif } void cpu_abort(CPUState *cpu, const char *fmt, ...) @@ -1402,12 +1386,13 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp) cpu_physical_memory_set_dirty_range(new_block->offset, new_block->used_length); - qemu_ram_setup_dump(new_block->host, new_block->max_length); - qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE); - qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); - - if (kvm_enabled()) { - kvm_setup_guest_memory(new_block->host, new_block->max_length); + if (new_block->host) { + qemu_ram_setup_dump(new_block->host, new_block->max_length); + qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE); + qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); + if (kvm_enabled()) { + kvm_setup_guest_memory(new_block->host, new_block->max_length); + } } return new_block->offset; diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index e4195ea42c..884dab3d45 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -166,7 +166,7 @@ const VMStateDescription vmstate_ich9_pm = { VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), - VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs), + VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 481a16c60a..184e7e49b9 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -285,7 +285,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState), + VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState), VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), VMSTATE_STRUCT_TEST( diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 64bd4b4c4b..ccc3b189c3 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -306,7 +306,7 @@ static const VMStateDescription vmstate_stellaris_gptm = { VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), VMSTATE_UINT32(rtc, gptm_state), VMSTATE_INT64_ARRAY(tick, gptm_state, 2), - VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), + VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2), VMSTATE_END_OF_LIST() } }; diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index bda26d0123..444eb9e419 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -999,7 +999,7 @@ static IO_READ_PROTO (dsp_read) retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80; if (s->mixer_regs[0x82] & 1) { ack = 1; - s->mixer_regs[0x82] &= 1; + s->mixer_regs[0x82] &= ~1; qemu_irq_lower (s->pic); } break; @@ -1008,7 +1008,7 @@ static IO_READ_PROTO (dsp_read) retval = 0xff; if (s->mixer_regs[0x82] & 2) { ack = 1; - s->mixer_regs[0x82] &= 2; + s->mixer_regs[0x82] &= ~2; qemu_irq_lower (s->pic); } break; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 739a03ed58..2bf87c9eea 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -791,7 +791,7 @@ static const VMStateDescription vmstate_fdc_result_timer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(result_timer, FDCtrl), + VMSTATE_TIMER_PTR(result_timer, FDCtrl), VMSTATE_END_OF_LIST() } }; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index b19b102b42..4032fcae27 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -115,6 +115,56 @@ static void virtio_blk_flush_complete(void *opaque, int ret) virtio_blk_free_request(req); } +#ifdef __linux__ + +typedef struct { + VirtIOBlockReq *req; + struct sg_io_hdr hdr; +} VirtIOBlockIoctlReq; + +static void virtio_blk_ioctl_complete(void *opaque, int status) +{ + VirtIOBlockIoctlReq *ioctl_req = opaque; + VirtIOBlockReq *req = ioctl_req->req; + VirtIODevice *vdev = VIRTIO_DEVICE(req->dev); + struct virtio_scsi_inhdr *scsi; + struct sg_io_hdr *hdr; + + scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + + if (status) { + status = VIRTIO_BLK_S_UNSUPP; + virtio_stl_p(vdev, &scsi->errors, 255); + goto out; + } + + hdr = &ioctl_req->hdr; + /* + * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) + * clear the masked_status field [hence status gets cleared too, see + * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED + * status has occurred. However they do set DRIVER_SENSE in driver_status + * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. + */ + if (hdr->status == 0 && hdr->sb_len_wr > 0) { + hdr->status = CHECK_CONDITION; + } + + virtio_stl_p(vdev, &scsi->errors, + hdr->status | (hdr->msg_status << 8) | + (hdr->host_status << 16) | (hdr->driver_status << 24)); + virtio_stl_p(vdev, &scsi->residual, hdr->resid); + virtio_stl_p(vdev, &scsi->sense_len, hdr->sb_len_wr); + virtio_stl_p(vdev, &scsi->data_len, hdr->dxfer_len); + +out: + virtio_blk_req_complete(req, status); + virtio_blk_free_request(req); + g_free(ioctl_req); +} + +#endif + static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); @@ -127,16 +177,17 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) return req; } -int virtio_blk_handle_scsi_req(VirtIOBlock *blk, - VirtQueueElement *elem) +static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req) { int status = VIRTIO_BLK_S_OK; struct virtio_scsi_inhdr *scsi = NULL; - VirtIODevice *vdev = VIRTIO_DEVICE(blk); + VirtIODevice *vdev = VIRTIO_DEVICE(req->dev); + VirtQueueElement *elem = &req->elem; + VirtIOBlock *blk = req->dev; #ifdef __linux__ int i; - struct sg_io_hdr hdr; + VirtIOBlockIoctlReq *ioctl_req; #endif /* @@ -171,71 +222,52 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk, } #ifdef __linux__ - memset(&hdr, 0, sizeof(struct sg_io_hdr)); - hdr.interface_id = 'S'; - hdr.cmd_len = elem->out_sg[1].iov_len; - hdr.cmdp = elem->out_sg[1].iov_base; - hdr.dxfer_len = 0; + ioctl_req = g_new0(VirtIOBlockIoctlReq, 1); + ioctl_req->req = req; + ioctl_req->hdr.interface_id = 'S'; + ioctl_req->hdr.cmd_len = elem->out_sg[1].iov_len; + ioctl_req->hdr.cmdp = elem->out_sg[1].iov_base; + ioctl_req->hdr.dxfer_len = 0; if (elem->out_num > 2) { /* * If there are more than the minimally required 2 output segments * there is write payload starting from the third iovec. */ - hdr.dxfer_direction = SG_DXFER_TO_DEV; - hdr.iovec_count = elem->out_num - 2; + ioctl_req->hdr.dxfer_direction = SG_DXFER_TO_DEV; + ioctl_req->hdr.iovec_count = elem->out_num - 2; - for (i = 0; i < hdr.iovec_count; i++) - hdr.dxfer_len += elem->out_sg[i + 2].iov_len; + for (i = 0; i < ioctl_req->hdr.iovec_count; i++) { + ioctl_req->hdr.dxfer_len += elem->out_sg[i + 2].iov_len; + } - hdr.dxferp = elem->out_sg + 2; + ioctl_req->hdr.dxferp = elem->out_sg + 2; } else if (elem->in_num > 3) { /* * If we have more than 3 input segments the guest wants to actually * read data. */ - hdr.dxfer_direction = SG_DXFER_FROM_DEV; - hdr.iovec_count = elem->in_num - 3; - for (i = 0; i < hdr.iovec_count; i++) - hdr.dxfer_len += elem->in_sg[i].iov_len; + ioctl_req->hdr.dxfer_direction = SG_DXFER_FROM_DEV; + ioctl_req->hdr.iovec_count = elem->in_num - 3; + for (i = 0; i < ioctl_req->hdr.iovec_count; i++) { + ioctl_req->hdr.dxfer_len += elem->in_sg[i].iov_len; + } - hdr.dxferp = elem->in_sg; + ioctl_req->hdr.dxferp = elem->in_sg; } else { /* * Some SCSI commands don't actually transfer any data. */ - hdr.dxfer_direction = SG_DXFER_NONE; + ioctl_req->hdr.dxfer_direction = SG_DXFER_NONE; } - hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base; - hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len; - - status = blk_ioctl(blk->blk, SG_IO, &hdr); - if (status) { - status = VIRTIO_BLK_S_UNSUPP; - goto fail; - } + ioctl_req->hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base; + ioctl_req->hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len; - /* - * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) - * clear the masked_status field [hence status gets cleared too, see - * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED - * status has occurred. However they do set DRIVER_SENSE in driver_status - * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. - */ - if (hdr.status == 0 && hdr.sb_len_wr > 0) { - hdr.status = CHECK_CONDITION; - } - - virtio_stl_p(vdev, &scsi->errors, - hdr.status | (hdr.msg_status << 8) | - (hdr.host_status << 16) | (hdr.driver_status << 24)); - virtio_stl_p(vdev, &scsi->residual, hdr.resid); - virtio_stl_p(vdev, &scsi->sense_len, hdr.sb_len_wr); - virtio_stl_p(vdev, &scsi->data_len, hdr.dxfer_len); - - return status; + blk_aio_ioctl(blk->blk, SG_IO, &ioctl_req->hdr, + virtio_blk_ioctl_complete, ioctl_req); + return -EINPROGRESS; #else abort(); #endif @@ -252,9 +284,11 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) { int status; - status = virtio_blk_handle_scsi_req(req->dev, &req->elem); - virtio_blk_req_complete(req, status); - virtio_blk_free_request(req); + status = virtio_blk_handle_scsi_req(req); + if (status != -EINPROGRESS) { + virtio_blk_req_complete(req, status); + virtio_blk_free_request(req); + } } void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb) diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index a5736cbc07..7044b357dc 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -520,7 +520,7 @@ static const VMStateDescription vmstate_cadence_uart = { VMSTATE_UINT32(rx_count, UartState), VMSTATE_UINT32(tx_count, UartState), VMSTATE_UINT32(rx_wpos, UartState), - VMSTATE_TIMER(fifo_trigger_handle, UartState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, UartState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/char/serial.c b/hw/char/serial.c index 3aca87416d..bd25c03bea 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -730,7 +730,7 @@ const VMStateDescription vmstate_serial_fifo_timeout_timer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(fifo_timeout_timer, SerialState), + VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState), VMSTATE_END_OF_LIST() } }; @@ -763,7 +763,7 @@ const VMStateDescription vmstate_serial_poll = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_INT32(poll_msl, SerialState), - VMSTATE_TIMER(modem_status_poll, SerialState), + VMSTATE_TIMER_PTR(modem_status_poll, SerialState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 466e543b3d..2abad1fa3d 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -214,7 +214,7 @@ const VMStateDescription vmstate_ptimer = { VMSTATE_INT64(period, ptimer_state), VMSTATE_INT64(last_event, ptimer_state), VMSTATE_INT64(next_event, ptimer_state), - VMSTATE_TIMER(timer, ptimer_state), + VMSTATE_TIMER_PTR(timer, ptimer_state), VMSTATE_END_OF_LIST() } }; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 901f289860..2eacac0787 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -189,6 +189,56 @@ int qdev_init(DeviceState *dev) return 0; } +static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners + = QTAILQ_HEAD_INITIALIZER(device_listeners); + +enum ListenerDirection { Forward, Reverse }; + +#define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \ + do { \ + DeviceListener *_listener; \ + \ + switch (_direction) { \ + case Forward: \ + QTAILQ_FOREACH(_listener, &device_listeners, link) { \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ + } \ + break; \ + case Reverse: \ + QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \ + device_listeners, link) { \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ + } \ + break; \ + default: \ + abort(); \ + } \ + } while (0) + +static int device_listener_add(DeviceState *dev, void *opaque) +{ + DEVICE_LISTENER_CALL(realize, Forward, dev); + + return 0; +} + +void device_listener_register(DeviceListener *listener) +{ + QTAILQ_INSERT_TAIL(&device_listeners, listener, link); + + qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add, + NULL, NULL); +} + +void device_listener_unregister(DeviceListener *listener) +{ + QTAILQ_REMOVE(&device_listeners, listener, link); +} + static void device_realize(DeviceState *dev, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(dev); @@ -994,6 +1044,8 @@ static void device_set_realized(Object *obj, bool value, Error **errp) goto fail; } + DEVICE_LISTENER_CALL(realize, Forward, dev); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { hotplug_handler_plug(hotplug_ctrl, dev, &local_err); @@ -1035,6 +1087,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) dc->unrealize(dev, local_errp); } dev->pending_deleted_event = true; + DEVICE_LISTENER_CALL(unrealize, Reverse, dev); } if (local_err != NULL) { diff --git a/hw/display/vga.c b/hw/display/vga.c index a620c07864..ffcfce38a4 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1437,6 +1437,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line = NULL; bool share_surface; + pixman_format_code_t format; #ifdef HOST_WORDS_BIGENDIAN bool byteswap = !s->big_endian_fb; #else @@ -1481,8 +1482,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) depth = s->get_bpp(s); - share_surface = (!s->force_shadow) && - ( depth == 32 || (depth == 16 && !byteswap) ); + /* + * Check whether we can share the surface with the backend + * or whether we need a shadow surface. We share native + * endian surfaces for 15bpp and above and byteswapped + * surfaces for 24bpp and above. + */ + format = qemu_default_pixman_format(depth, !byteswap); + if (format) { + share_surface = dpy_gfx_check_format(s->con, format) + && !s->force_shadow; + } else { + share_surface = false; + } if (s->line_offset != s->last_line_offset || disp_width != s->last_width || height != s->last_height || @@ -1490,8 +1502,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->last_byteswap != byteswap || share_surface != is_buffer_shared(surface)) { if (share_surface) { - pixman_format_code_t format = - qemu_default_pixman_format(depth, !byteswap); surface = qemu_create_displaysurface_from(disp_width, height, format, s->line_offset, s->vram_ptr + (s->start_addr * 4)); diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 6b6eaaeb47..16cf77e7b2 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -286,7 +286,7 @@ static const VMStateDescription vmstate_pl330 = { PL330Queue), VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue, PL330Queue), - VMSTATE_TIMER(timer, PL330State), + VMSTATE_TIMER_PTR(timer, PL330State), VMSTATE_UINT32(inten, PL330State), VMSTATE_UINT32(int_status, PL330State), VMSTATE_UINT32(ev_status, PL330State), diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index f86d351b3e..1adbe9e25f 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -156,6 +156,7 @@ int load_multiboot(FWCfgState *fw_cfg, MultibootState mbs; uint8_t bootinfo[MBI_SIZE]; uint8_t *mb_bootinfo_data; + uint32_t cmdline_len; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -258,27 +259,28 @@ int load_multiboot(FWCfgState *fw_cfg, mbs.offset_mbinfo = mbs.mb_buf_size; /* Calculate space for cmdlines, bootloader name, and mb_mods */ - mbs.mb_buf_size += strlen(kernel_filename) + 1; - mbs.mb_buf_size += strlen(kernel_cmdline) + 1; - mbs.mb_buf_size += strlen(bootloader_name) + 1; + cmdline_len = strlen(kernel_filename) + 1; + cmdline_len += strlen(kernel_cmdline) + 1; if (initrd_filename) { const char *r = initrd_filename; - mbs.mb_buf_size += strlen(r) + 1; + cmdline_len += strlen(r) + 1; mbs.mb_mods_avail = 1; while (*(r = get_opt_value(NULL, 0, r))) { mbs.mb_mods_avail++; r++; } - mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; } + mbs.mb_buf_size += cmdline_len; + mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail; + mbs.mb_buf_size += strlen(bootloader_name) + 1; + mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size); /* enlarge mb_buf to hold cmdlines, bootloader, mb-info structs */ mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE; - mbs.offset_bootloader = mbs.offset_cmdlines + strlen(kernel_filename) + 1 - + strlen(kernel_cmdline) + 1; + mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len; if (initrd_filename) { char *next_initrd, not_last; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f0a3201e19..38b42b05f8 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -328,6 +328,10 @@ static void pc_compat_2_2(MachineState *machine) x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); + x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); + x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); } static void pc_compat_2_1(MachineState *machine) @@ -406,7 +410,7 @@ static void pc_compat_1_3(MachineState *machine) static void pc_compat_1_2(MachineState *machine) { pc_compat_1_3(machine); - x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI); + x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); } static void pc_init_pci_2_2(MachineState *machine) @@ -483,7 +487,7 @@ static void pc_init_isa(MachineState *machine) if (!machine->cpu_model) { machine->cpu_model = "486"; } - x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI); + x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); pc_init1(machine, 0, 1); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a432944f02..63027ee76b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -307,6 +307,10 @@ static void pc_compat_2_2(MachineState *machine) x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); + x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); + x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX, + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0); } static void pc_compat_2_1(MachineState *machine) diff --git a/hw/input/hid.c b/hw/input/hid.c index 148c003bb2..6841cb8649 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -41,7 +41,7 @@ static const uint8_t hid_usage_keys[0x100] = { 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, - 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, @@ -514,6 +514,27 @@ static int hid_post_load(void *opaque, int version_id) HIDState *s = opaque; hid_set_next_idle(s); + + if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET || + s->kind == HID_MOUSE)) { + /* + * Handle ptr device migration from old qemu with full queue. + * + * Throw away everything but the last event, so we propagate + * at least the current button state to the guest. Also keep + * current position for the tablet, signal "no motion" for the + * mouse. + */ + HIDPointerEvent evt; + evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK]; + if (s->kind == HID_MOUSE) { + evt.xdx = 0; + evt.ydy = 0; + } + s->ptr.queue[0] = evt; + s->head = 0; + s->n = 1; + } return 0; } diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index 9eb68e87cb..530a6e01f5 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -455,7 +455,7 @@ static const VMStateDescription vmstate_lm_kbd = { VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256), VMSTATE_UINT8(pwm.faddr, LM823KbdState), VMSTATE_BUFFER(pwm.addr, LM823KbdState), - VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3), + VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3), VMSTATE_END_OF_LIST() } }; diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index d9bb188c15..0858b45943 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -177,13 +177,14 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time) void apic_init_reset(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); - APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + APICCommonState *s; + APICCommonClass *info; int i; - if (!s) { + if (!dev) { return; } + s = APIC_COMMON(dev); s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; @@ -208,6 +209,7 @@ void apic_init_reset(DeviceState *dev) } s->timer_expiry = -1; + info = APIC_COMMON_GET_CLASS(s); if (info->reset) { info->reset(s); } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index d0543d4b9d..6ff6c7f0cc 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -450,7 +450,7 @@ static const VMStateDescription vmstate_nvic = { VMSTATE_UINT32(systick.control, nvic_state), VMSTATE_UINT32(systick.reload, nvic_state), VMSTATE_INT64(systick.tick, nvic_state), - VMSTATE_TIMER(systick.timer, nvic_state), + VMSTATE_TIMER_PTR(systick.timer, nvic_state), VMSTATE_END_OF_LIST() } }; diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 2f53bf8194..17510ce528 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -234,7 +234,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState), VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(ar.tmr.timer, VT686PMState), + VMSTATE_TIMER_PTR(ar.tmr.timer, VT686PMState), VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8530..029a56f279 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-$(CONFIG_EDU) += edu.o diff --git a/hw/misc/edu.c b/hw/misc/edu.c new file mode 100644 index 0000000000..f601069e82 --- /dev/null +++ b/hw/misc/edu.c @@ -0,0 +1,408 @@ +/* + * QEMU educational PCI device + * + * Copyright (c) 2012-2015 Jiri Slaby + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "hw/pci/pci.h" +#include "qemu/timer.h" +#include "qemu/main-loop.h" /* iothread mutex */ +#include "qapi/visitor.h" + +#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu") + +#define FACT_IRQ 0x00000001 +#define DMA_IRQ 0x00000100 + +#define DMA_START 0x40000 +#define DMA_SIZE 4096 + +typedef struct { + PCIDevice pdev; + MemoryRegion mmio; + + QemuThread thread; + QemuMutex thr_mutex; + QemuCond thr_cond; + bool stopping; + + uint32_t addr4; + uint32_t fact; +#define EDU_STATUS_COMPUTING 0x01 +#define EDU_STATUS_IRQFACT 0x80 + uint32_t status; + + uint32_t irq_status; + +#define EDU_DMA_RUN 0x1 +#define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1) +# define EDU_DMA_FROM_PCI 0 +# define EDU_DMA_TO_PCI 1 +#define EDU_DMA_IRQ 0x4 + struct dma_state { + dma_addr_t src; + dma_addr_t dst; + dma_addr_t cnt; + dma_addr_t cmd; + } dma; + QEMUTimer dma_timer; + char dma_buf[DMA_SIZE]; + uint64_t dma_mask; +} EduState; + +static void edu_raise_irq(EduState *edu, uint32_t val) +{ + edu->irq_status |= val; + if (edu->irq_status) { + pci_set_irq(&edu->pdev, 1); + } +} + +static void edu_lower_irq(EduState *edu, uint32_t val) +{ + edu->irq_status &= ~val; + + if (!edu->irq_status) { + pci_set_irq(&edu->pdev, 0); + } +} + +static bool within(uint32_t addr, uint32_t start, uint32_t end) +{ + return start <= addr && addr < end; +} + +static void edu_check_range(uint32_t addr, uint32_t size1, uint32_t start, + uint32_t size2) +{ + uint32_t end1 = addr + size1; + uint32_t end2 = start + size2; + + if (within(addr, start, end2) && + end1 > addr && within(end1, start, end2)) { + return; + } + + hw_error("EDU: DMA range 0x%.8x-0x%.8x out of bounds (0x%.8x-0x%.8x)!", + addr, end1 - 1, start, end2 - 1); +} + +static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr) +{ + dma_addr_t res = addr & edu->dma_mask; + + if (addr != res) { + printf("EDU: clamping DMA %#.16"PRIx64" to %#.16"PRIx64"!\n", addr, res); + } + + return res; +} + +static void edu_dma_timer(void *opaque) +{ + EduState *edu = opaque; + bool raise_irq = false; + + if (!(edu->dma.cmd & EDU_DMA_RUN)) { + return; + } + + if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) { + uint32_t dst = edu->dma.dst; + edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE); + dst -= DMA_START; + pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src), + edu->dma_buf + dst, edu->dma.cnt); + } else { + uint32_t src = edu->dma.src; + edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE); + src -= DMA_START; + pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst), + edu->dma_buf + src, edu->dma.cnt); + } + + edu->dma.cmd &= ~EDU_DMA_RUN; + if (edu->dma.cmd & EDU_DMA_IRQ) { + raise_irq = true; + } + + if (raise_irq) { + edu_raise_irq(edu, DMA_IRQ); + } +} + +static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma, + bool timer) +{ + if (write && (edu->dma.cmd & EDU_DMA_RUN)) { + return; + } + + if (write) { + *dma = *val; + } else { + *val = *dma; + } + + if (timer) { + timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); + } +} + +static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + EduState *edu = opaque; + uint64_t val = ~0ULL; + + if (size != 4) { + return val; + } + + switch (addr) { + case 0x00: + val = 0x010000edu; + break; + case 0x04: + val = edu->addr4; + break; + case 0x08: + qemu_mutex_lock(&edu->thr_mutex); + val = edu->fact; + qemu_mutex_unlock(&edu->thr_mutex); + break; + case 0x20: + val = atomic_read(&edu->status); + break; + case 0x24: + val = edu->irq_status; + break; + case 0x80: + dma_rw(edu, false, &val, &edu->dma.src, false); + break; + case 0x88: + dma_rw(edu, false, &val, &edu->dma.dst, false); + break; + case 0x90: + dma_rw(edu, false, &val, &edu->dma.cnt, false); + break; + case 0x98: + dma_rw(edu, false, &val, &edu->dma.cmd, false); + break; + } + + return val; +} + +static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + EduState *edu = opaque; + + if (addr < 0x80 && size != 4) { + return; + } + + if (addr >= 0x80 && size != 4 && size != 8) { + return; + } + + switch (addr) { + case 0x04: + edu->addr4 = ~val; + break; + case 0x08: + if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) { + break; + } + /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only + * set in this function and it is under the iothread mutex. + */ + qemu_mutex_lock(&edu->thr_mutex); + edu->fact = val; + atomic_or(&edu->status, EDU_STATUS_COMPUTING); + qemu_cond_signal(&edu->thr_cond); + qemu_mutex_unlock(&edu->thr_mutex); + break; + case 0x20: + if (val & EDU_STATUS_IRQFACT) { + atomic_or(&edu->status, EDU_STATUS_IRQFACT); + } else { + atomic_and(&edu->status, ~EDU_STATUS_IRQFACT); + } + break; + case 0x60: + edu_raise_irq(edu, val); + break; + case 0x64: + edu_lower_irq(edu, val); + break; + case 0x80: + dma_rw(edu, true, &val, &edu->dma.src, false); + break; + case 0x88: + dma_rw(edu, true, &val, &edu->dma.dst, false); + break; + case 0x90: + dma_rw(edu, true, &val, &edu->dma.cnt, false); + break; + case 0x98: + if (!(val & EDU_DMA_RUN)) { + break; + } + dma_rw(edu, true, &val, &edu->dma.cmd, true); + break; + } +} + +static const MemoryRegionOps edu_mmio_ops = { + .read = edu_mmio_read, + .write = edu_mmio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +/* + * We purposedly use a thread, so that users are forced to wait for the status + * register. + */ +static void *edu_fact_thread(void *opaque) +{ + EduState *edu = opaque; + + while (1) { + uint32_t val, ret = 1; + + qemu_mutex_lock(&edu->thr_mutex); + while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && + !edu->stopping) { + qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex); + } + + if (edu->stopping) { + qemu_mutex_unlock(&edu->thr_mutex); + break; + } + + val = edu->fact; + qemu_mutex_unlock(&edu->thr_mutex); + + while (val > 0) { + ret *= val--; + } + + /* + * We should sleep for a random period here, so that students are + * forced to check the status properly. + */ + + qemu_mutex_lock(&edu->thr_mutex); + edu->fact = ret; + qemu_mutex_unlock(&edu->thr_mutex); + atomic_and(&edu->status, ~EDU_STATUS_COMPUTING); + + if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) { + qemu_mutex_lock_iothread(); + edu_raise_irq(edu, FACT_IRQ); + qemu_mutex_unlock_iothread(); + } + } + + return NULL; +} + +static int pci_edu_init(PCIDevice *pdev) +{ + EduState *edu = DO_UPCAST(EduState, pdev, pdev); + uint8_t *pci_conf = pdev->config; + + timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); + + qemu_mutex_init(&edu->thr_mutex); + qemu_cond_init(&edu->thr_cond); + qemu_thread_create(&edu->thread, "edu", edu_fact_thread, + edu, QEMU_THREAD_JOINABLE); + + pci_config_set_interrupt_pin(pci_conf, 1); + + memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, + "edu-mmio", 1 << 20); + pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); + + return 0; +} + +static void pci_edu_uninit(PCIDevice *pdev) +{ + EduState *edu = DO_UPCAST(EduState, pdev, pdev); + + qemu_mutex_lock(&edu->thr_mutex); + edu->stopping = true; + qemu_mutex_unlock(&edu->thr_mutex); + qemu_cond_signal(&edu->thr_cond); + qemu_thread_join(&edu->thread); + + qemu_cond_destroy(&edu->thr_cond); + qemu_mutex_destroy(&edu->thr_mutex); + + timer_del(&edu->dma_timer); +} + +static void edu_obj_uint64(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + uint64_t *val = opaque; + + visit_type_uint64(v, val, name, errp); +} + +static void edu_instance_init(Object *obj) +{ + EduState *edu = EDU(obj); + + edu->dma_mask = (1UL << 28) - 1; + object_property_add(obj, "dma_mask", "uint64", edu_obj_uint64, + edu_obj_uint64, NULL, &edu->dma_mask, NULL); +} + +static void edu_class_init(ObjectClass *class, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(class); + + k->init = pci_edu_init; + k->exit = pci_edu_uninit; + k->vendor_id = PCI_VENDOR_ID_QEMU; + k->device_id = 0x11e8; + k->revision = 0x10; + k->class_id = PCI_CLASS_OTHERS; +} + +static void pci_edu_register_types(void) +{ + static const TypeInfo edu_info = { + .name = "edu", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EduState), + .instance_init = edu_instance_init, + .class_init = edu_class_init, + }; + + type_register_static(&edu_info); +} +type_init(pci_edu_register_types) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b4273aa171..47d9771a04 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -631,7 +631,7 @@ static const VMStateDescription vmstate_cuda_timer = { VMSTATE_UINT16(counter_value, CUDATimer), VMSTATE_INT64(load_time, CUDATimer), VMSTATE_INT64(next_irq_time, CUDATimer), - VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist), + VMSTATE_TIMER_PTR_TEST(timer, CUDATimer, cuda_timer_exist), VMSTATE_END_OF_LIST() } }; diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 8a1c8f17b0..8486b80bb7 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -1719,7 +1719,7 @@ const VMStateDescription vmstate_pcnet = { VMSTATE_BUFFER(buffer, PCNetState), VMSTATE_UNUSED_TEST(is_version_2, 4), VMSTATE_INT32(tx_busy, PCNetState), - VMSTATE_TIMER(poll_timer, PCNetState), + VMSTATE_TIMER_PTR(poll_timer, PCNetState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 15064d3ec2..10e5355de7 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1205,8 +1205,8 @@ const VMStateDescription sdhci_vmstate = { VMSTATE_UINT64(admasysaddr, SDHCIState), VMSTATE_UINT8(stopped_state, SDHCIState), VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz), - VMSTATE_TIMER(insert_timer, SDHCIState), - VMSTATE_TIMER(transfer_timer, SDHCIState), + VMSTATE_TIMER_PTR(insert_timer, SDHCIState), + VMSTATE_TIMER_PTR(transfer_timer, SDHCIState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index a0656d58a1..435142a3c9 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -328,7 +328,7 @@ static const VMStateDescription vmstate_a9_gtimer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_TIMER(timer, A9GTimerState), + VMSTATE_TIMER_PTR(timer, A9GTimerState), VMSTATE_UINT64(counter, A9GTimerState), VMSTATE_UINT64(ref_counter, A9GTimerState), VMSTATE_UINT64(cpu_ref_time, A9GTimerState), diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 35a0a2356f..8b93b3c1ae 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -246,7 +246,7 @@ static const VMStateDescription vmstate_timerblock = { VMSTATE_UINT32(control, TimerBlock), VMSTATE_UINT32(status, TimerBlock), VMSTATE_INT64(tick, TimerBlock), - VMSTATE_TIMER(timer, TimerBlock), + VMSTATE_TIMER_PTR(timer, TimerBlock), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index d8bc231e5b..78d86be91c 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -299,7 +299,7 @@ static const VMStateDescription vmstate_hpet_timer = { VMSTATE_UINT64(fsb, HPETTimer), VMSTATE_UINT64(period, HPETTimer), VMSTATE_UINT8(wrap_flag, HPETTimer), - VMSTATE_TIMER(qemu_timer, HPETTimer), + VMSTATE_TIMER_PTR(qemu_timer, HPETTimer), VMSTATE_END_OF_LIST() } }; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index f18d1281ca..5a107fad5d 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -758,7 +758,7 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_BUFFER(cmos_data, RTCState), VMSTATE_UINT8(cmos_index, RTCState), VMSTATE_UNUSED(7*4), - VMSTATE_TIMER(periodic_timer, RTCState), + VMSTATE_TIMER_PTR(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), VMSTATE_UNUSED(3*8), VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), @@ -766,7 +766,7 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_UINT64_V(base_rtc, RTCState, 3), VMSTATE_UINT64_V(last_update, RTCState, 3), VMSTATE_INT64_V(offset, RTCState, 3), - VMSTATE_TIMER_V(update_timer, RTCState, 3), + VMSTATE_TIMER_PTR_V(update_timer, RTCState, 3), VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), VMSTATE_END_OF_LIST() }, diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 1cc0fc116d..ccf54b6e09 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2437,7 +2437,7 @@ const VMStateDescription vmstate_ehci = { VMSTATE_UINT32(portsc[4], EHCIState), VMSTATE_UINT32(portsc[5], EHCIState), /* frame timer */ - VMSTATE_TIMER(frame_timer, EHCIState), + VMSTATE_TIMER_PTR(frame_timer, EHCIState), VMSTATE_UINT64(last_run_ns, EHCIState), VMSTATE_UINT32(async_stepdown, EHCIState), /* schedule state */ diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 9a84eb6950..a0d478e63e 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -2015,7 +2015,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = { .minimum_version_id = 1, .pre_load = ohci_eof_timer_pre_load, .fields = (VMStateField[]) { - VMSTATE_TIMER(eof_timer, OHCIState), + VMSTATE_TIMER_PTR(eof_timer, OHCIState), VMSTATE_END_OF_LIST() }, }; diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 4a4215d332..f903de7072 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -419,7 +419,7 @@ static const VMStateDescription vmstate_uhci = { VMSTATE_UINT32(fl_base_addr, UHCIState), VMSTATE_UINT8(sof_timing, UHCIState), VMSTATE_UINT8(status2, UHCIState), - VMSTATE_TIMER(frame_timer, UHCIState), + VMSTATE_TIMER_PTR(frame_timer, UHCIState), VMSTATE_INT64_V(expire_time, UHCIState, 2), VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3), VMSTATE_END_OF_LIST() diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 9a942cfad4..776699b44e 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3855,7 +3855,7 @@ static const VMStateDescription vmstate_xhci = { /* Runtime Registers & state */ VMSTATE_INT64(mfindex_start, XHCIState), - VMSTATE_TIMER(mfwrap_timer, XHCIState), + VMSTATE_TIMER_PTR(mfwrap_timer, XHCIState), VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing), VMSTATE_END_OF_LIST() diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 9fbd59e5ee..962d3f5118 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2438,7 +2438,7 @@ static const VMStateDescription usbredir_vmstate = { .post_load = usbredir_post_load, .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBRedirDevice), - VMSTATE_TIMER(attach_timer, USBRedirDevice), + VMSTATE_TIMER_PTR(attach_timer, USBRedirDevice), { .name = "parser", .version_id = 0, diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 687c8b1d4a..33dd6d43c0 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -398,7 +398,7 @@ static const VMStateDescription vmstate_i6300esb = { VMSTATE_INT32(free_run, I6300State), VMSTATE_INT32(locked, I6300State), VMSTATE_INT32(enabled, I6300State), - VMSTATE_TIMER(timer, I6300State), + VMSTATE_TIMER_PTR(timer, I6300State), VMSTATE_UINT32(timer1_preload, I6300State), VMSTATE_UINT32(timer2_preload, I6300State), VMSTATE_INT32(stage, I6300State), diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index 8cb9827e3b..0917a713db 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -93,7 +93,7 @@ static const VMStateDescription vmstate_ib700 = { .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { - VMSTATE_TIMER(timer, IB700State), + VMSTATE_TIMER_PTR(timer, IB700State), VMSTATE_END_OF_LIST() } }; diff --git a/include/block/block_int.h b/include/block/block_int.h index 06a21dd13d..e264be97b2 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -339,13 +339,13 @@ struct BlockDriverState { * regarding this BDS's context */ QLIST_HEAD(, BdrvAioNotifier) aio_notifiers; - char filename[1024]; - char backing_file[1024]; /* if non zero, the image is a diff of - this file image */ + char filename[PATH_MAX]; + char backing_file[PATH_MAX]; /* if non zero, the image is a diff of + this file image */ char backing_format[16]; /* if non-zero and backing_file exists */ QDict *full_open_options; - char exact_filename[1024]; + char exact_filename[PATH_MAX]; BlockDriverState *backing_hd; BlockDriverState *file; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 5fdd2fee80..2c4828694b 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -115,43 +115,9 @@ static inline void tswap64s(uint64_t *s) #define bswaptls(s) bswap64s(s) #endif -/* CPU memory access without any memory or io remapping */ - -/* - * the generic syntax for the memory accesses is: - * - * load: ld{type}{sign}{size}{endian}_{access_type}(ptr) - * - * store: st{type}{size}{endian}_{access_type}(ptr, val) - * - * type is: - * (empty): integer access - * f : float access - * - * sign is: - * (empty): for floats or 32 bit size - * u : unsigned - * s : signed - * - * size is: - * b: 8 bits - * w: 16 bits - * l: 32 bits - * q: 64 bits - * - * endian is: - * (empty): target cpu endianness or 8 bit access - * r : reversed target cpu endianness (not implemented yet) - * be : big endian (not implemented yet) - * le : little endian (not implemented yet) - * - * access_type is: - * raw : host memory access - * user : user mode access using soft MMU - * kernel : kernel mode access using soft MMU +/* Target-endianness CPU memory access functions. These fit into the + * {ld,st}{type}{sign}{size}{endian}_p naming scheme described in bswap.h. */ - -/* target-endianness CPU memory access functions */ #if defined(TARGET_WORDS_BIGENDIAN) #define lduw_p(p) lduw_be_p(p) #define ldsw_p(p) ldsw_be_p(p) diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index e5550e7175..0e825ea773 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -23,7 +23,26 @@ * * Used by target op helpers. * - * MMU mode suffixes are defined in target cpu.h. + * The syntax for the accessors is: + * + * load: cpu_ld{sign}{size}_{mmusuffix}(env, ptr) + * + * store: cpu_st{sign}{size}_{mmusuffix}(env, ptr, val) + * + * sign is: + * (empty): for 32 and 64 bit sizes + * u : unsigned + * s : signed + * + * size is: + * b: 8 bits + * w: 16 bits + * l: 32 bits + * q: 64 bits + * + * mmusuffix is one of the generic suffixes "data" or "code", or + * (for softmmu configs) a target-specific MMU mode suffix as defined + * in target cpu.h. */ #ifndef CPU_LDST_H #define CPU_LDST_H @@ -53,112 +72,43 @@ h2g_nocheck(x); \ }) -#define saddr(x) g2h(x) -#define laddr(x) g2h(x) - -#else /* !CONFIG_USER_ONLY */ -/* NOTE: we use double casts if pointers and target_ulong have - different sizes */ -#define saddr(x) (uint8_t *)(intptr_t)(x) -#define laddr(x) (uint8_t *)(intptr_t)(x) #endif -#define ldub_raw(p) ldub_p(laddr((p))) -#define ldsb_raw(p) ldsb_p(laddr((p))) -#define lduw_raw(p) lduw_p(laddr((p))) -#define ldsw_raw(p) ldsw_p(laddr((p))) -#define ldl_raw(p) ldl_p(laddr((p))) -#define ldq_raw(p) ldq_p(laddr((p))) -#define ldfl_raw(p) ldfl_p(laddr((p))) -#define ldfq_raw(p) ldfq_p(laddr((p))) -#define stb_raw(p, v) stb_p(saddr((p)), v) -#define stw_raw(p, v) stw_p(saddr((p)), v) -#define stl_raw(p, v) stl_p(saddr((p)), v) -#define stq_raw(p, v) stq_p(saddr((p)), v) -#define stfl_raw(p, v) stfl_p(saddr((p)), v) -#define stfq_raw(p, v) stfq_p(saddr((p)), v) +#if defined(CONFIG_USER_ONLY) +/* In user-only mode we provide only the _code and _data accessors. */ -#if defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "exec/cpu_ldst_useronly_template.h" -/* if user mode, no other memory access functions */ -#define ldub(p) ldub_raw(p) -#define ldsb(p) ldsb_raw(p) -#define lduw(p) lduw_raw(p) -#define ldsw(p) ldsw_raw(p) -#define ldl(p) ldl_raw(p) -#define ldq(p) ldq_raw(p) -#define ldfl(p) ldfl_raw(p) -#define ldfq(p) ldfq_raw(p) -#define stb(p, v) stb_raw(p, v) -#define stw(p, v) stw_raw(p, v) -#define stl(p, v) stl_raw(p, v) -#define stq(p, v) stq_raw(p, v) -#define stfl(p, v) stfl_raw(p, v) -#define stfq(p, v) stfq_raw(p, v) - -#define cpu_ldub_code(env1, p) ldub_raw(p) -#define cpu_ldsb_code(env1, p) ldsb_raw(p) -#define cpu_lduw_code(env1, p) lduw_raw(p) -#define cpu_ldsw_code(env1, p) ldsw_raw(p) -#define cpu_ldl_code(env1, p) ldl_raw(p) -#define cpu_ldq_code(env1, p) ldq_raw(p) - -#define cpu_ldub_data(env, addr) ldub_raw(addr) -#define cpu_lduw_data(env, addr) lduw_raw(addr) -#define cpu_ldsw_data(env, addr) ldsw_raw(addr) -#define cpu_ldl_data(env, addr) ldl_raw(addr) -#define cpu_ldq_data(env, addr) ldq_raw(addr) - -#define cpu_stb_data(env, addr, data) stb_raw(addr, data) -#define cpu_stw_data(env, addr, data) stw_raw(addr, data) -#define cpu_stl_data(env, addr, data) stl_raw(addr, data) -#define cpu_stq_data(env, addr, data) stq_raw(addr, data) - -#define cpu_ldub_kernel(env, addr) ldub_raw(addr) -#define cpu_lduw_kernel(env, addr) lduw_raw(addr) -#define cpu_ldsw_kernel(env, addr) ldsw_raw(addr) -#define cpu_ldl_kernel(env, addr) ldl_raw(addr) -#define cpu_ldq_kernel(env, addr) ldq_raw(addr) - -#define cpu_stb_kernel(env, addr, data) stb_raw(addr, data) -#define cpu_stw_kernel(env, addr, data) stw_raw(addr, data) -#define cpu_stl_kernel(env, addr, data) stl_raw(addr, data) -#define cpu_stq_kernel(env, addr, data) stq_raw(addr, data) - -#define ldub_kernel(p) ldub_raw(p) -#define ldsb_kernel(p) ldsb_raw(p) -#define lduw_kernel(p) lduw_raw(p) -#define ldsw_kernel(p) ldsw_raw(p) -#define ldl_kernel(p) ldl_raw(p) -#define ldq_kernel(p) ldq_raw(p) -#define ldfl_kernel(p) ldfl_raw(p) -#define ldfq_kernel(p) ldfq_raw(p) -#define stb_kernel(p, v) stb_raw(p, v) -#define stw_kernel(p, v) stw_raw(p, v) -#define stl_kernel(p, v) stl_raw(p, v) -#define stq_kernel(p, v) stq_raw(p, v) -#define stfl_kernel(p, v) stfl_raw(p, v) -#define stfq_kernel(p, vt) stfq_raw(p, v) - -#define cpu_ldub_data(env, addr) ldub_raw(addr) -#define cpu_lduw_data(env, addr) lduw_raw(addr) -#define cpu_ldl_data(env, addr) ldl_raw(addr) - -#define cpu_stb_data(env, addr, data) stb_raw(addr, data) -#define cpu_stw_data(env, addr, data) stw_raw(addr, data) -#define cpu_stl_data(env, addr, data) stl_raw(addr, data) +#define DATA_SIZE 2 +#include "exec/cpu_ldst_useronly_template.h" -#else +#define DATA_SIZE 4 +#include "exec/cpu_ldst_useronly_template.h" -/* XXX: find something cleaner. - * Furthermore, this is false for 64 bits targets - */ -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel -#define ldul_hypv ldl_hypv -#define ldul_executive ldl_executive -#define ldul_supervisor ldl_supervisor +#define DATA_SIZE 8 +#include "exec/cpu_ldst_useronly_template.h" +#undef MEMSUFFIX + +#define MEMSUFFIX _code +#define CODE_ACCESS +#define DATA_SIZE 1 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 2 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 4 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 8 +#include "exec/cpu_ldst_useronly_template.h" +#undef MEMSUFFIX +#undef CODE_ACCESS + +#else /* The memory helpers for tcg-generated code need tcg_target_long etc. */ #include "tcg.h" @@ -182,6 +132,7 @@ uint16_t helper_ldw_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); uint32_t helper_ldl_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); +#ifdef MMU_MODE0_SUFFIX #define CPU_MMU_INDEX 0 #define MEMSUFFIX MMU_MODE0_SUFFIX #define DATA_SIZE 1 @@ -197,7 +148,9 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #include "exec/cpu_ldst_template.h" #undef CPU_MMU_INDEX #undef MEMSUFFIX +#endif +#if (NB_MMU_MODES >= 2) && defined(MMU_MODE1_SUFFIX) #define CPU_MMU_INDEX 1 #define MEMSUFFIX MMU_MODE1_SUFFIX #define DATA_SIZE 1 @@ -213,8 +166,9 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #include "exec/cpu_ldst_template.h" #undef CPU_MMU_INDEX #undef MEMSUFFIX +#endif -#if (NB_MMU_MODES >= 3) +#if (NB_MMU_MODES >= 3) && defined(MMU_MODE2_SUFFIX) #define CPU_MMU_INDEX 2 #define MEMSUFFIX MMU_MODE2_SUFFIX @@ -233,7 +187,7 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #undef MEMSUFFIX #endif /* (NB_MMU_MODES >= 3) */ -#if (NB_MMU_MODES >= 4) +#if (NB_MMU_MODES >= 4) && defined(MMU_MODE3_SUFFIX) #define CPU_MMU_INDEX 3 #define MEMSUFFIX MMU_MODE3_SUFFIX @@ -252,7 +206,7 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #undef MEMSUFFIX #endif /* (NB_MMU_MODES >= 4) */ -#if (NB_MMU_MODES >= 5) +#if (NB_MMU_MODES >= 5) && defined(MMU_MODE4_SUFFIX) #define CPU_MMU_INDEX 4 #define MEMSUFFIX MMU_MODE4_SUFFIX @@ -271,7 +225,7 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #undef MEMSUFFIX #endif /* (NB_MMU_MODES >= 5) */ -#if (NB_MMU_MODES >= 6) +#if (NB_MMU_MODES >= 6) && defined(MMU_MODE5_SUFFIX) #define CPU_MMU_INDEX 5 #define MEMSUFFIX MMU_MODE5_SUFFIX @@ -311,18 +265,6 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); #undef CPU_MMU_INDEX #undef MEMSUFFIX -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) - #define CPU_MMU_INDEX (cpu_mmu_index(env)) #define MEMSUFFIX _code #define SOFTMMU_CODE_ACCESS diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h index 006093ac49..95ab7504e2 100644 --- a/include/exec/cpu_ldst_template.h +++ b/include/exec/cpu_ldst_template.h @@ -4,9 +4,7 @@ * Generate inline load/store functions for one MMU mode and data * size. * - * Generate a store function as well as signed and unsigned loads. For - * 32 and 64 bit cases, also generate floating point functions with - * the same size. + * Generate a store function as well as signed and unsigned loads. * * Not used directly but included from cpu_ldst.h. * @@ -79,7 +77,7 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) res = glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(env, addr, mmu_idx); } else { uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; - res = glue(glue(ld, USUFFIX), _raw)(hostaddr); + res = glue(glue(ld, USUFFIX), _p)((uint8_t *)hostaddr); } return res; } @@ -101,7 +99,7 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) MMUSUFFIX)(env, addr, mmu_idx); } else { uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; - res = glue(glue(lds, SUFFIX), _raw)(hostaddr); + res = glue(glue(lds, SUFFIX), _p)((uint8_t *)hostaddr); } return res; } @@ -127,60 +125,10 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr, glue(glue(helper_st, SUFFIX), MMUSUFFIX)(env, addr, v, mmu_idx); } else { uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; - glue(glue(st, SUFFIX), _raw)(hostaddr, v); + glue(glue(st, SUFFIX), _p)((uint8_t *)hostaddr, v); } } - - -#if DATA_SIZE == 8 -static inline float64 glue(cpu_ldfq, MEMSUFFIX)(CPUArchState *env, - target_ulong ptr) -{ - union { - float64 d; - uint64_t i; - } u; - u.i = glue(cpu_ldq, MEMSUFFIX)(env, ptr); - return u.d; -} - -static inline void glue(cpu_stfq, MEMSUFFIX)(CPUArchState *env, - target_ulong ptr, float64 v) -{ - union { - float64 d; - uint64_t i; - } u; - u.d = v; - glue(cpu_stq, MEMSUFFIX)(env, ptr, u.i); -} -#endif /* DATA_SIZE == 8 */ - -#if DATA_SIZE == 4 -static inline float32 glue(cpu_ldfl, MEMSUFFIX)(CPUArchState *env, - target_ulong ptr) -{ - union { - float32 f; - uint32_t i; - } u; - u.i = glue(cpu_ldl, MEMSUFFIX)(env, ptr); - return u.f; -} - -static inline void glue(cpu_stfl, MEMSUFFIX)(CPUArchState *env, - target_ulong ptr, float32 v) -{ - union { - float32 f; - uint32_t i; - } u; - u.f = v; - glue(cpu_stl, MEMSUFFIX)(env, ptr, u.i); -} -#endif /* DATA_SIZE == 4 */ - #endif /* !SOFTMMU_CODE_ACCESS */ #undef RES_TYPE diff --git a/include/exec/cpu_ldst_useronly_template.h b/include/exec/cpu_ldst_useronly_template.h new file mode 100644 index 0000000000..b3b865fae8 --- /dev/null +++ b/include/exec/cpu_ldst_useronly_template.h @@ -0,0 +1,81 @@ +/* + * User-only accessor function support + * + * Generate inline load/store functions for one data size. + * + * Generate a store function as well as signed and unsigned loads. + * + * Not used directly but included from cpu_ldst.h. + * + * Copyright (c) 2015 Linaro Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * 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/>. + */ +#if DATA_SIZE == 8 +#define SUFFIX q +#define USUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define USUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define USUFFIX uw +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define USUFFIX ub +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#else +#error unsupported data size +#endif + +#if DATA_SIZE == 8 +#define RES_TYPE uint64_t +#else +#define RES_TYPE uint32_t +#endif + +static inline RES_TYPE +glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) +{ + return glue(glue(ld, USUFFIX), _p)(g2h(ptr)); +} + +#if DATA_SIZE <= 2 +static inline int +glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) +{ + return glue(glue(lds, SUFFIX), _p)(g2h(ptr)); +} +#endif + +#ifndef CODE_ACCESS +static inline void +glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr, + RES_TYPE v) +{ + glue(glue(st, SUFFIX), _p)(g2h(ptr), v); +} +#endif + +#undef RES_TYPE +#undef DATA_TYPE +#undef DATA_STYPE +#undef SUFFIX +#undef USUFFIX +#undef DATA_SIZE diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 589bbe7360..15a226f24a 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -165,6 +165,12 @@ struct DeviceState { int alias_required_for_version; }; +struct DeviceListener { + void (*realize)(DeviceListener *listener, DeviceState *dev); + void (*unrealize)(DeviceListener *listener, DeviceState *dev); + QTAILQ_ENTRY(DeviceListener) link; +}; + #define TYPE_BUS "bus" #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) @@ -376,4 +382,8 @@ static inline bool qbus_is_hotpluggable(BusState *bus) { return bus->hotplug_handler; } + +void device_listener_register(DeviceListener *listener); +void device_listener_unregister(DeviceListener *listener); + #endif diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 3979dc41af..4652b70b5d 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -153,9 +153,6 @@ VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s); void virtio_blk_free_request(VirtIOBlockReq *req); -int virtio_blk_handle_scsi_req(VirtIOBlock *blk, - VirtQueueElement *elem); - void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb); diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 95612a40c1..38f29fb098 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -16,7 +16,9 @@ #include "hw/hw.h" #include "hw/xen/xen.h" +#include "hw/pci/pci.h" #include "qemu/queue.h" +#include "trace.h" /* * We don't support Xen prior to 3.3.0. @@ -166,17 +168,243 @@ void xen_shutdown_fatal_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2); #ifdef HVM_PARAM_VMPORT_REGS_PFN static inline int xen_get_vmport_regs_pfn(XenXC xc, domid_t dom, - unsigned long *vmport_regs_pfn) + xen_pfn_t *vmport_regs_pfn) { - return xc_get_hvm_param(xc, dom, HVM_PARAM_VMPORT_REGS_PFN, - vmport_regs_pfn); + int rc; + uint64_t value; + rc = xc_hvm_param_get(xc, dom, HVM_PARAM_VMPORT_REGS_PFN, &value); + if (rc >= 0) { + *vmport_regs_pfn = (xen_pfn_t) value; + } + return rc; } #else static inline int xen_get_vmport_regs_pfn(XenXC xc, domid_t dom, - unsigned long *vmport_regs_pfn) + xen_pfn_t *vmport_regs_pfn) { return -ENOSYS; } #endif +/* Xen before 4.5 */ +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 450 + +#ifndef HVM_PARAM_BUFIOREQ_EVTCHN +#define HVM_PARAM_BUFIOREQ_EVTCHN 26 +#endif + +#define IOREQ_TYPE_PCI_CONFIG 2 + +typedef uint32_t ioservid_t; + +static inline void xen_map_memory_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ +} + +static inline void xen_unmap_memory_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ +} + +static inline void xen_map_io_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ +} + +static inline void xen_unmap_io_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ +} + +static inline void xen_map_pcidev(XenXC xc, domid_t dom, + ioservid_t ioservid, + PCIDevice *pci_dev) +{ +} + +static inline void xen_unmap_pcidev(XenXC xc, domid_t dom, + ioservid_t ioservid, + PCIDevice *pci_dev) +{ +} + +static inline int xen_create_ioreq_server(XenXC xc, domid_t dom, + ioservid_t *ioservid) +{ + return 0; +} + +static inline void xen_destroy_ioreq_server(XenXC xc, domid_t dom, + ioservid_t ioservid) +{ +} + +static inline int xen_get_ioreq_server_info(XenXC xc, domid_t dom, + ioservid_t ioservid, + xen_pfn_t *ioreq_pfn, + xen_pfn_t *bufioreq_pfn, + evtchn_port_t *bufioreq_evtchn) +{ + unsigned long param; + int rc; + + rc = xc_get_hvm_param(xc, dom, HVM_PARAM_IOREQ_PFN, ¶m); + if (rc < 0) { + fprintf(stderr, "failed to get HVM_PARAM_IOREQ_PFN\n"); + return -1; + } + + *ioreq_pfn = param; + + rc = xc_get_hvm_param(xc, dom, HVM_PARAM_BUFIOREQ_PFN, ¶m); + if (rc < 0) { + fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_PFN\n"); + return -1; + } + + *bufioreq_pfn = param; + + rc = xc_get_hvm_param(xc, dom, HVM_PARAM_BUFIOREQ_EVTCHN, + ¶m); + if (rc < 0) { + fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_EVTCHN\n"); + return -1; + } + + *bufioreq_evtchn = param; + + return 0; +} + +static inline int xen_set_ioreq_server_state(XenXC xc, domid_t dom, + ioservid_t ioservid, + bool enable) +{ + return 0; +} + +/* Xen 4.5 */ +#else + +static inline void xen_map_memory_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ + hwaddr start_addr = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + hwaddr end_addr = start_addr + size - 1; + + trace_xen_map_mmio_range(ioservid, start_addr, end_addr); + xc_hvm_map_io_range_to_ioreq_server(xc, dom, ioservid, 1, + start_addr, end_addr); +} + +static inline void xen_unmap_memory_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ + hwaddr start_addr = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + hwaddr end_addr = start_addr + size - 1; + + trace_xen_unmap_mmio_range(ioservid, start_addr, end_addr); + xc_hvm_unmap_io_range_from_ioreq_server(xc, dom, ioservid, 1, + start_addr, end_addr); +} + +static inline void xen_map_io_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ + hwaddr start_addr = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + hwaddr end_addr = start_addr + size - 1; + + trace_xen_map_portio_range(ioservid, start_addr, end_addr); + xc_hvm_map_io_range_to_ioreq_server(xc, dom, ioservid, 0, + start_addr, end_addr); +} + +static inline void xen_unmap_io_section(XenXC xc, domid_t dom, + ioservid_t ioservid, + MemoryRegionSection *section) +{ + hwaddr start_addr = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + hwaddr end_addr = start_addr + size - 1; + + trace_xen_unmap_portio_range(ioservid, start_addr, end_addr); + xc_hvm_unmap_io_range_from_ioreq_server(xc, dom, ioservid, 0, + start_addr, end_addr); +} + +static inline void xen_map_pcidev(XenXC xc, domid_t dom, + ioservid_t ioservid, + PCIDevice *pci_dev) +{ + trace_xen_map_pcidev(ioservid, pci_bus_num(pci_dev->bus), + PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); + xc_hvm_map_pcidev_to_ioreq_server(xc, dom, ioservid, + 0, pci_bus_num(pci_dev->bus), + PCI_SLOT(pci_dev->devfn), + PCI_FUNC(pci_dev->devfn)); +} + +static inline void xen_unmap_pcidev(XenXC xc, domid_t dom, + ioservid_t ioservid, + PCIDevice *pci_dev) +{ + trace_xen_unmap_pcidev(ioservid, pci_bus_num(pci_dev->bus), + PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); + xc_hvm_unmap_pcidev_from_ioreq_server(xc, dom, ioservid, + 0, pci_bus_num(pci_dev->bus), + PCI_SLOT(pci_dev->devfn), + PCI_FUNC(pci_dev->devfn)); +} + +static inline int xen_create_ioreq_server(XenXC xc, domid_t dom, + ioservid_t *ioservid) +{ + int rc = xc_hvm_create_ioreq_server(xc, dom, 1, ioservid); + + if (rc == 0) { + trace_xen_ioreq_server_create(*ioservid); + } + + return rc; +} + +static inline void xen_destroy_ioreq_server(XenXC xc, domid_t dom, + ioservid_t ioservid) +{ + trace_xen_ioreq_server_destroy(ioservid); + xc_hvm_destroy_ioreq_server(xc, dom, ioservid); +} + +static inline int xen_get_ioreq_server_info(XenXC xc, domid_t dom, + ioservid_t ioservid, + xen_pfn_t *ioreq_pfn, + xen_pfn_t *bufioreq_pfn, + evtchn_port_t *bufioreq_evtchn) +{ + return xc_hvm_get_ioreq_server_info(xc, dom, ioservid, + ioreq_pfn, bufioreq_pfn, + bufioreq_evtchn); +} + +static inline int xen_set_ioreq_server_state(XenXC xc, domid_t dom, + ioservid_t ioservid, + bool enable) +{ + trace_xen_ioreq_server_state(ioservid, enable); + return xc_hvm_set_ioreq_server_state(xc, dom, ioservid, enable); +} + +#endif + #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index d712a651ca..fa307a6c0f 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -359,6 +359,16 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_array(_s, _f, _type*, _n), \ } +#define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .num = (_num), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_ARRAY, \ + .offset = vmstate_offset_sub_array(_state, _field, _type, _start), \ +} + #define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ .num = (_num), \ @@ -642,17 +652,29 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_FLOAT64(_f, _s) \ VMSTATE_FLOAT64_V(_f, _s, 0) -#define VMSTATE_TIMER_TEST(_f, _s, _test) \ +#define VMSTATE_TIMER_PTR_TEST(_f, _s, _test) \ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *) -#define VMSTATE_TIMER_V(_f, _s, _v) \ +#define VMSTATE_TIMER_PTR_V(_f, _s, _v) \ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *) +#define VMSTATE_TIMER_PTR(_f, _s) \ + VMSTATE_TIMER_PTR_V(_f, _s, 0) + +#define VMSTATE_TIMER_PTR_ARRAY(_f, _s, _n) \ + VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) + +#define VMSTATE_TIMER_TEST(_f, _s, _test) \ + VMSTATE_SINGLE_TEST(_f, _s, _test, 0, vmstate_info_timer, QEMUTimer) + +#define VMSTATE_TIMER_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_timer, QEMUTimer) + #define VMSTATE_TIMER(_f, _s) \ VMSTATE_TIMER_V(_f, _s, 0) #define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ - VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) + VMSTATE_ARRAY(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer) #define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 78c1ced4e7..07d88de746 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -204,7 +204,7 @@ typedef union { * f : float access * * sign is: - * (empty): for floats or 32 bit size + * (empty): for 32 or 64 bit sizes (including floats and doubles) * u : unsigned * s : signed * @@ -218,7 +218,16 @@ typedef union { * he : host endian * be : big endian * le : little endian + * te : target endian * (except for byte accesses, which have no endian infix). + * + * The target endian accessors are obviously only available to source + * files which are built per-target; they are defined in cpu-all.h. + * + * In all cases these functions take a host pointer. + * For accessors that take a guest address rather than a + * host address, see the cpu_{ld,st}_* accessors defined in + * cpu_ldst.h. */ static inline int ldub_p(const void *ptr) diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 0666920652..ca5befba0e 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -428,6 +428,79 @@ void timer_init_tl(QEMUTimer *ts, QEMUTimerCB *cb, void *opaque); /** + * timer_init: + * @type: the clock to associate with the timer + * @scale: the scale value for the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with the given scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init(QEMUTimer *ts, QEMUClockType type, int scale, + QEMUTimerCB *cb, void *opaque) +{ + timer_init_tl(ts, main_loop_tlg.tl[type], scale, cb, opaque); +} + +/** + * timer_init_ns: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with nanosecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_ns(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_NS, cb, opaque); +} + +/** + * timer_init_us: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with microsecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_us(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_US, cb, opaque); +} + +/** + * timer_init_ms: + * @type: the clock to associate with the timer + * @cb: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Initialize a timer with millisecond scale on the default timer list + * associated with the clock. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +static inline void timer_init_ms(QEMUTimer *ts, QEMUClockType type, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, type, SCALE_MS, cb, opaque); +} + +/** * timer_new_tl: * @timer_list: the timer list to attach the timer to * @scale: the scale value for the timer @@ -522,6 +595,17 @@ static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb, } /** + * timer_deinit: + * @ts: the timer to be de-initialised + * + * Deassociate the timer from any timerlist. You should + * call timer_del before. After this call, any further + * timer_del call cannot cause dangling pointer accesses + * even if the previously used timerlist is freed. + */ +void timer_deinit(QEMUTimer *ts); + +/** * timer_free: * @ts: the timer * diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index f2bbaaf86a..cde3314896 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -17,6 +17,7 @@ typedef struct BusState BusState; typedef struct CharDriverState CharDriverState; typedef struct CompatProperty CompatProperty; typedef struct DeviceState DeviceState; +typedef struct DeviceListener DeviceListener; typedef struct DisplayChangeListener DisplayChangeListener; typedef struct DisplayState DisplayState; typedef struct DisplaySurface DisplaySurface; diff --git a/include/ui/console.h b/include/ui/console.h index 22ef8ca6b3..8a4d671fbc 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -161,6 +161,8 @@ typedef struct DisplayChangeListenerOps { void (*dpy_gfx_copy)(DisplayChangeListener *dcl, int src_x, int src_y, int dst_x, int dst_y, int w, int h); + bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl, + pixman_format_code_t format); void (*dpy_text_cursor)(DisplayChangeListener *dcl, int x, int y); @@ -235,6 +237,8 @@ void dpy_gfx_update_dirty(QemuConsole *con, MemoryRegion *address_space, uint64_t base, bool invalidate); +bool dpy_gfx_check_format(QemuConsole *con, + pixman_format_code_t format); static inline int surface_stride(DisplaySurface *s) { @@ -327,19 +331,21 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ -void vnc_display_init(DisplayState *ds); -void vnc_display_open(DisplayState *ds, const char *display, Error **errp); -void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth); -char *vnc_display_local_addr(DisplayState *ds); +void vnc_display_init(const char *id); +void vnc_display_open(const char *id, Error **errp); +void vnc_display_add_client(const char *id, int csock, bool skipauth); +char *vnc_display_local_addr(const char *id); #ifdef CONFIG_VNC -int vnc_display_password(DisplayState *ds, const char *password); -int vnc_display_pw_expire(DisplayState *ds, time_t expires); +int vnc_display_password(const char *id, const char *password); +int vnc_display_pw_expire(const char *id, time_t expires); +QemuOpts *vnc_parse_func(const char *str); +int vnc_init_func(QemuOpts *opts, void *opaque); #else -static inline int vnc_display_password(DisplayState *ds, const char *password) +static inline int vnc_display_password(const char *id, const char *password) { return -ENODEV; } -static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) +static inline int vnc_display_pw_expire(const char *id, time_t expires) { return -ENODEV; }; diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 381969d97b..3dee5761cc 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -37,6 +37,8 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format); pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian); int qemu_pixman_get_type(int rshift, int gshift, int bshift); pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf); +bool qemu_pixman_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format); pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width); diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h index f56c596e31..51fff2e9b8 100644 --- a/include/ui/sdl2.h +++ b/include/ui/sdl2.h @@ -28,5 +28,7 @@ void sdl2_2d_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface); void sdl2_2d_refresh(DisplayChangeListener *dcl); void sdl2_2d_redraw(struct sdl2_console *scon); +bool sdl2_2d_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format); #endif /* SDL2_H */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e2596a4201..399c021337 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -829,8 +829,11 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * _regs->gpr[1] = infop->start_stack; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) if (get_ppc64_abi(infop) < 2) { - _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias; - infop->entry = ldq_raw(infop->entry) + infop->load_bias; + uint64_t val; + get_user_u64(val, infop->entry + 8); + _regs->gpr[2] = val + infop->load_bias; + get_user_u64(val, infop->entry); + infop->entry = val + infop->load_bias; } else { _regs->gpr[12] = infop->entry; /* r12 set to global entry address */ } diff --git a/linux-user/main.c b/linux-user/main.c index 67b02316c1..8c70be4c1b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2972,7 +2972,7 @@ void cpu_loop(CPUM68KState *env) { if (ts->sim_syscalls) { uint16_t nr; - nr = lduw(env->pc + 2); + get_user_u16(nr, env->pc + 2); env->pc += 4; do_m68k_simcall(env, nr); } else { @@ -3436,10 +3436,8 @@ CPUArchState *cpu_copy(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); CPUArchState *new_env = cpu_init(cpu_model); CPUState *new_cpu = ENV_GET_CPU(new_env); -#if defined(TARGET_HAS_ICE) CPUBreakpoint *bp; CPUWatchpoint *wp; -#endif /* Reset non arch specific state */ cpu_reset(new_cpu); @@ -3451,14 +3449,12 @@ CPUArchState *cpu_copy(CPUArchState *env) BP_CPU break/watchpoints are handled correctly on clone. */ QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); -#if defined(TARGET_HAS_ICE) QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL); } QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { cpu_watchpoint_insert(new_cpu, wp->vaddr, wp->len, wp->flags, NULL); } -#endif return new_env; } diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 45ef559ec6..22a4eb9625 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -45,29 +45,34 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1; } -static inline void vm_putw(uint32_t segptr, unsigned int reg16, unsigned int val) +static inline void vm_putw(CPUX86State *env, uint32_t segptr, + unsigned int reg16, unsigned int val) { - stw(segptr + (reg16 & 0xffff), val); + cpu_stw_data(env, segptr + (reg16 & 0xffff), val); } -static inline void vm_putl(uint32_t segptr, unsigned int reg16, unsigned int val) +static inline void vm_putl(CPUX86State *env, uint32_t segptr, + unsigned int reg16, unsigned int val) { - stl(segptr + (reg16 & 0xffff), val); + cpu_stl_data(env, segptr + (reg16 & 0xffff), val); } -static inline unsigned int vm_getb(uint32_t segptr, unsigned int reg16) +static inline unsigned int vm_getb(CPUX86State *env, + uint32_t segptr, unsigned int reg16) { - return ldub(segptr + (reg16 & 0xffff)); + return cpu_ldub_data(env, segptr + (reg16 & 0xffff)); } -static inline unsigned int vm_getw(uint32_t segptr, unsigned int reg16) +static inline unsigned int vm_getw(CPUX86State *env, + uint32_t segptr, unsigned int reg16) { - return lduw(segptr + (reg16 & 0xffff)); + return cpu_lduw_data(env, segptr + (reg16 & 0xffff)); } -static inline unsigned int vm_getl(uint32_t segptr, unsigned int reg16) +static inline unsigned int vm_getl(CPUX86State *env, + uint32_t segptr, unsigned int reg16) { - return ldl(segptr + (reg16 & 0xffff)); + return cpu_ldl_data(env, segptr + (reg16 & 0xffff)); } void save_v86_state(CPUX86State *env) @@ -221,7 +226,7 @@ static void do_int(CPUX86State *env, int intno) &ts->vm86plus.int21_revectored)) goto cannot_handle; int_addr = (intno << 2); - segoffs = ldl(int_addr); + segoffs = cpu_ldl_data(env, int_addr); if ((segoffs >> 16) == TARGET_BIOSSEG) goto cannot_handle; LOG_VM86("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", @@ -229,9 +234,9 @@ static void do_int(CPUX86State *env, int intno) /* save old state */ ssp = env->segs[R_SS].selector << 4; sp = env->regs[R_ESP] & 0xffff; - vm_putw(ssp, sp - 2, get_vflags(env)); - vm_putw(ssp, sp - 4, env->segs[R_CS].selector); - vm_putw(ssp, sp - 6, env->eip); + vm_putw(env, ssp, sp - 2, get_vflags(env)); + vm_putw(env, ssp, sp - 4, env->segs[R_CS].selector); + vm_putw(env, ssp, sp - 6, env->eip); ADD16(env->regs[R_ESP], -6); /* goto interrupt handler */ env->eip = segoffs & 0xffff; @@ -285,7 +290,7 @@ void handle_vm86_fault(CPUX86State *env) data32 = 0; pref_done = 0; do { - opcode = vm_getb(csp, ip); + opcode = vm_getb(env, csp, ip); ADD16(ip, 1); switch (opcode) { case 0x66: /* 32-bit data */ data32=1; break; @@ -306,10 +311,10 @@ void handle_vm86_fault(CPUX86State *env) switch(opcode) { case 0x9c: /* pushf */ if (data32) { - vm_putl(ssp, sp - 4, get_vflags(env)); + vm_putl(env, ssp, sp - 4, get_vflags(env)); ADD16(env->regs[R_ESP], -4); } else { - vm_putw(ssp, sp - 2, get_vflags(env)); + vm_putw(env, ssp, sp - 2, get_vflags(env)); ADD16(env->regs[R_ESP], -2); } env->eip = ip; @@ -317,10 +322,10 @@ void handle_vm86_fault(CPUX86State *env) case 0x9d: /* popf */ if (data32) { - newflags = vm_getl(ssp, sp); + newflags = vm_getl(env, ssp, sp); ADD16(env->regs[R_ESP], 4); } else { - newflags = vm_getw(ssp, sp); + newflags = vm_getw(env, ssp, sp); ADD16(env->regs[R_ESP], 2); } env->eip = ip; @@ -335,7 +340,7 @@ void handle_vm86_fault(CPUX86State *env) VM86_FAULT_RETURN; case 0xcd: /* int */ - intno = vm_getb(csp, ip); + intno = vm_getb(env, csp, ip); ADD16(ip, 1); env->eip = ip; if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { @@ -350,14 +355,14 @@ void handle_vm86_fault(CPUX86State *env) case 0xcf: /* iret */ if (data32) { - newip = vm_getl(ssp, sp) & 0xffff; - newcs = vm_getl(ssp, sp + 4) & 0xffff; - newflags = vm_getl(ssp, sp + 8); + newip = vm_getl(env, ssp, sp) & 0xffff; + newcs = vm_getl(env, ssp, sp + 4) & 0xffff; + newflags = vm_getl(env, ssp, sp + 8); ADD16(env->regs[R_ESP], 12); } else { - newip = vm_getw(ssp, sp); - newcs = vm_getw(ssp, sp + 2); - newflags = vm_getw(ssp, sp + 4); + newip = vm_getw(env, ssp, sp); + newcs = vm_getw(env, ssp, sp + 2); + newflags = vm_getw(env, ssp, sp + 4); ADD16(env->regs[R_ESP], 6); } env->eip = newip; diff --git a/monitor.c b/monitor.c index 1808e41932..7e4f605e6d 100644 --- a/monitor.c +++ b/monitor.c @@ -1292,16 +1292,16 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, switch(wsize) { default: case 1: - v = ldub_raw(buf + i); + v = ldub_p(buf + i); break; case 2: - v = lduw_raw(buf + i); + v = lduw_p(buf + i); break; case 4: - v = (uint32_t)ldl_raw(buf + i); + v = (uint32_t)ldl_p(buf + i); break; case 8: - v = ldq_raw(buf + i); + v = ldq_p(buf + i); break; } monitor_printf(mon, " "); diff --git a/qapi-schema.json b/qapi-schema.json index fbfc52f94d..e16f8eb110 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -672,12 +672,15 @@ # # @family: address family # +# @websocket: true in case the socket is a websocket (since 2.3). +# # Since: 2.1 ## { 'type': 'VncBasicInfo', 'data': { 'host': 'str', 'service': 'str', - 'family': 'NetworkAddressFamily' } } + 'family': 'NetworkAddressFamily', + 'websocket': 'bool' } } ## # @VncServerInfo @@ -751,6 +754,63 @@ '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} } ## +# @VncPriAuth: +# +# vnc primary authentication method. +# +# Since: 2.3 +## +{ 'enum': 'VncPrimaryAuth', + 'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra', + 'tls', 'vencrypt', 'sasl' ] } + +## +# @VncVencryptSubAuth: +# +# vnc sub authentication method with vencrypt. +# +# Since: 2.3 +## +{ 'enum': 'VncVencryptSubAuth', + 'data': [ 'plain', + 'tls-none', 'x509-none', + 'tls-vnc', 'x509-vnc', + 'tls-plain', 'x509-plain', + 'tls-sasl', 'x509-sasl' ] } + +## +# @VncInfo2: +# +# Information about a vnc server +# +# @id: vnc server name. +# +# @server: A list of @VncBasincInfo describing all listening sockets. +# The list can be empty (in case the vnc server is disabled). +# It also may have multiple entries: normal + websocket, +# possibly also ipv4 + ipv6 in the future. +# +# @clients: A list of @VncClientInfo of all currently connected clients. +# The list can be empty, for obvious reasons. +# +# @auth: The current authentication type used by the server +# +# @vencrypt: #optional The vencrypt sub authentication type used by the server, +# only specified in case auth == vencrypt. +# +# @display: #optional The display device the vnc server is linked to. +# +# Since: 2.3 +## +{ 'type': 'VncInfo2', + 'data': { 'id' : 'str', + 'server' : ['VncBasicInfo'], + 'clients' : ['VncClientInfo'], + 'auth' : 'VncPrimaryAuth', + '*vencrypt' : 'VncVencryptSubAuth', + '*display' : 'str' } } + +## # @query-vnc: # # Returns information about the current VNC server @@ -762,6 +822,17 @@ { 'command': 'query-vnc', 'returns': 'VncInfo' } ## +# @query-vnc-servers: +# +# Returns a list of vnc servers. The list can be empty. +# +# Returns: a list of @VncInfo2 +# +# Since: 2.3 +## +{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] } + +## # @SpiceBasicInfo # # The basic information for SPICE network connection @@ -3258,6 +3329,18 @@ # Send input event(s) to guest. # # @console: #optional console to send event(s) to. +# This parameter can be used to send the input event to +# specific input devices in case (a) multiple input devices +# of the same kind are added to the virtual machine and (b) +# you have configured input routing (see docs/multiseat.txt) +# for those input devices. If input routing is not +# configured this parameter has no effect. +# If @console is missing, only devices that aren't associated +# with a console are admissible. +# If @console is specified, it must exist, and both devices +# associated with that console and devices not associated with a +# console are admissible, but the former take precedence. + # # @events: List of InputEvent union. # diff --git a/qemu-img.c b/qemu-img.c index 7876258fa9..4e9a7f5741 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2556,7 +2556,7 @@ static int img_rebase(int argc, char **argv) /* For safe rebasing we need to compare old and new backing file */ if (!unsafe) { - char backing_name[1024]; + char backing_name[PATH_MAX]; blk_old_backing = blk_new_with_bs("old_backing", &error_abort); bs_old_backing = blk_bs(blk_old_backing); @@ -2614,7 +2614,7 @@ static int img_rebase(int argc, char **argv) } old_backing_num_sectors = bdrv_nb_sectors(bs_old_backing); if (old_backing_num_sectors < 0) { - char backing_name[1024]; + char backing_name[PATH_MAX]; bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); error_report("Could not get size of '%s': %s", diff --git a/qemu-options.hx b/qemu-options.hx index 10b9568815..85ca3ad55b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -953,7 +953,7 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice, "-spice [port=port][,tls-port=secured-port][,x509-dir=<dir>]\n" " [,x509-key-file=<file>][,x509-key-password=<file>]\n" " [,x509-cert-file=<file>][,x509-cacert-file=<file>]\n" - " [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6]\n" + " [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6|unix]\n" " [,tls-ciphers=<list>]\n" " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n" " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n" @@ -982,6 +982,7 @@ Set the IP address spice is listening on. Default is any address. @item ipv4 @item ipv6 +@item unix Force using the specified IP version. @item password=<secret> diff --git a/qemu-seccomp.c b/qemu-seccomp.c index b0c626984f..f9de0d3390 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -229,6 +229,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(shmdt), 240 }, { SCMP_SYS(timerfd_create), 240 }, { SCMP_SYS(shmctl), 240 }, + { SCMP_SYS(mlockall), 240 }, { SCMP_SYS(mlock), 240 }, { SCMP_SYS(munlock), 240 }, { SCMP_SYS(semctl), 240 }, diff --git a/qemu-timer.c b/qemu-timer.c index 98d9d1bc0b..5741f0d0e0 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -22,13 +22,9 @@ * THE SOFTWARE. */ -#include "sysemu/sysemu.h" -#include "monitor/monitor.h" -#include "ui/console.h" - -#include "hw/hw.h" - +#include "qemu/main-loop.h" #include "qemu/timer.h" + #ifdef CONFIG_POSIX #include <pthread.h> #endif @@ -342,6 +338,12 @@ void timer_init_tl(QEMUTimer *ts, ts->expire_time = -1; } +void timer_deinit(QEMUTimer *ts) +{ + assert(ts->expire_time == -1); + ts->timer_list = NULL; +} + void timer_free(QEMUTimer *ts) { g_free(ts); @@ -398,9 +400,11 @@ void timer_del(QEMUTimer *ts) { QEMUTimerList *timer_list = ts->timer_list; - qemu_mutex_lock(&timer_list->active_timers_lock); - timer_del_locked(timer_list, ts); - qemu_mutex_unlock(&timer_list->active_timers_lock); + if (timer_list) { + qemu_mutex_lock(&timer_list->active_timers_lock); + timer_del_locked(timer_list, ts); + qemu_mutex_unlock(&timer_list->active_timers_lock); + } } /* modify the current timer so that it will be fired when current_time diff --git a/qmp-commands.hx b/qmp-commands.hx index 8957201f73..c5f16dd922 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2867,6 +2867,11 @@ EQMP .args_type = "", .mhandler.cmd_new = qmp_marshal_input_query_vnc, }, + { + .name = "query-vnc-servers", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_vnc_servers, + }, SQMP query-spice diff --git a/qmp.c b/qmp.c index 0b4f131936..963305c269 100644 --- a/qmp.c +++ b/qmp.c @@ -368,7 +368,20 @@ void qmp_change_vnc_password(const char *password, Error **errp) static void qmp_change_vnc_listen(const char *target, Error **errp) { - vnc_display_open(NULL, target, errp); + QemuOptsList *olist = qemu_find_opts("vnc"); + QemuOpts *opts; + + if (strstr(target, "id=")) { + error_setg(errp, "id not supported"); + return; + } + + opts = qemu_opts_find(olist, "default"); + if (opts) { + qemu_opts_del(opts); + } + opts = vnc_parse_func(target); + vnc_display_open("default", errp); } static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 7b1437ca21..c0c4ff0de3 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -13,6 +13,7 @@ import curses import sys, os, time, optparse, ctypes +from ctypes import * class DebugfsProvider(object): def __init__(self): @@ -65,6 +66,8 @@ vmx_exit_reasons = { 49: 'EPT_MISCONFIG', 54: 'WBINVD', 55: 'XSETBV', + 56: 'APIC_WRITE', + 58: 'INVPCID', } svm_exit_reasons = { @@ -138,6 +141,7 @@ svm_exit_reasons = { 0x08a: 'MONITOR', 0x08b: 'MWAIT', 0x08c: 'MWAIT_COND', + 0x08d: 'XSETBV', 0x400: 'NPF', } @@ -167,6 +171,7 @@ userspace_exit_reasons = { 21: 'WATCHDOG', 22: 'S390_TSCH', 23: 'EPR', + 24: 'SYSTEM_EVENT', } x86_exit_reasons = { @@ -181,6 +186,7 @@ ioctl_numbers = { 'SET_FILTER' : 0x40082406, 'ENABLE' : 0x00002400, 'DISABLE' : 0x00002401, + 'RESET' : 0x00002403, } def x86_init(flag): @@ -204,10 +210,18 @@ def ppc_init(): } }) +def aarch64_init(): + globals().update({ + 'sc_perf_evt_open' : 241 + }) + def detect_platform(): if os.uname()[4].startswith('ppc'): ppc_init() return + elif os.uname()[4].startswith('aarch64'): + aarch64_init() + return for line in file('/proc/cpuinfo').readlines(): if line.startswith('flags'): @@ -235,6 +249,9 @@ import struct, array libc = ctypes.CDLL('libc.so.6') syscall = libc.syscall +get_errno = libc.__errno_location +get_errno.restype = POINTER(c_int) + class perf_event_attr(ctypes.Structure): _fields_ = [('type', ctypes.c_uint32), ('size', ctypes.c_uint32), @@ -318,7 +335,8 @@ class Event(object): group_leader = group.events[0].fd fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0) if fd == -1: - raise Exception('perf_event_open failed') + err = get_errno()[0] + raise Exception('perf_event_open failed, errno = ' + err.__str__()) if filter: import fcntl fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter) @@ -329,6 +347,9 @@ class Event(object): def disable(self): import fcntl fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0) + def reset(self): + import fcntl + fcntl.ioctl(self.fd, ioctl_numbers['RESET'], 0) class TracepointProvider(object): def __init__(self): @@ -388,6 +409,7 @@ class TracepointProvider(object): for group in self.group_leaders: for event in group.events: if event.name in fields: + event.reset() event.enable() else: event.disable() diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index d2f815bca2..1eb272dd26 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -99,6 +99,14 @@ struct %(name)s ret += generate_struct_fields(members) + # Make sure that all structs have at least one field; this avoids + # potential issues with attempting to malloc space for zero-length structs + # in C, and also incompatibility with C++ (where an empty struct is size 1). + if not base and not members: + ret += mcgen(''' + char qapi_dummy_field_for_empty_struct; +''') + if len(fieldname): fieldname = " " + fieldname ret += mcgen(''' diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index d9b861f404..e276dbf9a2 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -32,8 +32,6 @@ #include "fpu/softfloat.h" -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE EM_ALPHA #define ICACHE_LINE_SIZE 32 diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7ba55f0c2e..cd7a9e8e14 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -39,8 +39,6 @@ #include "fpu/softfloat.h" -#define TARGET_HAS_ICE 1 - #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 diff --git a/target-arm/machine.c b/target-arm/machine.c index c29e7a2ac1..9446e5a8ab 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -277,8 +277,8 @@ const VMStateDescription vmstate_arm_cpu = { VMSTATE_UINT32(env.exception.syndrome, ARMCPU), VMSTATE_UINT32(env.exception.fsr, ARMCPU), VMSTATE_UINT64(env.exception.vaddress, ARMCPU), - VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU), - VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU), + VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU), VMSTATE_BOOL(powered_off, ARMCPU), VMSTATE_END_OF_LIST() }, diff --git a/target-cris/cpu.h b/target-cris/cpu.h index b88c147518..eea14b6462 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -29,8 +29,6 @@ #include "exec/cpu-defs.h" -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE EM_CRIS #define EXCP_NMI 1 diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b81ac5cda1..3a9b32ef7d 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1100,9 +1100,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_LAHF_LM, .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM, + CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, .xlevel = 0x8000000A, @@ -1135,9 +1134,9 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | - CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | - CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | + CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3ecff96325..478450cfb6 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -37,8 +37,6 @@ close to the modifying instruction */ #define TARGET_HAS_PRECISE_SMC -#define TARGET_HAS_ICE 1 - #ifdef TARGET_X86_64 #define ELF_MACHINE EM_X86_64 #define ELF_MACHINE_UNAME "x86_64" @@ -715,31 +713,13 @@ typedef struct SegmentCache { } SegmentCache; typedef union { - uint8_t _b[16]; - uint16_t _w[8]; - uint32_t _l[4]; - uint64_t _q[2]; - float32 _s[4]; - float64 _d[2]; -} XMMReg; - -typedef union { - uint8_t _b[32]; - uint16_t _w[16]; - uint32_t _l[8]; - uint64_t _q[4]; - float32 _s[8]; - float64 _d[4]; -} YMMReg; - -typedef union { uint8_t _b[64]; uint16_t _w[32]; uint32_t _l[16]; uint64_t _q[8]; float32 _s[16]; float64 _d[8]; -} ZMMReg; +} XMMReg; /* really zmm */ typedef union { uint8_t _b[8]; @@ -760,46 +740,18 @@ typedef struct BNDCSReg { } BNDCSReg; #ifdef HOST_WORDS_BIGENDIAN -#define ZMM_B(n) _b[63 - (n)] -#define ZMM_W(n) _w[31 - (n)] -#define ZMM_L(n) _l[15 - (n)] -#define ZMM_S(n) _s[15 - (n)] -#define ZMM_Q(n) _q[7 - (n)] -#define ZMM_D(n) _d[7 - (n)] - -#define YMM_B(n) _b[31 - (n)] -#define YMM_W(n) _w[15 - (n)] -#define YMM_L(n) _l[7 - (n)] -#define YMM_S(n) _s[7 - (n)] -#define YMM_Q(n) _q[3 - (n)] -#define YMM_D(n) _d[3 - (n)] - -#define XMM_B(n) _b[15 - (n)] -#define XMM_W(n) _w[7 - (n)] -#define XMM_L(n) _l[3 - (n)] -#define XMM_S(n) _s[3 - (n)] -#define XMM_Q(n) _q[1 - (n)] -#define XMM_D(n) _d[1 - (n)] +#define XMM_B(n) _b[63 - (n)] +#define XMM_W(n) _w[31 - (n)] +#define XMM_L(n) _l[15 - (n)] +#define XMM_S(n) _s[15 - (n)] +#define XMM_Q(n) _q[7 - (n)] +#define XMM_D(n) _d[7 - (n)] #define MMX_B(n) _b[7 - (n)] #define MMX_W(n) _w[3 - (n)] #define MMX_L(n) _l[1 - (n)] #define MMX_S(n) _s[1 - (n)] #else -#define ZMM_B(n) _b[n] -#define ZMM_W(n) _w[n] -#define ZMM_L(n) _l[n] -#define ZMM_S(n) _s[n] -#define ZMM_Q(n) _q[n] -#define ZMM_D(n) _d[n] - -#define YMM_B(n) _b[n] -#define YMM_W(n) _w[n] -#define YMM_L(n) _l[n] -#define YMM_S(n) _s[n] -#define YMM_Q(n) _q[n] -#define YMM_D(n) _d[n] - #define XMM_B(n) _b[n] #define XMM_W(n) _w[n] #define XMM_L(n) _l[n] @@ -898,17 +850,11 @@ typedef struct CPUX86State { float_status mmx_status; /* for 3DNow! float ops */ float_status sse_status; uint32_t mxcsr; - XMMReg xmm_regs[CPU_NB_REGS]; + XMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32]; XMMReg xmm_t0; MMXReg mmx_t0; - XMMReg ymmh_regs[CPU_NB_REGS]; - uint64_t opmask_regs[NB_OPMASK_REGS]; - YMMReg zmmh_regs[CPU_NB_REGS]; -#ifdef TARGET_X86_64 - ZMMReg hi16_zmm_regs[CPU_NB_REGS]; -#endif /* sysenter registers */ uint32_t sysenter_cs; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 36b1519f34..40d6a14c85 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1048,7 +1048,7 @@ static int kvm_put_xsave(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; uint16_t cwd, swd, twd; - uint8_t *xmm; + uint8_t *xmm, *ymmh, *zmmh; int i, r; if (!kvm_has_xsave()) { @@ -1071,26 +1071,30 @@ static int kvm_put_xsave(X86CPU *cpu) sizeof env->fpregs); xsave->region[XSAVE_MXCSR] = env->mxcsr; *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv; - memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs, - sizeof env->ymmh_regs); memcpy(&xsave->region[XSAVE_BNDREGS], env->bnd_regs, sizeof env->bnd_regs); memcpy(&xsave->region[XSAVE_BNDCSR], &env->bndcs_regs, sizeof(env->bndcs_regs)); memcpy(&xsave->region[XSAVE_OPMASK], env->opmask_regs, sizeof env->opmask_regs); - memcpy(&xsave->region[XSAVE_ZMM_Hi256], env->zmmh_regs, - sizeof env->zmmh_regs); xmm = (uint8_t *)&xsave->region[XSAVE_XMM_SPACE]; - for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) { + ymmh = (uint8_t *)&xsave->region[XSAVE_YMMH_SPACE]; + zmmh = (uint8_t *)&xsave->region[XSAVE_ZMM_Hi256]; + for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) { stq_p(xmm, env->xmm_regs[i].XMM_Q(0)); stq_p(xmm+8, env->xmm_regs[i].XMM_Q(1)); + stq_p(ymmh, env->xmm_regs[i].XMM_Q(2)); + stq_p(ymmh+8, env->xmm_regs[i].XMM_Q(3)); + stq_p(zmmh, env->xmm_regs[i].XMM_Q(4)); + stq_p(zmmh+8, env->xmm_regs[i].XMM_Q(5)); + stq_p(zmmh+16, env->xmm_regs[i].XMM_Q(6)); + stq_p(zmmh+24, env->xmm_regs[i].XMM_Q(7)); } #ifdef TARGET_X86_64 - memcpy(&xsave->region[XSAVE_Hi16_ZMM], env->hi16_zmm_regs, - sizeof env->hi16_zmm_regs); + memcpy(&xsave->region[XSAVE_Hi16_ZMM], &env->xmm_regs[16], + 16 * sizeof env->xmm_regs[16]); #endif r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave); return r; @@ -1407,7 +1411,7 @@ static int kvm_get_xsave(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; int ret, i; - const uint8_t *xmm; + const uint8_t *xmm, *ymmh, *zmmh; uint16_t cwd, swd, twd; if (!kvm_has_xsave()) { @@ -1435,26 +1439,30 @@ static int kvm_get_xsave(X86CPU *cpu) memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE], sizeof env->fpregs); env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV]; - memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE], - sizeof env->ymmh_regs); memcpy(env->bnd_regs, &xsave->region[XSAVE_BNDREGS], sizeof env->bnd_regs); memcpy(&env->bndcs_regs, &xsave->region[XSAVE_BNDCSR], sizeof(env->bndcs_regs)); memcpy(env->opmask_regs, &xsave->region[XSAVE_OPMASK], sizeof env->opmask_regs); - memcpy(env->zmmh_regs, &xsave->region[XSAVE_ZMM_Hi256], - sizeof env->zmmh_regs); xmm = (const uint8_t *)&xsave->region[XSAVE_XMM_SPACE]; - for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) { + ymmh = (const uint8_t *)&xsave->region[XSAVE_YMMH_SPACE]; + zmmh = (const uint8_t *)&xsave->region[XSAVE_ZMM_Hi256]; + for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) { env->xmm_regs[i].XMM_Q(0) = ldq_p(xmm); env->xmm_regs[i].XMM_Q(1) = ldq_p(xmm+8); + env->xmm_regs[i].XMM_Q(2) = ldq_p(ymmh); + env->xmm_regs[i].XMM_Q(3) = ldq_p(ymmh+8); + env->xmm_regs[i].XMM_Q(4) = ldq_p(zmmh); + env->xmm_regs[i].XMM_Q(5) = ldq_p(zmmh+8); + env->xmm_regs[i].XMM_Q(6) = ldq_p(zmmh+16); + env->xmm_regs[i].XMM_Q(7) = ldq_p(zmmh+24); } #ifdef TARGET_X86_64 - memcpy(env->hi16_zmm_regs, &xsave->region[XSAVE_Hi16_ZMM], - sizeof env->hi16_zmm_regs); + memcpy(&env->xmm_regs[16], &xsave->region[XSAVE_Hi16_ZMM], + 16 * sizeof env->xmm_regs[16]); #endif return 0; } diff --git a/target-i386/machine.c b/target-i386/machine.c index 722d62e471..cd1ddd29e9 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -42,39 +42,42 @@ static const VMStateDescription vmstate_xmm_reg = { } }; -#define VMSTATE_XMM_REGS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg) +#define VMSTATE_XMM_REGS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_xmm_reg, XMMReg) -/* YMMH format is the same as XMM */ +/* YMMH format is the same as XMM, but for bits 128-255 */ static const VMStateDescription vmstate_ymmh_reg = { .name = "ymmh_reg", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(XMM_Q(0), XMMReg), - VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_UINT64(XMM_Q(2), XMMReg), + VMSTATE_UINT64(XMM_Q(3), XMMReg), VMSTATE_END_OF_LIST() } }; -#define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg) +#define VMSTATE_YMMH_REGS_VARS(_field, _state, _start, _v) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, _v, \ + vmstate_ymmh_reg, XMMReg) static const VMStateDescription vmstate_zmmh_reg = { .name = "zmmh_reg", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(YMM_Q(0), YMMReg), - VMSTATE_UINT64(YMM_Q(1), YMMReg), - VMSTATE_UINT64(YMM_Q(2), YMMReg), - VMSTATE_UINT64(YMM_Q(3), YMMReg), + VMSTATE_UINT64(XMM_Q(4), XMMReg), + VMSTATE_UINT64(XMM_Q(5), XMMReg), + VMSTATE_UINT64(XMM_Q(6), XMMReg), + VMSTATE_UINT64(XMM_Q(7), XMMReg), VMSTATE_END_OF_LIST() } }; -#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_zmmh_reg, YMMReg) +#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_zmmh_reg, XMMReg) #ifdef TARGET_X86_64 static const VMStateDescription vmstate_hi16_zmm_reg = { @@ -82,20 +85,21 @@ static const VMStateDescription vmstate_hi16_zmm_reg = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(ZMM_Q(0), ZMMReg), - VMSTATE_UINT64(ZMM_Q(1), ZMMReg), - VMSTATE_UINT64(ZMM_Q(2), ZMMReg), - VMSTATE_UINT64(ZMM_Q(3), ZMMReg), - VMSTATE_UINT64(ZMM_Q(4), ZMMReg), - VMSTATE_UINT64(ZMM_Q(5), ZMMReg), - VMSTATE_UINT64(ZMM_Q(6), ZMMReg), - VMSTATE_UINT64(ZMM_Q(7), ZMMReg), + VMSTATE_UINT64(XMM_Q(0), XMMReg), + VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_UINT64(XMM_Q(2), XMMReg), + VMSTATE_UINT64(XMM_Q(3), XMMReg), + VMSTATE_UINT64(XMM_Q(4), XMMReg), + VMSTATE_UINT64(XMM_Q(5), XMMReg), + VMSTATE_UINT64(XMM_Q(6), XMMReg), + VMSTATE_UINT64(XMM_Q(7), XMMReg), VMSTATE_END_OF_LIST() } }; -#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _n) \ - VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_hi16_zmm_reg, ZMMReg) +#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _start) \ + VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \ + vmstate_hi16_zmm_reg, XMMReg) #endif static const VMStateDescription vmstate_bnd_regs = { @@ -654,17 +658,16 @@ static bool avx512_needed(void *opaque) } for (i = 0; i < CPU_NB_REGS; i++) { -#define ENV_ZMMH(reg, field) (env->zmmh_regs[reg].YMM_Q(field)) - if (ENV_ZMMH(i, 0) || ENV_ZMMH(i, 1) || - ENV_ZMMH(i, 2) || ENV_ZMMH(i, 3)) { +#define ENV_XMM(reg, field) (env->xmm_regs[reg].XMM_Q(field)) + if (ENV_XMM(i, 4) || ENV_XMM(i, 6) || + ENV_XMM(i, 5) || ENV_XMM(i, 7)) { return true; } #ifdef TARGET_X86_64 -#define ENV_Hi16_ZMM(reg, field) (env->hi16_zmm_regs[reg].ZMM_Q(field)) - if (ENV_Hi16_ZMM(i, 0) || ENV_Hi16_ZMM(i, 1) || - ENV_Hi16_ZMM(i, 2) || ENV_Hi16_ZMM(i, 3) || - ENV_Hi16_ZMM(i, 4) || ENV_Hi16_ZMM(i, 5) || - ENV_Hi16_ZMM(i, 6) || ENV_Hi16_ZMM(i, 7)) { + if (ENV_XMM(i+16, 0) || ENV_XMM(i+16, 1) || + ENV_XMM(i+16, 2) || ENV_XMM(i+16, 3) || + ENV_XMM(i+16, 4) || ENV_XMM(i+16, 5) || + ENV_XMM(i+16, 6) || ENV_XMM(i+16, 7)) { return true; } #endif @@ -679,9 +682,9 @@ static const VMStateDescription vmstate_avx512 = { .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.opmask_regs, X86CPU, NB_OPMASK_REGS), - VMSTATE_ZMMH_REGS_VARS(env.zmmh_regs, X86CPU, CPU_NB_REGS), + VMSTATE_ZMMH_REGS_VARS(env.xmm_regs, X86CPU, 0), #ifdef TARGET_X86_64 - VMSTATE_Hi16_ZMM_REGS_VARS(env.hi16_zmm_regs, X86CPU, CPU_NB_REGS), + VMSTATE_Hi16_ZMM_REGS_VARS(env.xmm_regs, X86CPU, 16), #endif VMSTATE_END_OF_LIST() } @@ -750,7 +753,7 @@ VMStateDescription vmstate_x86_cpu = { VMSTATE_INT32(env.a20_mask, X86CPU), /* XMM */ VMSTATE_UINT32(env.mxcsr, X86CPU), - VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS), + VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, 0), #ifdef TARGET_X86_64 VMSTATE_UINT64(env.efer, X86CPU), @@ -803,7 +806,7 @@ VMStateDescription vmstate_x86_cpu = { /* XSAVE related fields */ VMSTATE_UINT64_V(env.xcr0, X86CPU, 12), VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12), - VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12), + VMSTATE_YMMH_REGS_VARS(env.xmm_regs, X86CPU, 0, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ }, diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index c98eeb4351..fa374d0c0b 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -34,7 +34,21 @@ # define LOG_PCALL_STATE(cpu) do { } while (0) #endif -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 2 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 4 +#include "exec/cpu_ldst_useronly_template.h" + +#define DATA_SIZE 8 +#include "exec/cpu_ldst_useronly_template.h" +#undef MEMSUFFIX +#else #define CPU_MMU_INDEX (cpu_mmu_index_kernel(env)) #define MEMSUFFIX _kernel #define DATA_SIZE 1 diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 0dab6e89ab..e558c59499 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -30,8 +30,6 @@ struct CPULM32State; typedef struct CPULM32State CPULM32State; -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE EM_LATTICEMICO32 #define NB_MMU_MODES 1 diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index f67bbcc646..3a1b9ab938 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -32,8 +32,6 @@ #define MAX_QREGS 32 -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE EM_68K #define EXCP_ACCESS 2 /* Access (MMU) error. */ diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 6ccd06068c..5794f8991a 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -34,8 +34,6 @@ typedef struct CPUMBState CPUMBState; #include "mmu.h" #endif -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE EM_MICROBLAZE #define EXCP_NMI 1 diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8875c975e0..5ea61bceea 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -4,7 +4,6 @@ //#define DEBUG_OP #define ALIGNED_ONLY -#define TARGET_HAS_ICE 1 #define ELF_MACHINE EM_MIPS diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d619ba4785..ea7d95f36c 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -74,7 +74,7 @@ void helper_raise_exception(CPUMIPSState *env, uint32_t exception) static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ int mem_idx) \ { \ - return (type) insn##_raw(addr); \ + return (type) cpu_##insn##_data(env, addr); \ } #else #define HELPER_LD(name, insn, type) \ @@ -101,7 +101,7 @@ HELPER_LD(ld, ldq, int64_t) static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ type val, int mem_idx) \ { \ - insn##_raw(addr, val); \ + cpu_##insn##_data(env, addr, val); \ } #else #define HELPER_ST(name, insn, type) \ diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h index c5b12a5244..d809393670 100644 --- a/target-moxie/cpu.h +++ b/target-moxie/cpu.h @@ -26,8 +26,6 @@ #define CPUArchState struct CPUMoxieState -#define TARGET_HAS_ICE 1 - #define ELF_MACHINE 0xFEED /* EM_MOXIE */ #define MOXIE_EX_DIV0 0 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index c62097bb8a..aae33a9237 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -79,8 +79,6 @@ #include "fpu/softfloat.h" -#define TARGET_HAS_ICE 1 - #if defined (TARGET_PPC64) #define ELF_MACHINE EM_PPC64 #else diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 23ad336803..c123b6f023 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -886,8 +886,6 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr); -#define TARGET_HAS_ICE 1 - /* The value of the TOD clock for 1.1.1970. */ #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index a2e9e2c031..b2fb1990dd 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -23,7 +23,6 @@ #include "qemu-common.h" #define TARGET_LONG_BITS 32 -#define TARGET_HAS_ICE 1 #define ELF_MACHINE EM_SH diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 836f87f42f..0a50e5d113 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -31,8 +31,6 @@ #include "fpu/softfloat.h" -#define TARGET_HAS_ICE 1 - #if !defined(TARGET_SPARC64) #define ELF_MACHINE EM_SPARC #else diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 1a62e193bd..c7ad47d35c 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -250,6 +250,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, #endif +#if defined(TARGET_SPARC64) || defined(CONFIG_USER_ONLY) static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr) { #ifdef TARGET_SPARC64 @@ -259,12 +260,14 @@ static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr) #endif return addr; } +#endif +#ifdef TARGET_SPARC64 /* returns true if access using this ASI is to have address translated by MMU otherwise access is to raw physical address */ +/* TODO: check sparc32 bits */ static inline int is_translating_asi(int asi) { -#ifdef TARGET_SPARC64 /* Ultrasparc IIi translating asi - note this list is defined by cpu implementation */ @@ -281,10 +284,6 @@ static inline int is_translating_asi(int asi) default: return 0; } -#else - /* TODO: check sparc32 bits */ - return 0; -#endif } static inline target_ulong asi_address_mask(CPUSPARCState *env, @@ -296,6 +295,7 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env, return addr; } } +#endif void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align) { @@ -1122,17 +1122,17 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, { switch (size) { case 1: - ret = ldub_raw(addr); + ret = cpu_ldub_data(env, addr); break; case 2: - ret = lduw_raw(addr); + ret = cpu_lduw_data(env, addr); break; case 4: - ret = ldl_raw(addr); + ret = cpu_ldl_data(env, addr); break; default: case 8: - ret = ldq_raw(addr); + ret = cpu_ldq_data(env, addr); break; } } @@ -1239,17 +1239,17 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, { switch (size) { case 1: - stb_raw(addr, val); + cpu_stb_data(env, addr, val); break; case 2: - stw_raw(addr, val); + cpu_stw_data(env, addr, val); break; case 4: - stl_raw(addr, val); + cpu_stl_data(env, addr, val); break; case 8: default: - stq_raw(addr, val); + cpu_stq_data(env, addr, val); break; } } @@ -2289,8 +2289,8 @@ void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx) break; } #else - u.ll.upper = ldq_raw(address_mask(env, addr)); - u.ll.lower = ldq_raw(address_mask(env, addr + 8)); + u.ll.upper = cpu_ldq_data(env, address_mask(env, addr)); + u.ll.lower = cpu_ldq_data(env, address_mask(env, addr + 8)); QT0 = u.q; #endif } @@ -2326,8 +2326,8 @@ void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx) } #else u.q = QT0; - stq_raw(address_mask(env, addr), u.ll.upper); - stq_raw(address_mask(env, addr + 8), u.ll.lower); + cpu_stq_data(env, address_mask(env, addr), u.ll.upper); + cpu_stq_data(env, address_mask(env, addr + 8), u.ll.lower); #endif } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 25d1bd6988..68527d595f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -363,14 +363,6 @@ static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src) tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_movi_tl(cpu_cc_src2, src2); - tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_src, src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -502,22 +494,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, } } -static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_movi_tl(cpu_cc_src2, src2); - if (src2 == 0) { - tcg_gen_mov_tl(cpu_cc_dst, src1); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); - dc->cc_op = CC_OP_LOGIC; - } else { - tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_src, src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB); - dc->cc_op = CC_OP_SUB; - } - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -2324,6 +2300,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) gen_update_fprs_dirty(qd); } +#ifndef CONFIG_USER_ONLY static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) { TCGv_i32 r_tl = tcg_temp_new_i32(); @@ -2348,6 +2325,7 @@ static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) tcg_temp_free_i32(r_tl); } +#endif static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2, int width, bool cc, bool left) diff --git a/target-tricore/cpu.c b/target-tricore/cpu.c index abe16fa7e6..2ba0cf4c89 100644 --- a/target-tricore/cpu.c +++ b/target-tricore/cpu.c @@ -118,7 +118,7 @@ static void tc1796_initfn(Object *obj) { TriCoreCPU *cpu = TRICORE_CPU(obj); - set_feature(&cpu->env, TRICORE_FEATURE_13); + set_feature(&cpu->env, TRICORE_FEATURE_131); } static void aurix_initfn(Object *obj) diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h index 7555b70a47..e5409e45f3 100644 --- a/target-tricore/cpu.h +++ b/target-tricore/cpu.h @@ -238,6 +238,7 @@ struct CPUTriCoreState { #define MASK_LCX_LCXS 0x000f0000 #define MASK_LCX_LCX0 0x0000ffff +#define TRICORE_HFLAG_KUU 0x3 #define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */ #define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */ #define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */ diff --git a/target-tricore/helper.h b/target-tricore/helper.h index 068dc7b422..7405feee88 100644 --- a/target-tricore/helper.h +++ b/target-tricore/helper.h @@ -60,10 +60,14 @@ DEF_HELPER_FLAGS_2(max_b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_h, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(max_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(ixmax, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(ixmax_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) DEF_HELPER_FLAGS_2(min_b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_bu, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_h, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) /* count leading ... */ DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32) @@ -81,12 +85,16 @@ DEF_HELPER_FLAGS_2(bmerge, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_1(bsplit, TCG_CALL_NO_RWG_SE, i64, i32) DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32) /* float */ +DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32) DEF_HELPER_1(unpack, i64, i32) /* dvinit */ DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32) DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32) DEF_HELPER_3(dvinit_h_13, i64, env, i32, i32) DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32) +DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32) +DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32) /* mulh */ DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c index 13e27291c1..ed26b302b0 100644 --- a/target-tricore/op_helper.c +++ b/target-tricore/op_helper.c @@ -80,29 +80,40 @@ static uint32_t ssov32(CPUTriCoreState *env, int64_t arg) return ret; } -static uint32_t suov32(CPUTriCoreState *env, int64_t arg) +static uint32_t suov32_pos(CPUTriCoreState *env, uint64_t arg) { uint32_t ret; - int64_t max_pos = UINT32_MAX; + uint64_t max_pos = UINT32_MAX; if (arg > max_pos) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); ret = (target_ulong)max_pos; } else { - if (arg < 0) { - env->PSW_USB_V = (1 << 31); - env->PSW_USB_SV = (1 << 31); - ret = 0; - } else { - env->PSW_USB_V = 0; - ret = (target_ulong)arg; - } + env->PSW_USB_V = 0; + ret = (target_ulong)arg; } env->PSW_USB_AV = arg ^ arg * 2u; env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } +static uint32_t suov32_neg(CPUTriCoreState *env, int64_t arg) +{ + uint32_t ret; + + if (arg < 0) { + env->PSW_USB_V = (1 << 31); + env->PSW_USB_SV = (1 << 31); + ret = 0; + } else { + env->PSW_USB_V = 0; + ret = (target_ulong)arg; + } + env->PSW_USB_AV = arg ^ arg * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + return ret; +} + static uint32_t ssov16(CPUTriCoreState *env, int32_t hw0, int32_t hw1) { int32_t max_pos = INT16_MAX; @@ -189,7 +200,7 @@ target_ulong helper_add_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 + t2; - return suov32(env, result); + return suov32_pos(env, result); } target_ulong helper_add_h_suov(CPUTriCoreState *env, target_ulong r1, @@ -227,7 +238,7 @@ target_ulong helper_sub_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 - t2; - return suov32(env, result); + return suov32_neg(env, result); } target_ulong helper_sub_h_suov(CPUTriCoreState *env, target_ulong r1, @@ -255,7 +266,8 @@ target_ulong helper_mul_suov(CPUTriCoreState *env, target_ulong r1, int64_t t1 = extract64(r1, 0, 32); int64_t t2 = extract64(r2, 0, 32); int64_t result = t1 * t2; - return suov32(env, result); + + return suov32_pos(env, result); } target_ulong helper_sha_ssov(CPUTriCoreState *env, target_ulong r1, @@ -355,7 +367,7 @@ target_ulong helper_madd32_suov(CPUTriCoreState *env, target_ulong r1, int64_t result; result = t2 + (t1 * t3); - return suov32(env, result); + return suov32_pos(env, result); } uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, @@ -370,6 +382,10 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, ret = mul + r2; ovf = (ret ^ mul) & ~(mul ^ r2); + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if ((int64_t)ovf < 0) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -383,9 +399,6 @@ uint64_t helper_madd64_ssov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -400,6 +413,10 @@ uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, mul = t1 * t3; ret = mul + r2; + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if (ret < r2) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -408,9 +425,6 @@ uint64_t helper_madd64_suov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -435,7 +449,7 @@ target_ulong helper_msub32_suov(CPUTriCoreState *env, target_ulong r1, int64_t result; result = t2 - (t1 * t3); - return suov32(env, result); + return suov32_neg(env, result); } uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, @@ -450,6 +464,10 @@ uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, ret = r2 - mul; ovf = (ret ^ r2) & (mul ^ r2); + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if ((int64_t)ovf < 0) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -463,9 +481,6 @@ uint64_t helper_msub64_ssov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -479,6 +494,10 @@ uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1, mul = t1 * t3; ret = r2 - mul; + t1 = ret >> 32; + env->PSW_USB_AV = t1 ^ t1 * 2u; + env->PSW_USB_SAV |= env->PSW_USB_AV; + if (ret > r2) { env->PSW_USB_V = (1 << 31); env->PSW_USB_SV = (1 << 31); @@ -487,9 +506,6 @@ uint64_t helper_msub64_suov(CPUTriCoreState *env, target_ulong r1, } else { env->PSW_USB_V = 0; } - t1 = ret >> 32; - env->PSW_USB_AV = t1 ^ t1 * 2u; - env->PSW_USB_SAV |= env->PSW_USB_AV; return ret; } @@ -867,6 +883,50 @@ uint32_t helper_##name ##_hu(target_ulong r1, target_ulong r2)\ \ return ret; \ } \ + \ +uint64_t helper_ix##name(uint64_t r1, uint32_t r2) \ +{ \ + int64_t r2l, r2h, r1hl; \ + uint64_t ret = 0; \ + \ + ret = ((r1 + 2) & 0xffff); \ + r2l = sextract64(r2, 0, 16); \ + r2h = sextract64(r2, 16, 16); \ + r1hl = sextract64(r1, 32, 16); \ + \ + if ((r2l op ## = r2h) && (r2l op r1hl)) { \ + ret |= (r2l & 0xffff) << 32; \ + ret |= extract64(r1, 0, 16) << 16; \ + } else if ((r2h op r2l) && (r2h op r1hl)) { \ + ret |= extract64(r2, 16, 16) << 32; \ + ret |= extract64(r1 + 1, 0, 16) << 16; \ + } else { \ + ret |= r1 & 0xffffffff0000ull; \ + } \ + return ret; \ +} \ + \ +uint64_t helper_ix##name ##_u(uint64_t r1, uint32_t r2) \ +{ \ + int64_t r2l, r2h, r1hl; \ + uint64_t ret = 0; \ + \ + ret = ((r1 + 2) & 0xffff); \ + r2l = extract64(r2, 0, 16); \ + r2h = extract64(r2, 16, 16); \ + r1hl = extract64(r1, 32, 16); \ + \ + if ((r2l op ## = r2h) && (r2l op r1hl)) { \ + ret |= (r2l & 0xffff) << 32; \ + ret |= extract64(r1, 0, 16) << 16; \ + } else if ((r2h op r2l) && (r2h op r1hl)) { \ + ret |= extract64(r2, 16, 16) << 32; \ + ret |= extract64(r1 + 1, 0, 16) << 16; \ + } else { \ + ret |= r1 & 0xffffffff0000ull; \ + } \ + return ret; \ +} EXTREMA_H_B(max, >) EXTREMA_H_B(min, <) @@ -994,7 +1054,7 @@ uint32_t helper_sha(CPUTriCoreState *env, target_ulong r1, target_ulong r2) } else if (shift_count > 0) { result = t1 << shift_count; /* calc carry */ - env->PSW_USB_C = ((result & 0xffffffff00000000) != 0); + env->PSW_USB_C = ((result & 0xffffffff00000000ULL) != 0); /* calc v */ env->PSW_USB_V = (((result > 0x7fffffffLL) || (result < -0x80000000LL)) << 31); @@ -1100,6 +1160,48 @@ uint32_t helper_parity(target_ulong r1) return ret; } +uint32_t helper_pack(uint32_t carry, uint32_t r1_low, uint32_t r1_high, + target_ulong r2) +{ + uint32_t ret; + int32_t fp_exp, fp_frac, temp_exp, fp_exp_frac; + int32_t int_exp = r1_high; + int32_t int_mant = r1_low; + uint32_t flag_rnd = (int_mant & (1 << 7)) && ( + (int_mant & (1 << 8)) || + (int_mant & 0x7f) || + (carry != 0)); + if (((int_mant & (1<<31)) == 0) && (int_exp == 255)) { + fp_exp = 255; + fp_frac = extract32(int_mant, 8, 23); + } else if ((int_mant & (1<<31)) && (int_exp >= 127)) { + fp_exp = 255; + fp_frac = 0; + } else if ((int_mant & (1<<31)) && (int_exp <= -128)) { + fp_exp = 0; + fp_frac = 0; + } else if (int_mant == 0) { + fp_exp = 0; + fp_frac = 0; + } else { + if (((int_mant & (1 << 31)) == 0)) { + temp_exp = 0; + } else { + temp_exp = int_exp + 128; + } + fp_exp_frac = (((temp_exp & 0xff) << 23) | + extract32(int_mant, 8, 23)) + + flag_rnd; + fp_exp = extract32(fp_exp_frac, 23, 8); + fp_frac = extract32(fp_exp_frac, 0, 23); + } + ret = r2 & (1 << 31); + ret = ret + (fp_exp << 23); + ret = ret + (fp_frac & 0x7fffff); + + return ret; +} + uint64_t helper_unpack(target_ulong arg1) { int32_t fp_exp = extract32(arg1, 23, 8); @@ -1228,6 +1330,80 @@ uint64_t helper_dvinit_h_131(CPUTriCoreState *env, uint32_t r1, uint32_t r2) return ret; } +uint64_t helper_dvadj(uint64_t r1, uint32_t r2) +{ + int32_t x_sign = (r1 >> 63); + int32_t q_sign = x_sign ^ (r2 >> 31); + int32_t eq_pos = x_sign & ((r1 >> 32) == r2); + int32_t eq_neg = x_sign & ((r1 >> 32) == -r2); + uint32_t quotient; + uint64_t ret, remainder; + + if ((q_sign & ~eq_neg) | eq_pos) { + quotient = (r1 + 1) & 0xffffffff; + } else { + quotient = r1 & 0xffffffff; + } + + if (eq_pos | eq_neg) { + remainder = 0; + } else { + remainder = (r1 & 0xffffffff00000000ull); + } + ret = remainder|quotient; + return ret; +} + +uint64_t helper_dvstep(uint64_t r1, uint32_t r2) +{ + int32_t dividend_sign = extract64(r1, 63, 1); + int32_t divisor_sign = extract32(r2, 31, 1); + int32_t quotient_sign = (dividend_sign != divisor_sign); + int32_t addend, dividend_quotient, remainder; + int32_t i, temp; + + if (quotient_sign) { + addend = r2; + } else { + addend = -r2; + } + dividend_quotient = (int32_t)r1; + remainder = (int32_t)(r1 >> 32); + + for (i = 0; i < 8; i++) { + remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1); + dividend_quotient <<= 1; + temp = remainder + addend; + if ((temp < 0) == dividend_sign) { + remainder = temp; + } + if (((temp < 0) == dividend_sign)) { + dividend_quotient = dividend_quotient | !quotient_sign; + } else { + dividend_quotient = dividend_quotient | quotient_sign; + } + } + return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient; +} + +uint64_t helper_dvstep_u(uint64_t r1, uint32_t r2) +{ + int32_t dividend_quotient = extract64(r1, 0, 32); + int64_t remainder = extract64(r1, 32, 32); + int32_t i; + int64_t temp; + for (i = 0; i < 8; i++) { + remainder = (remainder << 1) | extract32(dividend_quotient, 31, 1); + dividend_quotient <<= 1; + temp = (remainder & 0xffffffff) - r2; + if (temp >= 0) { + remainder = temp; + } + dividend_quotient = dividend_quotient | !(temp < 0); + } + return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient; +} + uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01, uint32_t arg10, uint32_t arg11, uint32_t n) { diff --git a/target-tricore/translate.c b/target-tricore/translate.c index def7f4ad45..a73b7000b4 100644 --- a/target-tricore/translate.c +++ b/target-tricore/translate.c @@ -182,6 +182,18 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, tcg_temp_free(arg11); \ } while (0) +#define GEN_HELPER_RRR(name, rl, rh, al1, ah1, arg2) do { \ + TCGv_i64 ret = tcg_temp_new_i64(); \ + TCGv_i64 arg1 = tcg_temp_new_i64(); \ + \ + tcg_gen_concat_i32_i64(arg1, al1, ah1); \ + gen_helper_##name(ret, arg1, arg2); \ + tcg_gen_extr_i64_i32(rl, rh, ret); \ + \ + tcg_temp_free_i64(ret); \ + tcg_temp_free_i64(arg1); \ +} while (0) + #define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF)) #define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \ ((offset & 0x0fffff) << 1)) @@ -343,7 +355,7 @@ static inline void gen_mfcr(CPUTriCoreState *env, TCGv ret, int32_t offset) static inline void gen_mtcr(CPUTriCoreState *env, DisasContext *ctx, TCGv r1, int32_t offset) { - if (ctx->hflags & TRICORE_HFLAG_SM) { + if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { gen_helper_psw_write(cpu_env, r1); @@ -745,7 +757,7 @@ static inline void gen_cond_add(TCGCond cond, TCGv r1, TCGv r2, TCGv r3, tcg_gen_and_tl(temp, temp, mask); tcg_gen_or_tl(cpu_PSW_SAV, temp, cpu_PSW_SAV); /* write back result */ - tcg_gen_movcond_tl(cond, r3, r4, t0, result, r3); + tcg_gen_movcond_tl(cond, r3, r4, t0, result, r1); tcg_temp_free(t0); tcg_temp_free(temp); @@ -820,6 +832,45 @@ static inline void gen_subc_CC(TCGv ret, TCGv r1, TCGv r2) tcg_temp_free(temp); } +static inline void gen_cond_sub(TCGCond cond, TCGv r1, TCGv r2, TCGv r3, + TCGv r4) +{ + TCGv temp = tcg_temp_new(); + TCGv temp2 = tcg_temp_new(); + TCGv result = tcg_temp_new(); + TCGv mask = tcg_temp_new(); + TCGv t0 = tcg_const_i32(0); + + /* create mask for sticky bits */ + tcg_gen_setcond_tl(cond, mask, r4, t0); + tcg_gen_shli_tl(mask, mask, 31); + + tcg_gen_sub_tl(result, r1, r2); + /* Calc PSW_V */ + tcg_gen_xor_tl(temp, result, r1); + tcg_gen_xor_tl(temp2, r1, r2); + tcg_gen_and_tl(temp, temp, temp2); + tcg_gen_movcond_tl(cond, cpu_PSW_V, r4, t0, temp, cpu_PSW_V); + /* Set PSW_SV */ + tcg_gen_and_tl(temp, temp, mask); + tcg_gen_or_tl(cpu_PSW_SV, temp, cpu_PSW_SV); + /* calc AV bit */ + tcg_gen_add_tl(temp, result, result); + tcg_gen_xor_tl(temp, temp, result); + tcg_gen_movcond_tl(cond, cpu_PSW_AV, r4, t0, temp, cpu_PSW_AV); + /* calc SAV bit */ + tcg_gen_and_tl(temp, temp, mask); + tcg_gen_or_tl(cpu_PSW_SAV, temp, cpu_PSW_SAV); + /* write back result */ + tcg_gen_movcond_tl(cond, r3, r4, t0, result, r1); + + tcg_temp_free(t0); + tcg_temp_free(temp); + tcg_temp_free(temp2); + tcg_temp_free(result); + tcg_temp_free(mask); +} + static inline void gen_abs(TCGv ret, TCGv r1) { TCGv temp = tcg_temp_new(); @@ -987,6 +1038,119 @@ static inline void gen_maddsui_32(TCGv ret, TCGv r1, TCGv r2, int32_t con) tcg_temp_free(temp); } +static void +gen_mul_q(TCGv rl, TCGv rh, TCGv arg1, TCGv arg2, uint32_t n, uint32_t up_shift) +{ + TCGv temp = tcg_temp_new(); + TCGv_i64 temp_64 = tcg_temp_new_i64(); + TCGv_i64 temp2_64 = tcg_temp_new_i64(); + + if (n == 0) { + if (up_shift == 32) { + tcg_gen_muls2_tl(rh, rl, arg1, arg2); + } else if (up_shift == 16) { + tcg_gen_ext_i32_i64(temp_64, arg1); + tcg_gen_ext_i32_i64(temp2_64, arg2); + + tcg_gen_mul_i64(temp_64, temp_64, temp2_64); + tcg_gen_shri_i64(temp_64, temp_64, up_shift); + tcg_gen_extr_i64_i32(rl, rh, temp_64); + } else { + tcg_gen_muls2_tl(rl, rh, arg1, arg2); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + } else { /* n is exspected to be 1 */ + tcg_gen_ext_i32_i64(temp_64, arg1); + tcg_gen_ext_i32_i64(temp2_64, arg2); + + tcg_gen_mul_i64(temp_64, temp_64, temp2_64); + + if (up_shift == 0) { + tcg_gen_shli_i64(temp_64, temp_64, 1); + } else { + tcg_gen_shri_i64(temp_64, temp_64, up_shift - 1); + } + tcg_gen_extr_i64_i32(rl, rh, temp_64); + /* overflow only occours if r1 = r2 = 0x8000 */ + if (up_shift == 0) {/* result is 64 bit */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, rh, + 0x80000000); + } else { /* result is 32 bit */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, rl, + 0x80000000); + } + tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); + /* calc sv overflow bit */ + tcg_gen_or_tl(cpu_PSW_SV, cpu_PSW_SV, cpu_PSW_V); + } + /* calc av overflow bit */ + if (up_shift == 0) { + tcg_gen_add_tl(cpu_PSW_AV, rh, rh); + tcg_gen_xor_tl(cpu_PSW_AV, rh, cpu_PSW_AV); + } else { + tcg_gen_add_tl(cpu_PSW_AV, rl, rl); + tcg_gen_xor_tl(cpu_PSW_AV, rl, cpu_PSW_AV); + } + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + tcg_temp_free(temp); + tcg_temp_free_i64(temp_64); + tcg_temp_free_i64(temp2_64); +} + +static void +gen_mul_q_16(TCGv ret, TCGv arg1, TCGv arg2, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(ret, arg1, arg2); + } else { /* n is exspected to be 1 */ + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_shli_tl(ret, ret, 1); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, ret, 0x80000000); + tcg_gen_sub_tl(ret, ret, temp); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc av overflow bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + + tcg_temp_free(temp); +} + +static void gen_mulr_q(TCGv ret, TCGv arg1, TCGv arg2, uint32_t n) +{ + TCGv temp = tcg_temp_new(); + if (n == 0) { + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_addi_tl(ret, ret, 0x8000); + } else { + tcg_gen_mul_tl(ret, arg1, arg2); + tcg_gen_shli_tl(ret, ret, 1); + tcg_gen_addi_tl(ret, ret, 0x8000); + /* catch special case r1 = r2 = 0x8000 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, temp, ret, 0x80008000); + tcg_gen_muli_tl(temp, temp, 0x8001); + tcg_gen_sub_tl(ret, ret, temp); + } + /* reset v bit */ + tcg_gen_movi_tl(cpu_PSW_V, 0); + /* calc av overflow bit */ + tcg_gen_add_tl(cpu_PSW_AV, ret, ret); + tcg_gen_xor_tl(cpu_PSW_AV, ret, cpu_PSW_AV); + /* calc sav overflow bit */ + tcg_gen_or_tl(cpu_PSW_SAV, cpu_PSW_SAV, cpu_PSW_AV); + /* cut halfword off */ + tcg_gen_andi_tl(ret, ret, 0xffff0000); + + tcg_temp_free(temp); +} + static inline void gen_maddsi_64(TCGv ret_low, TCGv ret_high, TCGv r1, TCGv r2_low, TCGv r2_high, int32_t con) @@ -1647,6 +1811,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, break; case OPC1_32_B_JLA: tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc); + /* fall through */ case OPC1_32_B_JA: gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset)); break; @@ -3898,7 +4063,7 @@ static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RCR_SEL: temp = tcg_const_i32(0); temp2 = tcg_const_i32(const9); - tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp2); tcg_temp_free(temp); tcg_temp_free(temp2); @@ -3906,7 +4071,7 @@ static void decode_rcr_cond_select(CPUTriCoreState *env, DisasContext *ctx) case OPC2_32_RCR_SELN: temp = tcg_const_i32(0); temp2 = tcg_const_i32(const9); - tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r4], temp, + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp2); tcg_temp_free(temp); tcg_temp_free(temp2); @@ -4778,6 +4943,249 @@ static void decode_rr1_mul(CPUTriCoreState *env, DisasContext *ctx) tcg_temp_free(n); } +static void decode_rr1_mulq(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + uint32_t n; + + TCGv temp, temp2; + + r1 = MASK_OP_RR1_S1(ctx->opcode); + r2 = MASK_OP_RR1_S2(ctx->opcode); + r3 = MASK_OP_RR1_D(ctx->opcode); + n = MASK_OP_RR1_N(ctx->opcode); + op2 = MASK_OP_RR1_OP2(ctx->opcode); + + temp = tcg_temp_new(); + temp2 = tcg_temp_new(); + + switch (op2) { + case OPC2_32_RR1_MUL_Q_32: + 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: + gen_mul_q(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2], + n, 0); + break; + case OPC2_32_RR1_MUL_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r2]); + gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); + break; + case OPC2_32_RR1_MUL_Q_64_L: + 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; + case OPC2_32_RR1_MUL_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r2], 16); + gen_mul_q(cpu_gpr_d[r3], temp, cpu_gpr_d[r1], temp, n, 16); + break; + case OPC2_32_RR1_MUL_Q_64_U: + 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; + case OPC2_32_RR1_MUL_Q_32_LL: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_mul_q_16(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MUL_Q_32_UU: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_mul_q_16(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MULR_Q_32_L: + tcg_gen_ext16s_tl(temp, cpu_gpr_d[r1]); + tcg_gen_ext16s_tl(temp2, cpu_gpr_d[r2]); + gen_mulr_q(cpu_gpr_d[r3], temp, temp2, n); + break; + case OPC2_32_RR1_MULR_Q_32_U: + tcg_gen_sari_tl(temp, cpu_gpr_d[r1], 16); + tcg_gen_sari_tl(temp2, cpu_gpr_d[r2], 16); + gen_mulr_q(cpu_gpr_d[r3], temp, temp2, n); + break; + } + tcg_temp_free(temp); + tcg_temp_free(temp2); +} + +/* RR2 format */ +static void decode_rr2_mul(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + + op2 = MASK_OP_RR2_OP2(ctx->opcode); + r1 = MASK_OP_RR2_S1(ctx->opcode); + r2 = MASK_OP_RR2_S2(ctx->opcode); + r3 = MASK_OP_RR2_D(ctx->opcode); + switch (op2) { + case OPC2_32_RR2_MUL_32: + gen_mul_i32s(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MUL_64: + gen_mul_i64s(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MULS_32: + gen_helper_mul_ssov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MUL_U_64: + gen_mul_i64u(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + case OPC2_32_RR2_MULS_U_32: + gen_helper_mul_suov(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], + cpu_gpr_d[r2]); + break; + } +} + +/* RRPW format */ +static void decode_rrpw_extract_insert(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3; + int32_t pos, width; + + op2 = MASK_OP_RRPW_OP2(ctx->opcode); + r1 = MASK_OP_RRPW_S1(ctx->opcode); + r2 = MASK_OP_RRPW_S2(ctx->opcode); + r3 = MASK_OP_RRPW_D(ctx->opcode); + pos = MASK_OP_RRPW_POS(ctx->opcode); + width = MASK_OP_RRPW_WIDTH(ctx->opcode); + + switch (op2) { + case OPC2_32_RRPW_EXTR: + if (pos + width <= 31) { + /* optimize special cases */ + if ((pos == 0) && (width == 8)) { + tcg_gen_ext8s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else if ((pos == 0) && (width == 16)) { + tcg_gen_ext16s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else { + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], 32 - pos - width); + tcg_gen_sari_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], 32 - width); + } + } + break; + case OPC2_32_RRPW_EXTR_U: + if (width == 0) { + tcg_gen_movi_tl(cpu_gpr_d[r3], 0); + } else { + tcg_gen_shri_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], pos); + tcg_gen_andi_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], ~0u >> (32-width)); + } + break; + case OPC2_32_RRPW_IMASK: + 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); + } + break; + case OPC2_32_RRPW_INSERT: + if (pos + width <= 31) { + tcg_gen_deposit_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], + width, pos); + } + break; + } +} + +/* RRR format */ +static void decode_rrr_cond_select(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + int r1, r2, r3, r4; + TCGv temp; + + op2 = MASK_OP_RRR_OP2(ctx->opcode); + r1 = MASK_OP_RRR_S1(ctx->opcode); + r2 = MASK_OP_RRR_S2(ctx->opcode); + r3 = MASK_OP_RRR_S3(ctx->opcode); + r4 = MASK_OP_RRR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR_CADD: + gen_cond_add(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], + cpu_gpr_d[r4], cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CADDN: + gen_cond_add(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CSUB: + gen_cond_sub(TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_CSUBN: + gen_cond_sub(TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], cpu_gpr_d[r4], + cpu_gpr_d[r3]); + break; + case OPC2_32_RRR_SEL: + temp = tcg_const_i32(0); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, + cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_temp_free(temp); + break; + case OPC2_32_RRR_SELN: + temp = tcg_const_i32(0); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr_d[r4], cpu_gpr_d[r3], temp, + cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_temp_free(temp); + break; + } +} + +static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx) +{ + uint32_t op2; + + int r1, r2, r3, r4; + + op2 = MASK_OP_RRR_OP2(ctx->opcode); + r1 = MASK_OP_RRR_S1(ctx->opcode); + r2 = MASK_OP_RRR_S2(ctx->opcode); + r3 = MASK_OP_RRR_S3(ctx->opcode); + r4 = MASK_OP_RRR_D(ctx->opcode); + + switch (op2) { + case OPC2_32_RRR_DVADJ: + 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: + 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: + 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: + 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: + 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: + 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: + 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; + case OPC2_32_RRR_PACK: + gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3], + cpu_gpr_d[r3+1], cpu_gpr_d[r1]); + break; + } +} + static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) { int op1; @@ -5035,6 +5443,38 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) case OPCM_32_RR1_MUL: decode_rr1_mul(env, ctx); break; + case OPCM_32_RR1_MULQ: + decode_rr1_mulq(env, ctx); + break; +/* RR2 format */ + case OPCM_32_RR2_MUL: + decode_rr2_mul(env, ctx); + break; +/* RRPW format */ + case OPCM_32_RRPW_EXTRACT_INSERT: + decode_rrpw_extract_insert(env, ctx); + break; + case OPC1_32_RRPW_DEXTR: + r1 = MASK_OP_RRPW_S1(ctx->opcode); + r2 = MASK_OP_RRPW_S2(ctx->opcode); + r3 = MASK_OP_RRPW_D(ctx->opcode); + const16 = MASK_OP_RRPW_POS(ctx->opcode); + if (r1 == r2) { + tcg_gen_rotli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], const16); + } else { + temp = tcg_temp_new(); + tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], const16); + tcg_gen_shri_tl(temp, cpu_gpr_d[r1], 32 - const16); + tcg_gen_or_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], temp); + tcg_temp_free(temp); + } + break; +/* RRR Format */ + case OPCM_32_RRR_COND_SELECT: + decode_rrr_cond_select(env, ctx); + break; + case OPCM_32_RRR_DIVIDE: + decode_rrr_divide(env, ctx); } } diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h index 82bd161645..baf537f160 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target-tricore/tricore-opcodes.h @@ -516,7 +516,7 @@ enum { OPC1_32_RRPW_DEXTR = 0x77, /* RRR Format */ OPCM_32_RRR_COND_SELECT = 0x2b, - OPCM_32_RRR_FLOAT = 0x6b, + OPCM_32_RRR_DIVIDE = 0x6b, /* RRR1 Format */ OPCM_32_RRR1_MADD = 0x83, OPCM_32_RRR1_MADDQ_H = 0x43, diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index a1bfbf7acf..60ee563080 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -39,8 +39,6 @@ #include "exec/cpu-defs.h" #include "fpu/softfloat.h" -#define TARGET_HAS_ICE 1 - #define NB_MMU_MODES 4 #define TARGET_PHYS_ADDR_SPACE_BITS 32 diff --git a/tests/multiboot/Makefile b/tests/multiboot/Makefile index 34cdd81a90..36f01dc647 100644 --- a/tests/multiboot/Makefile +++ b/tests/multiboot/Makefile @@ -6,11 +6,14 @@ LD=ld LDFLAGS=-melf_i386 -T link.ld LIBS=$(shell $(CC) $(CCFLAGS) -print-libgcc-file-name) -all: mmap.elf +all: mmap.elf modules.elf mmap.elf: start.o mmap.o libc.o $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +modules.elf: start.o modules.o libc.o + $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + %.o: %.c $(CC) $(CCFLAGS) -c -o $@ $^ diff --git a/tests/multiboot/libc.c b/tests/multiboot/libc.c index 05abbd92cc..6df9bda96d 100644 --- a/tests/multiboot/libc.c +++ b/tests/multiboot/libc.c @@ -22,6 +22,18 @@ #include "libc.h" +void* memcpy(void *dest, const void *src, int n) +{ + char *d = dest; + const char *s = src; + + while (n--) { + *d++ = *s++; + } + + return dest; +} + static void print_char(char c) { outb(0xe9, c); diff --git a/tests/multiboot/libc.h b/tests/multiboot/libc.h index 80eec5b7a0..04c9922c27 100644 --- a/tests/multiboot/libc.h +++ b/tests/multiboot/libc.h @@ -57,5 +57,6 @@ static inline void outb(uint16_t port, uint8_t data) /* Misc functions */ void printf(const char *fmt, ...); +void* memcpy(void *dest, const void *src, int n); #endif diff --git a/tests/multiboot/mmap.out b/tests/multiboot/mmap.out index e70b6eb45d..003e109b4c 100644 --- a/tests/multiboot/mmap.out +++ b/tests/multiboot/mmap.out @@ -4,14 +4,14 @@ === Running test case: mmap.elf === Lower memory: 639k -Upper memory: 130040k +Upper memory: 129920k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x7ffe000: type 1 [entry size: 20] -0x7ffe000 - 0x8000000: type 2 [entry size: 20] +0x100000 - 0x7fe0000: type 1 [entry size: 20] +0x7fe0000 - 0x8000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 @@ -22,32 +22,31 @@ real mmap end: 0x9090 === Running test case: mmap.elf -m 1.1M === Lower memory: 639k -Upper memory: 96k +Upper memory: 104k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x118000: type 1 [entry size: 20] -0x118000 - 0x11a000: type 2 [entry size: 20] +0x100000 - 0x11a000: type 1 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 -mmap end: 0x9090 -real mmap end: 0x9090 +mmap end: 0x9078 +real mmap end: 0x9078 === Running test case: mmap.elf -m 2G === Lower memory: 639k -Upper memory: 2096120k +Upper memory: 2096000k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0x7fffe000: type 1 [entry size: 20] -0x7fffe000 - 0x80000000: type 2 [entry size: 20] +0x100000 - 0x7ffe0000: type 1 [entry size: 20] +0x7ffe0000 - 0x80000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] mmap start: 0x9000 @@ -58,16 +57,16 @@ real mmap end: 0x9090 === Running test case: mmap.elf -m 4G === Lower memory: 639k -Upper memory: 3668984k +Upper memory: 3144576k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0xdfffe000: type 1 [entry size: 20] -0xdfffe000 - 0xe0000000: type 2 [entry size: 20] +0x100000 - 0xbffe0000: type 1 [entry size: 20] +0xbffe0000 - 0xc0000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] -0x100000000 - 0x120000000: type 1 [entry size: 20] +0x100000000 - 0x140000000: type 1 [entry size: 20] mmap start: 0x9000 mmap end: 0x90a8 @@ -77,16 +76,16 @@ real mmap end: 0x90a8 === Running test case: mmap.elf -m 8G === Lower memory: 639k -Upper memory: 3668984k +Upper memory: 3144576k e820 memory map: 0x0 - 0x9fc00: type 1 [entry size: 20] 0x9fc00 - 0xa0000: type 2 [entry size: 20] 0xf0000 - 0x100000: type 2 [entry size: 20] -0x100000 - 0xdfffe000: type 1 [entry size: 20] -0xdfffe000 - 0xe0000000: type 2 [entry size: 20] +0x100000 - 0xbffe0000: type 1 [entry size: 20] +0xbffe0000 - 0xc0000000: type 2 [entry size: 20] 0xfffc0000 - 0x100000000: type 2 [entry size: 20] -0x100000000 - 0x220000000: type 1 [entry size: 20] +0x100000000 - 0x240000000: type 1 [entry size: 20] mmap start: 0x9000 mmap end: 0x90a8 diff --git a/tests/multiboot/module.txt b/tests/multiboot/module.txt new file mode 100644 index 0000000000..54c1d27988 --- /dev/null +++ b/tests/multiboot/module.txt @@ -0,0 +1 @@ +This is a test file that is used as a multiboot module. diff --git a/tests/multiboot/modules.c b/tests/multiboot/modules.c new file mode 100644 index 0000000000..531601fb30 --- /dev/null +++ b/tests/multiboot/modules.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 Kevin Wolf <kwolf@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "libc.h" +#include "multiboot.h" + +int test_main(uint32_t magic, struct mb_info *mbi) +{ + struct mb_module *mod; + unsigned int i; + + (void) magic; + + printf("Module list with %d entries at %x\n", + mbi->mods_count, mbi->mods_addr); + + for (i = 0, mod = (struct mb_module*) mbi->mods_addr; + i < mbi->mods_count; + i++, mod++) + { + char buf[1024]; + unsigned int size = mod->mod_end - mod->mod_start; + + printf("[%p] Module: %x - %x (%d bytes) '%s'\n", + mod, mod->mod_start, mod->mod_end, size, mod->string); + + /* Print test file, but remove the newline at the end */ + if (size < sizeof(buf)) { + memcpy(buf, (void*) mod->mod_start, size); + buf[size - 1] = '\0'; + printf(" Content: '%s'\n", buf); + } + } + + return 0; +} diff --git a/tests/multiboot/modules.out b/tests/multiboot/modules.out new file mode 100644 index 0000000000..1636708035 --- /dev/null +++ b/tests/multiboot/modules.out @@ -0,0 +1,38 @@ + + + +=== Running test case: modules.elf === + +Module list with 0 entries at 102000 + + +=== Running test case: modules.elf -initrd module.txt === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt argument === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt argument,,with,,commas === + +Module list with 1 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument,with,commas' + Content: 'This is a test file that is used as a multiboot module.' + + +=== Running test case: modules.elf -initrd module.txt,module.txt argument,module.txt === + +Module list with 3 entries at 102000 +[102000] Module: 103000 - 103038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' +[102010] Module: 104000 - 104038 (56 bytes) 'module.txt argument' + Content: 'This is a test file that is used as a multiboot module.' +[102020] Module: 105000 - 105038 (56 bytes) 'module.txt' + Content: 'This is a test file that is used as a multiboot module.' diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 97a9a49f8b..78d7edfc3b 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -48,10 +48,17 @@ mmap() { run_qemu mmap.elf -m 8G } +modules() { + run_qemu modules.elf + run_qemu modules.elf -initrd module.txt + run_qemu modules.elf -initrd "module.txt argument" + run_qemu modules.elf -initrd "module.txt argument,,with,,commas" + run_qemu modules.elf -initrd "module.txt,module.txt argument,module.txt" +} make all -for t in mmap; do +for t in mmap modules; do echo > test.log $t diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 73863bf1f6..c81319c169 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -186,6 +186,12 @@ $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00" $QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io +# Test how well zero cluster expansion can cope with this +_make_test_img 64M +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io +poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x04\x2a\x00" +$QEMU_IMG amend -o compat=0.10 "$TEST_IMG" + echo echo "=== Testing unaligned L2 entry ===" echo @@ -195,6 +201,15 @@ poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x00" $QEMU_IO -c "read 0 64k" "$TEST_IMG" | _filter_qemu_io echo +echo "=== Testing unaligned pre-allocated zero cluster ===" +echo +_make_test_img 64M +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io +poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x05\x2a\x01" +# zero cluster expansion +$QEMU_IMG amend -o compat=0.10 "$TEST_IMG" + +echo echo "=== Testing unaligned reftable entry ===" echo _make_test_img 64M diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 7d493bbe61..dc9f6b7570 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -123,6 +123,11 @@ wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: L2 table offset 0x42a00 unaligned (L1 index: 0); further corruption events will be suppressed read failed: Input/output error +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Marking image as corrupt: L2 table offset 0x42a00 unaligned (L1 index: 0); further corruption events will be suppressed +qemu-img: Error while amending options: Input/output error === Testing unaligned L2 entry === @@ -132,6 +137,14 @@ wrote 65536/65536 bytes at offset 0 qcow2: Marking image as corrupt: Data cluster offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed read failed: Input/output error +=== Testing unaligned pre-allocated zero cluster === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Marking image as corrupt: Data cluster offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed +qemu-img: Error while amending options: Input/output error + === Testing unaligned reftable entry === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 diff --git a/tests/qemu-iotests/064 b/tests/qemu-iotests/064 index 1c74c31a1a..7564563abd 100755 --- a/tests/qemu-iotests/064 +++ b/tests/qemu-iotests/064 @@ -54,7 +54,15 @@ $QEMU_IO -r -c "read -pP 0x96 33M 33M" "$TEST_IMG" | _filter_qemu_io echo echo "=== Verify pattern 0x00, 66M - 1024M ===" -$QEMU_IO -r -c "read -pP 0x00 66M 958M" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -r -c "read -pP 0x00 66M 62M" \ + -c "read -pP 0x00 128M 128M" \ + -c "read -pP 0x00 256M 128M" \ + -c "read -pP 0x00 384M 128M" \ + -c "read -pP 0x00 512M 128M" \ + -c "read -pP 0x00 640M 128M" \ + -c "read -pP 0x00 768M 128M" \ + -c "read -pP 0x00 896M 128M" \ + "$TEST_IMG" | _filter_qemu_io echo echo "=== Verify pattern write, 0xc3 99M-157M ===" @@ -63,7 +71,14 @@ $QEMU_IO -c "write -pP 0xc3 99M 58M" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -pP 0xa5 0 33M" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -pP 0x96 33M 33M" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -pP 0x00 66M 33M" "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -c "read -pP 0x00 157MM 867MM" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -pP 0x00 157M 99M" \ + -c "read -pP 0x00 256M 128M" \ + -c "read -pP 0x00 384M 128M" \ + -c "read -pP 0x00 512M 128M" \ + -c "read -pP 0x00 640M 128M" \ + -c "read -pP 0x00 768M 128M" \ + -c "read -pP 0x00 896M 128M" \ + "$TEST_IMG" | _filter_qemu_io # now verify what we should have actually written $QEMU_IO -c "read -pP 0xc3 99M 58M" "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/064.out b/tests/qemu-iotests/064.out index 5346a4e630..1a5b9e2d7b 100644 --- a/tests/qemu-iotests/064.out +++ b/tests/qemu-iotests/064.out @@ -9,8 +9,22 @@ read 34603008/34603008 bytes at offset 34603008 33 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Verify pattern 0x00, 66M - 1024M === -read 1004535808/1004535808 bytes at offset 69206016 -958 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65011712/65011712 bytes at offset 69206016 +62 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 134217728 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 268435456 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 402653184 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 536870912 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 671088640 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 805306368 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 939524096 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Verify pattern write, 0xc3 99M-157M === wrote 60817408/60817408 bytes at offset 103809024 @@ -21,8 +35,20 @@ read 34603008/34603008 bytes at offset 34603008 33 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 34603008/34603008 bytes at offset 69206016 33 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 909115392/909115392 bytes at offset 164626432 -867 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 103809024/103809024 bytes at offset 164626432 +99 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 268435456 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 402653184 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 536870912 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 671088640 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 805306368 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 939524096 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 60817408/60817408 bytes at offset 103809024 58 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/trace-events b/trace-events index 3db2f0ccea..04f5df2526 100644 --- a/trace-events +++ b/trace-events @@ -897,6 +897,15 @@ pvscsi_tx_rings_num_pages(const char* label, uint32_t num) "Number of %s pages: # xen-hvm.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx" xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "%#"PRIx64" size %#lx, log_dirty %i" +xen_ioreq_server_create(uint32_t id) "id: %u" +xen_ioreq_server_destroy(uint32_t id) "id: %u" +xen_ioreq_server_state(uint32_t id, bool enable) "id: %u: enable: %i" +xen_map_mmio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64 +xen_unmap_mmio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64 +xen_map_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64 +xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id: %u start: %#"PRIx64" end: %#"PRIx64 +xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x" +xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x" # xen-mapcache.c xen_map_cache(uint64_t phys_addr) "want %#"PRIx64 diff --git a/translate-all.c b/translate-all.c index 687ba7d177..4a1b64fd83 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1451,7 +1451,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) return &tcg_ctx.tb_ctx.tbs[m_max]; } -#if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr) { ram_addr_t ram_addr; @@ -1467,7 +1467,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr) + addr; tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); } -#endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */ +#endif /* !defined(CONFIG_USER_ONLY) */ void tb_check_watchpoint(CPUState *cpu) { diff --git a/ui/console.c b/ui/console.c index 258af5dfff..87574a73a8 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1439,6 +1439,31 @@ void dpy_gfx_replace_surface(QemuConsole *con, qemu_free_displaysurface(old_surface); } +bool dpy_gfx_check_format(QemuConsole *con, + pixman_format_code_t format) +{ + DisplayChangeListener *dcl; + DisplayState *s = con->ds; + + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->con && dcl->con != con) { + /* dcl bound to another console -> skip */ + continue; + } + if (dcl->ops->dpy_gfx_check_format) { + if (!dcl->ops->dpy_gfx_check_format(dcl, format)) { + return false; + } + } else { + /* default is to whitelist native 32 bpp only */ + if (format != qemu_default_pixman_format(32, true)) { + return false; + } + } + } + return true; +} + static void dpy_refresh(DisplayState *s) { DisplayChangeListener *dcl; diff --git a/ui/gtk.c b/ui/gtk.c index 0385757bf5..6a81076ffc 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1654,12 +1654,13 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s) } static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "gtk", - .dpy_gfx_update = gd_update, - .dpy_gfx_switch = gd_switch, - .dpy_refresh = gd_refresh, - .dpy_mouse_set = gd_mouse_set, - .dpy_cursor_define = gd_cursor_define, + .dpy_name = "gtk", + .dpy_gfx_update = gd_update, + .dpy_gfx_switch = gd_switch, + .dpy_gfx_check_format = qemu_pixman_check_format, + .dpy_refresh = gd_refresh, + .dpy_mouse_set = gd_mouse_set, + .dpy_cursor_define = gd_cursor_define, }; static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 1f6fea535b..4116e1507b 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -84,7 +84,7 @@ pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian) break; } } - g_assert_not_reached(); + return 0; } int qemu_pixman_get_type(int rshift, int gshift, int bshift) @@ -125,6 +125,33 @@ pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf) return format; } +/* + * Return true for known-good pixman conversions. + * + * UIs using pixman for format conversion can hook this into + * DisplayChangeListenerOps->dpy_gfx_check_format + */ +bool qemu_pixman_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format) +{ + switch (format) { + /* 32 bpp */ + case PIXMAN_x8r8g8b8: + case PIXMAN_a8r8g8b8: + case PIXMAN_b8g8r8x8: + case PIXMAN_b8g8r8a8: + /* 24 bpp */ + case PIXMAN_r8g8b8: + case PIXMAN_b8g8r8: + /* 16 bpp */ + case PIXMAN_x1r5g5b5: + case PIXMAN_r5g6b5: + return true; + default: + return false; + } +} + pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width) { diff --git a/ui/sdl.c b/ui/sdl.c index 3e9d81076b..138ca73407 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -151,6 +151,19 @@ static void sdl_switch(DisplayChangeListener *dcl, pf.bmask, pf.amask); } +static bool sdl_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format) +{ + /* + * We let SDL convert for us a few more formats than, + * the native ones. Thes are the ones I have tested. + */ + return (format == PIXMAN_x8r8g8b8 || + format == PIXMAN_b8g8r8x8 || + format == PIXMAN_x1r5g5b5 || + format == PIXMAN_r5g6b5); +} + /* generic keyboard conversion */ #include "sdl_keysym.h" @@ -865,12 +878,13 @@ static void sdl_cleanup(void) } static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "sdl", - .dpy_gfx_update = sdl_update, - .dpy_gfx_switch = sdl_switch, - .dpy_refresh = sdl_refresh, - .dpy_mouse_set = sdl_mouse_warp, - .dpy_cursor_define = sdl_mouse_define, + .dpy_name = "sdl", + .dpy_gfx_update = sdl_update, + .dpy_gfx_switch = sdl_switch, + .dpy_gfx_check_format = sdl_check_format, + .dpy_refresh = sdl_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, }; void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c index 9264817e76..f907c21895 100644 --- a/ui/sdl2-2d.c +++ b/ui/sdl2-2d.c @@ -120,3 +120,16 @@ void sdl2_2d_redraw(struct sdl2_console *scon) surface_width(scon->surface), surface_height(scon->surface)); } + +bool sdl2_2d_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format) +{ + /* + * We let SDL convert for us a few more formats than, + * the native ones. Thes are the ones I have tested. + */ + return (format == PIXMAN_x8r8g8b8 || + format == PIXMAN_b8g8r8x8 || + format == PIXMAN_x1r5g5b5 || + format == PIXMAN_r5g6b5); +} diff --git a/ui/sdl2.c b/ui/sdl2.c index 1ae2781624..60e3c3b6fa 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -668,12 +668,13 @@ static void sdl_cleanup(void) } static const DisplayChangeListenerOps dcl_2d_ops = { - .dpy_name = "sdl2-2d", - .dpy_gfx_update = sdl2_2d_update, - .dpy_gfx_switch = sdl2_2d_switch, - .dpy_refresh = sdl2_2d_refresh, - .dpy_mouse_set = sdl_mouse_warp, - .dpy_cursor_define = sdl_mouse_define, + .dpy_name = "sdl2-2d", + .dpy_gfx_update = sdl2_2d_update, + .dpy_gfx_switch = sdl2_2d_switch, + .dpy_gfx_check_format = sdl2_2d_check_format, + .dpy_refresh = sdl2_2d_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, }; void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) diff --git a/ui/spice-core.c b/ui/spice-core.c index fe705c1ae2..c8f7f183c6 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -436,6 +436,11 @@ static QemuOptsList qemu_spice_opts = { },{ .name = "ipv6", .type = QEMU_OPT_BOOL, +#ifdef SPICE_ADDR_FLAG_UNIX_ONLY + },{ + .name = "unix", + .type = QEMU_OPT_BOOL, +#endif },{ .name = "password", .type = QEMU_OPT_STRING, @@ -708,6 +713,10 @@ void qemu_spice_init(void) addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY; } else if (qemu_opt_get_bool(opts, "ipv6", 0)) { addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY; +#ifdef SPICE_ADDR_FLAG_UNIX_ONLY + } else if (qemu_opt_get_bool(opts, "unix", 0)) { + addr_flags |= SPICE_ADDR_FLAG_UNIX_ONLY; +#endif } spice_server = spice_server_new(); diff --git a/ui/spice-display.c b/ui/spice-display.c index d2e379379f..16441852e4 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -438,9 +438,6 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, qemu_mutex_lock(&ssd->lock); need_destroy = (ssd->ds != NULL); ssd->ds = surface; - ssd->surface = pixman_image_ref(ssd->ds->image); - ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, - ssd->ds->image); while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { QTAILQ_REMOVE(&ssd->updates, update, next); qemu_spice_destroy_update(ssd, update); @@ -450,6 +447,9 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, qemu_spice_destroy_host_primary(ssd); } if (ssd->ds) { + ssd->surface = pixman_image_ref(ssd->ds->image); + ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, + ssd->ds->image); qemu_spice_create_host_primary(ssd); } @@ -760,12 +760,13 @@ static void display_mouse_define(DisplayChangeListener *dcl, } static const DisplayChangeListenerOps display_listener_ops = { - .dpy_name = "spice", - .dpy_gfx_update = display_update, - .dpy_gfx_switch = display_switch, - .dpy_refresh = display_refresh, - .dpy_mouse_set = display_mouse_set, - .dpy_cursor_define = display_mouse_define, + .dpy_name = "spice", + .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, }; static void qemu_spice_display_init_one(QemuConsole *con) diff --git a/ui/vnc.c b/ui/vnc.c index 57070150d4..a742c9071c 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -27,10 +27,12 @@ #include "vnc.h" #include "vnc-jobs.h" #include "trace.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qemu/sockets.h" #include "qemu/timer.h" #include "qemu/acl.h" +#include "qemu/config-file.h" #include "qapi/qmp/types.h" #include "qmp-commands.h" #include "qemu/osdep.h" @@ -46,7 +48,8 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 }; #include "vnc_keysym.h" #include "d3des.h" -static VncDisplay *vnc_display; /* needed for info vnc */ +static QTAILQ_HEAD(, VncDisplay) vnc_displays = + QTAILQ_HEAD_INITIALIZER(vnc_displays); static int vnc_cursor_define(VncState *vs); static void vnc_release_modifiers(VncState *vs); @@ -65,12 +68,34 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode) vs->csock, mn[vs->share_mode], mn[mode]); #endif - if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) { + switch (vs->share_mode) { + case VNC_SHARE_MODE_CONNECTING: + vs->vd->num_connecting--; + break; + case VNC_SHARE_MODE_SHARED: + vs->vd->num_shared--; + break; + case VNC_SHARE_MODE_EXCLUSIVE: vs->vd->num_exclusive--; + break; + default: + break; } + vs->share_mode = mode; - if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) { + + switch (vs->share_mode) { + case VNC_SHARE_MODE_CONNECTING: + vs->vd->num_connecting++; + break; + case VNC_SHARE_MODE_SHARED: + vs->vd->num_shared++; + break; + case VNC_SHARE_MODE_EXCLUSIVE: vs->vd->num_exclusive++; + break; + default: + break; } } @@ -226,10 +251,10 @@ static const char *vnc_auth_name(VncDisplay *vd) { return "unknown"; } -static VncServerInfo *vnc_server_info_get(void) +static VncServerInfo *vnc_server_info_get(VncDisplay *vd) { VncServerInfo *info; - VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vnc_display->lsock); + VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vd->lsock); if (!bi) { return NULL; } @@ -237,7 +262,7 @@ static VncServerInfo *vnc_server_info_get(void) info = g_malloc(sizeof(*info)); info->base = bi; info->has_auth = true; - info->auth = g_strdup(vnc_auth_name(vnc_display)); + info->auth = g_strdup(vnc_auth_name(vd)); return info; } @@ -282,7 +307,7 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event) } g_assert(vs->info->base); - si = vnc_server_info_get(); + si = vnc_server_info_get(vs->vd); if (!si) { return; } @@ -328,6 +353,9 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client) info->base->host = g_strdup(host); info->base->service = g_strdup(serv); info->base->family = inet_netfamily(sa.ss_family); +#ifdef CONFIG_VNC_WS + info->base->websocket = client->websocket; +#endif #ifdef CONFIG_VNC_TLS if (client->tls.session && client->tls.dname) { @@ -345,43 +373,59 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client) return info; } +static VncDisplay *vnc_display_find(const char *id) +{ + VncDisplay *vd; + + if (id == NULL) { + return QTAILQ_FIRST(&vnc_displays); + } + QTAILQ_FOREACH(vd, &vnc_displays, next) { + if (strcmp(id, vd->id) == 0) { + return vd; + } + } + return NULL; +} + +static VncClientInfoList *qmp_query_client_list(VncDisplay *vd) +{ + VncClientInfoList *cinfo, *prev = NULL; + VncState *client; + + QTAILQ_FOREACH(client, &vd->clients, next) { + cinfo = g_new0(VncClientInfoList, 1); + cinfo->value = qmp_query_vnc_client(client); + cinfo->next = prev; + prev = cinfo; + } + return prev; +} + VncInfo *qmp_query_vnc(Error **errp) { VncInfo *info = g_malloc0(sizeof(*info)); + VncDisplay *vd = vnc_display_find(NULL); - if (vnc_display == NULL || vnc_display->display == NULL) { + if (vd == NULL || vd->display == NULL) { info->enabled = false; } else { - VncClientInfoList *cur_item = NULL; struct sockaddr_storage sa; socklen_t salen = sizeof(sa); char host[NI_MAXHOST]; char serv[NI_MAXSERV]; - VncState *client; info->enabled = true; /* for compatibility with the original command */ info->has_clients = true; + info->clients = qmp_query_client_list(vd); - QTAILQ_FOREACH(client, &vnc_display->clients, next) { - VncClientInfoList *cinfo = g_malloc0(sizeof(*info)); - cinfo->value = qmp_query_vnc_client(client); - - /* XXX: waiting for the qapi to support GSList */ - if (!cur_item) { - info->clients = cur_item = cinfo; - } else { - cur_item->next = cinfo; - cur_item = cinfo; - } - } - - if (vnc_display->lsock == -1) { + if (vd->lsock == -1) { return info; } - if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa, + if (getsockname(vd->lsock, (struct sockaddr *)&sa, &salen) == -1) { error_set(errp, QERR_UNDEFINED_ERROR); goto out_error; @@ -405,7 +449,7 @@ VncInfo *qmp_query_vnc(Error **errp) info->family = inet_netfamily(sa.ss_family); info->has_auth = true; - info->auth = g_strdup(vnc_auth_name(vnc_display)); + info->auth = g_strdup(vnc_auth_name(vd)); } return info; @@ -415,6 +459,142 @@ out_error: return NULL; } +static VncBasicInfoList *qmp_query_server_entry(int socket, + bool websocket, + VncBasicInfoList *prev) +{ + VncBasicInfoList *list; + VncBasicInfo *info; + struct sockaddr_storage sa; + socklen_t salen = sizeof(sa); + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + + if (getsockname(socket, (struct sockaddr *)&sa, &salen) < 0 || + getnameinfo((struct sockaddr *)&sa, salen, + host, sizeof(host), serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + return prev; + } + + info = g_new0(VncBasicInfo, 1); + info->host = g_strdup(host); + info->service = g_strdup(serv); + info->family = inet_netfamily(sa.ss_family); + info->websocket = websocket; + + list = g_new0(VncBasicInfoList, 1); + list->value = info; + list->next = prev; + return list; +} + +static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info) +{ + switch (vd->auth) { + case VNC_AUTH_VNC: + info->auth = VNC_PRIMARY_AUTH_VNC; + break; + case VNC_AUTH_RA2: + info->auth = VNC_PRIMARY_AUTH_RA2; + break; + case VNC_AUTH_RA2NE: + info->auth = VNC_PRIMARY_AUTH_RA2NE; + break; + case VNC_AUTH_TIGHT: + info->auth = VNC_PRIMARY_AUTH_TIGHT; + break; + case VNC_AUTH_ULTRA: + info->auth = VNC_PRIMARY_AUTH_ULTRA; + break; + case VNC_AUTH_TLS: + info->auth = VNC_PRIMARY_AUTH_TLS; + break; + case VNC_AUTH_VENCRYPT: + info->auth = VNC_PRIMARY_AUTH_VENCRYPT; +#ifdef CONFIG_VNC_TLS + info->has_vencrypt = true; + switch (vd->subauth) { + case VNC_AUTH_VENCRYPT_PLAIN: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_PLAIN; + break; + case VNC_AUTH_VENCRYPT_TLSNONE: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_NONE; + break; + case VNC_AUTH_VENCRYPT_TLSVNC: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_VNC; + break; + case VNC_AUTH_VENCRYPT_TLSPLAIN: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_PLAIN; + break; + case VNC_AUTH_VENCRYPT_X509NONE: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_NONE; + break; + case VNC_AUTH_VENCRYPT_X509VNC: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_VNC; + break; + case VNC_AUTH_VENCRYPT_X509PLAIN: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_PLAIN; + break; + case VNC_AUTH_VENCRYPT_TLSSASL: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_SASL; + break; + case VNC_AUTH_VENCRYPT_X509SASL: + info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_SASL; + break; + default: + info->has_vencrypt = false; + break; + } +#endif + break; + case VNC_AUTH_SASL: + info->auth = VNC_PRIMARY_AUTH_SASL; + break; + case VNC_AUTH_NONE: + default: + info->auth = VNC_PRIMARY_AUTH_NONE; + break; + } +} + +VncInfo2List *qmp_query_vnc_servers(Error **errp) +{ + VncInfo2List *item, *prev = NULL; + VncInfo2 *info; + VncDisplay *vd; + DeviceState *dev; + + QTAILQ_FOREACH(vd, &vnc_displays, next) { + info = g_new0(VncInfo2, 1); + info->id = g_strdup(vd->id); + info->clients = qmp_query_client_list(vd); + qmp_query_auth(vd, info); + if (vd->dcl.con) { + dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con), + "device", NULL)); + info->has_display = true; + info->display = g_strdup(dev->id); + } + if (vd->lsock != -1) { + info->server = qmp_query_server_entry(vd->lsock, false, + info->server); + } +#ifdef CONFIG_VNC_WS + if (vd->lwebsock != -1) { + info->server = qmp_query_server_entry(vd->lwebsock, true, + info->server); + } +#endif + + item = g_new0(VncInfo2List, 1); + item->value = info; + item->next = prev; + prev = item; + } + return prev; +} + /* TODO 1) Get the queue working for IO. 2) there is some weirdness when using the -S option (the screen is grey @@ -853,7 +1033,7 @@ static int vnc_cursor_define(VncState *vs) static void vnc_dpy_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c) { - VncDisplay *vd = vnc_display; + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncState *vs; cursor_put(vd->cursor); @@ -1647,7 +1827,8 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) vs->modifiers_state[keycode] = 0; break; case 0x02 ... 0x0a: /* '1' to '9' keys */ - if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { + if (vs->vd->dcl.con == NULL && + down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { /* Reset the modifiers sent to the current console */ reset_keys(vs); console_select(keycode - 0x02); @@ -2055,8 +2236,8 @@ static void set_pixel_format(VncState *vs, set_pixel_conversion(vs); - graphic_hw_invalidate(NULL); - graphic_hw_update(NULL); + graphic_hw_invalidate(vs->vd->dcl.con); + graphic_hw_update(vs->vd->dcl.con); } static void pixel_format_message (VncState *vs) { @@ -2317,6 +2498,11 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) } vnc_set_share_mode(vs, mode); + if (vs->vd->num_shared > vs->vd->connections_limit) { + vnc_disconnect_start(vs); + return 0; + } + vs->client_width = pixman_image_get_width(vs->vd->server); vs->client_height = pixman_image_get_height(vs->vd->server); vnc_write_u16(vs, vs->client_width); @@ -2783,7 +2969,7 @@ static void vnc_refresh(DisplayChangeListener *dcl) return; } - graphic_hw_update(NULL); + graphic_hw_update(vd->dcl.con); if (vnc_trylock_display(vd)) { update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); @@ -2818,6 +3004,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int i; vs->csock = csock; + vs->vd = vd; if (skipauth) { vs->auth = VNC_AUTH_NONE; @@ -2862,14 +3049,21 @@ static void vnc_connect(VncDisplay *vd, int csock, vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED); vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING); - vs->vd = vd; - #ifdef CONFIG_VNC_WS if (!vs->websocket) #endif { vnc_init_state(vs); } + + if (vd->num_connecting > vd->connections_limit) { + QTAILQ_FOREACH(vs, &vd->clients, next) { + if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) { + vnc_disconnect_start(vs); + return; + } + } + } } void vnc_init_state(VncState *vs) @@ -2888,9 +3082,9 @@ void vnc_init_state(VncState *vs) qemu_mutex_init(&vs->output_mutex); vs->bh = qemu_bh_new(vnc_jobs_bh, vs); - QTAILQ_INSERT_HEAD(&vd->clients, vs, next); + QTAILQ_INSERT_TAIL(&vd->clients, vs, next); - graphic_hw_update(NULL); + graphic_hw_update(vd->dcl.con); vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); @@ -2913,7 +3107,7 @@ static void vnc_listen_read(void *opaque, bool websocket) int csock; /* Catch-up */ - graphic_hw_update(NULL); + graphic_hw_update(vs->dcl.con); #ifdef CONFIG_VNC_WS if (websocket) { csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen); @@ -2942,20 +3136,27 @@ static void vnc_listen_websocket_read(void *opaque) #endif /* CONFIG_VNC_WS */ static const DisplayChangeListenerOps dcl_ops = { - .dpy_name = "vnc", - .dpy_refresh = vnc_refresh, - .dpy_gfx_copy = vnc_dpy_copy, - .dpy_gfx_update = vnc_dpy_update, - .dpy_gfx_switch = vnc_dpy_switch, - .dpy_mouse_set = vnc_mouse_set, - .dpy_cursor_define = vnc_dpy_cursor_define, + .dpy_name = "vnc", + .dpy_refresh = vnc_refresh, + .dpy_gfx_copy = vnc_dpy_copy, + .dpy_gfx_update = vnc_dpy_update, + .dpy_gfx_switch = vnc_dpy_switch, + .dpy_gfx_check_format = qemu_pixman_check_format, + .dpy_mouse_set = vnc_mouse_set, + .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init(DisplayState *ds) +void vnc_display_init(const char *id) { - VncDisplay *vs = g_malloc0(sizeof(*vs)); + VncDisplay *vs; + + if (vnc_display_find(id) != NULL) { + return; + } + vs = g_malloc0(sizeof(*vs)); - vnc_display = vs; + vs->id = strdup(id); + QTAILQ_INSERT_TAIL(&vnc_displays, vs, next); vs->lsock = -1; #ifdef CONFIG_VNC_WS @@ -2983,10 +3184,8 @@ void vnc_display_init(DisplayState *ds) } -static void vnc_display_close(DisplayState *ds) +static void vnc_display_close(VncDisplay *vs) { - VncDisplay *vs = vnc_display; - if (!vs) return; g_free(vs->display); @@ -3012,9 +3211,9 @@ static void vnc_display_close(DisplayState *ds) #endif } -int vnc_display_password(DisplayState *ds, const char *password) +int vnc_display_password(const char *id, const char *password) { - VncDisplay *vs = vnc_display; + VncDisplay *vs = vnc_display_find(id); if (!vs) { return -EINVAL; @@ -3031,9 +3230,9 @@ int vnc_display_password(DisplayState *ds, const char *password) return 0; } -int vnc_display_pw_expire(DisplayState *ds, time_t expires) +int vnc_display_pw_expire(const char *id, time_t expires) { - VncDisplay *vs = vnc_display; + VncDisplay *vs = vnc_display_find(id); if (!vs) { return -EINVAL; @@ -3043,21 +3242,85 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires) return 0; } -char *vnc_display_local_addr(DisplayState *ds) +char *vnc_display_local_addr(const char *id) { - VncDisplay *vs = vnc_display; - + VncDisplay *vs = vnc_display_find(id); + return vnc_socket_local_addr("%s:%s", vs->lsock); } -void vnc_display_open(DisplayState *ds, const char *display, Error **errp) +static QemuOptsList qemu_vnc_opts = { + .name = "vnc", + .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head), + .implied_opt_name = "vnc", + .desc = { + { + .name = "vnc", + .type = QEMU_OPT_STRING, + },{ + .name = "websocket", + .type = QEMU_OPT_STRING, + },{ + .name = "x509", + .type = QEMU_OPT_STRING, + },{ + .name = "share", + .type = QEMU_OPT_STRING, + },{ + .name = "display", + .type = QEMU_OPT_STRING, + },{ + .name = "head", + .type = QEMU_OPT_NUMBER, + },{ + .name = "connections", + .type = QEMU_OPT_NUMBER, + },{ + .name = "password", + .type = QEMU_OPT_BOOL, + },{ + .name = "reverse", + .type = QEMU_OPT_BOOL, + },{ + .name = "lock-key-sync", + .type = QEMU_OPT_BOOL, + },{ + .name = "sasl", + .type = QEMU_OPT_BOOL, + },{ + .name = "tls", + .type = QEMU_OPT_BOOL, + },{ + .name = "x509verify", + .type = QEMU_OPT_BOOL, + },{ + .name = "acl", + .type = QEMU_OPT_BOOL, + },{ + .name = "lossy", + .type = QEMU_OPT_BOOL, + },{ + .name = "non-adaptive", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; + +void vnc_display_open(const char *id, Error **errp) { - VncDisplay *vs = vnc_display; - const char *options; + VncDisplay *vs = vnc_display_find(id); + QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); + const char *display, *share, *device_id; + QemuConsole *con; int password = 0; int reverse = 0; +#ifdef CONFIG_VNC_WS + const char *websocket; +#endif #ifdef CONFIG_VNC_TLS int tls = 0, x509 = 0; + const char *path; #endif #ifdef CONFIG_VNC_SASL int sasl = 0; @@ -3068,120 +3331,92 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) #endif int lock_key_sync = 1; - if (!vnc_display) { + if (!vs) { error_setg(errp, "VNC display not active"); return; } - vnc_display_close(ds); - if (strcmp(display, "none") == 0) - return; + vnc_display_close(vs); + if (!opts) { + return; + } + display = qemu_opt_get(opts, "vnc"); + if (!display || strcmp(display, "none") == 0) { + return; + } vs->display = g_strdup(display); - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; - - options = display; - while ((options = strchr(options, ','))) { - options++; - if (strncmp(options, "password", 8) == 0) { - if (fips_get_state()) { - error_setg(errp, - "VNC password auth disabled due to FIPS mode, " - "consider using the VeNCrypt or SASL authentication " - "methods as an alternative"); - goto fail; - } - password = 1; /* Require password auth */ - } else if (strncmp(options, "reverse", 7) == 0) { - reverse = 1; - } else if (strncmp(options, "no-lock-key-sync", 16) == 0) { - lock_key_sync = 0; + + password = qemu_opt_get_bool(opts, "password", false); + if (password && fips_get_state()) { + error_setg(errp, + "VNC password auth disabled due to FIPS mode, " + "consider using the VeNCrypt or SASL authentication " + "methods as an alternative"); + goto fail; + } + + reverse = qemu_opt_get_bool(opts, "reverse", false); + lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); #ifdef CONFIG_VNC_SASL - } else if (strncmp(options, "sasl", 4) == 0) { - sasl = 1; /* Require SASL auth */ + sasl = qemu_opt_get_bool(opts, "sasl", false); #endif -#ifdef CONFIG_VNC_WS - } else if (strncmp(options, "websocket", 9) == 0) { - char *start, *end; - vs->websocket = 1; - - /* Check for 'websocket=<port>' */ - start = strchr(options, '='); - end = strchr(options, ','); - if (start && (!end || (start < end))) { - int len = end ? end-(start+1) : strlen(start+1); - if (len < 6) { - /* extract the host specification from display */ - char *host = NULL, *port = NULL, *host_end = NULL; - port = g_strndup(start + 1, len); - - /* ipv6 hosts have colons */ - end = strchr(display, ','); - host_end = g_strrstr_len(display, end - display, ":"); - - if (host_end) { - host = g_strndup(display, host_end - display + 1); - } else { - host = g_strndup(":", 1); - } - vs->ws_display = g_strconcat(host, port, NULL); - g_free(host); - g_free(port); - } - } -#endif /* CONFIG_VNC_WS */ #ifdef CONFIG_VNC_TLS - } else if (strncmp(options, "tls", 3) == 0) { - tls = 1; /* Require TLS */ - } else if (strncmp(options, "x509", 4) == 0) { - char *start, *end; - x509 = 1; /* Require x509 certificates */ - if (strncmp(options, "x509verify", 10) == 0) - vs->tls.x509verify = 1; /* ...and verify client certs */ - - /* Now check for 'x509=/some/path' postfix - * and use that to setup x509 certificate/key paths */ - start = strchr(options, '='); - end = strchr(options, ','); - if (start && (!end || (start < end))) { - int len = end ? end-(start+1) : strlen(start+1); - char *path = g_strndup(start + 1, len); - - VNC_DEBUG("Trying certificate path '%s'\n", path); - if (vnc_tls_set_x509_creds_dir(vs, path) < 0) { - error_setg(errp, "Failed to find x509 certificates/keys in %s", path); - g_free(path); - goto fail; - } - g_free(path); - } else { - error_setg(errp, "No certificate path provided"); - goto fail; - } + tls = qemu_opt_get_bool(opts, "tls", false); + path = qemu_opt_get(opts, "x509"); + if (path) { + x509 = 1; + vs->tls.x509verify = qemu_opt_get_bool(opts, "x509verify", false); + if (vnc_tls_set_x509_creds_dir(vs, path) < 0) { + error_setg(errp, "Failed to find x509 certificates/keys in %s", + path); + goto fail; + } + } #endif #if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL) - } else if (strncmp(options, "acl", 3) == 0) { - acl = 1; + acl = qemu_opt_get_bool(opts, "acl", false); #endif - } else if (strncmp(options, "lossy", 5) == 0) { -#ifdef CONFIG_VNC_JPEG - vs->lossy = true; -#endif - } else if (strncmp(options, "non-adaptive", 12) == 0) { - vs->non_adaptive = true; - } else if (strncmp(options, "share=", 6) == 0) { - if (strncmp(options+6, "ignore", 6) == 0) { - vs->share_policy = VNC_SHARE_POLICY_IGNORE; - } else if (strncmp(options+6, "allow-exclusive", 15) == 0) { - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; - } else if (strncmp(options+6, "force-shared", 12) == 0) { - vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; - } else { - error_setg(errp, "unknown vnc share= option"); - goto fail; - } + + share = qemu_opt_get(opts, "share"); + if (share) { + if (strcmp(share, "ignore") == 0) { + vs->share_policy = VNC_SHARE_POLICY_IGNORE; + } else if (strcmp(share, "allow-exclusive") == 0) { + vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; + } else if (strcmp(share, "force-shared") == 0) { + vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; + } else { + error_setg(errp, "unknown vnc share= option"); + goto fail; + } + } else { + vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; + } + vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); + + #ifdef CONFIG_VNC_WS + websocket = qemu_opt_get(opts, "websocket"); + if (websocket) { + /* extract the host specification from display */ + char *host = NULL, *host_end = NULL; + vs->websocket = 1; + + /* ipv6 hosts have colons */ + host_end = strrchr(display, ':'); + if (host_end) { + host = g_strndup(display, host_end - display + 1); + } else { + host = g_strdup(":"); } + vs->ws_display = g_strconcat(host, websocket, NULL); + g_free(host); } +#endif /* CONFIG_VNC_WS */ +#ifdef CONFIG_VNC_JPEG + vs->lossy = qemu_opt_get_bool(opts, "lossy", false); +#endif + vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false); /* adaptive updates are only used with tight encoding and * if lossy updates are enabled so we can disable all the * calculations otherwise */ @@ -3191,18 +3426,36 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) #ifdef CONFIG_VNC_TLS if (acl && x509 && vs->tls.x509verify) { - if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) { + char *aclname; + + if (strcmp(vs->id, "default") == 0) { + aclname = g_strdup("vnc.x509dname"); + } else { + aclname = g_strdup_printf("vnc.%s.x509dname", vs->id); + } + vs->tls.acl = qemu_acl_init(aclname); + if (!vs->tls.acl) { fprintf(stderr, "Failed to create x509 dname ACL\n"); exit(1); } + g_free(aclname); } #endif #ifdef CONFIG_VNC_SASL if (acl && sasl) { - if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) { + char *aclname; + + if (strcmp(vs->id, "default") == 0) { + aclname = g_strdup("vnc.username"); + } else { + aclname = g_strdup_printf("vnc.%s.username", vs->id); + } + vs->sasl.acl = qemu_acl_init(aclname); + if (!vs->sasl.acl) { fprintf(stderr, "Failed to create username ACL\n"); exit(1); } + g_free(aclname); } #endif @@ -3292,6 +3545,33 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) #endif vs->lock_key_sync = lock_key_sync; + device_id = qemu_opt_get(opts, "display"); + if (device_id) { + DeviceState *dev; + int head = qemu_opt_get_number(opts, "head", 0); + + dev = qdev_find_recursive(sysbus_get_default(), device_id); + if (dev == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device_id); + goto fail; + } + + con = qemu_console_lookup_by_device(dev, head); + if (con == NULL) { + error_setg(errp, "Device %s is not bound to a QemuConsole", + device_id); + goto fail; + } + } else { + con = NULL; + } + + if (con != vs->dcl.con) { + unregister_displaychangelistener(&vs->dcl); + vs->dcl.con = con; + register_displaychangelistener(&vs->dcl); + } + if (reverse) { /* connect to viewer */ int csock; @@ -3365,9 +3645,52 @@ fail: #endif /* CONFIG_VNC_WS */ } -void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth) +void vnc_display_add_client(const char *id, int csock, bool skipauth) { - VncDisplay *vs = vnc_display; + VncDisplay *vs = vnc_display_find(id); + if (!vs) { + return; + } vnc_connect(vs, csock, skipauth, false); } + +QemuOpts *vnc_parse_func(const char *str) +{ + return qemu_opts_parse(qemu_find_opts("vnc"), str, 1); +} + +int vnc_init_func(QemuOpts *opts, void *opaque) +{ + Error *local_err = NULL; + QemuOptsList *olist = qemu_find_opts("vnc"); + char *id = (char *)qemu_opts_id(opts); + + if (!id) { + /* auto-assign id if not present */ + int i = 2; + id = g_strdup("default"); + while (qemu_opts_find(olist, id)) { + g_free(id); + id = g_strdup_printf("vnc%d", i++); + } + qemu_opts_set_id(opts, id); + } + + vnc_display_init(id); + vnc_display_open(id, &local_err); + if (local_err != NULL) { + error_report("Failed to start VNC server on `%s': %s", + qemu_opt_get(opts, "display"), + error_get_pretty(local_err)); + error_free(local_err); + exit(1); + } + return 0; +} + +static void vnc_register_config(void) +{ + qemu_add_opts(&qemu_vnc_opts); +} +machine_init(vnc_register_config); diff --git a/ui/vnc.h b/ui/vnc.h index 334de9ddb1..5e2b1a561e 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -150,7 +150,10 @@ typedef enum VncSharePolicy { struct VncDisplay { QTAILQ_HEAD(, VncState) clients; + int num_connecting; + int num_shared; int num_exclusive; + int connections_limit; VncSharePolicy share_policy; int lsock; #ifdef CONFIG_VNC_WS @@ -171,6 +174,8 @@ struct VncDisplay struct VncSurface guest; /* guest visible surface (aka ds->surface) */ pixman_image_t *server; /* vnc server surface */ + const char *id; + QTAILQ_ENTRY(VncDisplay) next; char *display; char *password; time_t expires; diff --git a/vl.c b/vl.c index fbf4240145..983259bc9f 100644 --- a/vl.c +++ b/vl.c @@ -158,9 +158,6 @@ int smp_cpus = 1; int max_cpus = 0; int smp_cores = 1; int smp_threads = 1; -#ifdef CONFIG_VNC -const char *vnc_display; -#endif int acpi_enabled = 1; int no_hpet = 0; int fd_bootchk = 1; @@ -2002,16 +1999,12 @@ static DisplayType select_display(const char *p) #endif } else if (strstart(p, "vnc", &opts)) { #ifdef CONFIG_VNC - display_remote++; - - if (*opts) { - const char *nextopt; - - if (strstart(opts, "=", &nextopt)) { - vnc_display = nextopt; + if (*opts == '=') { + display_remote++; + if (vnc_parse_func(opts+1) == NULL) { + exit(1); } - } - if (!vnc_display) { + } else { fprintf(stderr, "VNC requires a display argument vnc=<display>\n"); exit(1); } @@ -3479,7 +3472,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_vnc: #ifdef CONFIG_VNC display_remote++; - vnc_display = optarg; + if (vnc_parse_func(optarg) == NULL) { + exit(1); + } #else fprintf(stderr, "VNC support is disabled\n"); exit(1); @@ -3975,7 +3970,7 @@ int main(int argc, char **argv, char **envp) #elif defined(CONFIG_SDL) || defined(CONFIG_COCOA) display_type = DT_SDL; #elif defined(CONFIG_VNC) - vnc_display = "localhost:0,to=99"; + vnc_parse_func("localhost:0,to=99,id=default"); show_vnc_port = 1; #else display_type = DT_NONE; @@ -4286,20 +4281,10 @@ int main(int argc, char **argv, char **envp) #ifdef CONFIG_VNC /* init remote displays */ - if (vnc_display) { - Error *local_err = NULL; - vnc_display_init(ds); - vnc_display_open(ds, vnc_display, &local_err); - if (local_err != NULL) { - error_report("Failed to start VNC server on `%s': %s", - vnc_display, error_get_pretty(local_err)); - error_free(local_err); - exit(1); - } - - if (show_vnc_port) { - printf("VNC server running on `%s'\n", vnc_display_local_addr(ds)); - } + qemu_opts_foreach(qemu_find_opts("vnc"), vnc_init_func, NULL, 0); + if (show_vnc_port) { + printf("VNC server running on `%s'\n", + vnc_display_local_addr("default")); } #endif #ifdef CONFIG_SPICE diff --git a/xen-hvm.c b/xen-hvm.c index e2e575b099..315864ca70 100644 --- a/xen-hvm.c +++ b/xen-hvm.c @@ -85,9 +85,6 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu) } # define FMT_ioreq_size "u" #endif -#ifndef HVM_PARAM_BUFIOREQ_EVTCHN -#define HVM_PARAM_BUFIOREQ_EVTCHN 26 -#endif #define BUFFER_IO_MAX_DELAY 100 /* Leave some slack so that hvmloader does not complain about lack of @@ -107,6 +104,7 @@ typedef struct XenPhysmap { } XenPhysmap; typedef struct XenIOState { + ioservid_t ioservid; shared_iopage_t *shared_page; shared_vmport_iopage_t *shared_vmport_page; buffered_iopage_t *buffered_io_page; @@ -123,6 +121,8 @@ typedef struct XenIOState { struct xs_handle *xenstore; MemoryListener memory_listener; + MemoryListener io_listener; + DeviceListener device_listener; QLIST_HEAD(, XenPhysmap) physmap; hwaddr free_phys_offset; const XenPhysmap *log_for_dirtybit; @@ -491,12 +491,23 @@ static void xen_set_memory(struct MemoryListener *listener, bool log_dirty = memory_region_is_logging(section->mr); hvmmem_type_t mem_type; + if (section->mr == &ram_memory) { + return; + } else { + if (add) { + xen_map_memory_section(xen_xc, xen_domid, state->ioservid, + section); + } else { + xen_unmap_memory_section(xen_xc, xen_domid, state->ioservid, + section); + } + } + if (!memory_region_is_ram(section->mr)) { return; } - if (!(section->mr != &ram_memory - && ( (log_dirty && add) || (!log_dirty && !add)))) { + if (log_dirty != add) { return; } @@ -539,6 +550,50 @@ static void xen_region_del(MemoryListener *listener, memory_region_unref(section->mr); } +static void xen_io_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + XenIOState *state = container_of(listener, XenIOState, io_listener); + + memory_region_ref(section->mr); + + xen_map_io_section(xen_xc, xen_domid, state->ioservid, section); +} + +static void xen_io_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + XenIOState *state = container_of(listener, XenIOState, io_listener); + + xen_unmap_io_section(xen_xc, xen_domid, state->ioservid, section); + + memory_region_unref(section->mr); +} + +static void xen_device_realize(DeviceListener *listener, + DeviceState *dev) +{ + XenIOState *state = container_of(listener, XenIOState, device_listener); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + PCIDevice *pci_dev = PCI_DEVICE(dev); + + xen_map_pcidev(xen_xc, xen_domid, state->ioservid, pci_dev); + } +} + +static void xen_device_unrealize(DeviceListener *listener, + DeviceState *dev) +{ + XenIOState *state = container_of(listener, XenIOState, device_listener); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + PCIDevice *pci_dev = PCI_DEVICE(dev); + + xen_unmap_pcidev(xen_xc, xen_domid, state->ioservid, pci_dev); + } +} + static void xen_sync_dirty_bitmap(XenIOState *state, hwaddr start_addr, ram_addr_t size) @@ -639,6 +694,17 @@ static MemoryListener xen_memory_listener = { .priority = 10, }; +static MemoryListener xen_io_listener = { + .region_add = xen_io_add, + .region_del = xen_io_del, + .priority = 10, +}; + +static DeviceListener xen_device_listener = { + .realize = xen_device_realize, + .unrealize = xen_device_unrealize, +}; + /* get the ioreq packets from share mem */ static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu) { @@ -887,6 +953,27 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req) case IOREQ_TYPE_INVALIDATE: xen_invalidate_map_cache(); break; + case IOREQ_TYPE_PCI_CONFIG: { + uint32_t sbdf = req->addr >> 32; + uint32_t val; + + /* Fake a write to port 0xCF8 so that + * the config space access will target the + * correct device model. + */ + val = (1u << 31) | + ((req->addr & 0x0f00) << 16) | + ((sbdf & 0xffff) << 8) | + (req->addr & 0xfc); + do_outp(0xcf8, 4, val); + + /* Now issue the config space access via + * port 0xCFC + */ + req->addr = 0xcfc | (req->addr & 0x03); + cpu_ioreq_pio(req); + break; + } default: hw_error("Invalid ioreq type 0x%x\n", req->type); } @@ -1017,9 +1104,15 @@ static void xen_main_loop_prepare(XenIOState *state) static void xen_hvm_change_state_handler(void *opaque, int running, RunState rstate) { + XenIOState *state = opaque; + if (running) { - xen_main_loop_prepare((XenIOState *)opaque); + xen_main_loop_prepare(state); } + + xen_set_ioreq_server_state(xen_xc, xen_domid, + state->ioservid, + (rstate == RUN_STATE_RUNNING)); } static void xen_exit_notifier(Notifier *n, void *data) @@ -1088,8 +1181,9 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, MemoryRegion **ram_memory) { int i, rc; - unsigned long ioreq_pfn; - unsigned long bufioreq_evtchn; + xen_pfn_t ioreq_pfn; + xen_pfn_t bufioreq_pfn; + evtchn_port_t bufioreq_evtchn; XenIOState *state; state = g_malloc0(sizeof (XenIOState)); @@ -1106,6 +1200,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, return -1; } + rc = xen_create_ioreq_server(xen_xc, xen_domid, &state->ioservid); + if (rc < 0) { + perror("xen: ioreq server create"); + return -1; + } + state->exit.notify = xen_exit_notifier; qemu_add_exit_notifier(&state->exit); @@ -1115,8 +1215,18 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, state->wakeup.notify = xen_wakeup_notifier; qemu_register_wakeup_notifier(&state->wakeup); - xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); + rc = xen_get_ioreq_server_info(xen_xc, xen_domid, state->ioservid, + &ioreq_pfn, &bufioreq_pfn, + &bufioreq_evtchn); + if (rc < 0) { + hw_error("failed to get ioreq server info: error %d handle=" XC_INTERFACE_FMT, + errno, xen_xc); + } + DPRINTF("shared page at pfn %lx\n", ioreq_pfn); + DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn); + DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn); + state->shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, PROT_READ|PROT_WRITE, ioreq_pfn); if (state->shared_page == NULL) { @@ -1138,10 +1248,10 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, hw_error("get vmport regs pfn returned error %d, rc=%d", errno, rc); } - xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); - DPRINTF("buffered io page at pfn %lx\n", ioreq_pfn); - state->buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, - PROT_READ|PROT_WRITE, ioreq_pfn); + state->buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, + XC_PAGE_SIZE, + PROT_READ|PROT_WRITE, + bufioreq_pfn); if (state->buffered_io_page == NULL) { hw_error("map buffered IO page returned error %d", errno); } @@ -1149,6 +1259,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, /* Note: cpus is empty at this point in init */ state->cpu_by_vcpu_id = g_malloc0(max_cpus * sizeof(CPUState *)); + rc = xen_set_ioreq_server_state(xen_xc, xen_domid, state->ioservid, true); + if (rc < 0) { + hw_error("failed to enable ioreq server info: error %d handle=" XC_INTERFACE_FMT, + errno, xen_xc); + } + state->ioreq_local_port = g_malloc0(max_cpus * sizeof (evtchn_port_t)); /* FIXME: how about if we overflow the page here? */ @@ -1156,22 +1272,16 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid, xen_vcpu_eport(state->shared_page, i)); if (rc == -1) { - fprintf(stderr, "bind interdomain ioctl error %d\n", errno); + fprintf(stderr, "shared evtchn %d bind error %d\n", i, errno); return -1; } state->ioreq_local_port[i] = rc; } - rc = xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_EVTCHN, - &bufioreq_evtchn); - if (rc < 0) { - fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_EVTCHN\n"); - return -1; - } rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid, - (uint32_t)bufioreq_evtchn); + bufioreq_evtchn); if (rc == -1) { - fprintf(stderr, "bind interdomain ioctl error %d\n", errno); + fprintf(stderr, "buffered evtchn bind error %d\n", errno); return -1; } state->bufioreq_local_port = rc; @@ -1187,6 +1297,12 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, memory_listener_register(&state->memory_listener, &address_space_memory); state->log_for_dirtybit = NULL; + state->io_listener = xen_io_listener; + memory_listener_register(&state->io_listener, &address_space_io); + + state->device_listener = xen_device_listener; + device_listener_register(&state->device_listener); + /* Initialize backend core & drivers */ if (xen_be_init() != 0) { fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); diff --git a/xen-mapcache.c b/xen-mapcache.c index 66da1a6d47..8cefd0c62f 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -49,9 +49,6 @@ */ #define NON_MCACHE_MEMORY_SIZE (80 * 1024 * 1024) -#define mapcache_lock() ((void)0) -#define mapcache_unlock() ((void)0) - typedef struct MapCacheEntry { hwaddr paddr_index; uint8_t *vaddr_base; @@ -79,11 +76,22 @@ typedef struct MapCache { unsigned int mcache_bucket_shift; phys_offset_to_gaddr_t phys_offset_to_gaddr; + QemuMutex lock; void *opaque; } MapCache; static MapCache *mapcache; +static inline void mapcache_lock(void) +{ + qemu_mutex_lock(&mapcache->lock); +} + +static inline void mapcache_unlock(void) +{ + qemu_mutex_unlock(&mapcache->lock); +} + static inline int test_bits(int nr, int size, const unsigned long *addr) { unsigned long res = find_next_zero_bit(addr, size + nr, nr); @@ -102,6 +110,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque) mapcache->phys_offset_to_gaddr = f; mapcache->opaque = opaque; + qemu_mutex_init(&mapcache->lock); QTAILQ_INIT(&mapcache->locked_entries); @@ -193,14 +202,14 @@ static void xen_remap_bucket(MapCacheEntry *entry, g_free(err); } -uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size, - uint8_t lock) +static uint8_t *xen_map_cache_unlocked(hwaddr phys_addr, hwaddr size, + uint8_t lock) { MapCacheEntry *entry, *pentry = NULL; hwaddr address_index; hwaddr address_offset; - hwaddr __size = size; - hwaddr __test_bit_size = size; + hwaddr cache_size = size; + hwaddr test_bit_size; bool translated = false; tryagain: @@ -209,22 +218,22 @@ tryagain: trace_xen_map_cache(phys_addr); - /* __test_bit_size is always a multiple of XC_PAGE_SIZE */ + /* test_bit_size is always a multiple of XC_PAGE_SIZE */ if (size) { - __test_bit_size = size + (phys_addr & (XC_PAGE_SIZE - 1)); + test_bit_size = size + (phys_addr & (XC_PAGE_SIZE - 1)); - if (__test_bit_size % XC_PAGE_SIZE) { - __test_bit_size += XC_PAGE_SIZE - (__test_bit_size % XC_PAGE_SIZE); + if (test_bit_size % XC_PAGE_SIZE) { + test_bit_size += XC_PAGE_SIZE - (test_bit_size % XC_PAGE_SIZE); } } else { - __test_bit_size = XC_PAGE_SIZE; + test_bit_size = XC_PAGE_SIZE; } if (mapcache->last_entry != NULL && mapcache->last_entry->paddr_index == address_index && - !lock && !__size && + !lock && !size && test_bits(address_offset >> XC_PAGE_SHIFT, - __test_bit_size >> XC_PAGE_SHIFT, + test_bit_size >> XC_PAGE_SHIFT, mapcache->last_entry->valid_mapping)) { trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset); return mapcache->last_entry->vaddr_base + address_offset; @@ -232,20 +241,20 @@ tryagain: /* size is always a multiple of MCACHE_BUCKET_SIZE */ if (size) { - __size = size + address_offset; - if (__size % MCACHE_BUCKET_SIZE) { - __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE); + cache_size = size + address_offset; + if (cache_size % MCACHE_BUCKET_SIZE) { + cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE); } } else { - __size = MCACHE_BUCKET_SIZE; + cache_size = MCACHE_BUCKET_SIZE; } entry = &mapcache->entry[address_index % mapcache->nr_buckets]; while (entry && entry->lock && entry->vaddr_base && - (entry->paddr_index != address_index || entry->size != __size || + (entry->paddr_index != address_index || entry->size != cache_size || !test_bits(address_offset >> XC_PAGE_SHIFT, - __test_bit_size >> XC_PAGE_SHIFT, + test_bit_size >> XC_PAGE_SHIFT, entry->valid_mapping))) { pentry = entry; entry = entry->next; @@ -253,19 +262,19 @@ tryagain: if (!entry) { entry = g_malloc0(sizeof (MapCacheEntry)); pentry->next = entry; - xen_remap_bucket(entry, __size, address_index); + xen_remap_bucket(entry, cache_size, address_index); } else if (!entry->lock) { if (!entry->vaddr_base || entry->paddr_index != address_index || - entry->size != __size || + entry->size != cache_size || !test_bits(address_offset >> XC_PAGE_SHIFT, - __test_bit_size >> XC_PAGE_SHIFT, + test_bit_size >> XC_PAGE_SHIFT, entry->valid_mapping)) { - xen_remap_bucket(entry, __size, address_index); + xen_remap_bucket(entry, cache_size, address_index); } } if(!test_bits(address_offset >> XC_PAGE_SHIFT, - __test_bit_size >> XC_PAGE_SHIFT, + test_bit_size >> XC_PAGE_SHIFT, entry->valid_mapping)) { mapcache->last_entry = NULL; if (!translated && mapcache->phys_offset_to_gaddr) { @@ -291,14 +300,27 @@ tryagain: return mapcache->last_entry->vaddr_base + address_offset; } +uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size, + uint8_t lock) +{ + uint8_t *p; + + mapcache_lock(); + p = xen_map_cache_unlocked(phys_addr, size, lock); + mapcache_unlock(); + return p; +} + ram_addr_t xen_ram_addr_from_mapcache(void *ptr) { MapCacheEntry *entry = NULL; MapCacheRev *reventry; hwaddr paddr_index; hwaddr size; + ram_addr_t raddr; int found = 0; + mapcache_lock(); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { if (reventry->vaddr_req == ptr) { paddr_index = reventry->paddr_index; @@ -323,13 +345,16 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr) } if (!entry) { DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr); - return 0; + raddr = 0; + } else { + raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + + ((unsigned long) ptr - (unsigned long) entry->vaddr_base); } - return (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + - ((unsigned long) ptr - (unsigned long) entry->vaddr_base); + mapcache_unlock(); + return raddr; } -void xen_invalidate_map_cache_entry(uint8_t *buffer) +static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) { MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; @@ -383,6 +408,13 @@ void xen_invalidate_map_cache_entry(uint8_t *buffer) g_free(entry); } +void xen_invalidate_map_cache_entry(uint8_t *buffer) +{ + mapcache_lock(); + xen_invalidate_map_cache_entry_unlocked(buffer); + mapcache_unlock(); +} + void xen_invalidate_map_cache(void) { unsigned long i; @@ -391,14 +423,14 @@ void xen_invalidate_map_cache(void) /* Flush pending AIO before destroying the mapcache */ bdrv_drain_all(); + mapcache_lock(); + QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { DPRINTF("There should be no locked mappings at this time, " "but "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); } - mapcache_lock(); - for (i = 0; i < mapcache->nr_buckets; i++) { MapCacheEntry *entry = &mapcache->entry[i]; |