diff options
147 files changed, 2160 insertions, 1237 deletions
diff --git a/.travis.yml b/.travis.yml index 678e33decc..b9a026c8ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,7 +77,7 @@ env: - SRC_DIR="." - BUILD_DIR="." - BASE_CONFIG="--disable-docs --disable-tools" - - TEST_CMD="make check -j3 V=1" + - TEST_CMD="make check V=1" # This is broadly a list of "mainline" softmmu targets which have support across the major distros - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu" - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime" diff --git a/LICENSE b/LICENSE index 9389ba614f..f19b018486 100644 --- a/LICENSE +++ b/LICENSE @@ -18,8 +18,9 @@ As of July 2013, contributions under version 2 of the GNU General Public License (and no later version) are only accepted for the following files or directories: bsd-user/, linux-user/, hw/vfio/, hw/xen/xen_pt*. -3) The Tiny Code Generator (TCG) is released under the BSD license - (see license headers in files). +3) The Tiny Code Generator (TCG) is mostly under the BSD or MIT licenses; + but some parts may be GPLv2 or other licenses. Again, see the + specific licensing information in each source file. 4) QEMU is a trademark of Fabrice Bellard. diff --git a/MAINTAINERS b/MAINTAINERS index c2a68555ae..ff8d0d29f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1241,18 +1241,19 @@ M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> S: Supported F: include/hw/i386/ F: hw/i386/ -F: hw/pci-host/piix.c +F: hw/pci-host/i440fx.c F: hw/pci-host/q35.c F: hw/pci-host/pam.c +F: include/hw/pci-host/i440fx.h F: include/hw/pci-host/q35.h F: include/hw/pci-host/pam.h -F: hw/isa/piix4.c +F: hw/isa/piix3.c F: hw/isa/lpc_ich9.c F: hw/i2c/smbus_ich9.c F: hw/acpi/piix4.c F: hw/acpi/ich9.c F: include/hw/acpi/ich9.h -F: include/hw/acpi/piix4.h +F: include/hw/southbridge/piix.h F: hw/misc/sga.c F: hw/isa/apm.c F: include/hw/isa/apm.h @@ -1753,6 +1754,13 @@ F: hw/display/edid* F: include/hw/display/edid.h F: qemu-edid.c +PIIX4 South Bridge (i82371AB) +M: Hervé Poussineau <hpoussin@reactos.org> +M: Philippe Mathieu-Daudé <f4bug@amsat.org> +S: Maintained +F: hw/isa/piix4.c +F: include/hw/southbridge/piix.h + Firmware configuration (fw_cfg) M: Philippe Mathieu-Daudé <philmd@redhat.com> R: Laszlo Ersek <lersek@redhat.com> @@ -2135,13 +2143,11 @@ F: include/hw/registerfields.h SLIRP M: Samuel Thibault <samuel.thibault@ens-lyon.org> -M: Jan Kiszka <jan.kiszka@siemens.com> S: Maintained F: slirp/ F: net/slirp.c F: include/net/slirp.h T: git https://people.debian.org/~sthibault/qemu.git slirp -T: git git://git.kiszka.org/qemu.git queues/slirp Stubs M: Paolo Bonzini <pbonzini@redhat.com> diff --git a/Makefile b/Makefile index bd6376d295..b437a346d7 100644 --- a/Makefile +++ b/Makefile @@ -390,7 +390,8 @@ MINIKCONF_ARGS = \ CONFIG_LINUX=$(CONFIG_LINUX) \ CONFIG_PVRDMA=$(CONFIG_PVRDMA) -MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig +MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig \ + $(wildcard $(SRC_PATH)/hw/*/Kconfig) MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \ $(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_INPUTS) $(BUILD_DIR)/config-host.mak @@ -479,7 +480,9 @@ $(SOFTMMU_ALL_RULES): $(chardev-obj-y) $(SOFTMMU_ALL_RULES): $(crypto-obj-y) $(SOFTMMU_ALL_RULES): $(io-obj-y) $(SOFTMMU_ALL_RULES): config-all-devices.mak +ifdef DECOMPRESS_EDK2_BLOBS $(SOFTMMU_ALL_RULES): $(edk2-decompressed) +endif .PHONY: $(TARGET_DIRS_RULES) # The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that @@ -770,7 +773,7 @@ de-ch es fo fr-ca hu ja mk pt sl tr \ bepo cz ifdef INSTALL_BLOBS -BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ +BLOBS=bios.bin bios-256k.bin bios-microvm.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \ vgabios-ramfb.bin vgabios-bochs-display.bin vgabios-ati.bin \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \ diff --git a/VERSION b/VERSION index 5f79df70a0..cfcbdd75dd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.50 +4.1.91 diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 68487dceb5..98221948d6 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -931,8 +931,6 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, cpu_io_recompile(cpu, retaddr); } - cpu->mem_io_access_type = access_type; - if (mr->global_locking && !qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; diff --git a/block/block-copy.c b/block/block-copy.c index c39cc9cffe..79798a1567 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -109,9 +109,9 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, s->use_copy_range = false; s->copy_size = cluster_size; } else if (write_flags & BDRV_REQ_WRITE_COMPRESSED) { - /* Compression is not supported for copy_range */ + /* Compression supports only cluster-size writes and no copy-range. */ s->use_copy_range = false; - s->copy_size = MAX(cluster_size, BLOCK_COPY_MAX_BUFFER); + s->copy_size = cluster_size; } else { /* * copy_range does not respect max_transfer (it's a TODO), so we factor diff --git a/block/file-posix.c b/block/file-posix.c index 0b7e904d48..1f0f61a02b 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2721,6 +2721,42 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, RawPosixAIOData acb; ThreadPoolFunc *handler; +#ifdef CONFIG_FALLOCATE + if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) { + BdrvTrackedRequest *req; + uint64_t end; + + /* + * This is a workaround for a bug in the Linux XFS driver, + * where writes submitted through the AIO interface will be + * discarded if they happen beyond a concurrently running + * fallocate() that increases the file length (i.e., both the + * write and the fallocate() happen beyond the EOF). + * + * To work around it, we extend the tracked request for this + * zero write until INT64_MAX (effectively infinity), and mark + * it as serializing. + * + * We have to enable this workaround for all filesystems and + * AIO modes (not just XFS with aio=native), because for + * remote filesystems we do not know the host configuration. + */ + + req = bdrv_co_get_self_request(bs); + assert(req); + assert(req->type == BDRV_TRACKED_WRITE); + assert(req->offset <= offset); + assert(req->offset + req->bytes >= offset + bytes); + + end = INT64_MAX & -(uint64_t)bs->bl.request_alignment; + req->bytes = end - req->offset; + req->overlap_bytes = req->bytes; + + bdrv_mark_request_serialising(req, bs->bl.request_alignment); + bdrv_wait_serialising_requests(req); + } +#endif + acb = (RawPosixAIOData) { .bs = bs, .aio_fildes = s->fd, diff --git a/block/io.c b/block/io.c index 02659f994d..f75777f5ea 100644 --- a/block/io.c +++ b/block/io.c @@ -715,7 +715,7 @@ static void tracked_request_begin(BdrvTrackedRequest *req, qemu_co_mutex_unlock(&bs->reqs_lock); } -static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) +void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) { int64_t overlap_offset = req->offset & ~(align - 1); uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align) @@ -743,6 +743,24 @@ static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req) } /** + * Return the tracked request on @bs for the current coroutine, or + * NULL if there is none. + */ +BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) +{ + BdrvTrackedRequest *req; + Coroutine *self = qemu_coroutine_self(); + + QLIST_FOREACH(req, &bs->tracked_requests, list) { + if (req->co == self) { + return req; + } + } + + return NULL; +} + +/** * Round a region to cluster boundaries */ void bdrv_round_to_clusters(BlockDriverState *bs, @@ -805,7 +823,7 @@ void bdrv_dec_in_flight(BlockDriverState *bs) bdrv_wakeup(bs); } -static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self) +bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self) { BlockDriverState *bs = self->bs; BdrvTrackedRequest *req; @@ -1437,14 +1455,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, * with each other for the same cluster. For example, in copy-on-read * it ensures that the CoR read and write operations are atomic and * guest writes cannot interleave between them. */ - mark_request_serialising(req, bdrv_get_cluster_size(bs)); + bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); } /* BDRV_REQ_SERIALISING is only for write operation */ assert(!(flags & BDRV_REQ_SERIALISING)); if (!(flags & BDRV_REQ_NO_SERIALISING)) { - wait_serialising_requests(req); + bdrv_wait_serialising_requests(req); } if (flags & BDRV_REQ_COPY_ON_READ) { @@ -1841,10 +1859,10 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes, assert(!(flags & ~BDRV_REQ_MASK)); if (flags & BDRV_REQ_SERIALISING) { - mark_request_serialising(req, bdrv_get_cluster_size(bs)); + bdrv_mark_request_serialising(req, bdrv_get_cluster_size(bs)); } - waited = wait_serialising_requests(req); + waited = bdrv_wait_serialising_requests(req); assert(!waited || !req->serialising || is_request_serialising_and_aligned(req)); @@ -2008,8 +2026,8 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, padding = bdrv_init_padding(bs, offset, bytes, &pad); if (padding) { - mark_request_serialising(req, align); - wait_serialising_requests(req); + bdrv_mark_request_serialising(req, align); + bdrv_wait_serialising_requests(req); bdrv_padding_rmw_read(child, req, &pad, true); @@ -2111,8 +2129,8 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, } if (bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad)) { - mark_request_serialising(&req, align); - wait_serialising_requests(&req); + bdrv_mark_request_serialising(&req, align); + bdrv_wait_serialising_requests(&req); bdrv_padding_rmw_read(child, &req, &pad, false); } @@ -3205,7 +3223,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( /* BDRV_REQ_SERIALISING is only for write operation */ assert(!(read_flags & BDRV_REQ_SERIALISING)); if (!(read_flags & BDRV_REQ_NO_SERIALISING)) { - wait_serialising_requests(&req); + bdrv_wait_serialising_requests(&req); } ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, @@ -3336,7 +3354,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, * new area, we need to make sure that no write requests are made to it * concurrently or they might be overwritten by preallocation. */ if (new_bytes) { - mark_request_serialising(&req, 1); + bdrv_mark_request_serialising(&req, 1); } if (bs->read_only) { error_setg(errp, "Image is read-only"); diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 98294a7696..ef9ef628a0 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -142,6 +142,13 @@ static int check_table_entry(uint64_t entry, int cluster_size) return 0; } +static int64_t get_bitmap_bytes_needed(int64_t len, uint32_t granularity) +{ + int64_t num_bits = DIV_ROUND_UP(len, granularity); + + return DIV_ROUND_UP(num_bits, 8); +} + static int check_constraints_on_bitmap(BlockDriverState *bs, const char *name, uint32_t granularity, @@ -150,6 +157,7 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, BDRVQcow2State *s = bs->opaque; int granularity_bits = ctz32(granularity); int64_t len = bdrv_getlength(bs); + int64_t bitmap_bytes; assert(granularity > 0); assert((granularity & (granularity - 1)) == 0); @@ -171,9 +179,9 @@ static int check_constraints_on_bitmap(BlockDriverState *bs, return -EINVAL; } - if ((len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) || - (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size << - granularity_bits)) + bitmap_bytes = get_bitmap_bytes_needed(len, granularity); + if ((bitmap_bytes > (uint64_t)BME_MAX_PHYS_SIZE) || + (bitmap_bytes > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size)) { error_setg(errp, "Too much space will be occupied by the bitmap. " "Use larger granularity"); diff --git a/block/qcow2.h b/block/qcow2.h index 601c2e4c82..0942126232 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -83,7 +83,7 @@ /* Defined in the qcow2 spec (compressed cluster descriptor) */ #define QCOW2_COMPRESSED_SECTOR_SIZE 512U -#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1)) +#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL)) /* Must be at least 2 to cover COW */ #define MIN_L2_CACHE_SIZE 2 /* cache entries */ diff --git a/configure b/configure index 72553f98ea..6099be1d84 100755 --- a/configure +++ b/configure @@ -427,6 +427,7 @@ softmmu="yes" linux_user="no" bsd_user="no" blobs="yes" +edk2_blobs="no" pkgversion="" pie="" qom_cast_debug="yes" @@ -2146,6 +2147,18 @@ case " $target_list " in ;; esac +for target in $target_list; do + case "$target" in + arm-softmmu | aarch64-softmmu | i386-softmmu | x86_64-softmmu) + edk2_blobs="yes" + ;; + esac +done +# The EDK2 binaries are compressed with bzip2 +if test "$edk2_blobs" = "yes" && ! has bzip2; then + error_exit "The bzip2 program is required for building QEMU" +fi + feature_not_found() { feature=$1 remedy=$2 @@ -3217,6 +3230,34 @@ else pvrdma="no" fi +# Let's see if enhanced reg_mr is supported +if test "$pvrdma" = "yes" ; then + +cat > $TMPC <<EOF && +#include <infiniband/verbs.h> + +int +main(void) +{ + struct ibv_mr *mr; + struct ibv_pd *pd = NULL; + size_t length = 10; + uint64_t iova = 0; + int access = 0; + void *addr = NULL; + + mr = ibv_reg_mr_iova(pd, addr, length, iova, access); + + ibv_dereg_mr(mr); + + return 0; +} +EOF + if ! compile_prog "" "-libverbs"; then + QEMU_CFLAGS="$QEMU_CFLAGS -DLEGACY_RDMA_REG_MR" + fi +fi + ########################################## # VNC SASL detection if test "$vnc" = "yes" && test "$vnc_sasl" != "no" ; then @@ -7498,6 +7539,10 @@ if test "$libudev" != "no"; then echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak fi +if test "$edk2_blobs" = "yes" ; then + echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak +fi + # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c index 77f97b209c..88daee812d 100644 --- a/contrib/ivshmem-server/ivshmem-server.c +++ b/contrib/ivshmem-server/ivshmem-server.c @@ -353,6 +353,9 @@ ivshmem_server_start(IvshmemServer *server) err_close_sock: close(sock_fd); err_close_shm: + if (server->use_shm_open) { + shm_unlink(server->shm_path); + } close(shm_fd); return -1; } @@ -370,6 +373,9 @@ ivshmem_server_close(IvshmemServer *server) } unlink(server->unix_sock_path); + if (server->use_shm_open) { + shm_unlink(server->shm_path); + } close(server->sock_fd); close(server->shm_fd); server->sock_fd = -1; diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c index 197c79c57e..e4cd35f74c 100644 --- a/contrib/ivshmem-server/main.c +++ b/contrib/ivshmem-server/main.c @@ -223,8 +223,9 @@ main(int argc, char *argv[]) sa_quit.sa_handler = ivshmem_server_quit_cb; sa_quit.sa_flags = 0; if (sigemptyset(&sa_quit.sa_mask) == -1 || - sigaction(SIGTERM, &sa_quit, 0) == -1) { - perror("failed to add SIGTERM handler; sigaction"); + sigaction(SIGTERM, &sa_quit, 0) == -1 || + sigaction(SIGINT, &sa_quit, 0) == -1) { + perror("failed to add signal handler; sigaction"); goto err; } diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst index 9f76d5bcf9..e926f0a6c9 100644 --- a/docs/interop/pr-helper.rst +++ b/docs/interop/pr-helper.rst @@ -10,7 +10,7 @@ can delegate implementation of persistent reservations to an external restricting access to block devices to specific initiators in a shared storage setup. -For a more detailed reference please refer the the SCSI Primary +For a more detailed reference please refer to the SCSI Primary Commands standard, specifically the section on Reservations and the "PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands. diff --git a/docs/specs/ppc-spapr-hotplug.txt b/docs/specs/ppc-spapr-hotplug.txt index cc7833108e..859d52cce6 100644 --- a/docs/specs/ppc-spapr-hotplug.txt +++ b/docs/specs/ppc-spapr-hotplug.txt @@ -385,7 +385,7 @@ Each LMB list entry consists of the following elements: is used to retrieve the right associativity list to be used for this LMB. - A 32bit flags word. The bit at bit position 0x00000008 defines whether - the LMB is assigned to the the partition as of boot time. + the LMB is assigned to the partition as of boot time. ibm,dynamic-memory-v2 diff --git a/docs/specs/ppc-xive.rst b/docs/specs/ppc-xive.rst index 148d57eb6a..83d43f658b 100644 --- a/docs/specs/ppc-xive.rst +++ b/docs/specs/ppc-xive.rst @@ -163,7 +163,7 @@ Interrupt Priority Register (PIPR) is also updated using the IPB. This register represent the priority of the most favored pending notification. -The PIPR is then compared to the the Current Processor Priority +The PIPR is then compared to the Current Processor Priority Register (CPPR). If it is more favored (numerically less than), the CPU interrupt line is raised and the EO bit of the Notification Source Register (NSR) is updated to notify the presence of an exception for diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt index 5d8c26b1ad..9c8cca042d 100644 --- a/docs/specs/tpm.txt +++ b/docs/specs/tpm.txt @@ -89,7 +89,7 @@ TPM upon reboot. The PPI specification defines the operation requests and the actions the firmware has to take. The system administrator passes the operation request number to the firmware through an ACPI interface which writes this number to a memory location that the firmware knows. Upon reboot, the firmware -finds the number and sends commands to the the TPM. The firmware writes the TPM +finds the number and sends commands to the TPM. The firmware writes the TPM result code and the operation request number to a memory location that ACPI can read from and pass the result on to the administrator. diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 82d295b6e8..8413348a33 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -27,7 +27,7 @@ #include "qemu/osdep.h" #include "hw/acpi/pcihp.h" -#include "hw/i386/pc.h" +#include "hw/pci-host/i440fx.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/acpi/acpi.h" diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 4e079b39bd..93aec2dd2c 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" +#include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/isa/apm.h" #include "hw/i2c/pm_smbus.h" @@ -32,7 +33,6 @@ #include "qapi/error.h" #include "qemu/range.h" #include "exec/address-spaces.h" -#include "hw/acpi/piix4.h" #include "hw/acpi/pcihp.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/acpi/cpu.h" @@ -41,7 +41,6 @@ #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/acpi_dev_interface.h" #include "hw/xen/xen.h" -#include "migration/qemu-file-types.h" #include "migration/vmstate.h" #include "hw/core/cpu.h" #include "trace.h" @@ -204,43 +203,6 @@ static const VMStateDescription vmstate_pci_status = { } }; -static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) -{ - PIIX4PMState *s = opaque; - int ret, i; - uint16_t temp; - - ret = pci_device_load(PCI_DEVICE(s), f); - if (ret < 0) { - return ret; - } - qemu_get_be16s(f, &s->ar.pm1.evt.sts); - qemu_get_be16s(f, &s->ar.pm1.evt.en); - qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); - - ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1); - if (ret) { - return ret; - } - - timer_get(f, s->ar.tmr.timer); - qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); - - qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); - for (i = 0; i < 3; i++) { - qemu_get_be16s(f, &temp); - } - - qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en); - for (i = 0; i < 3; i++) { - qemu_get_be16s(f, &temp); - } - - ret = vmstate_load_state(f, &vmstate_pci_status, - &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1); - return ret; -} - static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id) { PIIX4PMState *s = opaque; @@ -312,8 +274,6 @@ static const VMStateDescription vmstate_acpi = { .name = "piix4_pm", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = acpi_load_old, .post_load = vmstate_acpi_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState), diff --git a/hw/arm/boot.c b/hw/arm/boot.c index ef6724960c..8fb4a63606 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -240,6 +240,9 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, }; uint32_t board_setup_blob[] = { /* board setup addr */ + 0xee110f51, /* mrc p15, 0, r0, c1, c1, 2 ;read NSACR */ + 0xe3800b03, /* orr r0, #0xc00 ;set CP11, CP10 */ + 0xee010f51, /* mcr p15, 0, r0, c1, c1, 2 ;write NSACR */ 0xe3a00e00 + (mvbar_addr >> 4), /* mov r0, #mvbar_addr */ 0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 ;set MVBAR */ 0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 ;read SCR */ diff --git a/hw/core/irq.c b/hw/core/irq.c index 7cc0295d0e..fb3045b912 100644 --- a/hw/core/irq.c +++ b/hw/core/irq.c @@ -120,20 +120,6 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2) return qemu_allocate_irq(qemu_splitirq, s, 0); } -static void proxy_irq_handler(void *opaque, int n, int level) -{ - qemu_irq **target = opaque; - - if (*target) { - qemu_set_irq((*target)[n], level); - } -} - -qemu_irq *qemu_irq_proxy(qemu_irq **target, int n) -{ - return qemu_allocate_irqs(proxy_irq_handler, target, n); -} - void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n) { int i; diff --git a/hw/core/numa.c b/hw/core/numa.c index 038c96d4ab..e3332a984f 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -503,7 +503,7 @@ static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner, warn_report("falling back to regular RAM allocation"); error_printf("This is deprecated. Make sure that -mem-path " " specified path has sufficient resources to allocate" - " -m specified RAM amount"); + " -m specified RAM amount\n"); /* Legacy behavior: if allocation failed, fall back to * regular RAM allocation. */ diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 7239b8227c..b5a54e2536 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -29,7 +29,6 @@ struct ptimer_state int64_t last_event; int64_t next_event; uint8_t policy_mask; - QEMUBH *bh; QEMUTimer *timer; ptimer_cb callback; void *callback_opaque; @@ -46,12 +45,7 @@ struct ptimer_state /* Use a bottom-half routine to avoid reentrancy issues. */ static void ptimer_trigger(ptimer_state *s) { - if (s->bh) { - replay_bh_schedule_event(s->bh); - } - if (s->callback) { - s->callback(s->callback_opaque); - } + s->callback(s->callback_opaque); } static void ptimer_reload(ptimer_state *s, int delta_adjust) @@ -296,15 +290,10 @@ uint64_t ptimer_get_count(ptimer_state *s) void ptimer_set_count(ptimer_state *s, uint64_t count) { - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); s->delta = count; if (s->enabled) { - if (!s->callback) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s, 0); - } else { - s->need_reload = true; - } + s->need_reload = true; } } @@ -312,7 +301,7 @@ void ptimer_run(ptimer_state *s, int oneshot) { bool was_disabled = !s->enabled; - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); if (was_disabled && s->period == 0) { if (!qtest_enabled()) { @@ -322,12 +311,7 @@ void ptimer_run(ptimer_state *s, int oneshot) } s->enabled = oneshot ? 2 : 1; if (was_disabled) { - if (!s->callback) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s, 0); - } else { - s->need_reload = true; - } + s->need_reload = true; } } @@ -335,7 +319,7 @@ void ptimer_run(ptimer_state *s, int oneshot) is immediately restarted. */ void ptimer_stop(ptimer_state *s) { - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); if (!s->enabled) return; @@ -343,42 +327,30 @@ void ptimer_stop(ptimer_state *s) s->delta = ptimer_get_count(s); timer_del(s->timer); s->enabled = 0; - if (s->callback) { - s->need_reload = false; - } + s->need_reload = false; } /* Set counter increment interval in nanoseconds. */ void ptimer_set_period(ptimer_state *s, int64_t period) { - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); s->delta = ptimer_get_count(s); s->period = period; s->period_frac = 0; if (s->enabled) { - if (!s->callback) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s, 0); - } else { - s->need_reload = true; - } + s->need_reload = true; } } /* Set counter frequency in Hz. */ void ptimer_set_freq(ptimer_state *s, uint32_t freq) { - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); s->delta = ptimer_get_count(s); s->period = 1000000000ll / freq; s->period_frac = (1000000000ll << 32) / freq; if (s->enabled) { - if (!s->callback) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s, 0); - } else { - s->need_reload = true; - } + s->need_reload = true; } } @@ -386,17 +358,12 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq) count = limit. */ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) { - assert(s->in_transaction || !s->callback); + assert(s->in_transaction); s->limit = limit; if (reload) s->delta = limit; if (s->enabled && reload) { - if (!s->callback) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s, 0); - } else { - s->need_reload = true; - } + s->need_reload = true; } } @@ -407,7 +374,7 @@ uint64_t ptimer_get_limit(ptimer_state *s) void ptimer_transaction_begin(ptimer_state *s) { - assert(!s->in_transaction || !s->callback); + assert(!s->in_transaction); s->in_transaction = true; s->need_reload = false; } @@ -448,37 +415,12 @@ const VMStateDescription vmstate_ptimer = { } }; -ptimer_state *ptimer_init_with_bh(QEMUBH *bh, uint8_t policy_mask) -{ - ptimer_state *s; - - s = (ptimer_state *)g_malloc0(sizeof(ptimer_state)); - s->bh = bh; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s); - s->policy_mask = policy_mask; - - /* - * These two policies are incompatible -- trigger-on-decrement implies - * a timer trigger when the count becomes 0, but no-immediate-trigger - * implies a trigger when the count stops being 0. - */ - assert(!((policy_mask & PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT) && - (policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER))); - return s; -} - ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque, uint8_t policy_mask) { ptimer_state *s; - /* - * The callback function is mandatory; so we use it to distinguish - * old-style QEMUBH ptimers from new transaction API ptimers. - * (ptimer_init_with_bh() allows a NULL bh pointer and at least - * one device (digic-timer) passes NULL, so it's not the case - * that either s->bh != NULL or s->callback != NULL.) - */ + /* The callback function is mandatory. */ assert(callback); s = g_new0(ptimer_state, 1); @@ -499,9 +441,6 @@ ptimer_state *ptimer_init(ptimer_cb callback, void *callback_opaque, void ptimer_free(ptimer_state *s) { - if (s->bh) { - qemu_bh_delete(s->bh); - } timer_free(s->timer); g_free(s); } diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index b25bb6d78a..5a494342ea 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -60,7 +60,8 @@ config I440FX select PC_PCI select PC_ACPI select ACPI_SMBUS - select PCI_PIIX + select PCI_I440FX + select PIIX3 select IDE_PIIX select DIMM select SMBIOS diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 9dd3dbb16c..12ff55fcfb 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -34,7 +34,6 @@ #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" #include "hw/acpi/cpu.h" -#include "hw/acpi/piix4.h" #include "hw/nvram/fw_cfg.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/isa/isa.h" @@ -52,7 +51,7 @@ #include "sysemu/reset.h" /* Supported chipsets: */ -#include "hw/acpi/piix4.h" +#include "hw/southbridge/piix.h" #include "hw/acpi/pcihp.h" #include "hw/i386/ich9.h" #include "hw/pci/pci_bus.h" @@ -210,7 +209,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) /* The above need not be conditional on machine type because the reset port * happens to be the same on PIIX (pc) and ICH9 (q35). */ - QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT); + QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != PIIX_RCR_IOPORT); /* Fill in optional s3/s4 related properties */ o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL); @@ -2518,12 +2517,105 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) */ #define IOAPIC_SB_DEVID (uint64_t)PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0)) +/* + * Insert IVHD entry for device and recurse, insert alias, or insert range as + * necessary for the PCI topology. + */ +static void +insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque) +{ + GArray *table_data = opaque; + uint32_t entry; + + /* "Select" IVHD entry, type 0x2 */ + entry = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn) << 8 | 0x2; + build_append_int_noprefix(table_data, entry, 4); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { + PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev)); + uint8_t sec = pci_bus_num(sec_bus); + uint8_t sub = dev->config[PCI_SUBORDINATE_BUS]; + + if (pci_bus_is_express(sec_bus)) { + /* + * Walk the bus if there are subordinates, otherwise use a range + * to cover an entire leaf bus. We could potentially also use a + * range for traversed buses, but we'd need to take care not to + * create both Select and Range entries covering the same device. + * This is easier and potentially more compact. + * + * An example bare metal system seems to use Select entries for + * root ports without a slot (ie. built-ins) and Range entries + * when there is a slot. The same system also only hard-codes + * the alias range for an onboard PCIe-to-PCI bridge, apparently + * making no effort to support nested bridges. We attempt to + * be more thorough here. + */ + if (sec == sub) { /* leaf bus */ + /* "Start of Range" IVHD entry, type 0x3 */ + entry = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)) << 8 | 0x3; + build_append_int_noprefix(table_data, entry, 4); + /* "End of Range" IVHD entry, type 0x4 */ + entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4; + build_append_int_noprefix(table_data, entry, 4); + } else { + pci_for_each_device(sec_bus, sec, insert_ivhd, table_data); + } + } else { + /* + * If the secondary bus is conventional, then we need to create an + * Alias range for everything downstream. The range covers the + * first devfn on the secondary bus to the last devfn on the + * subordinate bus. The alias target depends on legacy versus + * express bridges, just as in pci_device_iommu_address_space(). + * DeviceIDa vs DeviceIDb as per the AMD IOMMU spec. + */ + uint16_t dev_id_a, dev_id_b; + + dev_id_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)); + + if (pci_is_express(dev) && + pcie_cap_get_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) { + dev_id_b = dev_id_a; + } else { + dev_id_b = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn); + } + + /* "Alias Start of Range" IVHD entry, type 0x43, 8 bytes */ + build_append_int_noprefix(table_data, dev_id_a << 8 | 0x43, 4); + build_append_int_noprefix(table_data, dev_id_b << 8 | 0x0, 4); + + /* "End of Range" IVHD entry, type 0x4 */ + entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4; + build_append_int_noprefix(table_data, entry, 4); + } + } +} + +/* For all PCI host bridges, walk and insert IVHD entries */ +static int +ivrs_host_bridges(Object *obj, void *opaque) +{ + GArray *ivhd_blob = opaque; + + if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { + PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; + + if (bus) { + pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob); + } + } + + return 0; +} + static void build_amd_iommu(GArray *table_data, BIOSLinker *linker) { - int ivhd_table_len = 28; + int ivhd_table_len = 24; int iommu_start = table_data->len; AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default()); + GArray *ivhd_blob = g_array_new(false, true, 1); /* IVRS header */ acpi_data_push(table_data, sizeof(AcpiTableHeader)); @@ -2545,12 +2637,34 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker) 1); /* + * A PCI bus walk, for each PCI host bridge, is necessary to create a + * complete set of IVHD entries. Do this into a separate blob so that we + * can calculate the total IVRS table length here and then append the new + * blob further below. Fall back to an entry covering all devices, which + * is sufficient when no aliases are present. + */ + object_child_foreach_recursive(object_get_root(), + ivrs_host_bridges, ivhd_blob); + + if (!ivhd_blob->len) { + /* + * Type 1 device entry reporting all devices + * These are 4-byte device entries currently reporting the range of + * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte) + */ + build_append_int_noprefix(ivhd_blob, 0x0000001, 4); + } + + ivhd_table_len += ivhd_blob->len; + + /* * When interrupt remapping is supported, we add a special IVHD device * for type IO-APIC. */ if (x86_iommu_ir_supported(x86_iommu_get_default())) { ivhd_table_len += 8; } + /* IVHD length */ build_append_int_noprefix(table_data, ivhd_table_len, 2); /* DeviceID */ @@ -2570,12 +2684,10 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker) (1UL << 2) | /* GTSup */ (1UL << 6), /* GASup */ 4); - /* - * Type 1 device entry reporting all devices - * These are 4-byte device entries currently reporting the range of - * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte) - */ - build_append_int_noprefix(table_data, 0x0000001, 4); + + /* IVHD entries as found above */ + g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len); + g_array_free(ivhd_blob, TRUE); /* * Add a special IVHD device type. diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index c15929a1f5..2aefa3b8df 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -30,6 +30,8 @@ #include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" +#include "hw/pci-host/i440fx.h" +#include "hw/southbridge/piix.h" #include "hw/display/ramfb.h" #include "hw/firmware/smbios.h" #include "hw/pci/pci.h" @@ -190,14 +192,20 @@ static void pc_init1(MachineState *machine, gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled); if (pcmc->pci_enabled) { + PIIX3State *piix3; + pci_bus = i440fx_init(host_type, pci_type, - &i440fx_state, &piix3_devfn, &isa_bus, x86ms->gsi, + &i440fx_state, system_memory, system_io, machine->ram_size, x86ms->below_4g_mem_size, x86ms->above_4g_mem_size, pci_memory, ram_memory); pcms->bus = pci_bus; + + piix3 = piix3_create(pci_bus, &isa_bus); + piix3->pic = x86ms->gsi; + piix3_devfn = piix3->dev.devfn; } else { pci_bus = NULL; i440fx_state = NULL; diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 95f23a263c..82ece6b9e7 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -14,6 +14,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "hw/i386/pc.h" +#include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/hw.h" #include "hw/i386/apic-msidef.h" @@ -156,8 +157,8 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) v = 0; } v &= 0xf; - if (((address + i) >= 0x60) && ((address + i) <= 0x63)) { - xen_set_pci_link_route(xen_domid, address + i - 0x60, v); + if (((address + i) >= PIIX_PIRQCA) && ((address + i) <= PIIX_PIRQCD)) { + xen_set_pci_link_route(xen_domid, address + i - PIIX_PIRQCA, v); } } } diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index aafd8e0e33..375cb6abe9 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -31,7 +31,6 @@ #include "sysemu/kvm.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" -#include "migration/qemu-file-types.h" #include "migration/vmstate.h" static int apic_irq_delivered; @@ -262,52 +261,6 @@ static void apic_reset_common(DeviceState *dev) apic_init_reset(dev); } -/* This function is only used for old state version 1 and 2 */ -static int apic_load_old(QEMUFile *f, void *opaque, int version_id) -{ - APICCommonState *s = opaque; - APICCommonClass *info = APIC_COMMON_GET_CLASS(s); - int i; - - if (version_id > 2) { - return -EINVAL; - } - - /* XXX: what if the base changes? (registered memory regions) */ - qemu_get_be32s(f, &s->apicbase); - qemu_get_8s(f, &s->id); - qemu_get_8s(f, &s->arb_id); - qemu_get_8s(f, &s->tpr); - qemu_get_be32s(f, &s->spurious_vec); - qemu_get_8s(f, &s->log_dest); - qemu_get_8s(f, &s->dest_mode); - for (i = 0; i < 8; i++) { - qemu_get_be32s(f, &s->isr[i]); - qemu_get_be32s(f, &s->tmr[i]); - qemu_get_be32s(f, &s->irr[i]); - } - for (i = 0; i < APIC_LVT_NB; i++) { - qemu_get_be32s(f, &s->lvt[i]); - } - qemu_get_be32s(f, &s->esr); - qemu_get_be32s(f, &s->icr[0]); - qemu_get_be32s(f, &s->icr[1]); - qemu_get_be32s(f, &s->divide_conf); - s->count_shift = qemu_get_be32(f); - qemu_get_be32s(f, &s->initial_count); - s->initial_count_load_time = qemu_get_be64(f); - s->next_time = qemu_get_be64(f); - - if (version_id >= 2) { - s->timer_expiry = qemu_get_be64(f); - } - - if (info->post_load) { - info->post_load(s); - } - return 0; -} - static const VMStateDescription vmstate_apic_common; static void apic_common_realize(DeviceState *dev, Error **errp) @@ -408,8 +361,6 @@ static const VMStateDescription vmstate_apic_common = { .name = "apic", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = apic_load_old, .pre_load = apic_pre_load, .pre_save = apic_dispatch_pre_save, .post_load = apic_dispatch_post_load, diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 98a289957e..8a38813cc1 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -29,6 +29,10 @@ config PC87312 select FDC select IDE_ISA +config PIIX3 + bool + select ISA_BUS + config PIIX4 bool # For historical reasons, SuperIO devices are created in the board diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index ff97485504..8e73960a75 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -3,6 +3,7 @@ common-obj-$(CONFIG_ISA_SUPERIO) += isa-superio.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o common-obj-$(CONFIG_PC87312) += pc87312.o +common-obj-$(CONFIG_PIIX3) += piix3.o common-obj-$(CONFIG_PIIX4) += piix4.o common-obj-$(CONFIG_VT82C686) += vt82c686.o common-obj-$(CONFIG_SMC37C669) += smc37c669-superio.o diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c new file mode 100644 index 0000000000..fd1c78879f --- /dev/null +++ b/hw/isa/piix3.c @@ -0,0 +1,399 @@ +/* + * QEMU PIIX PCI ISA Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * 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 "qemu/osdep.h" +#include "qemu/range.h" +#include "hw/southbridge/piix.h" +#include "hw/irq.h" +#include "hw/isa/isa.h" +#include "hw/xen/xen.h" +#include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" +#include "migration/vmstate.h" + +#define XEN_PIIX_NUM_PIRQS 128ULL + +#define TYPE_PIIX3_PCI_DEVICE "pci-piix3" +#define PIIX3_PCI_DEVICE(obj) \ + OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE) + +#define TYPE_PIIX3_DEVICE "PIIX3" +#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" + +static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) +{ + qemu_set_irq(piix3->pic[pic_irq], + !!(piix3->pic_levels & + (((1ULL << PIIX_NUM_PIRQS) - 1) << + (pic_irq * PIIX_NUM_PIRQS)))); +} + +static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) +{ + int pic_irq; + uint64_t mask; + + pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; + if (pic_irq >= PIIX_NUM_PIC_IRQS) { + return; + } + + mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); + piix3->pic_levels &= ~mask; + piix3->pic_levels |= mask * !!level; +} + +static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) +{ + int pic_irq; + + pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq]; + if (pic_irq >= PIIX_NUM_PIC_IRQS) { + return; + } + + piix3_set_irq_level_internal(piix3, pirq, level); + + piix3_set_irq_pic(piix3, pic_irq); +} + +static void piix3_set_irq(void *opaque, int pirq, int level) +{ + PIIX3State *piix3 = opaque; + piix3_set_irq_level(piix3, pirq, level); +} + +static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) +{ + PIIX3State *piix3 = opaque; + int irq = piix3->dev.config[PIIX_PIRQCA + pin]; + PCIINTxRoute route; + + if (irq < PIIX_NUM_PIC_IRQS) { + route.mode = PCI_INTX_ENABLED; + route.irq = irq; + } else { + route.mode = PCI_INTX_DISABLED; + route.irq = -1; + } + return route; +} + +/* irq routing is changed. so rebuild bitmap */ +static void piix3_update_irq_levels(PIIX3State *piix3) +{ + PCIBus *bus = pci_get_bus(&piix3->dev); + int pirq; + + piix3->pic_levels = 0; + for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { + piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq)); + } +} + +static void piix3_write_config(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + pci_default_write_config(dev, address, val, len); + if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) { + PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); + int pic_irq; + + pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); + piix3_update_irq_levels(piix3); + for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { + piix3_set_irq_pic(piix3, pic_irq); + } + } +} + +static void piix3_write_config_xen(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + xen_piix_pci_write_config_client(address, val, len); + piix3_write_config(dev, address, val, len); +} + +static void piix3_reset(void *opaque) +{ + PIIX3State *d = opaque; + uint8_t *pci_conf = d->dev.config; + + pci_conf[0x04] = 0x07; /* master, memory and I/O */ + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */ + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x61] = 0x80; + pci_conf[0x62] = 0x80; + pci_conf[0x63] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; + + d->pic_levels = 0; + d->rcr = 0; +} + +static int piix3_post_load(void *opaque, int version_id) +{ + PIIX3State *piix3 = opaque; + int pirq; + + /* + * Because the i8259 has not been deserialized yet, qemu_irq_raise + * might bring the system to a different state than the saved one; + * for example, the interrupt could be masked but the i8259 would + * not know that yet and would trigger an interrupt in the CPU. + * + * Here, we update irq levels without raising the interrupt. + * Interrupt state will be deserialized separately through the i8259. + */ + piix3->pic_levels = 0; + for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { + piix3_set_irq_level_internal(piix3, pirq, + pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq)); + } + return 0; +} + +static int piix3_pre_save(void *opaque) +{ + int i; + PIIX3State *piix3 = opaque; + + for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { + piix3->pci_irq_levels_vmstate[i] = + pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i); + } + + return 0; +} + +static bool piix3_rcr_needed(void *opaque) +{ + PIIX3State *piix3 = opaque; + + return (piix3->rcr != 0); +} + +static const VMStateDescription vmstate_piix3_rcr = { + .name = "PIIX3/rcr", + .version_id = 1, + .minimum_version_id = 1, + .needed = piix3_rcr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8(rcr, PIIX3State), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_piix3 = { + .name = "PIIX3", + .version_id = 3, + .minimum_version_id = 2, + .post_load = piix3_post_load, + .pre_save = piix3_pre_save, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PIIX3State), + VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, + PIIX_NUM_PIRQS, 3), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_piix3_rcr, + NULL + } +}; + + +static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) +{ + PIIX3State *d = opaque; + + if (val & 4) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + } + d->rcr = val & 2; /* keep System Reset type only */ +} + +static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) +{ + PIIX3State *d = opaque; + + return d->rcr; +} + +static const MemoryRegionOps rcr_ops = { + .read = rcr_read, + .write = rcr_write, + .endianness = DEVICE_LITTLE_ENDIAN +}; + +static void piix3_realize(PCIDevice *dev, Error **errp) +{ + PIIX3State *d = PIIX3_PCI_DEVICE(dev); + + if (!isa_bus_new(DEVICE(d), get_system_memory(), + pci_address_space_io(dev), errp)) { + return; + } + + memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d, + "piix3-reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(dev), + PIIX_RCR_IOPORT, &d->rcr_mem, 1); + + qemu_register_reset(piix3_reset, d); +} + +static void pci_piix3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_piix3; + dc->hotpluggable = false; + k->realize = piix3_realize; + k->vendor_id = PCI_VENDOR_ID_INTEL; + /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; + k->class_id = PCI_CLASS_BRIDGE_ISA; + /* + * Reason: part of PIIX3 southbridge, needs to be wired up by + * pc_piix.c's pc_init1() + */ + dc->user_creatable = false; +} + +static const TypeInfo piix3_pci_type_info = { + .name = TYPE_PIIX3_PCI_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX3State), + .abstract = true, + .class_init = pci_piix3_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void piix3_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->config_write = piix3_write_config; +} + +static const TypeInfo piix3_info = { + .name = TYPE_PIIX3_DEVICE, + .parent = TYPE_PIIX3_PCI_DEVICE, + .class_init = piix3_class_init, +}; + +static void piix3_xen_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->config_write = piix3_write_config_xen; +}; + +static const TypeInfo piix3_xen_info = { + .name = TYPE_PIIX3_XEN_DEVICE, + .parent = TYPE_PIIX3_PCI_DEVICE, + .class_init = piix3_xen_class_init, +}; + +static void piix3_register_types(void) +{ + type_register_static(&piix3_pci_type_info); + type_register_static(&piix3_info); + type_register_static(&piix3_xen_info); +} + +type_init(piix3_register_types) + +/* + * Return the global irq number corresponding to a given device irq + * pin. We could also use the bus number to have a more precise mapping. + */ +static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3) - 1; + return (pci_intx + slot_addend) & 3; +} + +PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus) +{ + PIIX3State *piix3; + PCIDevice *pci_dev; + + /* + * Xen supports additional interrupt routes from the PCI devices to + * the IOAPIC: the four pins of each PCI device on the bus are also + * connected to the IOAPIC directly. + * These additional routes can be discovered through ACPI. + */ + if (xen_enabled()) { + pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, + TYPE_PIIX3_XEN_DEVICE); + piix3 = PIIX3_PCI_DEVICE(pci_dev); + pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq, + piix3, XEN_PIIX_NUM_PIRQS); + } else { + pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, + TYPE_PIIX3_DEVICE); + piix3 = PIIX3_PCI_DEVICE(pci_dev); + pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq, + piix3, PIIX_NUM_PIRQS); + pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); + } + *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); + + return piix3; +} diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 890d999abf..86678e6829 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -2,6 +2,7 @@ * QEMU PIIX4 PCI Bridge Emulation * * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2018 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,19 +24,34 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/irq.h" #include "hw/i386/pc.h" +#include "hw/southbridge/piix.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "hw/sysbus.h" +#include "hw/dma/i8257.h" +#include "hw/timer/i8254.h" +#include "hw/rtc/mc146818rtc.h" +#include "hw/ide.h" #include "migration/vmstate.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" PCIDevice *piix4_dev; typedef struct PIIX4State { PCIDevice dev; + qemu_irq cpu_intr; + qemu_irq *isa; + + RTCState rtc; + /* Reset Control Register */ + MemoryRegion rcr_mem; + uint8_t rcr; } PIIX4State; -#define TYPE_PIIX4_PCI_DEVICE "PIIX4" #define PIIX4_PCI_DEVICE(obj) \ OBJECT_CHECK(PIIX4State, (obj), TYPE_PIIX4_PCI_DEVICE) @@ -87,24 +103,102 @@ static const VMStateDescription vmstate_piix4 = { } }; +static void piix4_request_i8259_irq(void *opaque, int irq, int level) +{ + PIIX4State *s = opaque; + qemu_set_irq(s->cpu_intr, level); +} + +static void piix4_set_i8259_irq(void *opaque, int irq, int level) +{ + PIIX4State *s = opaque; + qemu_set_irq(s->isa[irq], level); +} + +static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int len) +{ + PIIX4State *s = opaque; + + if (val & 4) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + } + + s->rcr = val & 2; /* keep System Reset type only */ +} + +static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len) +{ + PIIX4State *s = opaque; + + return s->rcr; +} + +static const MemoryRegionOps piix4_rcr_ops = { + .read = piix4_rcr_read, + .write = piix4_rcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void piix4_realize(PCIDevice *dev, Error **errp) { - PIIX4State *d = PIIX4_PCI_DEVICE(dev); + PIIX4State *s = PIIX4_PCI_DEVICE(dev); + ISABus *isa_bus; + qemu_irq *i8259_out_irq; + Error *err = NULL; - if (!isa_bus_new(DEVICE(d), pci_address_space(dev), - pci_address_space_io(dev), errp)) { + isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), + pci_address_space_io(dev), errp); + if (!isa_bus) { return; } - piix4_dev = &d->dev; + + qdev_init_gpio_in_named(DEVICE(dev), piix4_set_i8259_irq, + "isa", ISA_NUM_IRQS); + qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, + "intr", 1); + + memory_region_init_io(&s->rcr_mem, OBJECT(dev), &piix4_rcr_ops, s, + "reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(dev), + PIIX_RCR_IOPORT, &s->rcr_mem, 1); + + /* initialize i8259 pic */ + i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); + s->isa = i8259_init(isa_bus, *i8259_out_irq); + + /* initialize ISA irqs */ + isa_bus_irqs(isa_bus, s->isa); + + /* initialize pit */ + i8254_pit_init(isa_bus, 0x40, 0, NULL); + + /* DMA */ + i8257_dma_init(isa_bus, 0); + + /* RTC */ + qdev_set_parent_bus(DEVICE(&s->rtc), BUS(isa_bus)); + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); + object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ); + + piix4_dev = dev; } -int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn) +static void piix4_init(Object *obj) { - PCIDevice *d; + PIIX4State *s = PIIX4_PCI_DEVICE(obj); - d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4"); - *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0")); - return d->devfn; + object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC); } static void piix4_class_init(ObjectClass *klass, void *data) @@ -131,6 +225,7 @@ static const TypeInfo piix4_info = { .name = TYPE_PIIX4_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4State), + .instance_init = piix4_init, .class_init = piix4_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -144,3 +239,31 @@ static void piix4_register_types(void) } type_init(piix4_register_types) + +DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, + I2CBus **smbus, size_t ide_buses) +{ + size_t ide_drives = ide_buses * MAX_IDE_DEVS; + DriveInfo **hd; + PCIDevice *pci; + DeviceState *dev; + + pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), + true, TYPE_PIIX4_PCI_DEVICE); + dev = DEVICE(pci); + if (isa_bus) { + *isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0")); + } + + hd = g_new(DriveInfo *, ide_drives); + ide_drive_get(hd, ide_drives); + pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1); + g_free(hd); + pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci"); + if (smbus) { + *smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100, + isa_get_irq(NULL, 9), NULL, 0, NULL); + } + + return dev; +} diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 2b4842f8c6..4ca8678007 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -60,14 +60,19 @@ #define MACH_MAC 3 #define Q800_MAC_CPU_ID 2 -#define VIA_BASE 0x50f00000 -#define SONIC_PROM_BASE 0x50f08000 -#define SONIC_BASE 0x50f0a000 -#define SCC_BASE 0x50f0c020 -#define ESP_BASE 0x50f10000 -#define ESP_PDMA 0x50f10100 -#define ASC_BASE 0x50F14000 -#define SWIM_BASE 0x50F1E000 +#define IO_BASE 0x50000000 +#define IO_SLICE 0x00040000 +#define IO_SIZE 0x04000000 + +#define VIA_BASE (IO_BASE + 0x00000) +#define SONIC_PROM_BASE (IO_BASE + 0x08000) +#define SONIC_BASE (IO_BASE + 0x0a000) +#define SCC_BASE (IO_BASE + 0x0c020) +#define ESP_BASE (IO_BASE + 0x10000) +#define ESP_PDMA (IO_BASE + 0x10100) +#define ASC_BASE (IO_BASE + 0x14000) +#define SWIM_BASE (IO_BASE + 0x1E000) + #define NUBUS_SUPER_SLOT_BASE 0x60000000 #define NUBUS_SLOT_BASE 0xf0000000 @@ -135,6 +140,9 @@ static void q800_init(MachineState *machine) int32_t initrd_size; MemoryRegion *rom; MemoryRegion *ram; + MemoryRegion *io; + const int io_slice_nb = (IO_SIZE / IO_SLICE) - 1; + int i; ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; @@ -163,10 +171,26 @@ static void q800_init(MachineState *machine) cpu = M68K_CPU(cpu_create(machine->cpu_type)); qemu_register_reset(main_cpu_reset, cpu); + /* RAM */ ram = g_malloc(sizeof(*ram)); memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort); memory_region_add_subregion(get_system_memory(), 0, ram); + /* + * Memory from IO_BASE to IO_BASE + IO_SLICE is repeated + * from IO_BASE + IO_SLICE to IO_BASE + IO_SIZE + */ + io = g_new(MemoryRegion, io_slice_nb); + for (i = 0; i < io_slice_nb; i++) { + char *name = g_strdup_printf("mac_m68k.io[%d]", i + 1); + + memory_region_init_alias(&io[i], NULL, name, get_system_memory(), + IO_BASE, IO_SLICE); + memory_region_add_subregion(get_system_memory(), + IO_BASE + (i + 1) * IO_SLICE, &io[i]); + g_free(name); + } + /* IRQ Glue */ irq = g_new0(GLUEState, 1); diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index f325bd6c1c..5cab9c1ee1 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -28,6 +28,7 @@ #include "hw/mips/mips.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" +#include "hw/southbridge/piix.h" #include "migration/vmstate.h" #include "hw/i386/pc.h" #include "hw/irq.h" @@ -1012,12 +1013,12 @@ static void gt64120_pci_set_irq(void *opaque, int irq_num, int level) /* now we change the pic irq level according to the piix irq mappings */ /* XXX: optimize */ - pic_irq = piix4_dev->config[0x60 + irq_num]; + pic_irq = piix4_dev->config[PIIX_PIRQCA + irq_num]; if (pic_irq < 16) { /* The pic level is the logical OR of all the PCI irqs mapped to it. */ pic_level = 0; for (i = 0; i < 4; i++) { - if (pic_irq == piix4_dev->config[0x60 + i]) { + if (pic_irq == piix4_dev->config[PIIX_PIRQCA + i]) { pic_level |= pci_irq_levels[i]; } } diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index c1c8810e71..92e9ca5bfa 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -26,9 +26,8 @@ #include "qemu/units.h" #include "qemu-common.h" #include "cpu.h" -#include "hw/i386/pc.h" +#include "hw/southbridge/piix.h" #include "hw/isa/superio.h" -#include "hw/dma/i8257.h" #include "hw/char/serial.h" #include "net/net.h" #include "hw/boards.h" @@ -45,8 +44,6 @@ #include "hw/irq.h" #include "hw/loader.h" #include "elf.h" -#include "hw/rtc/mc146818rtc.h" -#include "hw/timer/i8254.h" #include "exec/address-spaces.h" #include "hw/sysbus.h" /* SysBusDevice */ #include "qemu/host-utils.h" @@ -97,11 +94,9 @@ typedef struct { SysBusDevice parent_obj; MIPSCPSState cps; - qemu_irq *i8259; + qemu_irq i8259[ISA_NUM_IRQS]; } MaltaState; -static ISADevice *pit; - static struct _loaderparams { int ram_size, ram_low_size; const char *kernel_filename; @@ -1235,12 +1230,9 @@ void mips_malta_init(MachineState *machine) int64_t kernel_entry, bootloader_run_addr; PCIBus *pci_bus; ISABus *isa_bus; - qemu_irq *isa_irq; qemu_irq cbus_irq, i8259_irq; - int piix4_devfn; I2CBus *smbus; DriveInfo *dinfo; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; int fl_idx = 0; int be; @@ -1407,37 +1399,17 @@ void mips_malta_init(MachineState *machine) /* Board ID = 0x420 (Malta Board with CoreLV) */ stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420); - /* - * We have a circular dependency problem: pci_bus depends on isa_irq, - * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends - * on piix4, and piix4 depends on pci_bus. To stop the cycle we have - * qemu_irq_proxy() adds an extra bit of indirection, allowing us - * to resolve the isa_irq -> i8259 dependency after i8259 is initialized. - */ - isa_irq = qemu_irq_proxy(&s->i8259, 16); - /* Northbridge */ - pci_bus = gt64120_register(isa_irq); + pci_bus = gt64120_register(s->i8259); /* Southbridge */ - ide_drive_get(hd, ARRAY_SIZE(hd)); + dev = piix4_create(pci_bus, &isa_bus, &smbus, MAX_IDE_BUS); - piix4_devfn = piix4_init(pci_bus, &isa_bus, 80); - - /* - * Interrupt controller - * The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 - */ - s->i8259 = i8259_init(isa_bus, i8259_irq); - - isa_bus_irqs(isa_bus, s->i8259); - pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1); - pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci"); - smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, - isa_get_irq(NULL, 9), NULL, 0, NULL); - pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - i8257_dma_init(isa_bus, 0); - mc146818_rtc_init(isa_bus, 2000, NULL); + /* Interrupt controller */ + qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq); + for (int i = 0; i < ISA_NUM_IRQS; i++) { + s->i8259[i] = qdev_get_gpio_in_named(dev, "isa", i); + } /* generate SPD EEPROM data */ generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index 7338461694..e230e25363 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/sysbus.h" #include "hw/misc/grlib_ahb_apb_pnp.h" @@ -231,9 +232,20 @@ static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) return apb_pnp->regs[offset >> 2]; } +static void grlib_apb_pnp_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); +} + static const MemoryRegionOps grlib_apb_pnp_ops = { .read = grlib_apb_pnp_read, + .write = grlib_apb_pnp_write, .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp) diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 693e244ce6..3d991af163 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -171,6 +171,7 @@ typedef struct dp8393xState { /* Temporaries */ uint8_t tx_buffer[0x10000]; + uint16_t data[12]; int loopback_packet; /* Memory access */ @@ -224,26 +225,25 @@ static uint32_t dp8393x_wt(dp8393xState *s) return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; } -static uint16_t dp8393x_get(dp8393xState *s, int width, uint16_t *base, - int offset) +static uint16_t dp8393x_get(dp8393xState *s, int width, int offset) { uint16_t val; if (s->big_endian) { - val = be16_to_cpu(base[offset * width + width - 1]); + val = be16_to_cpu(s->data[offset * width + width - 1]); } else { - val = le16_to_cpu(base[offset * width]); + val = le16_to_cpu(s->data[offset * width]); } return val; } -static void dp8393x_put(dp8393xState *s, int width, uint16_t *base, int offset, +static void dp8393x_put(dp8393xState *s, int width, int offset, uint16_t val) { if (s->big_endian) { - base[offset * width + width - 1] = cpu_to_be16(val); + s->data[offset * width + width - 1] = cpu_to_be16(val); } else { - base[offset * width] = cpu_to_le16(val); + s->data[offset * width] = cpu_to_le16(val); } } @@ -267,7 +267,6 @@ static void dp8393x_update_irq(dp8393xState *s) static void dp8393x_do_load_cam(dp8393xState *s) { - uint16_t data[8]; int width, size; uint16_t index = 0; @@ -277,13 +276,13 @@ static void dp8393x_do_load_cam(dp8393xState *s) while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ address_space_rw(&s->as, dp8393x_cdp(s), - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->cam[index][0] = dp8393x_get(s, width, data, 1) & 0xff; - s->cam[index][1] = dp8393x_get(s, width, data, 1) >> 8; - s->cam[index][2] = dp8393x_get(s, width, data, 2) & 0xff; - s->cam[index][3] = dp8393x_get(s, width, data, 2) >> 8; - s->cam[index][4] = dp8393x_get(s, width, data, 3) & 0xff; - s->cam[index][5] = dp8393x_get(s, width, data, 3) >> 8; + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); + s->cam[index][0] = dp8393x_get(s, width, 1) & 0xff; + s->cam[index][1] = dp8393x_get(s, width, 1) >> 8; + s->cam[index][2] = dp8393x_get(s, width, 2) & 0xff; + s->cam[index][3] = dp8393x_get(s, width, 2) >> 8; + s->cam[index][4] = dp8393x_get(s, width, 3) & 0xff; + s->cam[index][5] = dp8393x_get(s, width, 3) >> 8; DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, s->cam[index][0], s->cam[index][1], s->cam[index][2], s->cam[index][3], s->cam[index][4], s->cam[index][5]); @@ -295,8 +294,8 @@ static void dp8393x_do_load_cam(dp8393xState *s) /* Read CAM enable */ address_space_rw(&s->as, dp8393x_cdp(s), - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_CE] = dp8393x_get(s, width, data, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); + s->regs[SONIC_CE] = dp8393x_get(s, width, 0); DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); /* Done */ @@ -307,20 +306,19 @@ static void dp8393x_do_load_cam(dp8393xState *s) static void dp8393x_do_read_rra(dp8393xState *s) { - uint16_t data[8]; int width, size; /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; address_space_rw(&s->as, dp8393x_rrp(s), - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); /* Update SONIC registers */ - s->regs[SONIC_CRBA0] = dp8393x_get(s, width, data, 0); - s->regs[SONIC_CRBA1] = dp8393x_get(s, width, data, 1); - s->regs[SONIC_RBWC0] = dp8393x_get(s, width, data, 2); - s->regs[SONIC_RBWC1] = dp8393x_get(s, width, data, 3); + s->regs[SONIC_CRBA0] = dp8393x_get(s, width, 0); + s->regs[SONIC_CRBA1] = dp8393x_get(s, width, 1); + s->regs[SONIC_RBWC0] = dp8393x_get(s, width, 2); + s->regs[SONIC_RBWC1] = dp8393x_get(s, width, 3); DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); @@ -417,7 +415,6 @@ static void dp8393x_do_receiver_disable(dp8393xState *s) static void dp8393x_do_transmit_packets(dp8393xState *s) { NetClientState *nc = qemu_get_queue(s->nic); - uint16_t data[12]; int width, size; int tx_len, len; uint16_t i; @@ -429,18 +426,17 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s)); - address_space_rw(&s->as, - dp8393x_ttda(s) + sizeof(uint16_t) * width, - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); + address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * width, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); tx_len = 0; /* Update registers */ - s->regs[SONIC_TCR] = dp8393x_get(s, width, data, 0) & 0xf000; - s->regs[SONIC_TPS] = dp8393x_get(s, width, data, 1); - s->regs[SONIC_TFC] = dp8393x_get(s, width, data, 2); - s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 3); - s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 4); - s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 5); + s->regs[SONIC_TCR] = dp8393x_get(s, width, 0) & 0xf000; + s->regs[SONIC_TPS] = dp8393x_get(s, width, 1); + s->regs[SONIC_TFC] = dp8393x_get(s, width, 2); + s->regs[SONIC_TSA0] = dp8393x_get(s, width, 3); + s->regs[SONIC_TSA1] = dp8393x_get(s, width, 4); + s->regs[SONIC_TFS] = dp8393x_get(s, width, 5); /* Handle programmable interrupt */ if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) { @@ -465,10 +461,10 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) size = sizeof(uint16_t) * 3 * width; address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width, - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_TSA0] = dp8393x_get(s, width, data, 0); - s->regs[SONIC_TSA1] = dp8393x_get(s, width, data, 1); - s->regs[SONIC_TFS] = dp8393x_get(s, width, data, 2); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); + s->regs[SONIC_TSA0] = dp8393x_get(s, width, 0); + s->regs[SONIC_TSA1] = dp8393x_get(s, width, 1); + s->regs[SONIC_TFS] = dp8393x_get(s, width, 2); } } @@ -495,12 +491,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) s->regs[SONIC_TCR] |= SONIC_TCR_PTX; /* Write status */ - dp8393x_put(s, width, data, 0, + dp8393x_put(s, width, 0, s->regs[SONIC_TCR] & 0x0fff); /* status */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_ttda(s), - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ @@ -509,9 +505,9 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_CTDA] = dp8393x_get(s, width, data, 0) & ~0x1; - if (dp8393x_get(s, width, data, 0) & 0x1) { + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); + s->regs[SONIC_CTDA] = dp8393x_get(s, width, 0) & ~0x1; + if (dp8393x_get(s, width, 0) & 0x1) { /* EOL detected */ break; } @@ -748,7 +744,6 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, size_t size) { dp8393xState *s = qemu_get_nic_opaque(nc); - uint16_t data[10]; int packet_type; uint32_t available, address; int width, rx_len = size; @@ -773,8 +768,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, size = sizeof(uint16_t) * 1 * width; address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, - (uint8_t *)data, size, 0); - if (dp8393x_get(s, width, data, 0) & 0x1) { + (uint8_t *)s->data, size, 0); + if (dp8393x_get(s, width, 0) & 0x1) { /* Still EOL ; stop reception */ return -1; } else { @@ -818,27 +813,33 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, /* Write status to memory */ DPRINTF("Write status at %08x\n", dp8393x_crda(s)); - dp8393x_put(s, width, data, 0, s->regs[SONIC_RCR]); /* status */ - dp8393x_put(s, width, data, 1, rx_len); /* byte count */ - dp8393x_put(s, width, data, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */ - dp8393x_put(s, width, data, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */ - dp8393x_put(s, width, data, 4, s->regs[SONIC_RSC]); /* seq_no */ + dp8393x_put(s, width, 0, s->regs[SONIC_RCR]); /* status */ + dp8393x_put(s, width, 1, rx_len); /* byte count */ + dp8393x_put(s, width, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */ + dp8393x_put(s, width, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */ + dp8393x_put(s, width, 4, s->regs[SONIC_RSC]); /* seq_no */ size = sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, dp8393x_crda(s), - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width, - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); - s->regs[SONIC_LLFA] = dp8393x_get(s, width, data, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->data, size, 0); + s->regs[SONIC_LLFA] = dp8393x_get(s, width, 0); if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { - dp8393x_put(s, width, data, 0, 0); /* in_use */ - address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width, - MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); + /* Clear in_use, but it is always 16bit wide */ + int offset = dp8393x_crda(s) + sizeof(uint16_t) * 6 * width; + if (s->big_endian && width == 2) { + /* we need to adjust the offset of the 16bit field */ + offset += sizeof(uint16_t); + } + s->data[0] = 0; + address_space_rw(&s->as, offset, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)s->data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 44a3c19326..5d879c471e 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -237,7 +237,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) static void fw_cfg_reboot(FWCfgState *s) { const char *reboot_timeout = NULL; - int64_t rt_val = -1; + uint64_t rt_val = -1; uint32_t rt_le32; /* get user configuration */ @@ -247,10 +247,11 @@ static void fw_cfg_reboot(FWCfgState *s) if (reboot_timeout) { rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1); + /* validate the input */ - if (rt_val < 0 || rt_val > 0xffff) { + if (rt_val > 0xffff && rt_val != (uint64_t)-1) { error_report("reboot timeout is invalid," - "it should be a value between 0 and 65535"); + "it should be a value between -1 and 65535"); exit(1); } } diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 1edc1a31d4..b0aa8351c4 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -28,11 +28,10 @@ config PCI_SABRE select PCI bool -config PCI_PIIX +config PCI_I440FX bool select PCI select PAM - select ISA_BUS config PCI_EXPRESS_Q35 bool diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index a9cd3e022d..efd752b766 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -13,7 +13,7 @@ common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o common-obj-$(CONFIG_PCI_SABRE) += sabre.o common-obj-$(CONFIG_FULONG) += bonito.o -common-obj-$(CONFIG_PCI_PIIX) += piix.o +common-obj-$(CONFIG_PCI_I440FX) += i440fx.o common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o common-obj-$(CONFIG_PCI_EXPRESS_GENERIC_BRIDGE) += gpex.o common-obj-$(CONFIG_PCI_EXPRESS_XILINX) += xilinx-pcie.o diff --git a/hw/pci-host/piix.c b/hw/pci-host/i440fx.c index 135c645535..f27131102d 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/i440fx.c @@ -24,21 +24,14 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" -#include "hw/irq.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" +#include "hw/pci-host/i440fx.h" #include "hw/qdev-properties.h" -#include "hw/isa/isa.h" #include "hw/sysbus.h" #include "qapi/error.h" -#include "qemu/range.h" -#include "hw/xen/xen.h" -#include "migration/qemu-file-types.h" #include "migration/vmstate.h" #include "hw/pci-host/pam.h" -#include "sysemu/reset.h" -#include "sysemu/runstate.h" -#include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" @@ -58,50 +51,9 @@ typedef struct I440FXState { uint32_t short_root_bus; } I440FXState; -#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ -#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ -#define XEN_PIIX_NUM_PIRQS 128ULL -#define PIIX_PIRQC 0x60 - -typedef struct PIIX3State { - PCIDevice dev; - - /* - * bitmap to track pic levels. - * The pic level is the logical OR of all the PCI irqs mapped to it - * So one PIC level is tracked by PIIX_NUM_PIRQS bits. - * - * PIRQ is mapped to PIC pins, we track it by - * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with - * pic_irq * PIIX_NUM_PIRQS + pirq - */ -#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 -#error "unable to encode pic state in 64bit in pic_levels." -#endif - uint64_t pic_levels; - - qemu_irq *pic; - - /* This member isn't used. Just for save/load compatibility */ - int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; - - /* Reset Control Register contents */ - uint8_t rcr; - - /* IO memory region for Reset Control Register (RCR_IOPORT) */ - MemoryRegion rcr_mem; -} PIIX3State; - -#define TYPE_PIIX3_PCI_DEVICE "pci-piix3" -#define PIIX3_PCI_DEVICE(obj) \ - OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE) - #define I440FX_PCI_DEVICE(obj) \ OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE) -#define TYPE_PIIX3_DEVICE "PIIX3" -#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" - struct PCII440FXState { /*< private >*/ PCIDevice parent_obj; @@ -128,21 +80,6 @@ struct PCII440FXState { */ #define I440FX_COREBOOT_RAM_SIZE 0x57 -static void piix3_set_irq(void *opaque, int pirq, int level); -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx); -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len); - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (pci_intx + slot_addend) & 3; -} - static void i440fx_update_memory_mappings(PCII440FXState *d) { int i; @@ -174,28 +111,6 @@ static void i440fx_write_config(PCIDevice *dev, } } -static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) -{ - PCII440FXState *d = opaque; - PCIDevice *pd = PCI_DEVICE(d); - int ret, i; - uint8_t smm_enabled; - - ret = pci_device_load(pd, f); - if (ret < 0) - return ret; - i440fx_update_memory_mappings(d); - qemu_get_8s(f, &smm_enabled); - - if (version_id == 2) { - for (i = 0; i < PIIX_NUM_PIRQS; i++) { - qemu_get_be32(f); /* dummy load for compatibility */ - } - } - - return 0; -} - static int i440fx_post_load(void *opaque, int version_id) { PCII440FXState *d = opaque; @@ -208,8 +123,6 @@ static const VMStateDescription vmstate_i440fx = { .name = "I440FX", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = i440fx_load_old, .post_load = i440fx_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState), @@ -358,8 +271,6 @@ static void i440fx_realize(PCIDevice *dev, Error **errp) PCIBus *i440fx_init(const char *host_type, const char *pci_type, PCII440FXState **pi440fx_state, - int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -372,7 +283,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, PCIBus *b; PCIDevice *d; PCIHostState *s; - PIIX3State *piix3; PCII440FXState *f; unsigned i; I440FXState *i440fx; @@ -425,29 +335,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, PAM_EXPAN_SIZE); } - /* Xen supports additional interrupt routes from the PCI devices to - * the IOAPIC: the four pins of each PCI device on the bus are also - * connected to the IOAPIC directly. - * These additional routes can be discovered through ACPI. */ - if (xen_enabled()) { - PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, TYPE_PIIX3_XEN_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); - } else { - PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, TYPE_PIIX3_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, - PIIX_NUM_PIRQS); - pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq); - } - piix3->pic = pic; - *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); - - *piix3_devfn = piix3->dev.devfn; - ram_size = ram_size / 8 / 1024 / 1024; if (ram_size > 255) { ram_size = 255; @@ -467,312 +354,6 @@ PCIBus *find_i440fx(void) return s ? s->bus : NULL; } -/* PIIX3 PCI to ISA bridge */ -static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) -{ - qemu_set_irq(piix3->pic[pic_irq], - !!(piix3->pic_levels & - (((1ULL << PIIX_NUM_PIRQS) - 1) << - (pic_irq * PIIX_NUM_PIRQS)))); -} - -static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) -{ - int pic_irq; - uint64_t mask; - - pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { - return; - } - - mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); - piix3->pic_levels &= ~mask; - piix3->pic_levels |= mask * !!level; -} - -static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) -{ - int pic_irq; - - pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { - return; - } - - piix3_set_irq_level_internal(piix3, pirq, level); - - piix3_set_irq_pic(piix3, pic_irq); -} - -static void piix3_set_irq(void *opaque, int pirq, int level) -{ - PIIX3State *piix3 = opaque; - piix3_set_irq_level(piix3, pirq, level); -} - -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) -{ - PIIX3State *piix3 = opaque; - int irq = piix3->dev.config[PIIX_PIRQC + pin]; - PCIINTxRoute route; - - if (irq < PIIX_NUM_PIC_IRQS) { - route.mode = PCI_INTX_ENABLED; - route.irq = irq; - } else { - route.mode = PCI_INTX_DISABLED; - route.irq = -1; - } - return route; -} - -/* irq routing is changed. so rebuild bitmap */ -static void piix3_update_irq_levels(PIIX3State *piix3) -{ - PCIBus *bus = pci_get_bus(&piix3->dev); - int pirq; - - piix3->pic_levels = 0; - for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq)); - } -} - -static void piix3_write_config(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - pci_default_write_config(dev, address, val, len); - if (ranges_overlap(address, len, PIIX_PIRQC, 4)) { - PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); - int pic_irq; - - pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); - piix3_update_irq_levels(piix3); - for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { - piix3_set_irq_pic(piix3, pic_irq); - } - } -} - -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - xen_piix_pci_write_config_client(address, val, len); - piix3_write_config(dev, address, val, len); -} - -static void piix3_reset(void *opaque) -{ - PIIX3State *d = opaque; - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; /* master, memory and I/O */ - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */ - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x61] = 0x80; - pci_conf[0x62] = 0x80; - pci_conf[0x63] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; - - d->pic_levels = 0; - d->rcr = 0; -} - -static int piix3_post_load(void *opaque, int version_id) -{ - PIIX3State *piix3 = opaque; - int pirq; - - /* Because the i8259 has not been deserialized yet, qemu_irq_raise - * might bring the system to a different state than the saved one; - * for example, the interrupt could be masked but the i8259 would - * not know that yet and would trigger an interrupt in the CPU. - * - * Here, we update irq levels without raising the interrupt. - * Interrupt state will be deserialized separately through the i8259. - */ - piix3->pic_levels = 0; - for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level_internal(piix3, pirq, - pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq)); - } - return 0; -} - -static int piix3_pre_save(void *opaque) -{ - int i; - PIIX3State *piix3 = opaque; - - for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { - piix3->pci_irq_levels_vmstate[i] = - pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i); - } - - return 0; -} - -static bool piix3_rcr_needed(void *opaque) -{ - PIIX3State *piix3 = opaque; - - return (piix3->rcr != 0); -} - -static const VMStateDescription vmstate_piix3_rcr = { - .name = "PIIX3/rcr", - .version_id = 1, - .minimum_version_id = 1, - .needed = piix3_rcr_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT8(rcr, PIIX3State), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_piix3 = { - .name = "PIIX3", - .version_id = 3, - .minimum_version_id = 2, - .post_load = piix3_post_load, - .pre_save = piix3_pre_save, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PIIX3State), - VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, - PIIX_NUM_PIRQS, 3), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_piix3_rcr, - NULL - } -}; - - -static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) -{ - PIIX3State *d = opaque; - - if (val & 4) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - return; - } - d->rcr = val & 2; /* keep System Reset type only */ -} - -static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) -{ - PIIX3State *d = opaque; - - return d->rcr; -} - -static const MemoryRegionOps rcr_ops = { - .read = rcr_read, - .write = rcr_write, - .endianness = DEVICE_LITTLE_ENDIAN -}; - -static void piix3_realize(PCIDevice *dev, Error **errp) -{ - PIIX3State *d = PIIX3_PCI_DEVICE(dev); - - if (!isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(dev), errp)) { - return; - } - - memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d, - "piix3-reset-control", 1); - memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT, - &d->rcr_mem, 1); - - qemu_register_reset(piix3_reset, d); -} - -static void pci_piix3_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix3; - dc->hotpluggable = false; - k->realize = piix3_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; - /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; - k->class_id = PCI_CLASS_BRIDGE_ISA; - /* - * Reason: part of PIIX3 southbridge, needs to be wired up by - * pc_piix.c's pc_init1() - */ - dc->user_creatable = false; -} - -static const TypeInfo piix3_pci_type_info = { - .name = TYPE_PIIX3_PCI_DEVICE, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX3State), - .abstract = true, - .class_init = pci_piix3_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void piix3_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->config_write = piix3_write_config; -} - -static const TypeInfo piix3_info = { - .name = TYPE_PIIX3_DEVICE, - .parent = TYPE_PIIX3_PCI_DEVICE, - .class_init = piix3_class_init, -}; - -static void piix3_xen_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->config_write = piix3_write_config_xen; -}; - -static const TypeInfo piix3_xen_info = { - .name = TYPE_PIIX3_XEN_DEVICE, - .parent = TYPE_PIIX3_PCI_DEVICE, - .class_init = piix3_xen_class_init, -}; - static void i440fx_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -934,9 +515,6 @@ static void i440fx_register_types(void) { type_register_static(&i440fx_info); type_register_static(&igd_passthrough_i440fx_info); - type_register_static(&piix3_pci_type_info); - type_register_static(&piix3_info); - type_register_static(&piix3_xen_info); type_register_static(&i440fx_pcihost_info); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index c68498c0de..cbc7a32568 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2646,12 +2646,49 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) { PCIBus *bus = pci_get_bus(dev); PCIBus *iommu_bus = bus; + uint8_t devfn = dev->devfn; - while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) { - iommu_bus = pci_get_bus(iommu_bus->parent_dev); + while (iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) { + PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev); + + /* + * The requester ID of the provided device may be aliased, as seen from + * the IOMMU, due to topology limitations. The IOMMU relies on a + * requester ID to provide a unique AddressSpace for devices, but + * conventional PCI buses pre-date such concepts. Instead, the PCIe- + * to-PCI bridge creates and accepts transactions on behalf of down- + * stream devices. When doing so, all downstream devices are masked + * (aliased) behind a single requester ID. The requester ID used + * depends on the format of the bridge devices. Proper PCIe-to-PCI + * bridges, with a PCIe capability indicating such, follow the + * guidelines of chapter 2.3 of the PCIe-to-PCI/X bridge specification, + * where the bridge uses the seconary bus as the bridge portion of the + * requester ID and devfn of 00.0. For other bridges, typically those + * found on the root complex such as the dmi-to-pci-bridge, we follow + * the convention of typical bare-metal hardware, which uses the + * requester ID of the bridge itself. There are device specific + * exceptions to these rules, but these are the defaults that the + * Linux kernel uses when determining DMA aliases itself and believed + * to be true for the bare metal equivalents of the devices emulated + * in QEMU. + */ + if (!pci_bus_is_express(iommu_bus)) { + PCIDevice *parent = iommu_bus->parent_dev; + + if (pci_is_express(parent) && + pcie_cap_get_type(parent) == PCI_EXP_TYPE_PCI_BRIDGE) { + devfn = PCI_DEVFN(0, 0); + bus = iommu_bus; + } else { + devfn = parent->devfn; + bus = parent_bus; + } + } + + iommu_bus = parent_bus; } if (iommu_bus && iommu_bus->iommu_fn) { - return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn); + return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn); } return &address_space_memory; } diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index c39051068d..c346407cd3 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -391,7 +391,11 @@ static int build_host_sge_array(RdmaDeviceResources *rdma_dev_res, return VENDOR_ERR_INVLKEY | ssge[ssge_idx].lkey; } +#ifdef LEGACY_RDMA_REG_MR dsge->addr = (uintptr_t)mr->virt + ssge[ssge_idx].addr - mr->start; +#else + dsge->addr = ssge[ssge_idx].addr; +#endif dsge->length = ssge[ssge_idx].length; dsge->lkey = rdma_backend_mr_lkey(&mr->backend_mr); @@ -735,10 +739,19 @@ void rdma_backend_destroy_pd(RdmaBackendPD *pd) } } +#ifdef LEGACY_RDMA_REG_MR int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr, size_t length, int access) +#else +int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr, + size_t length, uint64_t guest_start, int access) +#endif { +#ifdef LEGACY_RDMA_REG_MR mr->ibmr = ibv_reg_mr(pd->ibpd, addr, length, access); +#else + mr->ibmr = ibv_reg_mr_iova(pd->ibpd, addr, length, guest_start, access); +#endif if (!mr->ibmr) { rdma_error_report("ibv_reg_mr fail, errno=%d", errno); return -EIO; diff --git a/hw/rdma/rdma_backend.h b/hw/rdma/rdma_backend.h index 7c1a19a2b5..127f96e2d5 100644 --- a/hw/rdma/rdma_backend.h +++ b/hw/rdma/rdma_backend.h @@ -78,8 +78,13 @@ int rdma_backend_query_port(RdmaBackendDev *backend_dev, int rdma_backend_create_pd(RdmaBackendDev *backend_dev, RdmaBackendPD *pd); void rdma_backend_destroy_pd(RdmaBackendPD *pd); +#ifdef LEGACY_RDMA_REG_MR int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr, size_t length, int access); +#else +int rdma_backend_create_mr(RdmaBackendMR *mr, RdmaBackendPD *pd, void *addr, + size_t length, uint64_t guest_start, int access); +#endif void rdma_backend_destroy_mr(RdmaBackendMR *mr); int rdma_backend_create_cq(RdmaBackendDev *backend_dev, RdmaBackendCQ *cq, diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c index 1927f85472..1524dfaeaa 100644 --- a/hw/rdma/rdma_rm.c +++ b/hw/rdma/rdma_rm.c @@ -227,8 +227,13 @@ int rdma_rm_alloc_mr(RdmaDeviceResources *dev_res, uint32_t pd_handle, mr->length = guest_length; mr->virt += (mr->start & (TARGET_PAGE_SIZE - 1)); +#ifdef LEGACY_RDMA_REG_MR ret = rdma_backend_create_mr(&mr->backend_mr, &pd->backend_pd, mr->virt, mr->length, access_flags); +#else + ret = rdma_backend_create_mr(&mr->backend_mr, &pd->backend_pd, mr->virt, + mr->length, guest_start, access_flags); +#endif if (ret) { ret = -EIO; goto out_dealloc_mr; diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 3722d9e772..6f0fc405c7 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -664,6 +664,12 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp) dev->shutdown_notifier.notify = pvrdma_shutdown_notifier; qemu_register_shutdown_notifier(&dev->shutdown_notifier); +#ifdef LEGACY_RDMA_REG_MR + rdma_info_report("Using legacy reg_mr"); +#else + rdma_info_report("Using iova reg_mr"); +#endif + out: if (rc) { pvrdma_fini(pdev); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index cc8f311e6b..23f340df19 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -62,7 +62,7 @@ static const struct MemmapEntry { [VIRT_PLIC] = { 0xc000000, 0x4000000 }, [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, - [VIRT_FLASH] = { 0x20000000, 0x2000000 }, + [VIRT_FLASH] = { 0x20000000, 0x4000000 }, [VIRT_DRAM] = { 0x80000000, 0x0 }, [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 }, diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c index 57bf10cc94..050875b497 100644 --- a/hw/timer/i8254_common.c +++ b/hw/timer/i8254_common.c @@ -29,7 +29,6 @@ #include "qemu/timer.h" #include "hw/timer/i8254.h" #include "hw/timer/i8254_internal.h" -#include "migration/qemu-file-types.h" #include "migration/vmstate.h" /* val must be 0 or 1 */ @@ -202,43 +201,6 @@ static const VMStateDescription vmstate_pit_channel = { } }; -static int pit_load_old(QEMUFile *f, void *opaque, int version_id) -{ - PITCommonState *pit = opaque; - PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); - PITChannelState *s; - int i; - - if (version_id != 1) { - return -EINVAL; - } - - for (i = 0; i < 3; i++) { - s = &pit->channels[i]; - s->count = qemu_get_be32(f); - qemu_get_be16s(f, &s->latched_count); - qemu_get_8s(f, &s->count_latched); - qemu_get_8s(f, &s->status_latched); - qemu_get_8s(f, &s->status); - qemu_get_8s(f, &s->read_state); - qemu_get_8s(f, &s->write_state); - qemu_get_8s(f, &s->write_latch); - qemu_get_8s(f, &s->rw_mode); - qemu_get_8s(f, &s->mode); - qemu_get_8s(f, &s->bcd); - qemu_get_8s(f, &s->gate); - s->count_load_time = qemu_get_be64(f); - s->irq_disabled = 0; - if (i == 0) { - s->next_transition_time = qemu_get_be64(f); - } - } - if (c->post_load) { - c->post_load(pit); - } - return 0; -} - static int pit_dispatch_pre_save(void *opaque) { PITCommonState *s = opaque; @@ -266,8 +228,6 @@ static const VMStateDescription vmstate_pit_common = { .name = "i8254", .version_id = 3, .minimum_version_id = 2, - .minimum_version_id_old = 1, - .load_state_old = pit_load_old, .pre_save = pit_dispatch_pre_save, .post_load = pit_dispatch_post_load, .fields = (VMStateField[]) { diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 472cc26fc4..fcf48c0193 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -86,7 +86,9 @@ struct USBHostDevice { uint32_t options; uint32_t loglevel; bool needs_autoscan; - bool allow_guest_reset; + bool allow_one_guest_reset; + bool allow_all_guest_resets; + /* state */ QTAILQ_ENTRY(USBHostDevice) next; int seen, errcount; @@ -1462,10 +1464,10 @@ static void usb_host_handle_reset(USBDevice *udev) USBHostDevice *s = USB_HOST_DEVICE(udev); int rc; - if (!s->allow_guest_reset) { + if (!s->allow_one_guest_reset && !s->allow_all_guest_resets) { return; } - if (udev->addr == 0) { + if (!s->allow_all_guest_resets && udev->addr == 0) { return; } @@ -1586,7 +1588,10 @@ static Property usb_host_dev_properties[] = { DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0), DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), - DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true), + DEFINE_PROP_BOOL("guest-reset", USBHostDevice, + allow_one_guest_reset, true), + DEFINE_PROP_BOOL("guest-resets-all", USBHostDevice, + allow_all_guest_resets, false), DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel, LIBUSB_LOG_LEVEL_WARNING), DEFINE_PROP_BIT("pipeline", USBHostDevice, options, diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index b2c804292e..d6332d45c3 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -288,6 +288,10 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) k->ioeventfd_assign(proxy, notifier, n, false); } + if (r == 0) { + virtio_queue_set_host_notifier_enabled(vq, assign); + } + return r; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 762df12f4c..04716b5f6c 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -128,6 +128,7 @@ struct VirtQueue VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; + bool host_notifier_enabled; QLIST_ENTRY(VirtQueue) node; }; @@ -2271,7 +2272,7 @@ void virtio_queue_notify(VirtIODevice *vdev, int n) } trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); - if (vq->handle_aio_output) { + if (vq->host_notifier_enabled) { event_notifier_set(&vq->host_notifier); } else if (vq->handle_output) { vq->handle_output(vdev, vq); @@ -3145,6 +3146,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; vdev->vq[i].queue_index = i; + vdev->vq[i].host_notifier_enabled = false; } vdev->name = name; @@ -3436,6 +3438,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) return &vq->host_notifier; } +void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) +{ + vq->host_notifier_enabled = enabled; +} + int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n, MemoryRegion *mr, bool assign) { diff --git a/include/block/block_int.h b/include/block/block_int.h index 02dc0034a2..dd033d0b37 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -999,6 +999,10 @@ extern unsigned int bdrv_drain_all_count; void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); +bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self); +void bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align); +BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); + int get_tmp_filename(char *filename, int size); BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, const char *filename); diff --git a/include/block/nvme.h b/include/block/nvme.h index ab5943b90a..8fb941c653 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -23,7 +23,7 @@ enum NvmeCapShift { CAP_AMS_SHIFT = 17, CAP_TO_SHIFT = 24, CAP_DSTRD_SHIFT = 32, - CAP_NSSRS_SHIFT = 33, + CAP_NSSRS_SHIFT = 36, CAP_CSS_SHIFT = 37, CAP_MPSMIN_SHIFT = 48, CAP_MPSMAX_SHIFT = 52, diff --git a/include/hw/acpi/piix4.h b/include/hw/acpi/piix4.h deleted file mode 100644 index 028bb53e3d..0000000000 --- a/include/hw/acpi/piix4.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef HW_ACPI_PIIX4_H -#define HW_ACPI_PIIX4_H - -#define TYPE_PIIX4_PM "PIIX4_PM" - -#endif diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index 7f4d0ca7cd..ce2b48b88b 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h @@ -107,9 +107,12 @@ struct arm_boot_info { void (*write_board_setup)(ARMCPU *cpu, const struct arm_boot_info *info); - /* If set, the board specific loader/setup blob will be run from secure + /* + * If set, the board specific loader/setup blob will be run from secure * mode, regardless of secure_boot. The blob becomes responsible for - * changing to non-secure state if implementing a non-secure boot + * changing to non-secure state if implementing a non-secure boot, + * including setting up EL3/Secure registers such as the NSACR as + * required by the Linux booting ABI before the switch to non-secure. */ bool secure_board_setup; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index e1c383ba84..77c6f05299 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -72,10 +72,6 @@ typedef enum MMUAccessType { typedef struct CPUWatchpoint CPUWatchpoint; -typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, int opaque, - unsigned size); - struct TranslationBlock; /** @@ -87,8 +83,6 @@ struct TranslationBlock; * @reset_dump_flags: #CPUDumpFlags to use for reset logging. * @has_work: Callback for checking if there is work to do. * @do_interrupt: Callback for interrupt handling. - * @do_unassigned_access: Callback for unassigned access handling. - * (this is deprecated: new targets should use do_transaction_failed instead) * @do_unaligned_access: Callback for unaligned access handling, if * the target defines #TARGET_ALIGNED_ONLY. * @do_transaction_failed: Callback for handling failed memory transactions @@ -175,7 +169,6 @@ typedef struct CPUClass { int reset_dump_flags; bool (*has_work)(CPUState *cpu); void (*do_interrupt)(CPUState *cpu); - CPUUnassignedAccess do_unassigned_access; void (*do_unaligned_access)(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); @@ -415,12 +408,6 @@ struct CPUState { * we store some rarely used information in the CPU context. */ uintptr_t mem_io_pc; - /* - * This is only needed for the legacy cpu_unassigned_access() hook; - * when all targets using it have been converted to use - * cpu_transaction_failed() instead it can be removed. - */ - MMUAccessType mem_io_access_type; int kvm_fd; struct KVMState *kvm_state; @@ -896,17 +883,6 @@ void cpu_interrupt(CPUState *cpu, int mask); #ifdef NEED_CPU_H #ifdef CONFIG_SOFTMMU -static inline void cpu_unassigned_access(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, - int opaque, unsigned size) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - - if (cc->do_unassigned_access) { - cc->do_unassigned_access(cpu, addr, is_write, is_exec, opaque, size); - } -} - static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index f040a72095..e6fa8418ca 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -228,46 +228,9 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0); #define PORT92_A20_LINE "a20" -/* acpi_piix.c */ - -I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, - qemu_irq sci_irq, qemu_irq smi_irq, - int smm_enabled, DeviceState **piix4_pm); - /* hpet.c */ extern int no_hpet; -/* piix_pci.c */ -struct PCII440FXState; -typedef struct PCII440FXState PCII440FXState; - -#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost" -#define TYPE_I440FX_PCI_DEVICE "i440FX" - -#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX" - -/* - * Reset Control Register: PCI-accessible ISA-Compatible Register at address - * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000). - */ -#define RCR_IOPORT 0xcf9 - -PCIBus *i440fx_init(const char *host_type, const char *pci_type, - PCII440FXState **pi440fx_state, int *piix_devfn, - ISABus **isa_bus, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, - MemoryRegion *pci_memory, - MemoryRegion *ram_memory); - -PCIBus *find_i440fx(void); -/* piix4.c */ -extern PCIDevice *piix4_dev; -int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); - /* pc_sysfw.c */ void pc_system_flash_create(PCMachineState *pcms); void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); diff --git a/include/hw/irq.h b/include/hw/irq.h index fe527f6f51..24ba0ece11 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -51,11 +51,6 @@ qemu_irq qemu_irq_invert(qemu_irq irq); */ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); -/* Returns a new IRQ set which connects 1:1 to another IRQ set, which - * may be set later. - */ -qemu_irq *qemu_irq_proxy(qemu_irq **target, int n); - /* For internal use in qtest. Similar to qemu_irq_split, but operating on an existing vector of qemu_irq. */ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 018ada4f6f..79f703fd6c 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -147,4 +147,6 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) return ISA_BUS(qdev_get_parent_bus(DEVICE(d))); } +#define TYPE_PIIX4_PCI_DEVICE "piix4-isa" + #endif diff --git a/include/hw/pci-host/i440fx.h b/include/hw/pci-host/i440fx.h new file mode 100644 index 0000000000..f54e6466e4 --- /dev/null +++ b/include/hw/pci-host/i440fx.h @@ -0,0 +1,36 @@ +/* + * QEMU i440FX North Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_PCI_I440FX_H +#define HW_PCI_I440FX_H + +#include "hw/hw.h" +#include "hw/pci/pci_bus.h" + +typedef struct PCII440FXState PCII440FXState; + +#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost" +#define TYPE_I440FX_PCI_DEVICE "i440FX" + +#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX" + +PCIBus *i440fx_init(const char *host_type, const char *pci_type, + PCII440FXState **pi440fx_state, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + ram_addr_t ram_size, + ram_addr_t below_4g_mem_size, + ram_addr_t above_4g_mem_size, + MemoryRegion *pci_memory, + MemoryRegion *ram_memory); + +PCIBus *find_i440fx(void); + +#endif diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index 4c321f65dc..412763fffb 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -10,15 +10,24 @@ #include "qemu/timer.h" -/* The ptimer API implements a simple periodic countdown timer. +/* + * The ptimer API implements a simple periodic countdown timer. * The countdown timer has a value (which can be read and written via * ptimer_get_count() and ptimer_set_count()). When it is enabled * using ptimer_run(), the value will count downwards at the frequency * which has been configured using ptimer_set_period() or ptimer_set_freq(). - * When it reaches zero it will trigger a QEMU bottom half handler, and + * When it reaches zero it will trigger a callback function, and * can be set to either reload itself from a specified limit value * and keep counting down, or to stop (as a one-shot timer). * + * A transaction-based API is used for modifying ptimer state: all calls + * to functions which modify ptimer state must be between matched calls to + * ptimer_transaction_begin() and ptimer_transaction_commit(). + * When ptimer_transaction_commit() is called it will evaluate the state + * of the timer after all the changes in the transaction, and call the + * callback if necessary. (See the ptimer_init() documentation for the full + * list of state-modifying functions and detailed semantics of the callback.) + * * Forgetting to set the period/frequency (or setting it to zero) is a * bug in the QEMU device and will cause warning messages to be printed * to stderr when the guest attempts to enable the timer. @@ -72,7 +81,7 @@ * ptimer_set_count() or ptimer_set_limit() will not trigger the timer * (though it will cause a reload). Only a counter decrement to "0" * will cause a trigger. Not compatible with NO_IMMEDIATE_TRIGGER; - * ptimer_init_with_bh() will assert() that you don't set both. + * ptimer_init() will assert() that you don't set both. */ #define PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT (1 << 5) @@ -81,17 +90,6 @@ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque); /** - * ptimer_init_with_bh - Allocate and return a new ptimer - * @bh: QEMU bottom half which is run on timer expiry - * @policy: PTIMER_POLICY_* bits specifying behaviour - * - * The ptimer returned must be freed using ptimer_free(). - * The ptimer takes ownership of @bh and will delete it - * when the ptimer is eventually freed. - */ -ptimer_state *ptimer_init_with_bh(QEMUBH *bh, uint8_t policy_mask); - -/** * ptimer_init - Allocate and return a new ptimer * @callback: function to call on ptimer expiry * @callback_opaque: opaque pointer passed to @callback @@ -127,8 +125,7 @@ ptimer_state *ptimer_init(ptimer_cb callback, * ptimer_free - Free a ptimer * @s: timer to free * - * Free a ptimer created using ptimer_init_with_bh() (including - * deleting the bottom half which it is using). + * Free a ptimer created using ptimer_init(). */ void ptimer_free(ptimer_state *s); @@ -164,7 +161,7 @@ void ptimer_transaction_commit(ptimer_state *s); * may be more appropriate. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_set_period(ptimer_state *s, int64_t period); @@ -180,7 +177,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period); * precise to fractions of a nanosecond, avoiding rounding errors. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_set_freq(ptimer_state *s, uint32_t freq); @@ -210,7 +207,7 @@ uint64_t ptimer_get_limit(ptimer_state *s); * reload the counter when their reload register is written to. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload); @@ -234,7 +231,7 @@ uint64_t ptimer_get_count(ptimer_state *s); * point in the future. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_set_count(ptimer_state *s, uint64_t count); @@ -243,15 +240,15 @@ void ptimer_set_count(ptimer_state *s, uint64_t count); * @s: ptimer * @oneshot: non-zero if this timer should only count down once * - * Start a ptimer counting down; when it reaches zero the bottom half - * passed to ptimer_init_with_bh() will be invoked. + * Start a ptimer counting down; when it reaches zero the callback function + * passed to ptimer_init() will be invoked. * If the @oneshot argument is zero, * the counter value will then be reloaded from the limit and it will * start counting down again. If @oneshot is non-zero, then the counter * will disable itself when it reaches zero. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_run(ptimer_state *s, int oneshot); @@ -266,7 +263,7 @@ void ptimer_run(ptimer_state *s, int oneshot); * restarted. * * This function will assert if it is called outside a - * ptimer_transaction_begin/commit block, unless this is a bottom-half ptimer. + * ptimer_transaction_begin/commit block. */ void ptimer_stop(ptimer_state *s); diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h new file mode 100644 index 0000000000..152628c6d9 --- /dev/null +++ b/include/hw/southbridge/piix.h @@ -0,0 +1,74 @@ +/* + * QEMU PIIX South Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2018 Hervé Poussineau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_SOUTHBRIDGE_PIIX_H +#define HW_SOUTHBRIDGE_PIIX_H + +#include "hw/pci/pci.h" + +#define TYPE_PIIX4_PM "PIIX4_PM" + +I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, + qemu_irq sci_irq, qemu_irq smi_irq, + int smm_enabled, DeviceState **piix4_pm); + +/* PIRQRC[A:D]: PIRQx Route Control Registers */ +#define PIIX_PIRQCA 0x60 +#define PIIX_PIRQCB 0x61 +#define PIIX_PIRQCC 0x62 +#define PIIX_PIRQCD 0x63 + +/* + * Reset Control Register: PCI-accessible ISA-Compatible Register at address + * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000). + */ +#define PIIX_RCR_IOPORT 0xcf9 + +#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ +#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ + +typedef struct PIIXState { + PCIDevice dev; + + /* + * bitmap to track pic levels. + * The pic level is the logical OR of all the PCI irqs mapped to it + * So one PIC level is tracked by PIIX_NUM_PIRQS bits. + * + * PIRQ is mapped to PIC pins, we track it by + * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with + * pic_irq * PIIX_NUM_PIRQS + pirq + */ +#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 +#error "unable to encode pic state in 64bit in pic_levels." +#endif + uint64_t pic_levels; + + qemu_irq *pic; + + /* This member isn't used. Just for save/load compatibility */ + int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; + + /* Reset Control Register contents */ + uint8_t rcr; + + /* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */ + MemoryRegion rcr_mem; +} PIIX3State; + +extern PCIDevice *piix4_dev; + +PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus); + +DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, + I2CBus **smbus, size_t ide_buses); + +#endif diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 3448d67d2a..c32a815303 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -312,6 +312,7 @@ int virtio_device_grab_ioeventfd(VirtIODevice *vdev); void virtio_device_release_ioeventfd(VirtIODevice *vdev); bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); +void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); void virtio_queue_host_notifier_read(EventNotifier *n); void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, VirtIOHandleAIOOutput handle_output); diff --git a/include/hw/xen/interface/io/blkif.h b/include/hw/xen/interface/io/blkif.h index 8b1be50ce8..d07fa1e078 100644 --- a/include/hw/xen/interface/io/blkif.h +++ b/include/hw/xen/interface/io/blkif.h @@ -341,7 +341,7 @@ * access (even when it should be read-only). If the frontend hits the * maximum number of allowed persistently mapped grants, it can fallback * to non persistent mode. This will cause a performance degradation, - * since the the backend driver will still try to map those grants + * since the backend driver will still try to map those grants * persistently. Since the persistent grants protocol is compatible with * the previous protocol, a frontend driver can choose to work in * persistent mode even when the backend doesn't support it. diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index a00a7deb46..5502e112c8 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -38,9 +38,28 @@ typedef uint64_t qemu_plugin_id_t; +/* + * Versioning plugins: + * + * The plugin API will pass a minimum and current API version that + * QEMU currently supports. The minimum API will be incremented if an + * API needs to be deprecated. + * + * The plugins export the API they were built against by exposing the + * symbol qemu_plugin_version which can be checked. + */ + +extern QEMU_PLUGIN_EXPORT int qemu_plugin_version; + +#define QEMU_PLUGIN_VERSION 0 + typedef struct { /* string describing architecture */ const char *target_name; + struct { + int min; + int cur; + } version; /* is this a full system emulation? */ bool system_emulation; union { diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h index a021c95fa4..6cc02e7dcd 100644 --- a/linux-user/aarch64/target_cpu.h +++ b/linux-user/aarch64/target_cpu.h @@ -19,7 +19,8 @@ #ifndef AARCH64_TARGET_CPU_H #define AARCH64_TARGET_CPU_H -static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUARMState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->xregs[31] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) env->xregs[0] = 0; } +static inline void cpu_clone_regs_parent(CPUARMState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) { /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is diff --git a/linux-user/alpha/target_cpu.h b/linux-user/alpha/target_cpu.h index ac4d255ae7..ad408ab5cc 100644 --- a/linux-user/alpha/target_cpu.h +++ b/linux-user/alpha/target_cpu.h @@ -19,13 +19,27 @@ #ifndef ALPHA_TARGET_CPU_H #define ALPHA_TARGET_CPU_H -static inline void cpu_clone_regs(CPUAlphaState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUAlphaState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->ir[IR_SP] = newsp; } env->ir[IR_V0] = 0; env->ir[IR_A3] = 0; + env->ir[IR_A4] = 1; /* OSF/1 secondary return: child */ +} + +static inline void cpu_clone_regs_parent(CPUAlphaState *env, unsigned flags) +{ + /* + * OSF/1 secondary return: parent + * Note that the kernel does not do this if SETTLS, because the + * settls argument register is still live after copy_thread. + */ + if (!(flags & CLONE_SETTLS)) { + env->ir[IR_A4] = 0; + } } static inline void cpu_set_tls(CPUAlphaState *env, target_ulong newtls) diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 3f79356a07..2747211b24 100644 --- a/linux-user/arm/target_cpu.h +++ b/linux-user/arm/target_cpu.h @@ -41,7 +41,8 @@ static inline unsigned long arm_max_reserved_va(CPUState *cs) } #define MAX_RESERVED_VA arm_max_reserved_va -static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUARMState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[13] = newsp; @@ -49,6 +50,10 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp) env->regs[0] = 0; } +static inline void cpu_clone_regs_parent(CPUARMState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) { if (access_secure_reg(env)) { diff --git a/linux-user/cris/target_cpu.h b/linux-user/cris/target_cpu.h index 2309343979..74ead55c81 100644 --- a/linux-user/cris/target_cpu.h +++ b/linux-user/cris/target_cpu.h @@ -20,7 +20,8 @@ #ifndef CRIS_TARGET_CPU_H #define CRIS_TARGET_CPU_H -static inline void cpu_clone_regs(CPUCRISState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUCRISState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[14] = newsp; @@ -28,6 +29,10 @@ static inline void cpu_clone_regs(CPUCRISState *env, target_ulong newsp) env->regs[10] = 0; } +static inline void cpu_clone_regs_parent(CPUCRISState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUCRISState *env, target_ulong newtls) { env->pregs[PR_PID] = (env->pregs[PR_PID] & 0xff) | newtls; diff --git a/linux-user/hppa/target_cpu.h b/linux-user/hppa/target_cpu.h index 1c539bdbd6..71654b3cd4 100644 --- a/linux-user/hppa/target_cpu.h +++ b/linux-user/hppa/target_cpu.h @@ -19,7 +19,8 @@ #ifndef HPPA_TARGET_CPU_H #define HPPA_TARGET_CPU_H -static inline void cpu_clone_regs(CPUHPPAState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUHPPAState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->gr[30] = newsp; @@ -31,6 +32,10 @@ static inline void cpu_clone_regs(CPUHPPAState *env, target_ulong newsp) env->iaoq_b = env->gr[31] + 4; } +static inline void cpu_clone_regs_parent(CPUHPPAState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUHPPAState *env, target_ulong newtls) { env->cr[27] = newtls; diff --git a/linux-user/i386/target_cpu.h b/linux-user/i386/target_cpu.h index ece04d0966..0b44530854 100644 --- a/linux-user/i386/target_cpu.h +++ b/linux-user/i386/target_cpu.h @@ -20,7 +20,8 @@ #ifndef I386_TARGET_CPU_H #define I386_TARGET_CPU_H -static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUX86State *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[R_ESP] = newsp; @@ -28,6 +29,10 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp) env->regs[R_EAX] = 0; } +static inline void cpu_clone_regs_parent(CPUX86State *env, unsigned flags) +{ +} + #if defined(TARGET_ABI32) abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr); diff --git a/linux-user/m68k/target_cpu.h b/linux-user/m68k/target_cpu.h index bc7446fbaf..c3f288dfe8 100644 --- a/linux-user/m68k/target_cpu.h +++ b/linux-user/m68k/target_cpu.h @@ -21,7 +21,8 @@ #ifndef M68K_TARGET_CPU_H #define M68K_TARGET_CPU_H -static inline void cpu_clone_regs(CPUM68KState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUM68KState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->aregs[7] = newsp; @@ -29,6 +30,10 @@ static inline void cpu_clone_regs(CPUM68KState *env, target_ulong newsp) env->dregs[0] = 0; } +static inline void cpu_clone_regs_parent(CPUM68KState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUM68KState *env, target_ulong newtls) { CPUState *cs = env_cpu(env); diff --git a/linux-user/microblaze/target_cpu.h b/linux-user/microblaze/target_cpu.h index 73e139938c..ce7b22ece7 100644 --- a/linux-user/microblaze/target_cpu.h +++ b/linux-user/microblaze/target_cpu.h @@ -19,7 +19,8 @@ #ifndef MICROBLAZE_TARGET_CPU_H #define MICROBLAZE_TARGET_CPU_H -static inline void cpu_clone_regs(CPUMBState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUMBState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[R_SP] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUMBState *env, target_ulong newsp) env->regs[3] = 0; } +static inline void cpu_clone_regs_parent(CPUMBState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUMBState *env, target_ulong newtls) { env->regs[21] = newtls; diff --git a/linux-user/mips/target_cpu.h b/linux-user/mips/target_cpu.h index 02cf5eeff7..758ae4d933 100644 --- a/linux-user/mips/target_cpu.h +++ b/linux-user/mips/target_cpu.h @@ -19,7 +19,8 @@ #ifndef MIPS_TARGET_CPU_H #define MIPS_TARGET_CPU_H -static inline void cpu_clone_regs(CPUMIPSState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUMIPSState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->active_tc.gpr[29] = newsp; @@ -28,6 +29,10 @@ static inline void cpu_clone_regs(CPUMIPSState *env, target_ulong newsp) env->active_tc.gpr[2] = 0; } +static inline void cpu_clone_regs_parent(CPUMIPSState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUMIPSState *env, target_ulong newtls) { env->active_tc.CP0_UserLocal = newtls; diff --git a/linux-user/nios2/target_cpu.h b/linux-user/nios2/target_cpu.h index 5596c05c9c..50f0381067 100644 --- a/linux-user/nios2/target_cpu.h +++ b/linux-user/nios2/target_cpu.h @@ -20,7 +20,8 @@ #ifndef NIOS2_TARGET_CPU_H #define NIOS2_TARGET_CPU_H -static inline void cpu_clone_regs(CPUNios2State *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUNios2State *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[R_SP] = newsp; @@ -28,6 +29,10 @@ static inline void cpu_clone_regs(CPUNios2State *env, target_ulong newsp) env->regs[R_RET0] = 0; } +static inline void cpu_clone_regs_parent(CPUNios2State *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUNios2State *env, target_ulong newtls) { /* diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h index 32ff135089..74370d67c4 100644 --- a/linux-user/openrisc/target_cpu.h +++ b/linux-user/openrisc/target_cpu.h @@ -20,7 +20,9 @@ #ifndef OPENRISC_TARGET_CPU_H #define OPENRISC_TARGET_CPU_H -static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUOpenRISCState *env, + target_ulong newsp, + unsigned flags) { if (newsp) { cpu_set_gpr(env, 1, newsp); @@ -28,6 +30,10 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) cpu_set_gpr(env, 11, 0); } +static inline void cpu_clone_regs_parent(CPUOpenRISCState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls) { cpu_set_gpr(env, 10, newtls); diff --git a/linux-user/ppc/target_cpu.h b/linux-user/ppc/target_cpu.h index c4641834e7..76b67d2882 100644 --- a/linux-user/ppc/target_cpu.h +++ b/linux-user/ppc/target_cpu.h @@ -19,7 +19,8 @@ #ifndef PPC_TARGET_CPU_H #define PPC_TARGET_CPU_H -static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUPPCState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->gpr[1] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) env->gpr[3] = 0; } +static inline void cpu_clone_regs_parent(CPUPPCState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUPPCState *env, target_ulong newtls) { #if defined(TARGET_PPC64) diff --git a/linux-user/riscv/target_cpu.h b/linux-user/riscv/target_cpu.h index 90f9a4171e..9c642367a3 100644 --- a/linux-user/riscv/target_cpu.h +++ b/linux-user/riscv/target_cpu.h @@ -1,7 +1,8 @@ #ifndef RISCV_TARGET_CPU_H #define RISCV_TARGET_CPU_H -static inline void cpu_clone_regs(CPURISCVState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPURISCVState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->gpr[xSP] = newsp; @@ -10,6 +11,10 @@ static inline void cpu_clone_regs(CPURISCVState *env, target_ulong newsp) env->gpr[xA0] = 0; } +static inline void cpu_clone_regs_parent(CPURISCVState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPURISCVState *env, target_ulong newtls) { env->gpr[xTP] = newtls; diff --git a/linux-user/s390x/target_cpu.h b/linux-user/s390x/target_cpu.h index aa181ceaee..7cd71e2dba 100644 --- a/linux-user/s390x/target_cpu.h +++ b/linux-user/s390x/target_cpu.h @@ -19,7 +19,8 @@ #ifndef S390X_TARGET_CPU_H #define S390X_TARGET_CPU_H -static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUS390XState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[15] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) env->regs[2] = 0; } +static inline void cpu_clone_regs_parent(CPUS390XState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) { env->aregs[0] = newtls >> 32; diff --git a/linux-user/sh4/target_cpu.h b/linux-user/sh4/target_cpu.h index b0be9a2c1b..5114f19424 100644 --- a/linux-user/sh4/target_cpu.h +++ b/linux-user/sh4/target_cpu.h @@ -19,7 +19,8 @@ #ifndef SH4_TARGET_CPU_H #define SH4_TARGET_CPU_H -static inline void cpu_clone_regs(CPUSH4State *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUSH4State *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->gregs[15] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUSH4State *env, target_ulong newsp) env->gregs[0] = 0; } +static inline void cpu_clone_regs_parent(CPUSH4State *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUSH4State *env, target_ulong newtls) { env->gbr = newtls; diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index ead169fbaa..d796f50f66 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -87,7 +87,7 @@ struct target_signal_frame { struct sparc_stackf ss; __siginfo_t info; abi_ulong fpu_save; - abi_ulong insns[2] __attribute__ ((aligned (8))); + uint32_t insns[2] QEMU_ALIGNED(8); abi_ulong extramask[TARGET_NSIG_WORDS - 1]; abi_ulong extra_size; /* Should be 0 */ qemu_siginfo_fpu_t fpu_state; @@ -98,26 +98,12 @@ struct target_rt_signal_frame { abi_ulong regs[20]; sigset_t mask; abi_ulong fpu_save; - unsigned int insns[2]; + uint32_t insns[2]; stack_t stack; unsigned int extra_size; /* Should be 0 */ qemu_siginfo_fpu_t fpu_state; }; -#define UREG_O0 16 -#define UREG_O6 22 -#define UREG_I0 0 -#define UREG_I1 1 -#define UREG_I2 2 -#define UREG_I3 3 -#define UREG_I4 4 -#define UREG_I5 5 -#define UREG_I6 6 -#define UREG_I7 7 -#define UREG_L0 8 -#define UREG_FP UREG_I6 -#define UREG_SP UREG_O6 - static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUSPARCState *env, unsigned long framesize) @@ -159,30 +145,12 @@ setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask) __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } for (i=0; i < 8; i++) { - __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); + __put_user(env->regwptr[WREG_O0 + i], &si->si_regs.u_regs[i + 8]); } __put_user(mask, &si->si_mask); return err; } -#if 0 -static int -setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ - CPUSPARCState *env, unsigned long mask) -{ - int err = 0; - - __put_user(mask, &sc->sigc_mask); - __put_user(env->regwptr[UREG_SP], &sc->sigc_sp); - __put_user(env->pc, &sc->sigc_pc); - __put_user(env->npc, &sc->sigc_npc); - __put_user(env->psr, &sc->sigc_psr); - __put_user(env->gregs[1], &sc->sigc_g1); - __put_user(env->regwptr[UREG_O0], &sc->sigc_o0); - - return err; -} -#endif #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) void setup_frame(int sig, struct target_sigaction *ka, @@ -221,20 +189,20 @@ void setup_frame(int sig, struct target_sigaction *ka, } for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); + __put_user(env->regwptr[i + WREG_L0], &sf->ss.locals[i]); } for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); + __put_user(env->regwptr[i + WREG_I0], &sf->ss.ins[i]); } if (err) goto sigsegv; /* 3. signal handler back-trampoline and parameters */ - env->regwptr[UREG_FP] = sf_addr; - env->regwptr[UREG_I0] = sig; - env->regwptr[UREG_I1] = sf_addr + + env->regwptr[WREG_SP] = sf_addr; + env->regwptr[WREG_O0] = sig; + env->regwptr[WREG_O1] = sf_addr + offsetof(struct target_signal_frame, info); - env->regwptr[UREG_I2] = sf_addr + + env->regwptr[WREG_O2] = sf_addr + offsetof(struct target_signal_frame, info); /* 4. signal handler */ @@ -242,11 +210,11 @@ void setup_frame(int sig, struct target_sigaction *ka, env->npc = (env->pc + 4); /* 5. return to kernel instructions */ if (ka->ka_restorer) { - env->regwptr[UREG_I7] = ka->ka_restorer; + env->regwptr[WREG_O7] = ka->ka_restorer; } else { uint32_t val32; - env->regwptr[UREG_I7] = sf_addr + + env->regwptr[WREG_O7] = sf_addr + offsetof(struct target_signal_frame, insns) - 2 * 4; /* mov __NR_sigreturn, %g1 */ @@ -284,7 +252,7 @@ long do_sigreturn(CPUSPARCState *env) sigset_t host_set; int i; - sf_addr = env->regwptr[UREG_FP]; + sf_addr = env->regwptr[WREG_SP]; trace_user_do_sigreturn(env, sf_addr); if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { goto segv_and_exit; @@ -316,7 +284,7 @@ long do_sigreturn(CPUSPARCState *env) __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); } for (i=0; i < 8; i++) { - __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + __get_user(env->regwptr[i + WREG_O0], &sf->info.si_regs.u_regs[i + 8]); } /* FIXME: implement FPU save/restore: @@ -433,7 +401,7 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong fp, i7, w_addr; unsigned int i; - ucp_addr = env->regwptr[UREG_I0]; + ucp_addr = env->regwptr[WREG_O0]; if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { goto do_sigsegv; } @@ -443,7 +411,7 @@ void sparc64_set_context(CPUSPARCState *env) if ((pc | npc) & 3) { goto do_sigsegv; } - if (env->regwptr[UREG_I1]) { + if (env->regwptr[WREG_O1]) { target_sigset_t target_set; sigset_t set; @@ -474,19 +442,19 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7])); - __get_user(env->regwptr[UREG_I0], (&(*grp)[SPARC_MC_O0])); - __get_user(env->regwptr[UREG_I1], (&(*grp)[SPARC_MC_O1])); - __get_user(env->regwptr[UREG_I2], (&(*grp)[SPARC_MC_O2])); - __get_user(env->regwptr[UREG_I3], (&(*grp)[SPARC_MC_O3])); - __get_user(env->regwptr[UREG_I4], (&(*grp)[SPARC_MC_O4])); - __get_user(env->regwptr[UREG_I5], (&(*grp)[SPARC_MC_O5])); - __get_user(env->regwptr[UREG_I6], (&(*grp)[SPARC_MC_O6])); - __get_user(env->regwptr[UREG_I7], (&(*grp)[SPARC_MC_O7])); + __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0])); + __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1])); + __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2])); + __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3])); + __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4])); + __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5])); + __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6])); + __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7])); __get_user(fp, &(ucp->tuc_mcontext.mc_fp)); __get_user(i7, &(ucp->tuc_mcontext.mc_i7)); - w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + w_addr = TARGET_STACK_BIAS + env->regwptr[WREG_O6]; if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), abi_ulong) != 0) { goto do_sigsegv; @@ -534,7 +502,7 @@ void sparc64_get_context(CPUSPARCState *env) target_sigset_t target_set; sigset_t set; - ucp_addr = env->regwptr[UREG_I0]; + ucp_addr = env->regwptr[WREG_O0]; if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) { goto do_sigsegv; } @@ -580,16 +548,16 @@ void sparc64_get_context(CPUSPARCState *env) __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5])); __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6])); __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7])); - __put_user(env->regwptr[UREG_I0], &((*grp)[SPARC_MC_O0])); - __put_user(env->regwptr[UREG_I1], &((*grp)[SPARC_MC_O1])); - __put_user(env->regwptr[UREG_I2], &((*grp)[SPARC_MC_O2])); - __put_user(env->regwptr[UREG_I3], &((*grp)[SPARC_MC_O3])); - __put_user(env->regwptr[UREG_I4], &((*grp)[SPARC_MC_O4])); - __put_user(env->regwptr[UREG_I5], &((*grp)[SPARC_MC_O5])); - __put_user(env->regwptr[UREG_I6], &((*grp)[SPARC_MC_O6])); - __put_user(env->regwptr[UREG_I7], &((*grp)[SPARC_MC_O7])); - - w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0])); + __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1])); + __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2])); + __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3])); + __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4])); + __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5])); + __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6])); + __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7])); + + w_addr = TARGET_STACK_BIAS + env->regwptr[WREG_O6]; fp = i7 = 0; if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), abi_ulong) != 0) { diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h index 1ffc0ae9f2..14b2158969 100644 --- a/linux-user/sparc/target_cpu.h +++ b/linux-user/sparc/target_cpu.h @@ -20,20 +20,54 @@ #ifndef SPARC_TARGET_CPU_H #define SPARC_TARGET_CPU_H -static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp, + unsigned flags) { + /* + * After cpu_copy, env->regwptr is pointing into the old env. + * Update the new cpu to use its own register window. + */ + env->regwptr = env->regbase + (env->cwp * 16); + if (newsp) { - env->regwptr[22] = newsp; + /* When changing stacks, do it with clean register windows. */ +#ifdef TARGET_SPARC64 + env->cansave = env->nwindows - 2; + env->cleanwin = env->nwindows - 2; + env->canrestore = 0; +#else + env->wim = 1 << env->cwp; +#endif + /* ??? The kernel appears to copy one stack frame to the new stack. */ + /* ??? The kernel force aligns the new stack. */ + env->regwptr[WREG_SP] = newsp; } - /* syscall return for clone child: 0, and clear CF since - * this counts as a success return value. - */ - env->regwptr[0] = 0; + + if (flags & CLONE_VM) { + /* + * Syscall return for clone child: %o0 = 0 and clear CF since this + * counts as a success return value. Advance the PC past the syscall. + * For fork child, all of this happens in cpu_loop, and we must not + * do the pc advance twice. + */ + env->regwptr[WREG_O0] = 0; #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc &= ~PSR_CARRY; + env->xcc &= ~PSR_CARRY; #else - env->psr &= ~PSR_CARRY; + env->psr &= ~PSR_CARRY; #endif + env->pc = env->npc; + env->npc = env->npc + 4; + } + + /* Set the second return value for the child: %o1 = 1. */ + env->regwptr[WREG_O1] = 1; +} + +static inline void cpu_clone_regs_parent(CPUSPARCState *env, unsigned flags) +{ + /* Set the second return value for the parent: %o1 = 0. */ + env->regwptr[WREG_O1] = 0; } static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) @@ -41,15 +75,9 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) env->gregs[7] = newtls; } -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { - return state->regwptr[UREG_FP]; + return state->regwptr[WREG_SP]; } + #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f6751eecb7..ce399a55f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2248,6 +2248,39 @@ set_timeout: return -TARGET_EFAULT; ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); break; +#ifdef SOL_NETLINK + case SOL_NETLINK: + switch (optname) { + case NETLINK_PKTINFO: + case NETLINK_ADD_MEMBERSHIP: + case NETLINK_DROP_MEMBERSHIP: + case NETLINK_BROADCAST_ERROR: + case NETLINK_NO_ENOBUFS: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) + case NETLINK_LISTEN_ALL_NSID: + case NETLINK_CAP_ACK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) + case NETLINK_EXT_ACK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) + case NETLINK_GET_STRICT_CHK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */ + break; + default: + goto unimplemented; + } + val = 0; + if (optlen < sizeof(uint32_t)) { + return -TARGET_EINVAL; + } + if (get_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, SOL_NETLINK, optname, &val, + sizeof(val))); + break; +#endif /* SOL_NETLINK */ default: unimplemented: gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname); @@ -2532,6 +2565,75 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, break; } break; +#ifdef SOL_NETLINK + case SOL_NETLINK: + switch (optname) { + case NETLINK_PKTINFO: + case NETLINK_BROADCAST_ERROR: + case NETLINK_NO_ENOBUFS: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) + case NETLINK_LISTEN_ALL_NSID: + case NETLINK_CAP_ACK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) + case NETLINK_EXT_ACK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) + case NETLINK_GET_STRICT_CHK: +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */ + if (get_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + if (len != sizeof(val)) { + return -TARGET_EINVAL; + } + lv = len; + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) { + return ret; + } + if (put_user_u32(lv, optlen) + || put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + break; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) + case NETLINK_LIST_MEMBERSHIPS: + { + uint32_t *results; + int i; + if (get_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + if (len < 0) { + return -TARGET_EINVAL; + } + results = lock_user(VERIFY_WRITE, optval_addr, len, 1); + if (!results) { + return -TARGET_EFAULT; + } + lv = len; + ret = get_errno(getsockopt(sockfd, level, optname, results, &lv)); + if (ret < 0) { + unlock_user(results, optval_addr, 0); + return ret; + } + /* swap host endianess to target endianess. */ + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + results[i] = tswap32(results[i]); + } + if (put_user_u32(lv, optlen)) { + return -TARGET_EFAULT; + } + unlock_user(results, optval_addr, 0); + break; + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */ + default: + goto unimplemented; + } + break; +#endif /* SOL_NETLINK */ default: unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", @@ -5719,7 +5821,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* we create a new CPU instance. */ new_env = cpu_copy(env); /* Init regs that differ from the parent. */ - cpu_clone_regs(new_env, newsp); + cpu_clone_regs_child(new_env, newsp, flags); + cpu_clone_regs_parent(env, flags); new_cpu = env_cpu(new_env); new_cpu->opaque = ts; ts->bprm = parent_ts->bprm; @@ -5798,7 +5901,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ret = fork(); if (ret == 0) { /* Child Process. */ - cpu_clone_regs(env, newsp); + cpu_clone_regs_child(env, newsp, flags); fork_end(1); /* There is a race condition here. The parent process could theoretically read the TID in the child process before the child @@ -5816,6 +5919,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, if (flags & CLONE_CHILD_CLEARTID) ts->child_tidptr = child_tidptr; } else { + cpu_clone_regs_parent(env, flags); fork_end(0); } } @@ -7660,10 +7764,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_stime /* not on alpha */ case TARGET_NR_stime: { - time_t host_time; - if (get_user_sal(host_time, arg1)) + struct timespec ts; + ts.tv_nsec = 0; + if (get_user_sal(ts.tv_sec, arg1)) { return -TARGET_EFAULT; - return get_errno(stime(&host_time)); + } + return get_errno(clock_settime(CLOCK_REALTIME, &ts)); } #endif #ifdef TARGET_NR_alarm /* not on alpha */ diff --git a/linux-user/tilegx/target_cpu.h b/linux-user/tilegx/target_cpu.h index d1aa5824f2..316b7a639c 100644 --- a/linux-user/tilegx/target_cpu.h +++ b/linux-user/tilegx/target_cpu.h @@ -19,7 +19,8 @@ #ifndef TILEGX_TARGET_CPU_H #define TILEGX_TARGET_CPU_H -static inline void cpu_clone_regs(CPUTLGState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUTLGState *env, target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[TILEGX_R_SP] = newsp; @@ -27,6 +28,10 @@ static inline void cpu_clone_regs(CPUTLGState *env, target_ulong newsp) env->regs[TILEGX_R_RE] = 0; } +static inline void cpu_clone_regs_parent(CPUTLGState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUTLGState *env, target_ulong newtls) { env->regs[TILEGX_R_TP] = newtls; diff --git a/linux-user/xtensa/target_cpu.h b/linux-user/xtensa/target_cpu.h index e31efe3ea0..0c77bafd66 100644 --- a/linux-user/xtensa/target_cpu.h +++ b/linux-user/xtensa/target_cpu.h @@ -4,7 +4,9 @@ #ifndef XTENSA_TARGET_CPU_H #define XTENSA_TARGET_CPU_H -static inline void cpu_clone_regs(CPUXtensaState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUXtensaState *env, + target_ulong newsp, + unsigned flags) { if (newsp) { env->regs[1] = newsp; @@ -14,6 +16,10 @@ static inline void cpu_clone_regs(CPUXtensaState *env, target_ulong newsp) env->regs[2] = 0; } +static inline void cpu_clone_regs_parent(CPUXtensaState *env, unsigned flags) +{ +} + static inline void cpu_set_tls(CPUXtensaState *env, target_ulong newtls) { env->uregs[THREADPTR] = newtls; diff --git a/memory.c b/memory.c index c952eabb5d..06484c2bff 100644 --- a/memory.c +++ b/memory.c @@ -1257,10 +1257,6 @@ static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif - if (current_cpu != NULL) { - bool is_exec = current_cpu->mem_io_access_type == MMU_INST_FETCH; - cpu_unassigned_access(current_cpu, addr, false, is_exec, 0, size); - } return 0; } @@ -1270,9 +1266,6 @@ static void unassigned_mem_write(void *opaque, hwaddr addr, #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val); #endif - if (current_cpu != NULL) { - cpu_unassigned_access(current_cpu, addr, true, false, 0, size); - } } static bool unassigned_mem_accepts(void *opaque, hwaddr addr, diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin index 04671f160a..c77468d5e6 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin Binary files differdiff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 0159c9b5e9..a84adde296 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin Binary files differdiff --git a/pc-bios/opensbi-riscv32-virt-fw_jump.bin b/pc-bios/opensbi-riscv32-virt-fw_jump.bin index f5bcaa5695..6c5b7b89f6 100644 --- a/pc-bios/opensbi-riscv32-virt-fw_jump.bin +++ b/pc-bios/opensbi-riscv32-virt-fw_jump.bin Binary files differdiff --git a/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin b/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin index eb22aefdfb..971f2be405 100644 --- a/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin +++ b/pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin Binary files differdiff --git a/pc-bios/opensbi-riscv64-virt-fw_jump.bin b/pc-bios/opensbi-riscv64-virt-fw_jump.bin index 4cec6f0210..45a5aed1ce 100644 --- a/pc-bios/opensbi-riscv64-virt-fw_jump.bin +++ b/pc-bios/opensbi-riscv64-virt-fw_jump.bin Binary files differdiff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin index 79644708ff..df9da73099 100644 --- a/pc-bios/vgabios-ati.bin +++ b/pc-bios/vgabios-ati.bin Binary files differdiff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin index dd8a1f7e66..8ab76bd755 100644 --- a/pc-bios/vgabios-bochs-display.bin +++ b/pc-bios/vgabios-bochs-display.bin Binary files differdiff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 66b2adc5ff..0a3ae298ac 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin Binary files differdiff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin index 96aab241be..6d56fdf64f 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin Binary files differdiff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin index 04eb20ed89..1214549b38 100644 --- a/pc-bios/vgabios-ramfb.bin +++ b/pc-bios/vgabios-ramfb.bin Binary files differdiff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin index 8559c4c562..d7274d8b4f 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin Binary files differdiff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin index 4e274c1e83..2420a9462c 100644 --- a/pc-bios/vgabios-virtio.bin +++ b/pc-bios/vgabios-virtio.bin Binary files differdiff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin index c6df59fb67..a89b9df1a6 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin Binary files differdiff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 6bf8e76874..a43eae8c61 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin Binary files differdiff --git a/plugins/loader.c b/plugins/loader.c index ce724ed583..15fc7e5515 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -178,6 +178,25 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info) goto err_symbol; } + if (!g_module_symbol(ctx->handle, "qemu_plugin_version", &sym)) { + error_report("TCG plugin %s does not declare API version %s", + desc->path, g_module_error()); + goto err_symbol; + } else { + int version = *(int *)sym; + if (version < QEMU_PLUGIN_MIN_VERSION) { + error_report("TCG plugin %s requires API version %d, but " + "this QEMU supports only a minimum version of %d", + desc->path, version, QEMU_PLUGIN_MIN_VERSION); + goto err_symbol; + } else if (version > QEMU_PLUGIN_VERSION) { + error_report("TCG plugin %s requires API version %d, but " + "this QEMU supports only up to version %d", + desc->path, version, QEMU_PLUGIN_VERSION); + goto err_symbol; + } + } + qemu_rec_mutex_lock(&plugin.lock); /* find an unused random id with &ctx as the seed */ @@ -248,6 +267,8 @@ int qemu_plugin_load_list(QemuPluginList *head) g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1); info->target_name = TARGET_NAME; + info->version.min = QEMU_PLUGIN_MIN_VERSION; + info->version.cur = QEMU_PLUGIN_VERSION; #ifndef CONFIG_USER_ONLY MachineState *ms = MACHINE(qdev_get_machine()); info->system_emulation = true; diff --git a/plugins/plugin.h b/plugins/plugin.h index 5482168d79..1aa29dcadd 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -14,6 +14,8 @@ #include <gmodule.h> +#define QEMU_PLUGIN_MIN_VERSION 0 + /* global state */ struct qemu_plugin_state { QTAILQ_HEAD(, qemu_plugin_ctx) ctxs; diff --git a/qemu-doc.texi b/qemu-doc.texi index 3c5022050f..3ddf5c0a68 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -44,6 +44,7 @@ * Security:: * Implementation notes:: * Deprecated features:: +* Recently removed features:: * Supported build platforms:: * License:: * Index:: diff --git a/qemu-options.hx b/qemu-options.hx index 1fc2470e2f..65c9473b73 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -471,6 +471,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, "-audiodev pa,id=id[,prop[=value][,...]]\n" " server= PulseAudio server address\n" " in|out.name= source/sink device name\n" + " in|out.latency= desired latency in microseconds\n" #endif #ifdef CONFIG_AUDIO_SDL "-audiodev sdl,id=id[,prop[=value][,...]]\n" @@ -645,6 +646,10 @@ Sets the PulseAudio @var{server} to connect to. @item in|out.name=@var{sink} Use the specified source/sink for recording/playback. +@item in|out.latency=@var{usecs} +Desired latency in microseconds. The PulseAudio server will try to honor this +value but actual latencies may be lower or higher. + @end table @item -audiodev sdl,id=@var{id}[,@var{prop}[=@var{value}][,...]] @@ -1546,26 +1551,38 @@ STEXI ETEXI DEF("display", HAS_ARG, QEMU_OPTION_display, +#if defined(CONFIG_SPICE) "-display spice-app[,gl=on|off]\n" - "-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off]\n" +#endif +#if defined(CONFIG_SDL) + "-display sdl[,alt_grab=on|off][,ctrl_grab=on|off]\n" " [,window_close=on|off][,gl=on|core|es|off]\n" +#endif +#if defined(CONFIG_GTK) "-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n" +#endif +#if defined(CONFIG_VNC) "-display vnc=<display>[,<optargs>]\n" +#endif +#if defined(CONFIG_CURSES) "-display curses[,charset=<encoding>]\n" +#endif +#if defined(CONFIG_OPENGL) + "-display egl-headless[,rendernode=<file>]\n" +#endif "-display none\n" - "-display egl-headless[,rendernode=<file>]" - " select display type\n" - "The default display is equivalent to\n" + " select display backend type\n" + " The default display is equivalent to\n " #if defined(CONFIG_GTK) - "\t\"-display gtk\"\n" + "\"-display gtk\"\n" #elif defined(CONFIG_SDL) - "\t\"-display sdl\"\n" + "\"-display sdl\"\n" #elif defined(CONFIG_COCOA) - "\t\"-display cocoa\"\n" + "\"-display cocoa\"\n" #elif defined(CONFIG_VNC) - "\t\"-vnc localhost:0,to=99,id=default\"\n" + "\"-vnc localhost:0,to=99,id=default\"\n" #else - "\t\"-display none\"\n" + "\"-display none\"\n" #endif , QEMU_ARCH_ALL) STEXI diff --git a/qga/commands-posix.c b/qga/commands-posix.c index dfc05f5b8a..1c1a165dae 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2730,7 +2730,8 @@ GList *ga_command_blacklist_init(GList *blacklist) "guest-suspend-hybrid", "guest-network-get-interfaces", "guest-get-vcpus", "guest-set-vcpus", "guest-get-memory-blocks", "guest-set-memory-blocks", - "guest-get-memory-block-size", NULL}; + "guest-get-memory-block-size", "guest-get-memory-block-info", + NULL}; char **p = (char **)list; while (*p) { diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 6b67f16faf..55ba5b263a 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1387,12 +1387,12 @@ static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp) static char *guest_wctomb_dup(WCHAR *wstr) { char *str; - size_t i; + size_t str_size; - i = wcslen(wstr) + 1; - str = g_malloc(i); - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - wstr, -1, str, i, NULL, NULL); + str_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + /* add 1 to str_size for NULL terminator */ + str = g_malloc(str_size + 1); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, str_size, NULL, NULL); return str; } @@ -1894,7 +1894,7 @@ GList *ga_command_blacklist_init(GList *blacklist) "guest-suspend-hybrid", "guest-set-vcpus", "guest-get-memory-blocks", "guest-set-memory-blocks", - "guest-get-memory-block-size", + "guest-get-memory-block-size", "guest-get-memory-block-info", NULL}; char **p = (char **)list_unsupported; diff --git a/qom/object.c b/qom/object.c index 6fa9c619fa..d51b57fba1 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1106,9 +1106,8 @@ object_property_add(Object *obj, const char *name, const char *type, } if (object_property_find(obj, name, NULL) != NULL) { - error_setg(errp, "attempt to add duplicate property '%s'" - " to object (type '%s')", name, - object_get_typename(obj)); + error_setg(errp, "attempt to add duplicate property '%s' to object (type '%s')", + name, object_get_typename(obj)); return NULL; } @@ -1139,9 +1138,8 @@ object_class_property_add(ObjectClass *klass, ObjectProperty *prop; if (object_class_property_find(klass, name, NULL) != NULL) { - error_setg(errp, "attempt to add duplicate property '%s'" - " to object (type '%s')", name, - object_class_get_name(klass)); + error_setg(errp, "attempt to add duplicate property '%s' to class (type '%s')", + name, object_class_get_name(klass)); return NULL; } diff --git a/roms/Makefile b/roms/Makefile index c150170519..28e1e557b0 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -1,5 +1,5 @@ -vgabios_variants := stdvga cirrus vmware qxl isavga virtio bochs-display ramfb +vgabios_variants := stdvga cirrus vmware qxl isavga virtio bochs-display ramfb ati vgabios_targets := $(subst -isavga,,$(patsubst %,vgabios-%.bin,$(vgabios_variants))) pxerom_variants := e1000 e1000e eepro100 ne2k_pci pcnet rtl8139 virtio vmxnet3 pxerom_targets := 8086100e 808610d3 80861209 10500940 10222000 10ec8139 1af41000 15ad07b0 diff --git a/roms/opensbi b/roms/opensbi -Subproject ce228ee0919deb9957192d723eecc8aaae2697c +Subproject be92da280d87c38a2e0adc5d3f43bab7b5468f0 diff --git a/roms/seabios b/roms/seabios -Subproject a5cab58e9a3fb6e168aba919c5669bea406573b +Subproject 3bdd2b77656124e3fa7693fbfd7a06f74c38eb8 diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py index 2c587cbefc..9371e45813 100644 --- a/scripts/dump-guest-memory.py +++ b/scripts/dump-guest-memory.py @@ -170,7 +170,7 @@ class ELF(object): self.ehdr.e_phnum += 1 def to_file(self, elf_file): - """Writes all ELF structures to the the passed file. + """Writes all ELF structures to the passed file. Structure: Ehdr diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index b5a16742a1..9f1580a91c 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -1,8 +1,8 @@ #!/bin/sh # Enable automatic program execution by the kernel. -qemu_target_list="i386 i486 alpha arm armeb sparc32plus ppc ppc64 ppc64le m68k \ -mips mipsel mipsn32 mipsn32el mips64 mips64el \ +qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \ +ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \ sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \ microblaze microblazeel or1k x86_64" @@ -38,6 +38,10 @@ sparc32plus_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x sparc32plus_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' sparc32plus_family=sparc +sparc64_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2b' +sparc64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' +sparc64_family=sparc + ppc_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14' ppc_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' ppc_family=ppc diff --git a/stubs/pci-host-piix.c b/stubs/pci-host-piix.c index 6ed81b1f21..93975adbfe 100644 --- a/stubs/pci-host-piix.c +++ b/stubs/pci-host-piix.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" -#include "hw/i386/pc.h" +#include "hw/pci-host/i440fx.h" + PCIBus *find_i440fx(void) { return NULL; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 761f535357..bdc7d5326a 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -962,17 +962,7 @@ static void dec_load(DisasContext *dc) switch (size) { case 1: { - /* 00 -> 11 - 01 -> 10 - 10 -> 10 - 11 -> 00 */ - TCGv low = tcg_temp_new(); - - tcg_gen_andi_tl(low, addr, 3); - tcg_gen_sub_tl(low, tcg_const_tl(3), low); - tcg_gen_andi_tl(addr, addr, ~3); - tcg_gen_or_tl(addr, addr, low); - tcg_temp_free(low); + tcg_gen_xori_tl(addr, addr, 3); break; } @@ -1006,9 +996,16 @@ static void dec_load(DisasContext *dc) tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + TCGv_i32 t0 = tcg_const_i32(0); + TCGv_i32 treg = tcg_const_i32(dc->rd); + TCGv_i32 tsize = tcg_const_i32(size - 1); + tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); - gen_helper_memalign(cpu_env, addr, tcg_const_i32(dc->rd), - tcg_const_i32(0), tcg_const_i32(size - 1)); + gen_helper_memalign(cpu_env, addr, treg, t0, tsize); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(treg); + tcg_temp_free_i32(tsize); } if (ex) { @@ -1095,17 +1092,7 @@ static void dec_store(DisasContext *dc) switch (size) { case 1: { - /* 00 -> 11 - 01 -> 10 - 10 -> 10 - 11 -> 00 */ - TCGv low = tcg_temp_new(); - - tcg_gen_andi_tl(low, addr, 3); - tcg_gen_sub_tl(low, tcg_const_tl(3), low); - tcg_gen_andi_tl(addr, addr, ~3); - tcg_gen_or_tl(addr, addr, low); - tcg_temp_free(low); + tcg_gen_xori_tl(addr, addr, 3); break; } @@ -1124,6 +1111,10 @@ static void dec_store(DisasContext *dc) /* Verify alignment if needed. */ if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + TCGv_i32 t1 = tcg_const_i32(1); + TCGv_i32 treg = tcg_const_i32(dc->rd); + TCGv_i32 tsize = tcg_const_i32(size - 1); + tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc); /* FIXME: if the alignment is wrong, we should restore the value * in memory. One possible way to achieve this is to probe @@ -1131,8 +1122,11 @@ static void dec_store(DisasContext *dc) * the alignment checks in between the probe and the mem * access. */ - gen_helper_memalign(cpu_env, addr, tcg_const_i32(dc->rd), - tcg_const_i32(1), tcg_const_i32(size - 1)); + gen_helper_memalign(cpu_env, addr, treg, t1, tsize); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(treg); + tcg_temp_free_i32(tsize); } if (ex) { @@ -1183,6 +1177,17 @@ static void eval_cond_jmp(DisasContext *dc, TCGv_i64 pc_true, TCGv_i64 pc_false) tcg_temp_free_i64(tmp_zero); } +static void dec_setup_dslot(DisasContext *dc) +{ + TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); + + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); + tcg_temp_free_i32(tmp); +} + static void dec_bcc(DisasContext *dc) { unsigned int cc; @@ -1194,10 +1199,7 @@ static void dec_bcc(DisasContext *dc) dc->delayed_branch = 1; if (dslot) { - dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; - tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)), - cpu_env, offsetof(CPUMBState, bimm)); + dec_setup_dslot(dc); } if (dec_alu_op_b_is_small_imm(dc)) { @@ -1256,10 +1258,7 @@ static void dec_br(DisasContext *dc) dc->delayed_branch = 1; if (dslot) { - dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; - tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)), - cpu_env, offsetof(CPUMBState, bimm)); + dec_setup_dslot(dc); } if (link && dc->rd) tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); @@ -1361,10 +1360,7 @@ static void dec_rts(DisasContext *dc) return; } - dc->delayed_branch = 2; - dc->tb_flags |= D_FLAG; - tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)), - cpu_env, offsetof(CPUMBState, bimm)); + dec_setup_dslot(dc); if (i_bit) { LOG_DIS("rtid ir=%x\n", dc->ir); @@ -1685,7 +1681,10 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) dc->tb_flags &= ~D_FLAG; /* If it is a direct jump, try direct chaining. */ if (dc->jmp == JMP_INDIRECT) { - eval_cond_jmp(dc, env_btarget, tcg_const_i64(dc->pc)); + TCGv_i64 tmp_pc = tcg_const_i64(dc->pc); + eval_cond_jmp(dc, env_btarget, tmp_pc); + tcg_temp_free_i64(tmp_pc); + dc->is_jmp = DISAS_JUMP; } else if (dc->jmp == JMP_DIRECT) { t_sync_flags(dc); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 3939963b71..d37861a430 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -224,8 +224,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) #ifndef CONFIG_USER_ONLY qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", - (target_ulong)atomic_read(&env->mip)); + qemu_fprintf(f, " %s 0x%x\n", "mip ", env->mip); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); @@ -275,7 +274,7 @@ static bool riscv_cpu_has_work(CPUState *cs) * Definition of the WFI instruction requires it to ignore the privilege * mode and delegation registers, but respect individual enables */ - return (atomic_read(&env->mip) & env->mie) != 0; + return (env->mip & env->mie) != 0; #else return true; #endif diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 8c64c68538..e59343e13c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -121,15 +121,6 @@ struct CPURISCVState { target_ulong mhartid; target_ulong mstatus; - /* - * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously - * by I/O threads. It should be read with atomic_read. It should be updated - * using riscv_cpu_update_mip with the iothread mutex held. The iothread - * mutex must be held because mip must be consistent with the CPU inturrept - * state. riscv_cpu_update_mip calls cpu_interrupt or cpu_reset_interrupt - * wuth the invariant that CPU_INTERRUPT_HARD is set iff mip is non-zero. - * mip is 32-bits to allow atomic_read on 32-bit hosts. - */ uint32_t mip; uint32_t miclaim; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f13131a51b..767c8762ac 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/main-loop.h" #include "cpu.h" #include "exec/exec-all.h" #include "tcg-op.h" @@ -38,7 +39,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env) { target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE); target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE); - target_ulong pending = atomic_read(&env->mip) & env->mie; + target_ulong pending = env->mip & env->mie; target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie); target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie); target_ulong irqs = (pending & ~env->mideleg & -mie) | @@ -92,42 +93,29 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) } } -struct CpuAsyncInfo { - uint32_t new_mip; -}; - -static void riscv_cpu_update_mip_irqs_async(CPUState *target_cpu_state, - run_on_cpu_data data) -{ - struct CpuAsyncInfo *info = (struct CpuAsyncInfo *) data.host_ptr; - - if (info->new_mip) { - cpu_interrupt(target_cpu_state, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(target_cpu_state, CPU_INTERRUPT_HARD); - } - - g_free(info); -} - uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { CPURISCVState *env = &cpu->env; CPUState *cs = CPU(cpu); - struct CpuAsyncInfo *info; - uint32_t old, new, cmp = atomic_read(&env->mip); + uint32_t old = env->mip; + bool locked = false; + + if (!qemu_mutex_iothread_locked()) { + locked = true; + qemu_mutex_lock_iothread(); + } - do { - old = cmp; - new = (old & ~mask) | (value & mask); - cmp = atomic_cmpxchg(&env->mip, old, new); - } while (old != cmp); + env->mip = (env->mip & ~mask) | (value & mask); - info = g_new(struct CpuAsyncInfo, 1); - info->new_mip = new; + if (env->mip) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } - async_run_on_cpu(cs, riscv_cpu_update_mip_irqs_async, - RUN_ON_CPU_HOST_PTR(info)); + if (locked) { + qemu_mutex_unlock_iothread(); + } return old; } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 974c9c20b5..da02f9f0b1 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -579,7 +579,7 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); } else { - old_mip = atomic_read(&env->mip); + old_mip = env->mip; } if (ret_value) { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index b26533d4fd..ab6a891dc3 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -64,12 +64,10 @@ static const int tcg_memop_lookup[8] = { [0] = MO_SB, [1] = MO_TESW, [2] = MO_TESL, + [3] = MO_TEQ, [4] = MO_UB, [5] = MO_TEUW, -#ifdef TARGET_RISCV64 - [3] = MO_TEQ, [6] = MO_TEUL, -#endif }; #endif diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 778aa8e073..ae97c7d9f7 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -13,6 +13,39 @@ /*#define EXCP_INTERRUPT 0x100*/ +/* Windowed register indexes. */ +enum { + WREG_O0, + WREG_O1, + WREG_O2, + WREG_O3, + WREG_O4, + WREG_O5, + WREG_O6, + WREG_O7, + + WREG_L0, + WREG_L1, + WREG_L2, + WREG_L3, + WREG_L4, + WREG_L5, + WREG_L6, + WREG_L7, + + WREG_I0, + WREG_I1, + WREG_I2, + WREG_I3, + WREG_I4, + WREG_I5, + WREG_I6, + WREG_I7, + + WREG_SP = WREG_O6, + WREG_FP = WREG_I6, +}; + /* trap definitions */ #ifndef TARGET_SPARC64 #define TT_TFAULT 0x01 diff --git a/tcg/LICENSE b/tcg/LICENSE deleted file mode 100644 index be817fa162..0000000000 --- a/tcg/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -All the files in this directory and subdirectories are released under -a BSD like license (see header in each file). No other license is -accepted. diff --git a/tcg/aarch64/tcg-target.opc.h b/tcg/aarch64/tcg-target.opc.h index 59e1d3f7f7..26bfd9c460 100644 --- a/tcg/aarch64/tcg-target.opc.h +++ b/tcg/aarch64/tcg-target.opc.h @@ -1,5 +1,14 @@ -/* Target-specific opcodes for host vector expansion. These will be - emitted by tcg_expand_vec_op. For those familiar with GCC internals, - consider these to be UNSPEC with names. */ +/* + * Copyright (c) 2019 Linaro + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + * + * See the COPYING file in the top-level directory for details. + * + * Target-specific opcodes for host vector expansion. These will be + * emitted by tcg_expand_vec_op. For those familiar with GCC internals, + * consider these to be UNSPEC with names. + */ DEF(aa64_sshl_vec, 1, 2, 0, IMPLVEC) diff --git a/tcg/i386/tcg-target.opc.h b/tcg/i386/tcg-target.opc.h index e5fa88ba25..1312941800 100644 --- a/tcg/i386/tcg-target.opc.h +++ b/tcg/i386/tcg-target.opc.h @@ -1,6 +1,28 @@ -/* Target-specific opcodes for host vector expansion. These will be - emitted by tcg_expand_vec_op. For those familiar with GCC internals, - consider these to be UNSPEC with names. */ +/* + * Copyright (c) 2019 Linaro + * + * 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. + * + * Target-specific opcodes for host vector expansion. These will be + * emitted by tcg_expand_vec_op. For those familiar with GCC internals, + * consider these to be UNSPEC with names. + */ DEF(x86_shufps_vec, 1, 2, 1, IMPLVEC) DEF(x86_vpblendvb_vec, 1, 3, 0, IMPLVEC) diff --git a/tcg/ppc/tcg-target.opc.h b/tcg/ppc/tcg-target.opc.h index db24a11987..1373f77e82 100644 --- a/tcg/ppc/tcg-target.opc.h +++ b/tcg/ppc/tcg-target.opc.h @@ -1,4 +1,24 @@ /* + * Copyright (c) 2019 Linaro Limited + * + * 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. + * * Target-specific opcodes for host vector expansion. These will be * emitted by tcg_expand_vec_op. For those familiar with GCC internals, * consider these to be UNSPEC with names. diff --git a/tests/Makefile.include b/tests/Makefile.include index 534ee48743..8566f5f119 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -177,7 +177,9 @@ check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF) check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF) +ifdef CONFIG_LINUX check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF) +endif check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/device-plug-test$(EXESUF) diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c index 058cef5ac1..30e514bbfb 100644 --- a/tests/cpu-plug-test.c +++ b/tests/cpu-plug-test.c @@ -99,6 +99,7 @@ static void test_plug_with_device_add(gconstpointer data) cpu = qobject_to(QDict, e); if (qdict_haskey(cpu, "qom-path")) { + qobject_unref(e); continue; } @@ -107,6 +108,7 @@ static void test_plug_with_device_add(gconstpointer data) qtest_qmp_device_add_qdict(qts, td->device_model, props); hotplugged++; + qobject_unref(e); } /* make sure that there were hotplugged CPUs */ diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c index 1d3147f821..5dc807ba23 100644 --- a/tests/fw_cfg-test.c +++ b/tests/fw_cfg-test.c @@ -194,6 +194,26 @@ static void test_fw_cfg_reboot_timeout(void) qtest_quit(s); } +static void test_fw_cfg_no_reboot_timeout(void) +{ + QFWCFG *fw_cfg; + QTestState *s; + uint32_t reboot_timeout = 0; + size_t filesize; + + /* Special value -1 means "don't reboot" */ + s = qtest_init("-boot reboot-timeout=-1"); + fw_cfg = pc_fw_cfg_init(s); + + filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait", + &reboot_timeout, sizeof(reboot_timeout)); + g_assert_cmpint(filesize, ==, sizeof(reboot_timeout)); + reboot_timeout = le32_to_cpu(reboot_timeout); + g_assert_cmpint(reboot_timeout, ==, UINT32_MAX); + pc_fw_cfg_uninit(fw_cfg); + qtest_quit(s); +} + static void test_fw_cfg_splash_time(void) { QFWCFG *fw_cfg; @@ -233,6 +253,7 @@ int main(int argc, char **argv) qtest_add_func("fw_cfg/numa", test_fw_cfg_numa); qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu); qtest_add_func("fw_cfg/reboot_timeout", test_fw_cfg_reboot_timeout); + qtest_add_func("fw_cfg/no_reboot_timeout", test_fw_cfg_no_reboot_timeout); qtest_add_func("fw_cfg/splash_time", test_fw_cfg_splash_time); return g_test_run(); diff --git a/tests/image-fuzzer/qcow2/__init__.py b/tests/image-fuzzer/qcow2/__init__.py index 09ef59821b..ed3af5da86 100644 --- a/tests/image-fuzzer/qcow2/__init__.py +++ b/tests/image-fuzzer/qcow2/__init__.py @@ -1,2 +1 @@ -from __future__ import absolute_import from .layout import create_image diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py index abc4f0635d..c58bf11005 100644 --- a/tests/image-fuzzer/qcow2/fuzz.py +++ b/tests/image-fuzzer/qcow2/fuzz.py @@ -27,20 +27,20 @@ UINT64 = 0xffffffffffffffff UINT32_M = 31 UINT64_M = 63 # Fuzz vectors -UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1, +UINT8_V = [0, 0x10, UINT8//4, UINT8//2 - 1, UINT8//2, UINT8//2 + 1, UINT8 - 1, UINT8] -UINT16_V = [0, 0x100, 0x1000, UINT16/4, UINT16/2 - 1, UINT16/2, UINT16/2 + 1, +UINT16_V = [0, 0x100, 0x1000, UINT16//4, UINT16//2 - 1, UINT16//2, UINT16//2 + 1, UINT16 - 1, UINT16] -UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1, - UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32] -UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4, - UINT64/2 - 1, UINT64/2, UINT64/2 + 1, UINT64 - 1, +UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32//4, UINT32//2 - 1, + UINT32//2, UINT32//2 + 1, UINT32 - 1, UINT32] +UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64//4, + UINT64//2 - 1, UINT64//2, UINT64//2 + 1, UINT64 - 1, UINT64] -STRING_V = ['%s%p%x%d', '.1024d', '%.2049d', '%p%p%p%p', '%x%x%x%x', - '%d%d%d%d', '%s%s%s%s', '%99999999999s', '%08x', '%%20d', '%%20n', - '%%20x', '%%20s', '%s%s%s%s%s%s%s%s%s%s', '%p%p%p%p%p%p%p%p%p%p', - '%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', - '%s x 129', '%x x 257'] +BYTES_V = [b'%s%p%x%d', b'.1024d', b'%.2049d', b'%p%p%p%p', b'%x%x%x%x', + b'%d%d%d%d', b'%s%s%s%s', b'%99999999999s', b'%08x', b'%%20d', b'%%20n', + b'%%20x', b'%%20s', b'%s%s%s%s%s%s%s%s%s%s', b'%p%p%p%p%p%p%p%p%p%p', + b'%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', + b'%s x 129', b'%x x 257'] def random_from_intervals(intervals): @@ -76,12 +76,12 @@ def random_bits(bit_ranges): return val -def truncate_string(strings, length): - """Return strings truncated to specified length.""" - if type(strings) == list: - return [s[:length] for s in strings] +def truncate_bytes(sequences, length): + """Return sequences truncated to specified length.""" + if type(sequences) == list: + return [s[:length] for s in sequences] else: - return strings[:length] + return sequences[:length] def validator(current, pick, choices): @@ -110,12 +110,12 @@ def bit_validator(current, bit_ranges): return validator(current, random_bits, bit_ranges) -def string_validator(current, strings): - """Return a random string value from the list not equal to the current. +def bytes_validator(current, sequences): + """Return a random bytes value from the list not equal to the current. This function is useful for selection from valid values except current one. """ - return validator(current, random.choice, strings) + return validator(current, random.choice, sequences) def selector(current, constraints, validate=int_validator): @@ -283,9 +283,9 @@ def header_length(current): def bf_name(current): """Fuzz the backing file name.""" constraints = [ - truncate_string(STRING_V, len(current)) + truncate_bytes(BYTES_V, len(current)) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def ext_magic(current): @@ -303,10 +303,10 @@ def ext_length(current): def bf_format(current): """Fuzz backing file format in the corresponding header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, (len(current) + 7) & ~7) # Fuzz padding + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, (len(current) + 7) & ~7) # Fuzz padding ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def feature_type(current): @@ -324,10 +324,10 @@ def feature_bit_number(current): def feature_name(current): """Fuzz feature name field of a feature name table header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, 46) # Fuzz padding (field length = 46) + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, 46) # Fuzz padding (field length = 46) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def l1_entry(current): diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py index 675877da96..57ebe86e9a 100644 --- a/tests/image-fuzzer/qcow2/layout.py +++ b/tests/image-fuzzer/qcow2/layout.py @@ -16,7 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import absolute_import import random import struct from . import fuzz @@ -53,8 +52,8 @@ class Field(object): return iter([self.fmt, self.offset, self.value, self.name]) def __repr__(self): - return "Field(fmt='%s', offset=%d, value=%s, name=%s)" % \ - (self.fmt, self.offset, str(self.value), self.name) + return "Field(fmt=%r, offset=%r, value=%r, name=%r)" % \ + (self.fmt, self.offset, self.value, self.name) class FieldsList(object): @@ -122,7 +121,7 @@ class Image(object): def create_header(self, cluster_bits, backing_file_name=None): """Generate a random valid header.""" meta_header = [ - ['>4s', 0, "QFI\xfb", 'magic'], + ['>4s', 0, b"QFI\xfb", 'magic'], ['>I', 4, random.randint(2, 3), 'version'], ['>Q', 8, 0, 'backing_file_offset'], ['>I', 16, 0, 'backing_file_size'], @@ -231,7 +230,7 @@ class Image(object): feature_tables = [] feature_ids = [] inner_offset = self.ext_offset + ext_header_len - feat_name = 'some cool feature' + feat_name = b'some cool feature' while len(feature_tables) < num_fnt_entries * 3: feat_type, feat_bit = gen_feat_ids() # Remove duplicates @@ -253,7 +252,7 @@ class Image(object): ['>I', self.ext_offset, 0x6803f857, 'ext_magic'], # One feature table contains 3 fields and takes 48 bytes ['>I', self.ext_offset + UINT32_S, - len(feature_tables) / 3 * 48, 'ext_length'] + len(feature_tables) // 3 * 48, 'ext_length'] ] + feature_tables) self.ext_offset = inner_offset @@ -271,7 +270,7 @@ class Image(object): def create_l2_entry(host, guest, l2_cluster): """Generate one L2 entry.""" offset = l2_cluster * self.cluster_size - l2_size = self.cluster_size / UINT64_S + l2_size = self.cluster_size // UINT64_S entry_offset = offset + UINT64_S * (guest % l2_size) cluster_descriptor = host * self.cluster_size if not self.header['version'][0].value == 2: @@ -283,8 +282,8 @@ class Image(object): def create_l1_entry(l2_cluster, l1_offset, guest): """Generate one L1 entry.""" - l2_size = self.cluster_size / UINT64_S - entry_offset = l1_offset + UINT64_S * (guest / l2_size) + l2_size = self.cluster_size // UINT64_S + entry_offset = l1_offset + UINT64_S * (guest // l2_size) # While snapshots are not supported bit #63 = 1 entry_val = (1 << 63) + l2_cluster * self.cluster_size return ['>Q', entry_offset, entry_val, 'l1_entry'] @@ -298,11 +297,11 @@ class Image(object): l2 = [] else: meta_data = self._get_metadata() - guest_clusters = random.sample(range(self.image_size / + guest_clusters = random.sample(range(self.image_size // self.cluster_size), len(self.data_clusters)) # Number of entries in a L1/L2 table - l_size = self.cluster_size / UINT64_S + l_size = self.cluster_size // UINT64_S # Number of clusters necessary for L1 table l1_size = int(ceil((max(guest_clusters) + 1) / float(l_size**2))) l1_start = self._get_adjacent_clusters(self.data_clusters | @@ -318,7 +317,7 @@ class Image(object): # L2 entries l2 = [] for host, guest in zip(self.data_clusters, guest_clusters): - l2_id = guest / l_size + l2_id = guest // l_size if l2_id not in l2_ids: l2_ids.append(l2_id) l2_clusters.append(self._get_adjacent_clusters( @@ -339,14 +338,14 @@ class Image(object): def allocate_rfc_blocks(data, size): """Return indices of clusters allocated for refcount blocks.""" cluster_ids = set() - diff = block_ids = set([x / size for x in data]) + diff = block_ids = set([x // size for x in data]) while len(diff) != 0: # Allocate all yet not allocated clusters new = self._get_available_clusters(data | cluster_ids, len(diff)) # Indices of new refcount blocks necessary to cover clusters # in 'new' - diff = set([x / size for x in new]) - block_ids + diff = set([x // size for x in new]) - block_ids cluster_ids |= new block_ids |= diff return cluster_ids, block_ids @@ -359,7 +358,7 @@ class Image(object): blocks = set(init_blocks) clusters = set() # Number of entries in one cluster of the refcount table - size = self.cluster_size / UINT64_S + size = self.cluster_size // UINT64_S # Number of clusters necessary for the refcount table based on # the current number of refcount blocks table_size = int(ceil((max(blocks) + 1) / float(size))) @@ -373,7 +372,7 @@ class Image(object): table_size + 1)) # New refcount blocks necessary for clusters occupied by the # refcount table - diff = set([c / block_size for c in table_clusters]) - blocks + diff = set([c // block_size for c in table_clusters]) - blocks blocks |= diff while len(diff) != 0: # Allocate clusters for new refcount blocks @@ -382,12 +381,12 @@ class Image(object): len(diff)) # Indices of new refcount blocks necessary to cover # clusters in 'new' - diff = set([x / block_size for x in new]) - blocks + diff = set([x // block_size for x in new]) - blocks clusters |= new blocks |= diff # Check if the refcount table needs one more cluster if int(ceil((max(blocks) + 1) / float(size))) > table_size: - new_block_id = (table_start + table_size) / block_size + new_block_id = (table_start + table_size) // block_size # Check if the additional table cluster needs # one more refcount block if new_block_id not in blocks: @@ -399,13 +398,13 @@ class Image(object): def create_table_entry(table_offset, block_cluster, block_size, cluster): """Generate a refcount table entry.""" - offset = table_offset + UINT64_S * (cluster / block_size) + offset = table_offset + UINT64_S * (cluster // block_size) return ['>Q', offset, block_cluster * self.cluster_size, 'refcount_table_entry'] def create_block_entry(block_cluster, block_size, cluster): """Generate a list of entries for the current block.""" - entry_size = self.cluster_size / block_size + entry_size = self.cluster_size // block_size offset = block_cluster * self.cluster_size entry_offset = offset + entry_size * (cluster % block_size) # While snapshots are not supported all refcounts are set to 1 @@ -415,7 +414,7 @@ class Image(object): # Number of refcount entries per refcount block # Convert self.cluster_size from bytes to bits to have the same # base for the numerator and denominator - block_size = self.cluster_size * 8 / refcount_bits + block_size = self.cluster_size * 8 // refcount_bits meta_data = self._get_metadata() if len(self.data_clusters) == 0: # All metadata for an empty guest image needs 4 clusters: @@ -452,8 +451,8 @@ class Image(object): rfc_blocks = [] for cluster in sorted(self.data_clusters | meta_data): - if cluster / block_size != block_id: - block_id = cluster / block_size + if cluster // block_size != block_id: + block_id = cluster // block_size block_cluster = block_clusters[block_ids.index(block_id)] rfc_table.append(create_table_entry(table_offset, block_cluster, @@ -503,7 +502,7 @@ class Image(object): def write(self, filename): """Write an entire image to the file.""" - image_file = open(filename, 'w') + image_file = open(filename, 'wb') for field in self: image_file.seek(field.offset) image_file.write(struct.pack(field.fmt, field.value)) @@ -518,7 +517,7 @@ class Image(object): rounded = (size + self.cluster_size - 1) & ~(self.cluster_size - 1) if rounded > size: image_file.seek(rounded - 1) - image_file.write("\0") + image_file.write(b'\x00') image_file.close() @staticmethod @@ -587,7 +586,7 @@ class Image(object): def _alloc_data(img_size, cluster_size): """Return a set of random indices of clusters allocated for guest data. """ - num_of_cls = img_size/cluster_size + num_of_cls = img_size // cluster_size return set(random.sample(range(1, num_of_cls + 1), random.randint(0, num_of_cls))) @@ -595,15 +594,15 @@ class Image(object): """Return indices of clusters allocated for image metadata.""" ids = set() for x in self: - ids.add(x.offset/self.cluster_size) + ids.add(x.offset // self.cluster_size) return ids def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None, fields_to_fuzz=None): """Create a fuzzed image and write it to the specified file.""" - image = Image(backing_file_name) - image.set_backing_file_format(backing_file_fmt) + image = Image(backing_file_name.encode()) + image.set_backing_file_format(backing_file_fmt.encode()) image.create_feature_name_table() image.set_end_of_extension_area() image.create_l_structures() diff --git a/tests/image-fuzzer/runner.py b/tests/image-fuzzer/runner.py index 95d84f38f3..2fc010fd9d 100755 --- a/tests/image-fuzzer/runner.py +++ b/tests/image-fuzzer/runner.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Tool for running fuzz tests # @@ -18,7 +18,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import print_function import sys import os import signal @@ -28,7 +27,7 @@ import shutil from itertools import count import time import getopt -import StringIO +import io import resource try: @@ -80,7 +79,8 @@ def run_app(fd, q_args): devnull = open('/dev/null', 'r+') process = subprocess.Popen(q_args, stdin=devnull, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + errors='replace') try: out, err = process.communicate() signal.alarm(0) @@ -159,7 +159,7 @@ class TestEnv(object): os.makedirs(self.current_dir) except OSError as e: print("Error: The working directory '%s' cannot be used. Reason: %s"\ - % (self.work_dir, e[1]), file=sys.stderr) + % (self.work_dir, e.strerror), file=sys.stderr) raise TestException self.log = open(os.path.join(self.current_dir, "test.log"), "w") self.parent_log = open(run_log, "a") @@ -183,7 +183,7 @@ class TestEnv(object): MAX_BACKING_FILE_SIZE) * (1 << 20) cmd = self.qemu_img + ['create', '-f', backing_file_fmt, backing_file_name, str(backing_file_size)] - temp_log = StringIO.StringIO() + temp_log = io.StringIO() retcode = run_app(temp_log, cmd) if retcode == 0: temp_log.close() @@ -240,13 +240,13 @@ class TestEnv(object): "Backing file: %s\n" \ % (self.seed, " ".join(current_cmd), self.current_dir, backing_file_name) - temp_log = StringIO.StringIO() + temp_log = io.StringIO() try: retcode = run_app(temp_log, current_cmd) except OSError as e: multilog("%sError: Start of '%s' failed. Reason: %s\n\n" % (test_summary, os.path.basename(current_cmd[0]), - e[1]), + e.strerror), sys.stderr, self.log, self.parent_log) raise TestException diff --git a/tests/libqtest.c b/tests/libqtest.c index 3706bccd8d..91e9cb220c 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -1274,6 +1274,7 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, qdict_put_str(args, "id", id); qtest_qmp_device_add_qdict(qts, driver, args); + qobject_unref(args); } static void device_deleted_cb(void *opaque, const char *name, QDict *data) diff --git a/tests/migration-test.c b/tests/migration-test.c index 59f291c654..ac780dffda 100644 --- a/tests/migration-test.c +++ b/tests/migration-test.c @@ -899,8 +899,13 @@ static void wait_for_migration_fail(QTestState *from, bool allow_active) do { status = migrate_query_status(from); - g_assert(!strcmp(status, "setup") || !strcmp(status, "failed") || - (allow_active && !strcmp(status, "active"))); + bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || + (allow_active && !strcmp(status, "active")); + if (!result) { + fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", + __func__, status, allow_active); + } + g_assert(result); failed = !strcmp(status, "failed"); g_free(status); } while (!failed); diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c index 45e1de5bd6..f30bea08dc 100644 --- a/tests/plugin/bb.c +++ b/tests/plugin/bb.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t bb_count; static uint64_t insn_count; static bool do_inline; diff --git a/tests/plugin/empty.c b/tests/plugin/empty.c index 3f60f69027..8fa6bacd93 100644 --- a/tests/plugin/empty.c +++ b/tests/plugin/empty.c @@ -13,6 +13,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + /* * Empty TB translation callback. * This allows us to measure the overhead of injecting and then diff --git a/tests/plugin/hotblocks.c b/tests/plugin/hotblocks.c index 1bd183849a..3942a2ca54 100644 --- a/tests/plugin/hotblocks.c +++ b/tests/plugin/hotblocks.c @@ -15,6 +15,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static bool do_inline; /* Plugins need to take care of their own locking */ diff --git a/tests/plugin/hotpages.c b/tests/plugin/hotpages.c index 77df07a3cc..ecd6c18732 100644 --- a/tests/plugin/hotpages.c +++ b/tests/plugin/hotpages.c @@ -18,6 +18,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static uint64_t page_size = 4096; diff --git a/tests/plugin/howvec.c b/tests/plugin/howvec.c index 58fa675e34..4ca555e123 100644 --- a/tests/plugin/howvec.c +++ b/tests/plugin/howvec.c @@ -20,6 +20,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) typedef enum { diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c index e5fd07fb64..0a8f5a0000 100644 --- a/tests/plugin/insn.c +++ b/tests/plugin/insn.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t insn_count; static bool do_inline; diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c index d967388989..878abf09d1 100644 --- a/tests/plugin/mem.c +++ b/tests/plugin/mem.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t mem_count; static uint64_t io_count; static bool do_inline; diff --git a/tests/qemu-iotests/272 b/tests/qemu-iotests/272 new file mode 100755 index 0000000000..c2f782d47b --- /dev/null +++ b/tests/qemu-iotests/272 @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# +# Test compressed write to a qcow2 image at an offset above 4 GB +# +# Copyright (C) 2019 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +seq=$(basename "$0") +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# This is a qcow2 regression test +_supported_fmt qcow2 +_supported_proto file + +# External data files do not support compression; +# We need an exact cluster size (2M) and refcount width (2) so we can +# get this test quickly over with; and this in turn require +# compat=1.1 +_unsupported_imgopts data_file cluster_size refcount_bits 'compat=0.10' + +# The idea is: Create an empty file, mark the first 4 GB as used, then +# do a compressed write that thus must be put beyond 4 GB. +# (This used to fail because the compressed sector mask was just a +# 32 bit mask, so qemu-img check will count a cluster before 4 GB as +# referenced twice.) + +# We would like to use refcount_bits=1 here, but then qemu-img check +# will throw an error when trying to count a cluster as referenced +# twice. +_make_test_img -o cluster_size=2M,refcount_bits=2 64M + +reft_offs=$(peek_file_be "$TEST_IMG" 48 8) +refb_offs=$(peek_file_be "$TEST_IMG" $reft_offs 8) + +# We want to cover 4 GB, those are 2048 clusters, equivalent to +# 4096 bit = 512 B. +truncate -s 4G "$TEST_IMG" +for ((in_refb_offs = 0; in_refb_offs < 512; in_refb_offs += 8)); do + poke_file "$TEST_IMG" $((refb_offs + in_refb_offs)) \ + '\x55\x55\x55\x55\x55\x55\x55\x55' +done + +$QEMU_IO -c 'write -c -P 42 0 2M' "$TEST_IMG" | _filter_qemu_io + +echo +echo '--- Check ---' + +# This should only print the leaked clusters in the first 4 GB +_check_test_img | grep -v '^Leaked cluster ' + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/272.out b/tests/qemu-iotests/272.out new file mode 100644 index 0000000000..35698b0e73 --- /dev/null +++ b/tests/qemu-iotests/272.out @@ -0,0 +1,10 @@ +QA output created by 272 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 2097152/2097152 bytes at offset 0 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +--- Check --- + +2044 leaked clusters were found on the image. +This means waste of disk space, but no harm to data. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 095ed1b880..065040398d 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -283,3 +283,4 @@ 267 rw auto quick snapshot 268 rw auto quick 270 rw backing quick +272 rw diff --git a/tests/tcg/multiarch/linux-test.c b/tests/tcg/multiarch/linux-test.c index fa4243fc04..673d7c8a1c 100644 --- a/tests/tcg/multiarch/linux-test.c +++ b/tests/tcg/multiarch/linux-test.c @@ -503,8 +503,9 @@ static void test_shm(void) shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); ptr = shmat(shmid, NULL, 0); - if (!ptr) + if (ptr == (void *)-1) { error("shmat"); + } memset(ptr, 0, SHM_SIZE); diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 2929de23aa..91a9226026 100755 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -95,19 +95,25 @@ class BaseVM(object): logging.info("KVM not available, not using -enable-kvm") self._data_args = [] - def _download_with_cache(self, url, sha256sum=None): + def _download_with_cache(self, url, sha256sum=None, sha512sum=None): def check_sha256sum(fname): if not sha256sum: return True checksum = subprocess.check_output(["sha256sum", fname]).split()[0] return sha256sum == checksum.decode("utf-8") + def check_sha512sum(fname): + if not sha512sum: + return True + checksum = subprocess.check_output(["sha512sum", fname]).split()[0] + return sha512sum == checksum.decode("utf-8") + cache_dir = os.path.expanduser("~/.cache/qemu-vm/download") if not os.path.exists(cache_dir): os.makedirs(cache_dir) fname = os.path.join(cache_dir, hashlib.sha1(url.encode("utf-8")).hexdigest()) - if os.path.exists(fname) and check_sha256sum(fname): + if os.path.exists(fname) and check_sha256sum(fname) and check_sha512sum(fname): return fname logging.debug("Downloading %s to %s...", url, fname) subprocess.check_call(["wget", "-c", url, "-O", fname + ".download"], @@ -242,6 +248,25 @@ class BaseVM(object): return False return True + def console_consume(self): + vm = self._guest + output = "" + vm.console_socket.setblocking(0) + while True: + try: + chars = vm.console_socket.recv(1) + except: + break + output += chars.decode("latin1") + if "\r" in output or "\n" in output: + lines = re.split("[\r\n]", output) + output = lines.pop() + if self.debug: + self.console_log("\n".join(lines)) + if self.debug: + self.console_log(output) + vm.console_socket.setblocking(1) + def console_send(self, command): vm = self._guest if self.debug: diff --git a/tests/vm/netbsd b/tests/vm/netbsd index 18aa56ae82..611e6cc5b5 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -2,10 +2,11 @@ # # NetBSD VM image # -# Copyright 2017 Red Hat Inc. +# Copyright 2017-2019 Red Hat Inc. # # Authors: # Fam Zheng <famz@redhat.com> +# Gerd Hoffmann <kraxel@redhat.com> # # This code is licensed under the GPL version 2 or later. See # the COPYING file in the top-level directory. @@ -13,20 +14,54 @@ import os import sys +import time import subprocess import basevm class NetBSDVM(basevm.BaseVM): name = "netbsd" arch = "x86_64" + + link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-8.1/images/NetBSD-8.1-amd64.iso" + csum = "718f275b7e0879599bdac95630c5e3f2184700032fdb6cdebf3bdd63687898c48ff3f08f57b89f4437a86cdd8ea07c01a39d432dbb37e1e4b008f4985f98da3f" + size = "20G" + pkgs = [ + # tools + "git-base", + "pkgconf", + "xz", + "python37", + + # gnu tools + "bash", + "gmake", + "gsed", + "flex", "bison", + + # libs: crypto + "gnutls", + + # libs: images + "jpeg", + "png", + + # libs: ui + "SDL2", + "gtk3+", + "libxkbcommon", + ] + BUILD_SCRIPT = """ set -e; - rm -rf /var/tmp/qemu-test.* - cd $(mktemp -d /var/tmp/qemu-test.XXXXXX); + rm -rf /home/qemu/qemu-test.* + cd $(mktemp -d /home/qemu/qemu-test.XXXXXX); + mkdir src build; cd src; tar -xf /dev/rld1a; - ./configure --python=python2.7 {configure_opts}; + cd ../build + ../src/configure --python=python3.7 --disable-opengl {configure_opts}; gmake --output-sync -j{jobs} {target} {verbose}; """ + poweroff = "/sbin/poweroff" # Workaround for NetBSD + IPv6 + slirp issues. # NetBSD seems to ignore the ICMPv6 Destination Unreachable @@ -36,14 +71,147 @@ class NetBSDVM(basevm.BaseVM): ipv6 = False def build_image(self, img): - cimg = self._download_with_cache("http://download.patchew.org/netbsd-7.1-amd64.img.xz", - sha256sum='b633d565b0eac3d02015cd0c81440bd8a7a8df8512615ac1ee05d318be015732') - img_tmp_xz = img + ".tmp.xz" + cimg = self._download_with_cache(self.link, sha512sum=self.csum) img_tmp = img + ".tmp" - sys.stderr.write("Extracting the image...\n") - subprocess.check_call(["ln", "-f", cimg, img_tmp_xz]) - subprocess.check_call(["xz", "--keep", "-dvf", img_tmp_xz]) + iso = img + ".install.iso" + + self.print_step("Preparing iso and disk image") + subprocess.check_call(["ln", "-f", cimg, iso]) + subprocess.check_call(["qemu-img", "create", "-f", "qcow2", + img_tmp, self.size]) + + self.print_step("Booting installer") + self.boot(img_tmp, extra_args = [ + "-bios", "pc-bios/bios-256k.bin", + "-machine", "graphics=off", + "-cdrom", iso + ]) + self.console_init() + self.console_wait("Primary Bootstrap") + + # serial console boot menu output doesn't work for some + # reason, so we have to fly blind ... + for char in list("5consdev com0\n"): + time.sleep(0.2) + self.console_send(char) + self.console_consume() + self.console_wait_send("> ", "boot\n") + + self.console_wait_send("Terminal type", "xterm\n") + self.console_wait_send("a: Installation messages", "a\n") + self.console_wait_send("b: US-English", "b\n") + self.console_wait_send("a: Install NetBSD", "a\n") + self.console_wait("Shall we continue?") + self.console_wait_send("b: Yes", "b\n") + + self.console_wait_send("a: ld0", "a\n") + self.console_wait_send("a: This is the correct", "a\n") + self.console_wait_send("b: Use the entire disk", "b\n") + self.console_wait("NetBSD bootcode") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("b: Use existing part", "b\n") + self.console_wait_send("x: Partition sizes ok", "x\n") + self.console_wait_send("for your NetBSD disk", "\n") + self.console_wait("Shall we continue?") + self.console_wait_send("b: Yes", "b\n") + + self.console_wait_send("b: Use serial port com0", "b\n") + self.console_wait_send("f: Set serial baud rate", "f\n") + self.console_wait_send("a: 9600", "a\n") + self.console_wait_send("x: Exit", "x\n") + + self.console_wait_send("a: Full installation", "a\n") + self.console_wait_send("a: CD-ROM", "a\n") + + self.print_step("Installation started now, this will take a while") + self.console_wait_send("Hit enter to continue", "\n") + + self.console_wait_send("d: Change root password", "d\n") + self.console_wait_send("a: Yes", "a\n") + self.console_wait("New password:") + self.console_send("%s\n" % self.ROOT_PASS) + self.console_wait("New password:") + self.console_send("%s\n" % self.ROOT_PASS) + self.console_wait("Retype new password:") + self.console_send("%s\n" % self.ROOT_PASS) + + self.console_wait_send("o: Add a user", "o\n") + self.console_wait("username") + self.console_send("%s\n" % self.GUEST_USER) + self.console_wait("to group wheel") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("a: /bin/sh", "a\n") + self.console_wait("New password:") + self.console_send("%s\n" % self.GUEST_PASS) + self.console_wait("New password:") + self.console_send("%s\n" % self.GUEST_PASS) + self.console_wait("Retype new password:") + self.console_send("%s\n" % self.GUEST_PASS) + + self.console_wait_send("a: Configure network", "a\n") + self.console_wait_send("a: vioif0", "a\n") + self.console_wait_send("Network media type", "\n") + self.console_wait("autoconfiguration") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("DNS domain", "localnet\n") + self.console_wait("Are they OK?") + self.console_wait_send("a: Yes", "a\n") + self.console_wait("installed in /etc") + self.console_wait_send("a: Yes", "a\n") + + self.console_wait_send("e: Enable install", "e\n") + proxy = os.environ.get("http_proxy") + if not proxy is None: + self.console_wait_send("f: Proxy", "f\n") + self.console_wait("Proxy") + self.console_send("%s\n" % proxy) + self.console_wait_send("x: Install pkgin", "x\n") + self.console_init(1200) + self.console_wait_send("Hit enter to continue", "\n") + self.console_init() + + self.console_wait_send("g: Enable sshd", "g\n") + self.console_wait_send("x: Finished conf", "x\n") + self.console_wait_send("Hit enter to continue", "\n") + + self.print_step("Installation finished, rebooting") + self.console_wait_send("d: Reboot the computer", "d\n") + + # setup qemu user + prompt = "localhost$" + self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_wait_send(prompt, "exit\n") + + # setup root user + prompt = "localhost#" + self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_sshd_config(prompt) + + # setup virtio-blk #1 (tarfile) + self.console_wait(prompt) + self.console_send("echo 'chmod 666 /dev/rld1a' >> /etc/rc.local\n") + + # turn off mprotect (conflicts with tcg) + self.console_wait(prompt) + self.console_send("echo security.pax.mprotect.enabled=0 >> /etc/sysctl.conf\n") + + self.print_step("Configuration finished, rebooting") + self.console_wait_send(prompt, "reboot\n") + self.console_wait("login:") + self.wait_ssh() + + self.print_step("Installing packages") + self.ssh_root_check("pkgin update\n") + self.ssh_root_check("pkgin -y install %s\n" % " ".join(self.pkgs)) + + # shutdown + self.ssh_root(self.poweroff) + self.console_wait("entering state S5") + self.wait() + os.rename(img_tmp, img) + os.remove(iso) + self.print_step("All done") if __name__ == "__main__": sys.exit(basevm.main(NetBSDVM)) |