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
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>
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
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
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,
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)
(req->bytes == req->overlap_bytes);
}
+/**
+ * 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
*/
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;
* 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) {
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));
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);
}
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);
}
/* 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,
* 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");
#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"
#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"
#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"
#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"
}
};
-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;
.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),
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;
select PC_PCI
select PC_ACPI
select ACPI_SMBUS
- select PCI_PIIX
+ select PCI_I440FX
+ select PIIX3
select IDE_PIIX
select DIMM
select SMBIOS
#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"
#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"
/* 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);
*/
#define IOAPIC_SB_DEVID (uint64_t)PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0))
+/*
+ * Insert IVHD entry for device and recurse, insert alias, or insert range as
+ * necessary for the PCI topology.
+ */
+static void
+insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque)
+{
+ GArray *table_data = opaque;
+ uint32_t entry;
+
+ /* "Select" IVHD entry, type 0x2 */
+ entry = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn) << 8 | 0x2;
+ build_append_int_noprefix(table_data, entry, 4);
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
+ PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
+ uint8_t sec = pci_bus_num(sec_bus);
+ uint8_t sub = dev->config[PCI_SUBORDINATE_BUS];
+
+ if (pci_bus_is_express(sec_bus)) {
+ /*
+ * Walk the bus if there are subordinates, otherwise use a range
+ * to cover an entire leaf bus. We could potentially also use a
+ * range for traversed buses, but we'd need to take care not to
+ * create both Select and Range entries covering the same device.
+ * This is easier and potentially more compact.
+ *
+ * An example bare metal system seems to use Select entries for
+ * root ports without a slot (ie. built-ins) and Range entries
+ * when there is a slot. The same system also only hard-codes
+ * the alias range for an onboard PCIe-to-PCI bridge, apparently
+ * making no effort to support nested bridges. We attempt to
+ * be more thorough here.
+ */
+ if (sec == sub) { /* leaf bus */
+ /* "Start of Range" IVHD entry, type 0x3 */
+ entry = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)) << 8 | 0x3;
+ build_append_int_noprefix(table_data, entry, 4);
+ /* "End of Range" IVHD entry, type 0x4 */
+ entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
+ build_append_int_noprefix(table_data, entry, 4);
+ } else {
+ pci_for_each_device(sec_bus, sec, insert_ivhd, table_data);
+ }
+ } else {
+ /*
+ * If the secondary bus is conventional, then we need to create an
+ * Alias range for everything downstream. The range covers the
+ * first devfn on the secondary bus to the last devfn on the
+ * subordinate bus. The alias target depends on legacy versus
+ * express bridges, just as in pci_device_iommu_address_space().
+ * DeviceIDa vs DeviceIDb as per the AMD IOMMU spec.
+ */
+ uint16_t dev_id_a, dev_id_b;
+
+ dev_id_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0));
+
+ if (pci_is_express(dev) &&
+ pcie_cap_get_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) {
+ dev_id_b = dev_id_a;
+ } else {
+ dev_id_b = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn);
+ }
+
+ /* "Alias Start of Range" IVHD entry, type 0x43, 8 bytes */
+ build_append_int_noprefix(table_data, dev_id_a << 8 | 0x43, 4);
+ build_append_int_noprefix(table_data, dev_id_b << 8 | 0x0, 4);
+
+ /* "End of Range" IVHD entry, type 0x4 */
+ entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4;
+ build_append_int_noprefix(table_data, entry, 4);
+ }
+ }
+}
+
+/* For all PCI host bridges, walk and insert IVHD entries */
+static int
+ivrs_host_bridges(Object *obj, void *opaque)
+{
+ GArray *ivhd_blob = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
+ PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
+
+ if (bus) {
+ pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob);
+ }
+ }
+
+ return 0;
+}
+
static void
build_amd_iommu(GArray *table_data, BIOSLinker *linker)
{
- int ivhd_table_len = 28;
+ int ivhd_table_len = 24;
int iommu_start = table_data->len;
AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());
+ GArray *ivhd_blob = g_array_new(false, true, 1);
/* IVRS header */
acpi_data_push(table_data, sizeof(AcpiTableHeader));
(1UL << 7), /* PPRSup */
1);
+ /*
+ * A PCI bus walk, for each PCI host bridge, is necessary to create a
+ * complete set of IVHD entries. Do this into a separate blob so that we
+ * can calculate the total IVRS table length here and then append the new
+ * blob further below. Fall back to an entry covering all devices, which
+ * is sufficient when no aliases are present.
+ */
+ object_child_foreach_recursive(object_get_root(),
+ ivrs_host_bridges, ivhd_blob);
+
+ if (!ivhd_blob->len) {
+ /*
+ * Type 1 device entry reporting all devices
+ * These are 4-byte device entries currently reporting the range of
+ * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
+ */
+ build_append_int_noprefix(ivhd_blob, 0x0000001, 4);
+ }
+
+ ivhd_table_len += ivhd_blob->len;
+
/*
* When interrupt remapping is supported, we add a special IVHD device
* for type IO-APIC.
if (x86_iommu_ir_supported(x86_iommu_get_default())) {
ivhd_table_len += 8;
}
+
/* IVHD length */
build_append_int_noprefix(table_data, ivhd_table_len, 2);
/* DeviceID */
(1UL << 2) | /* GTSup */
(1UL << 6), /* GASup */
4);
- /*
- * Type 1 device entry reporting all devices
- * These are 4-byte device entries currently reporting the range of
- * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte)
- */
- build_append_int_noprefix(table_data, 0x0000001, 4);
+
+ /* IVHD entries as found above */
+ g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len);
+ g_array_free(ivhd_blob, TRUE);
/*
* Add a special IVHD device type.
#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"
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;
#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"
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);
}
}
}
#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;
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)
.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,
select FDC
select IDE_ISA
+config PIIX3
+ bool
+ select ISA_BUS
+
config PIIX4
bool
# For historical reasons, SuperIO devices are created in the board
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
--- /dev/null
+/*
+ * 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;
+}
* 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
*/
#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)
}
};
+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)
.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 },
}
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;
+}
#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
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;
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);
#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"
/* 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];
}
}
#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"
#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"
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;
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;
/* 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);
select PCI
bool
-config PCI_PIIX
+config PCI_I440FX
bool
select PCI
select PAM
- select ISA_BUS
config PCI_EXPRESS_Q35
bool
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
#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"
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;
*/
#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;
}
}
-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;
.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),
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,
PCIBus *b;
PCIDevice *d;
PCIHostState *s;
- PIIX3State *piix3;
PCII440FXState *f;
unsigned i;
I440FXState *i440fx;
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;
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);
{
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);
}
{
PCIBus *bus = pci_get_bus(dev);
PCIBus *iommu_bus = bus;
+ uint8_t devfn = dev->devfn;
- while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
- iommu_bus = pci_get_bus(iommu_bus->parent_dev);
+ while (iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) {
+ PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev);
+
+ /*
+ * The requester ID of the provided device may be aliased, as seen from
+ * the IOMMU, due to topology limitations. The IOMMU relies on a
+ * requester ID to provide a unique AddressSpace for devices, but
+ * conventional PCI buses pre-date such concepts. Instead, the PCIe-
+ * to-PCI bridge creates and accepts transactions on behalf of down-
+ * stream devices. When doing so, all downstream devices are masked
+ * (aliased) behind a single requester ID. The requester ID used
+ * depends on the format of the bridge devices. Proper PCIe-to-PCI
+ * bridges, with a PCIe capability indicating such, follow the
+ * guidelines of chapter 2.3 of the PCIe-to-PCI/X bridge specification,
+ * where the bridge uses the seconary bus as the bridge portion of the
+ * requester ID and devfn of 00.0. For other bridges, typically those
+ * found on the root complex such as the dmi-to-pci-bridge, we follow
+ * the convention of typical bare-metal hardware, which uses the
+ * requester ID of the bridge itself. There are device specific
+ * exceptions to these rules, but these are the defaults that the
+ * Linux kernel uses when determining DMA aliases itself and believed
+ * to be true for the bare metal equivalents of the devices emulated
+ * in QEMU.
+ */
+ if (!pci_bus_is_express(iommu_bus)) {
+ PCIDevice *parent = iommu_bus->parent_dev;
+
+ if (pci_is_express(parent) &&
+ pcie_cap_get_type(parent) == PCI_EXP_TYPE_PCI_BRIDGE) {
+ devfn = PCI_DEVFN(0, 0);
+ bus = iommu_bus;
+ } else {
+ devfn = parent->devfn;
+ bus = parent_bus;
+ }
+ }
+
+ iommu_bus = parent_bus;
}
if (iommu_bus && iommu_bus->iommu_fn) {
- return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
+ return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn);
}
return &address_space_memory;
}
#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 */
}
};
-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;
.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[]) {
k->ioeventfd_assign(proxy, notifier, n, false);
}
+ if (r == 0) {
+ virtio_queue_set_host_notifier_enabled(vq, assign);
+ }
+
return r;
}
VirtIODevice *vdev;
EventNotifier guest_notifier;
EventNotifier host_notifier;
+ bool host_notifier_enabled;
QLIST_ENTRY(VirtQueue) node;
};
}
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
- if (vq->handle_aio_output) {
+ if (vq->host_notifier_enabled) {
event_notifier_set(&vq->host_notifier);
} else if (vq->handle_output) {
vq->handle_output(vdev, vq);
vdev->vq[i].vector = VIRTIO_NO_VECTOR;
vdev->vq[i].vdev = vdev;
vdev->vq[i].queue_index = i;
+ vdev->vq[i].host_notifier_enabled = false;
}
vdev->name = name;
return &vq->host_notifier;
}
+void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled)
+{
+ vq->host_notifier_enabled = enabled;
+}
+
int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n,
MemoryRegion *mr, bool assign)
{
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);
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,
+++ /dev/null
-#ifndef HW_ACPI_PIIX4_H
-#define HW_ACPI_PIIX4_H
-
-#define TYPE_PIIX4_PM "PIIX4_PM"
-
-#endif
#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);
*/
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);
return ISA_BUS(qdev_get_parent_bus(DEVICE(d)));
}
+#define TYPE_PIIX4_PCI_DEVICE "piix4-isa"
+
#endif
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
void virtio_device_release_ioeventfd(VirtIODevice *vdev);
bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
+void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
void virtio_queue_host_notifier_read(EventNotifier *n);
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,
VirtIOHandleAIOOutput handle_output);
#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;
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
#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)
}
#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;
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)) {
#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;
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;
#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;
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;
#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;
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);
#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;
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);
#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;
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;
#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;
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;
#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;
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)
{
/*
#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);
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);
#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;
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)
#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;
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;
#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;
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;
#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;
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;
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;
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)
__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,
}
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 */
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 */
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;
__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:
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;
}
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;
__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;
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;
}
__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) {
#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)
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
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);
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",
/* 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;
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
if (flags & CLONE_CHILD_CLEARTID)
ts->child_tidptr = child_tidptr;
} else {
+ cpu_clone_regs_parent(env, flags);
fork_end(0);
}
}
#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;
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;
#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;
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;
"-audiodev pa,id=id[,prop[=value][,...]]\n"
" server= PulseAudio server address\n"
" in|out.name= source/sink device name\n"
+ " in|out.latency= desired latency in microseconds\n"
#endif
#ifdef CONFIG_AUDIO_SDL
"-audiodev sdl,id=id[,prop[=value][,...]]\n"
@item in|out.name=@var{sink}
Use the specified source/sink for recording/playback.
+@item in|out.latency=@var{usecs}
+Desired latency in microseconds. The PulseAudio server will try to honor this
+value but actual latencies may be lower or higher.
+
@end table
@item -audiodev sdl,id=@var{id}[,@var{prop}[=@var{value}][,...]]
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
"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) {
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;
}
"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;
#!/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"
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
#include "qemu/osdep.h"
-#include "hw/i386/pc.h"
+#include "hw/pci-host/i440fx.h"
+
PCIBus *find_i440fx(void)
{
return NULL;
/*#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
-from __future__ import absolute_import
from .layout import create_image
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):
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):
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):
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):
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):
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):
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-from __future__ import absolute_import
import random
import struct
from . import fuzz
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):
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'],
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
['>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
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:
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']
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 |
# 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(
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
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)))
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
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:
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
# 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:
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,
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))
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
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)))
"""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()
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Tool for running fuzz tests
#
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-from __future__ import print_function
import sys
import os
import signal
from itertools import count
import time
import getopt
-import StringIO
+import io
import resource
try:
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)
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")
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()
"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
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);