diff options
85 files changed, 1588 insertions, 911 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index c2a68555ae..363e72a467 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> diff --git a/Makefile b/Makefile index bd6376d295..aa9d1a42aa 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 diff --git a/VERSION b/VERSION index 5f79df70a0..b9d9a6438b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.50 +4.1.90 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..efe165edf9 100755 --- a/configure +++ b/configure @@ -3217,6 +3217,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 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/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/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/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/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/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/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/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/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..ab9d933e53 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,74 @@ 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; + } +#endif /* SOL_NETLINK */ default: unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", @@ -5719,7 +5820,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 +5900,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 +5918,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); } } 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/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/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/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/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/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); |