diff options
65 files changed, 1257 insertions, 892 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> @@ -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/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/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..266d9b534b 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); 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/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 44a3c19326..5d879c471e 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -237,7 +237,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) static void fw_cfg_reboot(FWCfgState *s) { const char *reboot_timeout = NULL; - int64_t rt_val = -1; + uint64_t rt_val = -1; uint32_t rt_le32; /* get user configuration */ @@ -247,10 +247,11 @@ static void fw_cfg_reboot(FWCfgState *s) if (reboot_timeout) { rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1); + /* validate the input */ - if (rt_val < 0 || rt_val > 0xffff) { + if (rt_val > 0xffff && rt_val != (uint64_t)-1) { error_report("reboot timeout is invalid," - "it should be a value between 0 and 65535"); + "it should be a value between -1 and 65535"); exit(1); } } diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 1edc1a31d4..b0aa8351c4 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -28,11 +28,10 @@ config PCI_SABRE select PCI bool -config PCI_PIIX +config PCI_I440FX bool select PCI select PAM - select ISA_BUS config PCI_EXPRESS_Q35 bool diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index a9cd3e022d..efd752b766 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -13,7 +13,7 @@ common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o common-obj-$(CONFIG_PCI_SABRE) += sabre.o common-obj-$(CONFIG_FULONG) += bonito.o -common-obj-$(CONFIG_PCI_PIIX) += piix.o +common-obj-$(CONFIG_PCI_I440FX) += i440fx.o common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o common-obj-$(CONFIG_PCI_EXPRESS_GENERIC_BRIDGE) += gpex.o common-obj-$(CONFIG_PCI_EXPRESS_XILINX) += xilinx-pcie.o diff --git a/hw/pci-host/piix.c b/hw/pci-host/i440fx.c index 135c645535..f27131102d 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/i440fx.c @@ -24,21 +24,14 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" -#include "hw/irq.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" +#include "hw/pci-host/i440fx.h" #include "hw/qdev-properties.h" -#include "hw/isa/isa.h" #include "hw/sysbus.h" #include "qapi/error.h" -#include "qemu/range.h" -#include "hw/xen/xen.h" -#include "migration/qemu-file-types.h" #include "migration/vmstate.h" #include "hw/pci-host/pam.h" -#include "sysemu/reset.h" -#include "sysemu/runstate.h" -#include "hw/i386/ioapic.h" #include "qapi/visitor.h" #include "qemu/error-report.h" @@ -58,50 +51,9 @@ typedef struct I440FXState { uint32_t short_root_bus; } I440FXState; -#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ -#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ -#define XEN_PIIX_NUM_PIRQS 128ULL -#define PIIX_PIRQC 0x60 - -typedef struct PIIX3State { - PCIDevice dev; - - /* - * bitmap to track pic levels. - * The pic level is the logical OR of all the PCI irqs mapped to it - * So one PIC level is tracked by PIIX_NUM_PIRQS bits. - * - * PIRQ is mapped to PIC pins, we track it by - * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with - * pic_irq * PIIX_NUM_PIRQS + pirq - */ -#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 -#error "unable to encode pic state in 64bit in pic_levels." -#endif - uint64_t pic_levels; - - qemu_irq *pic; - - /* This member isn't used. Just for save/load compatibility */ - int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; - - /* Reset Control Register contents */ - uint8_t rcr; - - /* IO memory region for Reset Control Register (RCR_IOPORT) */ - MemoryRegion rcr_mem; -} PIIX3State; - -#define TYPE_PIIX3_PCI_DEVICE "pci-piix3" -#define PIIX3_PCI_DEVICE(obj) \ - OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE) - #define I440FX_PCI_DEVICE(obj) \ OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE) -#define TYPE_PIIX3_DEVICE "PIIX3" -#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" - struct PCII440FXState { /*< private >*/ PCIDevice parent_obj; @@ -128,21 +80,6 @@ struct PCII440FXState { */ #define I440FX_COREBOOT_RAM_SIZE 0x57 -static void piix3_set_irq(void *opaque, int pirq, int level); -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx); -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len); - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (pci_intx + slot_addend) & 3; -} - static void i440fx_update_memory_mappings(PCII440FXState *d) { int i; @@ -174,28 +111,6 @@ static void i440fx_write_config(PCIDevice *dev, } } -static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) -{ - PCII440FXState *d = opaque; - PCIDevice *pd = PCI_DEVICE(d); - int ret, i; - uint8_t smm_enabled; - - ret = pci_device_load(pd, f); - if (ret < 0) - return ret; - i440fx_update_memory_mappings(d); - qemu_get_8s(f, &smm_enabled); - - if (version_id == 2) { - for (i = 0; i < PIIX_NUM_PIRQS; i++) { - qemu_get_be32(f); /* dummy load for compatibility */ - } - } - - return 0; -} - static int i440fx_post_load(void *opaque, int version_id) { PCII440FXState *d = opaque; @@ -208,8 +123,6 @@ static const VMStateDescription vmstate_i440fx = { .name = "I440FX", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = i440fx_load_old, .post_load = i440fx_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState), @@ -358,8 +271,6 @@ static void i440fx_realize(PCIDevice *dev, Error **errp) PCIBus *i440fx_init(const char *host_type, const char *pci_type, PCII440FXState **pi440fx_state, - int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -372,7 +283,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, PCIBus *b; PCIDevice *d; PCIHostState *s; - PIIX3State *piix3; PCII440FXState *f; unsigned i; I440FXState *i440fx; @@ -425,29 +335,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, PAM_EXPAN_SIZE); } - /* Xen supports additional interrupt routes from the PCI devices to - * the IOAPIC: the four pins of each PCI device on the bus are also - * connected to the IOAPIC directly. - * These additional routes can be discovered through ACPI. */ - if (xen_enabled()) { - PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, TYPE_PIIX3_XEN_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); - } else { - PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, TYPE_PIIX3_DEVICE); - piix3 = PIIX3_PCI_DEVICE(pci_dev); - pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, - PIIX_NUM_PIRQS); - pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq); - } - piix3->pic = pic; - *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0")); - - *piix3_devfn = piix3->dev.devfn; - ram_size = ram_size / 8 / 1024 / 1024; if (ram_size > 255) { ram_size = 255; @@ -467,312 +354,6 @@ PCIBus *find_i440fx(void) return s ? s->bus : NULL; } -/* PIIX3 PCI to ISA bridge */ -static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) -{ - qemu_set_irq(piix3->pic[pic_irq], - !!(piix3->pic_levels & - (((1ULL << PIIX_NUM_PIRQS) - 1) << - (pic_irq * PIIX_NUM_PIRQS)))); -} - -static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level) -{ - int pic_irq; - uint64_t mask; - - pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { - return; - } - - mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); - piix3->pic_levels &= ~mask; - piix3->pic_levels |= mask * !!level; -} - -static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) -{ - int pic_irq; - - pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { - return; - } - - piix3_set_irq_level_internal(piix3, pirq, level); - - piix3_set_irq_pic(piix3, pic_irq); -} - -static void piix3_set_irq(void *opaque, int pirq, int level) -{ - PIIX3State *piix3 = opaque; - piix3_set_irq_level(piix3, pirq, level); -} - -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) -{ - PIIX3State *piix3 = opaque; - int irq = piix3->dev.config[PIIX_PIRQC + pin]; - PCIINTxRoute route; - - if (irq < PIIX_NUM_PIC_IRQS) { - route.mode = PCI_INTX_ENABLED; - route.irq = irq; - } else { - route.mode = PCI_INTX_DISABLED; - route.irq = -1; - } - return route; -} - -/* irq routing is changed. so rebuild bitmap */ -static void piix3_update_irq_levels(PIIX3State *piix3) -{ - PCIBus *bus = pci_get_bus(&piix3->dev); - int pirq; - - piix3->pic_levels = 0; - for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq)); - } -} - -static void piix3_write_config(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - pci_default_write_config(dev, address, val, len); - if (ranges_overlap(address, len, PIIX_PIRQC, 4)) { - PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev); - int pic_irq; - - pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev)); - piix3_update_irq_levels(piix3); - for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { - piix3_set_irq_pic(piix3, pic_irq); - } - } -} - -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - xen_piix_pci_write_config_client(address, val, len); - piix3_write_config(dev, address, val, len); -} - -static void piix3_reset(void *opaque) -{ - PIIX3State *d = opaque; - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; /* master, memory and I/O */ - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */ - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x61] = 0x80; - pci_conf[0x62] = 0x80; - pci_conf[0x63] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; - - d->pic_levels = 0; - d->rcr = 0; -} - -static int piix3_post_load(void *opaque, int version_id) -{ - PIIX3State *piix3 = opaque; - int pirq; - - /* Because the i8259 has not been deserialized yet, qemu_irq_raise - * might bring the system to a different state than the saved one; - * for example, the interrupt could be masked but the i8259 would - * not know that yet and would trigger an interrupt in the CPU. - * - * Here, we update irq levels without raising the interrupt. - * Interrupt state will be deserialized separately through the i8259. - */ - piix3->pic_levels = 0; - for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level_internal(piix3, pirq, - pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq)); - } - return 0; -} - -static int piix3_pre_save(void *opaque) -{ - int i; - PIIX3State *piix3 = opaque; - - for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { - piix3->pci_irq_levels_vmstate[i] = - pci_bus_get_irq_level(pci_get_bus(&piix3->dev), i); - } - - return 0; -} - -static bool piix3_rcr_needed(void *opaque) -{ - PIIX3State *piix3 = opaque; - - return (piix3->rcr != 0); -} - -static const VMStateDescription vmstate_piix3_rcr = { - .name = "PIIX3/rcr", - .version_id = 1, - .minimum_version_id = 1, - .needed = piix3_rcr_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT8(rcr, PIIX3State), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_piix3 = { - .name = "PIIX3", - .version_id = 3, - .minimum_version_id = 2, - .post_load = piix3_post_load, - .pre_save = piix3_pre_save, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PIIX3State), - VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, - PIIX_NUM_PIRQS, 3), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_piix3_rcr, - NULL - } -}; - - -static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) -{ - PIIX3State *d = opaque; - - if (val & 4) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - return; - } - d->rcr = val & 2; /* keep System Reset type only */ -} - -static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) -{ - PIIX3State *d = opaque; - - return d->rcr; -} - -static const MemoryRegionOps rcr_ops = { - .read = rcr_read, - .write = rcr_write, - .endianness = DEVICE_LITTLE_ENDIAN -}; - -static void piix3_realize(PCIDevice *dev, Error **errp) -{ - PIIX3State *d = PIIX3_PCI_DEVICE(dev); - - if (!isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(dev), errp)) { - return; - } - - memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d, - "piix3-reset-control", 1); - memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT, - &d->rcr_mem, 1); - - qemu_register_reset(piix3_reset, d); -} - -static void pci_piix3_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix3; - dc->hotpluggable = false; - k->realize = piix3_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; - /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; - k->class_id = PCI_CLASS_BRIDGE_ISA; - /* - * Reason: part of PIIX3 southbridge, needs to be wired up by - * pc_piix.c's pc_init1() - */ - dc->user_creatable = false; -} - -static const TypeInfo piix3_pci_type_info = { - .name = TYPE_PIIX3_PCI_DEVICE, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX3State), - .abstract = true, - .class_init = pci_piix3_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, -}; - -static void piix3_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->config_write = piix3_write_config; -} - -static const TypeInfo piix3_info = { - .name = TYPE_PIIX3_DEVICE, - .parent = TYPE_PIIX3_PCI_DEVICE, - .class_init = piix3_class_init, -}; - -static void piix3_xen_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->config_write = piix3_write_config_xen; -}; - -static const TypeInfo piix3_xen_info = { - .name = TYPE_PIIX3_XEN_DEVICE, - .parent = TYPE_PIIX3_PCI_DEVICE, - .class_init = piix3_xen_class_init, -}; - static void i440fx_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -934,9 +515,6 @@ static void i440fx_register_types(void) { type_register_static(&i440fx_info); type_register_static(&igd_passthrough_i440fx_info); - type_register_static(&piix3_pci_type_info); - type_register_static(&piix3_info); - type_register_static(&piix3_xen_info); type_register_static(&i440fx_pcihost_info); } diff --git a/hw/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/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/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 ee4a099e25..65c9473b73 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1551,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/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/fw_cfg-test.c b/tests/fw_cfg-test.c index 1d3147f821..5dc807ba23 100644 --- a/tests/fw_cfg-test.c +++ b/tests/fw_cfg-test.c @@ -194,6 +194,26 @@ static void test_fw_cfg_reboot_timeout(void) qtest_quit(s); } +static void test_fw_cfg_no_reboot_timeout(void) +{ + QFWCFG *fw_cfg; + QTestState *s; + uint32_t reboot_timeout = 0; + size_t filesize; + + /* Special value -1 means "don't reboot" */ + s = qtest_init("-boot reboot-timeout=-1"); + fw_cfg = pc_fw_cfg_init(s); + + filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait", + &reboot_timeout, sizeof(reboot_timeout)); + g_assert_cmpint(filesize, ==, sizeof(reboot_timeout)); + reboot_timeout = le32_to_cpu(reboot_timeout); + g_assert_cmpint(reboot_timeout, ==, UINT32_MAX); + pc_fw_cfg_uninit(fw_cfg); + qtest_quit(s); +} + static void test_fw_cfg_splash_time(void) { QFWCFG *fw_cfg; @@ -233,6 +253,7 @@ int main(int argc, char **argv) qtest_add_func("fw_cfg/numa", test_fw_cfg_numa); qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu); qtest_add_func("fw_cfg/reboot_timeout", test_fw_cfg_reboot_timeout); + qtest_add_func("fw_cfg/no_reboot_timeout", test_fw_cfg_no_reboot_timeout); qtest_add_func("fw_cfg/splash_time", test_fw_cfg_splash_time); return g_test_run(); diff --git a/tests/image-fuzzer/qcow2/__init__.py b/tests/image-fuzzer/qcow2/__init__.py index 09ef59821b..ed3af5da86 100644 --- a/tests/image-fuzzer/qcow2/__init__.py +++ b/tests/image-fuzzer/qcow2/__init__.py @@ -1,2 +1 @@ -from __future__ import absolute_import from .layout import create_image diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py index abc4f0635d..c58bf11005 100644 --- a/tests/image-fuzzer/qcow2/fuzz.py +++ b/tests/image-fuzzer/qcow2/fuzz.py @@ -27,20 +27,20 @@ UINT64 = 0xffffffffffffffff UINT32_M = 31 UINT64_M = 63 # Fuzz vectors -UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1, +UINT8_V = [0, 0x10, UINT8//4, UINT8//2 - 1, UINT8//2, UINT8//2 + 1, UINT8 - 1, UINT8] -UINT16_V = [0, 0x100, 0x1000, UINT16/4, UINT16/2 - 1, UINT16/2, UINT16/2 + 1, +UINT16_V = [0, 0x100, 0x1000, UINT16//4, UINT16//2 - 1, UINT16//2, UINT16//2 + 1, UINT16 - 1, UINT16] -UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1, - UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32] -UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4, - UINT64/2 - 1, UINT64/2, UINT64/2 + 1, UINT64 - 1, +UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32//4, UINT32//2 - 1, + UINT32//2, UINT32//2 + 1, UINT32 - 1, UINT32] +UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64//4, + UINT64//2 - 1, UINT64//2, UINT64//2 + 1, UINT64 - 1, UINT64] -STRING_V = ['%s%p%x%d', '.1024d', '%.2049d', '%p%p%p%p', '%x%x%x%x', - '%d%d%d%d', '%s%s%s%s', '%99999999999s', '%08x', '%%20d', '%%20n', - '%%20x', '%%20s', '%s%s%s%s%s%s%s%s%s%s', '%p%p%p%p%p%p%p%p%p%p', - '%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', - '%s x 129', '%x x 257'] +BYTES_V = [b'%s%p%x%d', b'.1024d', b'%.2049d', b'%p%p%p%p', b'%x%x%x%x', + b'%d%d%d%d', b'%s%s%s%s', b'%99999999999s', b'%08x', b'%%20d', b'%%20n', + b'%%20x', b'%%20s', b'%s%s%s%s%s%s%s%s%s%s', b'%p%p%p%p%p%p%p%p%p%p', + b'%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', + b'%s x 129', b'%x x 257'] def random_from_intervals(intervals): @@ -76,12 +76,12 @@ def random_bits(bit_ranges): return val -def truncate_string(strings, length): - """Return strings truncated to specified length.""" - if type(strings) == list: - return [s[:length] for s in strings] +def truncate_bytes(sequences, length): + """Return sequences truncated to specified length.""" + if type(sequences) == list: + return [s[:length] for s in sequences] else: - return strings[:length] + return sequences[:length] def validator(current, pick, choices): @@ -110,12 +110,12 @@ def bit_validator(current, bit_ranges): return validator(current, random_bits, bit_ranges) -def string_validator(current, strings): - """Return a random string value from the list not equal to the current. +def bytes_validator(current, sequences): + """Return a random bytes value from the list not equal to the current. This function is useful for selection from valid values except current one. """ - return validator(current, random.choice, strings) + return validator(current, random.choice, sequences) def selector(current, constraints, validate=int_validator): @@ -283,9 +283,9 @@ def header_length(current): def bf_name(current): """Fuzz the backing file name.""" constraints = [ - truncate_string(STRING_V, len(current)) + truncate_bytes(BYTES_V, len(current)) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def ext_magic(current): @@ -303,10 +303,10 @@ def ext_length(current): def bf_format(current): """Fuzz backing file format in the corresponding header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, (len(current) + 7) & ~7) # Fuzz padding + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, (len(current) + 7) & ~7) # Fuzz padding ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def feature_type(current): @@ -324,10 +324,10 @@ def feature_bit_number(current): def feature_name(current): """Fuzz feature name field of a feature name table header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, 46) # Fuzz padding (field length = 46) + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, 46) # Fuzz padding (field length = 46) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def l1_entry(current): diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py index 675877da96..57ebe86e9a 100644 --- a/tests/image-fuzzer/qcow2/layout.py +++ b/tests/image-fuzzer/qcow2/layout.py @@ -16,7 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import absolute_import import random import struct from . import fuzz @@ -53,8 +52,8 @@ class Field(object): return iter([self.fmt, self.offset, self.value, self.name]) def __repr__(self): - return "Field(fmt='%s', offset=%d, value=%s, name=%s)" % \ - (self.fmt, self.offset, str(self.value), self.name) + return "Field(fmt=%r, offset=%r, value=%r, name=%r)" % \ + (self.fmt, self.offset, self.value, self.name) class FieldsList(object): @@ -122,7 +121,7 @@ class Image(object): def create_header(self, cluster_bits, backing_file_name=None): """Generate a random valid header.""" meta_header = [ - ['>4s', 0, "QFI\xfb", 'magic'], + ['>4s', 0, b"QFI\xfb", 'magic'], ['>I', 4, random.randint(2, 3), 'version'], ['>Q', 8, 0, 'backing_file_offset'], ['>I', 16, 0, 'backing_file_size'], @@ -231,7 +230,7 @@ class Image(object): feature_tables = [] feature_ids = [] inner_offset = self.ext_offset + ext_header_len - feat_name = 'some cool feature' + feat_name = b'some cool feature' while len(feature_tables) < num_fnt_entries * 3: feat_type, feat_bit = gen_feat_ids() # Remove duplicates @@ -253,7 +252,7 @@ class Image(object): ['>I', self.ext_offset, 0x6803f857, 'ext_magic'], # One feature table contains 3 fields and takes 48 bytes ['>I', self.ext_offset + UINT32_S, - len(feature_tables) / 3 * 48, 'ext_length'] + len(feature_tables) // 3 * 48, 'ext_length'] ] + feature_tables) self.ext_offset = inner_offset @@ -271,7 +270,7 @@ class Image(object): def create_l2_entry(host, guest, l2_cluster): """Generate one L2 entry.""" offset = l2_cluster * self.cluster_size - l2_size = self.cluster_size / UINT64_S + l2_size = self.cluster_size // UINT64_S entry_offset = offset + UINT64_S * (guest % l2_size) cluster_descriptor = host * self.cluster_size if not self.header['version'][0].value == 2: @@ -283,8 +282,8 @@ class Image(object): def create_l1_entry(l2_cluster, l1_offset, guest): """Generate one L1 entry.""" - l2_size = self.cluster_size / UINT64_S - entry_offset = l1_offset + UINT64_S * (guest / l2_size) + l2_size = self.cluster_size // UINT64_S + entry_offset = l1_offset + UINT64_S * (guest // l2_size) # While snapshots are not supported bit #63 = 1 entry_val = (1 << 63) + l2_cluster * self.cluster_size return ['>Q', entry_offset, entry_val, 'l1_entry'] @@ -298,11 +297,11 @@ class Image(object): l2 = [] else: meta_data = self._get_metadata() - guest_clusters = random.sample(range(self.image_size / + guest_clusters = random.sample(range(self.image_size // self.cluster_size), len(self.data_clusters)) # Number of entries in a L1/L2 table - l_size = self.cluster_size / UINT64_S + l_size = self.cluster_size // UINT64_S # Number of clusters necessary for L1 table l1_size = int(ceil((max(guest_clusters) + 1) / float(l_size**2))) l1_start = self._get_adjacent_clusters(self.data_clusters | @@ -318,7 +317,7 @@ class Image(object): # L2 entries l2 = [] for host, guest in zip(self.data_clusters, guest_clusters): - l2_id = guest / l_size + l2_id = guest // l_size if l2_id not in l2_ids: l2_ids.append(l2_id) l2_clusters.append(self._get_adjacent_clusters( @@ -339,14 +338,14 @@ class Image(object): def allocate_rfc_blocks(data, size): """Return indices of clusters allocated for refcount blocks.""" cluster_ids = set() - diff = block_ids = set([x / size for x in data]) + diff = block_ids = set([x // size for x in data]) while len(diff) != 0: # Allocate all yet not allocated clusters new = self._get_available_clusters(data | cluster_ids, len(diff)) # Indices of new refcount blocks necessary to cover clusters # in 'new' - diff = set([x / size for x in new]) - block_ids + diff = set([x // size for x in new]) - block_ids cluster_ids |= new block_ids |= diff return cluster_ids, block_ids @@ -359,7 +358,7 @@ class Image(object): blocks = set(init_blocks) clusters = set() # Number of entries in one cluster of the refcount table - size = self.cluster_size / UINT64_S + size = self.cluster_size // UINT64_S # Number of clusters necessary for the refcount table based on # the current number of refcount blocks table_size = int(ceil((max(blocks) + 1) / float(size))) @@ -373,7 +372,7 @@ class Image(object): table_size + 1)) # New refcount blocks necessary for clusters occupied by the # refcount table - diff = set([c / block_size for c in table_clusters]) - blocks + diff = set([c // block_size for c in table_clusters]) - blocks blocks |= diff while len(diff) != 0: # Allocate clusters for new refcount blocks @@ -382,12 +381,12 @@ class Image(object): len(diff)) # Indices of new refcount blocks necessary to cover # clusters in 'new' - diff = set([x / block_size for x in new]) - blocks + diff = set([x // block_size for x in new]) - blocks clusters |= new blocks |= diff # Check if the refcount table needs one more cluster if int(ceil((max(blocks) + 1) / float(size))) > table_size: - new_block_id = (table_start + table_size) / block_size + new_block_id = (table_start + table_size) // block_size # Check if the additional table cluster needs # one more refcount block if new_block_id not in blocks: @@ -399,13 +398,13 @@ class Image(object): def create_table_entry(table_offset, block_cluster, block_size, cluster): """Generate a refcount table entry.""" - offset = table_offset + UINT64_S * (cluster / block_size) + offset = table_offset + UINT64_S * (cluster // block_size) return ['>Q', offset, block_cluster * self.cluster_size, 'refcount_table_entry'] def create_block_entry(block_cluster, block_size, cluster): """Generate a list of entries for the current block.""" - entry_size = self.cluster_size / block_size + entry_size = self.cluster_size // block_size offset = block_cluster * self.cluster_size entry_offset = offset + entry_size * (cluster % block_size) # While snapshots are not supported all refcounts are set to 1 @@ -415,7 +414,7 @@ class Image(object): # Number of refcount entries per refcount block # Convert self.cluster_size from bytes to bits to have the same # base for the numerator and denominator - block_size = self.cluster_size * 8 / refcount_bits + block_size = self.cluster_size * 8 // refcount_bits meta_data = self._get_metadata() if len(self.data_clusters) == 0: # All metadata for an empty guest image needs 4 clusters: @@ -452,8 +451,8 @@ class Image(object): rfc_blocks = [] for cluster in sorted(self.data_clusters | meta_data): - if cluster / block_size != block_id: - block_id = cluster / block_size + if cluster // block_size != block_id: + block_id = cluster // block_size block_cluster = block_clusters[block_ids.index(block_id)] rfc_table.append(create_table_entry(table_offset, block_cluster, @@ -503,7 +502,7 @@ class Image(object): def write(self, filename): """Write an entire image to the file.""" - image_file = open(filename, 'w') + image_file = open(filename, 'wb') for field in self: image_file.seek(field.offset) image_file.write(struct.pack(field.fmt, field.value)) @@ -518,7 +517,7 @@ class Image(object): rounded = (size + self.cluster_size - 1) & ~(self.cluster_size - 1) if rounded > size: image_file.seek(rounded - 1) - image_file.write("\0") + image_file.write(b'\x00') image_file.close() @staticmethod @@ -587,7 +586,7 @@ class Image(object): def _alloc_data(img_size, cluster_size): """Return a set of random indices of clusters allocated for guest data. """ - num_of_cls = img_size/cluster_size + num_of_cls = img_size // cluster_size return set(random.sample(range(1, num_of_cls + 1), random.randint(0, num_of_cls))) @@ -595,15 +594,15 @@ class Image(object): """Return indices of clusters allocated for image metadata.""" ids = set() for x in self: - ids.add(x.offset/self.cluster_size) + ids.add(x.offset // self.cluster_size) return ids def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None, fields_to_fuzz=None): """Create a fuzzed image and write it to the specified file.""" - image = Image(backing_file_name) - image.set_backing_file_format(backing_file_fmt) + image = Image(backing_file_name.encode()) + image.set_backing_file_format(backing_file_fmt.encode()) image.create_feature_name_table() image.set_end_of_extension_area() image.create_l_structures() diff --git a/tests/image-fuzzer/runner.py b/tests/image-fuzzer/runner.py index 95d84f38f3..2fc010fd9d 100755 --- a/tests/image-fuzzer/runner.py +++ b/tests/image-fuzzer/runner.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Tool for running fuzz tests # @@ -18,7 +18,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import print_function import sys import os import signal @@ -28,7 +27,7 @@ import shutil from itertools import count import time import getopt -import StringIO +import io import resource try: @@ -80,7 +79,8 @@ def run_app(fd, q_args): devnull = open('/dev/null', 'r+') process = subprocess.Popen(q_args, stdin=devnull, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + errors='replace') try: out, err = process.communicate() signal.alarm(0) @@ -159,7 +159,7 @@ class TestEnv(object): os.makedirs(self.current_dir) except OSError as e: print("Error: The working directory '%s' cannot be used. Reason: %s"\ - % (self.work_dir, e[1]), file=sys.stderr) + % (self.work_dir, e.strerror), file=sys.stderr) raise TestException self.log = open(os.path.join(self.current_dir, "test.log"), "w") self.parent_log = open(run_log, "a") @@ -183,7 +183,7 @@ class TestEnv(object): MAX_BACKING_FILE_SIZE) * (1 << 20) cmd = self.qemu_img + ['create', '-f', backing_file_fmt, backing_file_name, str(backing_file_size)] - temp_log = StringIO.StringIO() + temp_log = io.StringIO() retcode = run_app(temp_log, cmd) if retcode == 0: temp_log.close() @@ -240,13 +240,13 @@ class TestEnv(object): "Backing file: %s\n" \ % (self.seed, " ".join(current_cmd), self.current_dir, backing_file_name) - temp_log = StringIO.StringIO() + temp_log = io.StringIO() try: retcode = run_app(temp_log, current_cmd) except OSError as e: multilog("%sError: Start of '%s' failed. Reason: %s\n\n" % (test_summary, os.path.basename(current_cmd[0]), - e[1]), + e.strerror), sys.stderr, self.log, self.parent_log) raise TestException diff --git a/tests/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); |